one-click-accessibility/classes/database/table.php
Raz Ohad ded7beb67b
Release/v3.0.0 (#200)
* Bump WP version

* ♻️ Initial Refactor commit [APP-687] (#109)

* Initial refactor commit

*  Added build and tests CI/CD

* PR Rejects

* Rejects leftover

* Setup base (#110)

* Initial refactor commit

*  Added build and tests CI/CD

* update: add src for admin settings

* update: incorrect constant names

* update: namespace

* add: accessibility settings

* update: webpack to output files inside a folder

* update: build output folders

* update: removed commented code

* update: npm scripts

* add: webpack config

* add: hooks

* update: move admin setting to the module folder

* update: assets loading logic

* update: settings variable

* update: removed duplicate css import

* Update modules/settings/assets/js/api/index.js

Co-authored-by: VasylD <vasyld@elementor.red>

---------

Co-authored-by: Ohad <ohad@elementor.com>
Co-authored-by: VasylD <vasyld@elementor.red>

* [Infra]  updated Github actions (#114)

* updated github actions

* removed composer github auth

* PHPCS

* removed package-lock.json from ignore to allow `npm ci`

* added missing husky

* ignore legacy

* removed unused non existing import

* Add connect modal (#111)

* Initial refactor commit

*  Added build and tests CI/CD

* update: add src for admin settings

* update: incorrect constant names

* update: namespace

* add: accessibility settings

* update: webpack to output files inside a folder

* update: build output folders

* update: removed commented code

* update: npm scripts

* add: webpack config

* add: hooks

* update: move admin setting to the module folder

* update: assets loading logic

* update: add rule to move jsx props to multiline imporving readability

* add: connect modal

* update: hooks import for better readability

* update: replace functions with hooks

* fix: alignment and style

* update: imports

* update: removed conflicting imports

* fix: add compatibility for mobile devices

---------

Co-authored-by: Ohad <ohad@elementor.com>

* [APP 705] add connect module, settings and notification component (#112)

* Initial refactor commit

*  Added build and tests CI/CD

* update: add src for admin settings

* update: incorrect constant names

* update: namespace

* add: accessibility settings

* update: webpack to output files inside a folder

* update: build output folders

* update: removed commented code

* update: npm scripts

* add: webpack config

* add: hooks

* update: move admin setting to the module folder

* update: assets loading logic

* update: add rule to move jsx props to multiline imporving readability

* add: connect modal

* update: hooks import for better readability

* update: replace functions with hooks

* add: connect module

* add: settings and get settings route

* add: hooks and contexts to get settings

* add: hooks

* add: notification component

* add: data api

* add: settings provider and connect settings

* add: husky

* fix: formatting and text-domain

* update: filter names

* fix: hook import

* add: set function for settings

* add: prop-types package

* update: refactor notification component and context

* update: remove filter for authorize url

* update: imports and exports of hooks

* update: plugin settings context filename and relevant imports

---------

Co-authored-by: Ohad <ohad@elementor.com>

* [APP 707] general setting components (#113)

* Initial refactor commit

*  Added build and tests CI/CD

* update: add src for admin settings

* update: incorrect constant names

* update: namespace

* add: accessibility settings

* update: webpack to output files inside a folder

* update: build output folders

* update: removed commented code

* update: npm scripts

* add: webpack config

* add: hooks

* update: move admin setting to the module folder

* update: assets loading logic

* update: add rule to move jsx props to multiline imporving readability

* add: connect modal

* update: hooks import for better readability

* update: replace functions with hooks

* add: connect module

* add: settings and get settings route

* add: hooks and contexts to get settings

* add: hooks

* add: notification component

* add: data api

* add: settings provider and connect settings

* add: husky

* add: icon size control

* fix: icon size control labels

* add: icon select component

* add: color picker component

* add: accessibility icons

* add: icon export

* update: add icons to the component

* fix: styling for the icon select control

* update: color picker with react-colorful component

* update: icon size component with live icon design

* fix: styling of radio boxes

* add: icon design settings layout

* add: position settings layout

* add: layout exports

* add: alignment matrix and position control components

* add: position settings  & position settings for mobile layout

* fix: formatting and text-domain

* update: filter names

* fix: hook import

* add: set function for settings

* add: prop-types package

* update: refactor notification component and context

* update: remove filter for authorize url

* Update modules/settings/assets/js/components/color-picker/style.css

Co-authored-by: Raz Ohad <admin@bainternet.info>

* update: color picker class name

---------

Co-authored-by: Ohad <ohad@elementor.com>
Co-authored-by: Raz Ohad <admin@bainternet.info>

* [App 780] Navigation Sidebar (#115)

* Initial refactor commit

*  Added build and tests CI/CD

* update: add src for admin settings

* update: incorrect constant names

* update: namespace

* add: accessibility settings

* update: webpack to output files inside a folder

* update: build output folders

* update: removed commented code

* update: npm scripts

* add: webpack config

* add: hooks

* update: move admin setting to the module folder

* update: assets loading logic

* update: add rule to move jsx props to multiline imporving readability

* add: connect modal

* update: hooks import for better readability

* update: replace functions with hooks

* add: connect module

* add: settings and get settings route

* add: hooks and contexts to get settings

* add: hooks

* add: notification component

* add: data api

* add: settings provider and connect settings

* add: husky

* fix: formatting and text-domain

* update: filter names

* fix: hook import

* add: set function for settings

* add: prop-types package

* update: refactor notification component and context

* update: remove filter for authorize url

* update: imports and exports of hooks

* update: plugin settings context filename and relevant imports

* update: icons and icon imports

* add: sidebar(wip)

* update: fix width of connect screen on mobile

* update: sidebar layout

* add: credit card and user arrow icons

* update: hidden wpfooter and fixed sidebar height

* update: sidebar layout

* add: basic page layouts

* update: sidebar layout

* add: sidebar menu, sidebar app bar and my account menu components

* update: add sidebar and menu settings

* update: add page layouts

* update: admin top bar

* add: bottom bar

* add: bottom bar and top bar

* add: bottom bar and top bar

* update: page content styling

* fix: styling

* fix: styling

* update: text domain

* update: added translations

* fix: admin top bar layout

* update: exports of icons

* update: exports of components

* add: aliases for imports and fix exports

* fix: height and styling of the layout

* fix: unhide wp footer

* update: keep widget menu open on page load (default)

* update: linter rules to move first prop to new line

* update: linter rules to move first prop to new line

---------

Co-authored-by: Ohad <ohad@elementor.com>

* Fix error on install plugin, add prettier (#116)

* Feature/app 810 assemble icon settings page (#117)

* Initial refactor commit

*  Added build and tests CI/CD

* update: add src for admin settings

* update: incorrect constant names

* update: namespace

* add: accessibility settings

* update: webpack to output files inside a folder

* update: build output folders

* update: removed commented code

* update: npm scripts

* add: webpack config

* add: hooks

* update: move admin setting to the module folder

* update: assets loading logic

* update: add rule to move jsx props to multiline imporving readability

* add: connect modal

* update: hooks import for better readability

* update: replace functions with hooks

* add: connect module

* add: settings and get settings route

* add: hooks and contexts to get settings

* add: hooks

* add: notification component

* add: data api

* add: settings provider and connect settings

* add: husky

* add: icon size control

* fix: icon size control labels

* add: icon select component

* add: color picker component

* add: accessibility icons

* add: icon export

* update: add icons to the component

* fix: styling for the icon select control

* update: color picker with react-colorful component

* update: icon size component with live icon design

* fix: styling of radio boxes

* add: icon design settings layout

* add: position settings layout

* add: layout exports

* add: alignment matrix and position control components

* add: position settings  & position settings for mobile layout

* fix: formatting and text-domain

* update: filter names

* fix: hook import

* add: set function for settings

* add: prop-types package

* update: refactor notification component and context

* update: remove filter for authorize url

* update: imports and exports of hooks

* update: plugin settings context filename and relevant imports

* update: icons and icon imports

* add: sidebar(wip)

* update: fix width of connect screen on mobile

* update: sidebar layout

* Update modules/settings/assets/js/components/color-picker/style.css

Co-authored-by: Raz Ohad <admin@bainternet.info>

* update: color picker class name

* add: credit card and user arrow icons

* update: hidden wpfooter and fixed sidebar height

* update: sidebar layout

* add: basic page layouts

* update: sidebar layout

* add: sidebar menu, sidebar app bar and my account menu components

* update: add sidebar and menu settings

* update: add page layouts

* update: admin top bar

* add: bottom bar

* add: bottom bar and top bar

* add: bottom bar and top bar

* update: page content styling

* fix: styling

* fix: styling

* update: text domain

* add: props to wrapper

* add: icon design and position setting layouts

* add: in page scroll behaviour to the settings

* add: widget icons and getter function

* update: icon design settings getter and setter functions

* update: imports

* add: mobile layout for position settings

* add: icon position settings

* add: icon position settings hooks and handlers

* fix: alignment of controls in AlignmentMatrixControl

* update: useSettings and usePositionSetting hooks and relevant functions

* fix: colors of AlignmentMatrixControl

* fix: styling of components and layouts

* add: aliases

* add: container wrapper to page

* update: accessibility options rendering logic

* fix: order of the icons

* add: aliases for components and hooks imports

* fix: styling of settings panel

* fix: container height for settings page

* update: toggle control states

* add: widget icon settings

* add: load saved widget icon settings

* update: move layout to page for different designs per page

* update: add changes tracking and disable button logic

* add: async/await to save settings

* update: convert options to array of objects

* Update modules/settings/assets/js/components/bottom-bar/index.js

Co-authored-by: VasylD <vasyld@elementor.red>

* Update modules/settings/assets/js/app.js

Co-authored-by: VasylD <vasyld@elementor.red>

* fix: remove duplicate entries

---------

Co-authored-by: Ohad <ohad@elementor.com>
Co-authored-by: Raz Ohad <admin@bainternet.info>
Co-authored-by: VasylD <vasyld@elementor.red>

* Feature/app 708 widget menu settings (#118)

* add: icons for menu settings

* add: placeholder layout for widget preview in menu settings

* update: load saved settings and updated imports

* add: logics for handling and saving menu settings

* add: useSavedSettings hook

* update: set export as default for Sidebar layout

* add: widget menu settings layout and settings

* update: add widget menu settings and widget preview layouts

* add: hide/show minimum option alert notification

* update: styling of the save button

* update: save settings logic to use async/await

* fix: accessibility text icon

* update: app type (#119)

* [APP-834] Update account menu buttons (#121)

* update: account menu buttons

* update: billing link

* add: error handling for switch account

* [APP-835] add service data (#122)

* add: client functions

* add: site register and site info endpoints

* update: add plan data settings

* update: add support for 201 response code

* update: add plan data key

* update: store the plan data on the once the site is registered

* update: add filter for client url

* add: retry registering in there is any error after connect

* update: setting prefix

* add: plan data

* update: add account details to menu

* fix: lint issues

* update: add data checkbox support (#123)

* [APP-928] Settings pointer (#125)

* add: settings pointer

* update: add alias for the settings

* [APP-837] Add post connect modal (#120)

* add: post connect modal

* update: settings prefix

* fix: connect modal design

* update: connect modal text

* add: connect modal graphics

* update: connect modal icon

* update: post connect modal

* update: sidebar menu text

* update: text of icon settings

* update: text

* update: php compatibility with return types

* add: accessibility statement page structure (#126)

* [APP-721] Render widget and global settings (#124)

* add: webhook endpoint

* add: widget module

* add: default widget settings on successful registration

* update: name of global object to ea11yWidget

* update: remove json encoding to make objects available on the frontend

* update: widget url, filter and enqueuing method

* update: removed obsolete code

* update: enqueue script only when connected

* update: add check for valid plan data and key

* update: conditional check

* update: conditional check

* fix: widget loading error (#128)

* [Legacy] Upgrade To New [APP-949] (#127)

* Added `Notice_Base` and `Notices` component to core module

* Always load core module and load all other modules based on legacy status

* added filter in customizer settings

* added bubble / pimple in admin menu to indicate upgrade

* added `Dismissible_Deprecated_Nag` notice to none legacy pages

* added `Dismissible_Deprecated_Nag` notice to legacy pages

* Added `Upgrade` component to legacy module

includes:
* loading of notices
* introduction modal
* admin menu pimple
* customizer notice
* pointer
* confirmation modal
* upgrade logic and handler

*  Fixed legacy module test

* added `local:quick-run` command to run in browser mode

* update phpunit workflow

* ensure wp.ajax is loaded

* wrong translations

* Updated strings

* added "Equally"

* remove unused test

*  use custom version of wp test library (#129)

*  use custom version of wp test library

* cleanup

* update WP versions for testing

* [APP-711] Widget preview (#130)

* add: dynamic script loader for widget

* update: settings name

* update: settings save function and comments

* update: tools settings object structure

* add: widget preview section

* update: added setting page slug as a constant

* update: enqueue widget for preview in the settings

* add: widget icon assets link

* add: widget icon svgs

* update: store widget url in a constant

* update: store widget url in a constant

* update: trigger widget preview update on menu item changes

* update: remove the icon option from the frontend.

* update: add widget URL

* update: plan data setting type

* update: widget plan url

* update: widget plan url and parse plan data

* fix: phpcs error ext-json missing

* fix: widget url

* fix: save and use plan data as a serialized option

* fix: use template string for widget url

* [APP-908] Accessibility generator (#131)

* add: accessibility statement radio icons

* update: add form group on radio buttons

* add: statement generator

* add: statement generator

* add: accessibility statement data option

* update: create page in WordPress and save it to the option

* update: exclude zip file from the git

* update: render statement page conditionally

* add: statement link layout and settings

* add: preload statement data

* update: publish the created page and add link for it

* update: changed Dynamic Script Loader to WidgetLoader

* add: accessibility statement url

* update: text and styling

* update: styling of the preview text

* update: restructure statement generator

* add: support for dynamic update in statement links

* update: remove index.css file for widget loader

* add: widget styling for settings page

* add: empty link when hide link is enabled

* update: statement page structure and logic

* fix: typo

* update: convert component into a styled component

* fix: styling and layout

* update: icons

* update: convert radio buttons to styled component

* fix: typo and style

* add: fading for the link preview

* update: import

* update: styling and spacing

* fix: sidebar layout

* update: wpcs to latest version

* fix: spacing

* fix: wpcs version

* add: check for valid statement page

* fix: jitters on rendering

* fix: use escape attribute

* update: settings menu slug and plugin name

* fix: menu item rendering

* update: definition of the styled text field

* add: addPage function to the API

* fix: add notification on page creation

* add: copy link icon

* update: optimize SVGs

* [APP-908] Additional fixes (#133)

* fix: text domains

* updated: styled component syntax

* update: use await instead of then

* fix: prevent application crash in case widget fails to load

* add: generated info tip card

* update: refactor function

* Fix: Fix the QA bugs [n/a] (#135)

* [APP-830] Add mixpanel events (#134)

* [APP-830] Add mixpanel events

* Merge branch 'develop' into feature/APP-830-add-mixpanel

# Conflicts:
#	.gitignore
#	modules/settings/assets/js/components/sidebar-menu/index.js
#	modules/settings/assets/js/pages/accessibility-statement.js

* Merge branch 'develop' into feature/APP-830-add-mixpanel

# Conflicts:
#	.gitignore
#	modules/settings/assets/js/components/sidebar-menu/index.js
#	modules/settings/assets/js/pages/accessibility-statement.js

* Merge branch 'develop' into feature/APP-830-add-mixpanel

# Conflicts:
#	.gitignore
#	modules/settings/assets/js/components/sidebar-menu/index.js
#	modules/settings/assets/js/pages/accessibility-statement.js

* Merge branch 'develop' into feature/APP-830-add-mixpanel

# Conflicts:
#	.gitignore
#	modules/settings/assets/js/components/sidebar-menu/index.js
#	modules/settings/assets/js/pages/accessibility-statement.js

* Merge branch 'develop' into feature/APP-830-add-mixpanel

# Conflicts:
#	.gitignore
#	modules/settings/assets/js/components/sidebar-menu/index.js
#	modules/settings/assets/js/pages/accessibility-statement.js

* Merge branch 'develop' into feature/APP-830-add-mixpanel

# Conflicts:
#	.gitignore
#	modules/settings/assets/js/components/sidebar-menu/index.js
#	modules/settings/assets/js/pages/accessibility-statement.js

* [APP-830] Add user to init Mixpanel (#136)

* [APP-830] Add mixpanel events

* Merge branch 'develop' into feature/APP-830-add-mixpanel

# Conflicts:
#	.gitignore
#	modules/settings/assets/js/components/sidebar-menu/index.js
#	modules/settings/assets/js/pages/accessibility-statement.js

* Merge branch 'develop' into feature/APP-830-add-mixpanel

# Conflicts:
#	.gitignore
#	modules/settings/assets/js/components/sidebar-menu/index.js
#	modules/settings/assets/js/pages/accessibility-statement.js

* Merge branch 'develop' into feature/APP-830-add-mixpanel

# Conflicts:
#	.gitignore
#	modules/settings/assets/js/components/sidebar-menu/index.js
#	modules/settings/assets/js/pages/accessibility-statement.js

* Merge branch 'develop' into feature/APP-830-add-mixpanel

# Conflicts:
#	.gitignore
#	modules/settings/assets/js/components/sidebar-menu/index.js
#	modules/settings/assets/js/pages/accessibility-statement.js

* Merge branch 'develop' into feature/APP-830-add-mixpanel

# Conflicts:
#	.gitignore
#	modules/settings/assets/js/components/sidebar-menu/index.js
#	modules/settings/assets/js/pages/accessibility-statement.js

* Merge branch 'develop' into feature/APP-830-add-mixpanel

# Conflicts:
#	.gitignore
#	modules/settings/assets/js/components/sidebar-menu/index.js
#	modules/settings/assets/js/pages/accessibility-statement.js

* [APP-830] Add user to init Mixpanel

* [APP-830] Add user to init Mixpanel

* [APP-830] Add user to init Mixpanel

* [APP-830] rename events (#137)

* Connect and Preview Fixes (#139)

* updated connect admin page

* Use unified widget URL instead of hardcoded Js to support envs

* Removed enqueue of fictional widget.js and reuse settings `admin` handle

* Fix: Fix the QA bugs [n/a] (#138)

* New: Finish the BE integration [n/a]

* Fix: Fix some bugs [n/a]

* upgrade flow UI and design tweaks [app-949] (#141)

* Updated Learn More links with UTM's

* Tweaked Pointer strings Icon and CTA

* dismissible notice strings

* sticky notice strings

* updated upgrade flow design for pointer, notices, introduction modal, and confirmation modal

* added build script

* [APP-979] Update links and plugin name (#140)

* Ensure loading of legacy widget based on any saved data and fixed legacy JS

* Bug/app 1002 (#143)

* Bug: Update the logo in the "Hide Widget" modal [APP-1001]

* Fix: Update the side menu spaces [APP-1002]

* [APP-991] Add translation for statement (#142)

* [APP-979] Update links and plugin name

* [APP-991] Add translation for statement

* Set Prod Widget URL

* [APP-1004][APP-1005][APP-1006] Fix generator UI and logic, fix statement UI, fix copy link (#144)

* [APP-1004] Fix generator UI and logic

* [APP-1005] Fix statement UI

* [APP-1005] Fix statement UI

* Mixpanel record session

* Fix: Enhance position values validation [APP-1009] (#146)

* Bug/app 1003 (#147)

* Fix: Add a border to the preview [n/a]

* Fix: Fix Capabilities screen UI [APP-1003]

* [APP-1020] add missed events (#148)

* [APP-1015] fix switch account (#149)

* [APP-1015] fix switch account (#150)

* [APP-1021] Fix switch modal ui (#151)

* fix: ui issues

* fix: translation strings

* [APP-912] add default settings for RTL (#152)

* [APP-912] add default settings for RTL

* [APP-912] add default settings for RTL

* [APP-912] add default settings for RTL

* [APP-1026] Remove HTML breaking <style> tag & update pointer logic (#153)

* fix: remove extra closing tag

* update: hide settings pointer when plugin settings is opened

* update: remove unused functions

* update: add help text to mobile position settings

* Bug/app 1003 (#157)

* Fix: Add missed translations [n/a]

* Fix: Refresh the plan data on page load [n/a]

* New: Add loader to the settings [n/a]

* update: delete lock key after each check (#160)

* New: Update dashboard icon size [n/a] (#158)

* New: Update dashboard icon size [n/a]

* Fix: Fix widget previews [n/a]

* [APP-1018] Help menu change (#155)

* update: remove accessibility word from menu items

* update: remove top bar

* update: add help button to the sidebar

* update: re-add spacing in styled css code

* update: create styled components

* [APP-973] Add an UTM for users upgrading from one click to the new widget (#165)

* update: ui of the statement preview (#166)

* [APP-1011][APP-1013] focus outline and sitemap settings (#161)

* [APP-1011][APP-1013] focus outline and sitemap settings

* [APP-1011][APP-1013] focus outline and sitemap settings

* [APP-1011][APP-1013] focus outline and sitemap settings

* [APP-1011][APP-1013] focus outline and sitemap settings

* update: video link (#167)

* [APP-1051] Fix layout on the small and medium devices (#156)

* fix: layout on the small and medium devices

* update: change components to styled components

* refactor: position settings wrapper into a separate component

* [APP-1012][APP-1085] Add skip to content settings and event for Mixpanel (#169)

* [APP-1012][APP-1085] Add skip to content settings and event for Mixpanel

* [APP-1012][APP-1085] Add skip to content settings and event for Mixpanel

* [APP-1012][APP-1085] Add skip to content settings and event for Mixpanel

* [APP-1012][APP-1085] Add skip to content settings and event for Mixpanel

* [APP-1048] Add tooltip to accessibility statement (#159)

* add: tooltip to accessibility statement

* update: hide infotip when statement link is set

* update: infotip's text

* fix: infotip naming and logic

* [APP-1049] Add back button accessibility statement (#164)

* add: back button to the statement link section

* add: Edit link button to statement page section

* update: add admin_url and generate query args properly

* update: learn more link for accessibility statement page (#168)

* Fix: Update overlay height [n/a] (#171)

* Fix settings and connect issues (#170)

* fix: token fails to refresh after expiry

* update: add 12 hour time for plan data refresh and fix missing subscription id

* update: add check to refresh plan data

* fix: decoding errors and alignment and add logging for errors

* update: refresh logic and formatting

* Update/app 1029 app name (#173)

* update: plugin name

* update: default menu option

* update: menu structure

* update: add inline checks

* update: reduce padding on app icon in menu

* fix: height of the modal

* update: app menu icon color

* update: menu icon colors

* fix: menu icon size

* update: plugin names

* update: HELP_LINK

* update: app name

* update: icon background color

* update: icon size

* fix: admin icon size

* fix: width of the sidebar

* Fix/toggle not working properly (#174)

* fix: toggles not working properly in some cases

* fix: saving of the settings was not working

* add: missing adminUrl in settings data

* fix: switch was not working properly in some cases (#175)

* Fix/app 1093 incorrect position on default (#176)

* fix: switch was not working properly in some cases

* fix: default setting structure for the icon position

* [APP-1096] Text changes (#177)

* fix: switch was not working properly in some cases

* update: plugin name and action buttons title

* fix: revert change to is_active function

* fix: button color

* New: Add the skip link [APP-1012] (#179)

* [APP-1097] Fix preview load (#178)

* [APP-1097] Fix preview load

* [APP-1097] Fix preview load

* [APP-1097] Fix preview load

* Update modules/settings/assets/js/components/widget-loader/index.js

---------

Co-authored-by: Raz Ohad <ohad@elementor.com>

* [APP-1123] Accessibility statement text (#181)

* fix: switch was not working properly in some cases

* update: accessibility statement content

* [APP-1121] Add support for react-jsx-runtime for older WP versions (#180)

* fix: switch was not working properly in some cases

* update: revert wp-scripts version to 28.0.0 to add support for older WordPress versions

* update: revert wp-scripts to 27.9.0

* add: support for react-jsx-runtime in older versions of WordPress

* update: version to the latest wp-scripts 30.3.0

* update: add lib/ to gitignore

* update: plugin name

* Fix: Fix admin widget previews [n/a] (#183)

* [APP-1061] change mixpanel user id (#184)

* [APP-1129] change toggle_event for mixpanel (#186)

* Remove skip to content btn if anchor does not exist (#187)

* fix: hide wp notices to keep the layout from shifting (#189)

* [APP-1143] fix bug with capability display (#195)

* [APP-1143] fix bug with capability display

* [APP-1143] fix bug with capability display

* [APP-1143] fix bug with capability display

* [APP-1143] fix bug with capability display

* add: loading text to widget preview (#196)

* [APP-1142] add 'appType' super props, change identify key (#191)

* [APP-1108][APP-1109][APP-1110] Add analytics backend logic

* [APP-1142] Add 'appType' super props

* [APP-1144] Accessibility statement tooltip text update (#198)

* update: text

* update: switch design

* Tweak: Update widget loaders [n/a] (#197)

* added images to readme (#172)

* added images to readme

* updated readme

* V3.0.0

* updated readme

* updated tested up to

* added deploy workflows

* Remove duplicate settings menu

* update: switch redirect url

---------

Co-authored-by: Yakir Sitbon <kingyes1@gmail.com>
Co-authored-by: Nirbhay Singh <121793120+nirbhayel@users.noreply.github.com>
Co-authored-by: VasylD <vasyld@elementor.red>
Co-authored-by: Pavlo Kniazevych <139438463+pkniazevych@users.noreply.github.com>
2025-02-19 12:39:50 +02:00

574 lines
20 KiB
PHP

<?php
namespace EA11y\Classes\Database;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
/**
* Class Table
* This class represents a database table
*/
class Table {
/**
* The current table version. Will be compared to the version installed in the database
*/
const DB_VERSION = '1';
/**
* Should hold the name of the WordPress option to hold the database version
*/
const DB_VERSION_FLAG_NAME = '';
/**
* @var string database table name
*/
public static $table_name = '';
/**
* @var bool flag whether the table name is already prefixed or not
*/
protected static $table_prefixed = false;
/**
* Get a reference to the WordPress database object.
* @return \wpdb A reference to the WordPress database object
*/
public static function db(): \wpdb {
global $wpdb;
if ( ! static::$table_prefixed ) {
static::$table_prefixed = true;
static::set_table_prefix();
}
return $wpdb;
}
/**
* table_name
*
* Returns the name of the table including the table prefix
* @return string The full name of the table
*/
public static function table_name(): string {
return self::db()->prefix . static::$table_name;
}
/**
* set_table_prefix
*
* Saves the table name as a property in the WP database object and
* sets it value to the table name and its prefix.
*/
protected static function set_table_prefix(): void {
static::db()->{static::$table_name} = static::table_name();
}
/**
* get_columns
*
* Should return an array of table columns details in the format of
* column_name => [ type => db_type, key => key_data (optional), flags => other_modifiers (optional) ]
*
* NOTE: A primary key column named /id/ which is an auto-incremented int/big int is assumed to exist and must be one
* of the columns this function returns.
* @return array The table column data.
*/
public static function get_columns(): array {
return [];
}
/**
* get_extra_keys
*
* Extra keys to the table definitions to be merged with column key definitions
* @return string[] SQL table key definitions
*/
protected static function get_extra_keys(): array {
return [];
}
/**
* get_keys
*
* Extracts the key definitions from the table's columns and merges with
* any extra key definitions
* @return string[] SQL table key definitions
*/
protected static function get_keys(): array {
$columns = static::get_columns();
$keys = [];
foreach ( $columns as $column ) {
if ( ! isset( $column['key'] ) ) {
continue;
}
$keys[] = $column['key'];
}
return array_merge( $keys, static::get_extra_keys() );
}
/**
* install
*
* This function compares the version of the installed table and the current version as reported by
* the class.
* If the versions are different, the table will be installed or updated, and the option
* will be set to the current version.
*/
public static function install(): void {
$installed_ver = get_option( static::DB_VERSION_FLAG_NAME, -1 );
if ( static::DB_VERSION !== $installed_ver ) {
$sql = static::get_create_table_sql();
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta( $sql );
update_option( static::DB_VERSION_FLAG_NAME, static::DB_VERSION, false );
}
static::set_table_prefix();
}
/**
* get_create_table_sql
*
* Generates the SQL command to run in the database to create the table
* based on the definitions of columns and keys.
* @return string The SQL command to create the table
*/
protected static function get_create_table_sql(): string {
$table = static::table_name();
$keys = static::get_keys();
$charset_collate = static::db()->get_charset_collate();
$table_columns = [];
$sql = [];
$sql[] = 'CREATE TABLE ' . $table . ' (';
$columns = static::get_columns();
foreach ( $columns as $column_name => $column ) {
$table_columns[] = sprintf( '`%s` %s %s,',
$column_name,
$column['type'],
$column['flags'] ?? ''
);
}
$sql[] = "\t" . implode( "\n\t", $table_columns );
$sql[] = "\t" . implode( ",\n\t", $keys );
$sql[] = ") AUTO_INCREMENT=11 {$charset_collate};";
return implode( "\n", $sql );
}
/**
* where
*
* Generates a proper WHERE clause for an SQL query.
* @param string|array $where Either a string of where clause (returns as is) or an array of
* conditions join with an AND, and in the format of column => (int|string) for exact value comparison
* or in the format of column => [column => string, value =>string|int|array<string|array>,
* comparison operator => string, relation_before=>string, optional, relation_after=>string, optional]
*
* @return string WHERE clause built from the function input
*/
public static function where( $where ): string {
if ( ! is_array( $where ) ) {
return $where;
}
$needs_relationship = false;
$where_string = '';
foreach ( $where as $key => $filter ) {
if ( ! is_array( $filter ) ) {
if ( $needs_relationship ) {
$where_string .= ' AND';
}
$where_string .= ' ' . self::get_where_string( $key, $filter );
$needs_relationship = true;
continue;
}
$where_string .= self::maybe_add_relation( $filter );
$where_string .= self::get_where_string( $filter['column'], $filter['value'], $filter['operator'] );
$where_string .= self::maybe_add_relation( $filter, false );
}
return $where_string;
}
/**
* maybe_add_relation
*
* Adds a logical relation ship (AND, OR...) if exists, based on the position (before|after) related to the condition.
* @param array $filter Object array describing the where condition that may contain the keys /relation_before/
* or /relation_after/ containing the logical relationship to add to the main WHERE condition.
* @param bool $is_before Whether the current position in the text is before the condition the object describes.
* Optional.
* Defaults to TRUE.
*
* @return string If the logical relationship exists, returns it. Otherwise - an empty string.
*/
private static function maybe_add_relation( array $filter, bool $is_before = true ): string {
$key_to_check = $is_before ? 'relation_before' : 'relation_after';
return isset( $filter[ $key_to_check ] ) ? ' ' . $filter[ $key_to_check ] : ' ';
}
/**
* get_where_string
*
* @param string $key The column name in the condition
* @param string|int|array $value The value being compared. If an array will be translated to a set.
* @param string $operator The comparison operator.
* Optional.
* Defaults to '='.
* @param null $format Unused.
*
* @return string An SQL condition based on the parameters.
*/
private static function get_where_string( string $key, $value, string $operator = '=', $format = null ): string {
$param_string = is_int( $value ) ? '%d' : '%s';
if ( is_array( $value ) ) {
$param_string = '(';
$count = count( $value );
for ( $i = 0; $i < $count; $i++ ) {
$param_string .= is_int( $value[ $i ] ) ? '%d' : '%s';
$param_string .= ( $i !== $count - 1 ) ? ', ' : '';
}
$param_string .= ')';
}
return static::db()->prepare( "$key $operator $param_string", $value );
}
/**
* get_columns_for_insert
* This function tries to get the column names for an INSERT operation based on the table column
* definition, and if that fails based on the /data/ parameter.
* The function will remove any column called /id/.
* @param mixed $data If a two-dimensional array, where the elements are in the form of column => value,
* the function will try to get the names of the columns off the first element.
*
* @return false|string A string representing the list of columns, comma separated and surrounded by parenthesis;
* or false in case of function failure.
*/
private static function get_columns_for_insert( $data ) {
$cols = static::get_columns();
if ( count( $cols ) ) {
$columns = array_keys( $cols );
} elseif ( is_array( $data ) ) {
//try to get from data
$columns = array_keys( $data[0] );
}
if ( empty( $columns ) || ! is_array( $columns ) ) {
return false;
}
// remove id $column
if ( ! empty( $columns['id'] ) ) {
unset( $columns['id'] );
}
$index = array_search( 'id', $columns, true );
if ( false !== $index ) {
unset( $columns[ $index ] );
}
return ' (`' . implode( '`,`', $columns ) . '`) ';
}
/**
* select_var
*
* Selects a single cell in the table and returns its value as string.
* Will return the first cell of the first row in the result set.
* @param string|array $fields A string of comma-separated list, or an array of columns from the table.
* Optional.
* Defaults to '*' (all table columns)
* @param string|array $where A string of WHERE conditions or an array of column => value entries connected with the
* AND logical operator. Or in the format of column => [column => string, value =>string|int|array<string|array>,
* comparison operator => string, relation_before=>string, optional, relation_after=>string, optional]
* Optional.
* Defaults tp '1', which is evaluated to true and will bring all records (no condition).
* @param int|null $limit Limit the number of results to return to this number, or NULL for no limit.
* Optional.
* Defaults to NULL (no limit)
* @param int|null $offset Skip this number of results or NULL for no skip
* Optional.
* Defaults to NULL (no offset)
* @param string $join JOIN table clause.
* Optional.
* Defaults to an empty string (no join)
*
* @return string|null The query result or NULL on error.
*/
public static function select_var( $fields = '*', $where = '1', int $limit = null, int $offset = null, string $join = '' ): ?string {
return static::db()->get_var( static::build_sql_string( $fields, $where, $limit, $offset, $join ) );
}
/**
* build_sql_string
*
* Generates a SELECT query based on the function input.
* @param string|array $fields A string of comma-separated list, or an array of columns from the table.
* Optional.
* Defaults to '*' (all table columns)
* @param string|array $where A string of WHERE conditions or an array of column => value entries connected with
* the AND logical operator. r in the format of column => [column => string, value =>string|int|array<string|array>,
* comparison operator => string, relation_before=>string, optional, relation_after=>string, optional]
* Optional.
* Defaults to '1', which is evaluated to true and will bring all records (no condition).
* @param int|null $limit Maximum number of results to return.
* Optional.
* Defaults to NULL (no limit)
* @param int|null $offset Start the results from a certain ordinal position.
* Optional.
* Defaults to NULL (no offset)
* @param string $join A table JOIN clause.
* Optional.
* Defaults to an empty string (no join)
* @param array $order_by an array of column => direction (asc|desc) to sort the results by.
* Optional.
* Defaults to an empty array (Default sort).
*
* @return string The SQL SELECT statement built according to the function parameters.
*/
private static function build_sql_string( $fields = '*', $where = '1', int $limit = null, int $offset = null, string $join = '', array $order_by = [] ): string {
if ( is_array( $fields ) ) {
$fields = implode( ', ', $fields );
}
$db = static::db();
$query_string = 'SELECT %s FROM %s %s WHERE %s';
$query_string = sprintf( $query_string,
$fields,
static::table_name(),
$join,
static::where( $where )
);
if ( $order_by ) {
$query_string .= static::build_order_by_sql_string( $order_by );
}
if ( $limit ) {
$query_string .= $db->prepare( ' LIMIT %d', $limit );
}
if ( $offset ) {
$query_string .= $db->prepare( ' OFFSET %d', $offset );
}
return $query_string;
}
/**
* build_order_by_sql_string
*
* Generates the ORDER BY clause of the query based on the passed on parameter
* @param array<string, string> $order_by An array of column => direction (asc/desc) pairs
*
* @return string The ORDER BY clause for a query
*/
public static function build_order_by_sql_string( array $order_by ): string {
return ' ORDER BY ' . implode( ', ', array_map( function( $column, $direction ) {
return "{$column} {$direction}";
}, array_keys( $order_by ), $order_by ) );
}
/**
* select
*
* Runs a SELECT query and returns the results as an array of objects, each object represents a row,
* @param string|array $fields A string of comma-separated list, or an array of columns from the table.
* Optional.
* Defaults to '*' (all table columns)
* @param string|array $where A string of WHERE conditions, or an array of column => value enteries
* for direct comparison joined with the AND logical operator, or in the format of column => [column => string, value =>string|int|array<string|array>,
* comparison operator => string, relation_before=>string, optional, relation_after=>string, optional]
* Optional.
* Defaults to '1', which is evaluated to true and will bring all records (no condition).
* @param int|null $limit Maximum number of results to return.
* Optional.
* Defaults to NULL (no limit)
* @param int|null $offset Start the results from a certain ordinal position.
* Optional.
* Defaults to NULL (no offset)
* @param string|array $join A table JOIN clause.
* Optional.
* Defaults to an empty string (no join)
* @param array $order_by an array of column => direction (asc|desc) to sort the results by.
* Optional.
* Defaults to an empty array (Default sort).
*
* @return array|object|\stdClass[]|null On success, an array of objects. Null on error.
*/
public static function select( $fields = '*', $where = '1', int $limit = null, int $offset = null, $join = '', array $order_by = [] ) {
// TODO: handle $wpdb->last_error
$query = static::build_sql_string( $fields, $where, $limit, $offset, $join, $order_by );
return static::db()->get_results( $query );
}
/**
* get_col
*
* Returns the first column of the result set.
* @param string $column The column to return.
* Optional.
* Defaults to an empty string.
* @param string|array $where A string of WHERE conditions or an array of column => value entries
* for direct comparison joined with the AND logical operator or in the format of column => [column => string, value =>string|int|array<string|array>,
* comparison operator => string, relation_before=>string, optional, relation_after=>string, optional]
* Optional.
* Defaults to '1', which is evaluated to true and will bring all records (no condition).
* @param int|null $limit Maximum number of results to return.
* Optional.
* Defaults to NULL (no limit)
* @param int|null $offset Start the results from a certain ordinal position.
* Optional.
* Defaults to NULL (no offset)
* @param string $join A table JOIN clause.
* Optional.
* Defaults to an empty string (no join)
* @param array $order_by an array of column => direction (asc|desc) to sort the results by.
* Optional.
* Defaults to an empty array (Default sort).
*
* @return string[] Array of the values of the column as strings, or an empty one on error.
*/
public static function get_col( string $column = '', $where = '1', int $limit = null, int $offset = null, string $join = '', array $order_by = [] ) : array {
return static::db()->get_col( static::build_sql_string( $column, $where, $limit, $offset, $join, $order_by ) );
}
/**
* first
*
* Returns the first row in the table according to the query filters.
* @param string|array $fields A string of comma-separated list, or an array of columns from the table.
* Optional.
* Defaults to '*' (all table columns)
* @param string|array $where A string of WHERE conditions or an array of column => value entries
* for direct comparison joined with the logical AND operator,
* or in the format of column => [column => string, value =>string|int|array<string|array>,
* comparison operator => string, relation_before=>string, optional, relation_after=>string, optional]
* Optional.
* Defaults to '1', which is evaluated to true and will bring all records (no condition).
* @param int $limit Unnecessary since we are only returning the first row.
* Optional.
* Defaults to 1.
* @param null $offset Start the results from a certain ordinal position.
* Optional.
* Defaults to NULL (no offset)
* @param string $join A table JOIN clause.
* Optional.
* Defaults to an empty string (no join)
*
* @return \stdClass|null An object representing the first row, or null on error
*/
public static function first( $fields = '*', $where = '1', int $limit = 1, $offset = null, string $join = '' ): ?\stdClass {
$result = static::select( $fields, $where, $limit, $offset, $join );
return ( ! empty( $result[0] ) ) ? $result[0] : null;
}
/**
* replace
*
* Replace a row in a table if it exists or insert a new row in a table if the row does not already exist.
* @param array $data Array of data in the form of column => (raw) value.
* Optional.
* Defaults to an empty array.
*
* @return false|int The number of rows affected or FALSE on error.
*/
public static function replace( array $data = [] ) {
return static::db()->replace( static::table_name(), $data );
}
/**
* insert
*
* Insert a single row into the table.
* @param array $data Array of data to insert in column => (raw) value format.
* Optional, defaults to an empty array.
*
* @return false|int The number of rows affected or FALSE on error
*/
public static function insert( array $data = [] ) {
return static::db()->insert( static::table_name(), $data );
}
/**
* insert_many
* Performs a bulk INSERT of many datasets/rows to the table
*
* @param array $data Optional. Defaults to an empty array.
* An array of datasets to be INSERTed into the table. Each value needs to be seperated by a comma,
* each data set needs to be surrounded by parenthesis.
* @param string|null $columns Optional. The columns being inserted. Defaults to NULL.
* Either a string of comma-separated column names surrounded by parenthesis, or NULL for the
* function to try guessing based on the data and column definitions.
*
* @return false|int Number of rows affected or false on error
*/
public static function insert_many( array $data = [], string $columns = null ) {
if ( null === $columns ) {
$columns = static::get_columns_for_insert( $data );
if ( ! $columns ) {
return false;
}
}
$insert_sql = 'INSERT INTO ' . static::table_name() . $columns . ' VALUES ' . implode( ",\n", $data ) . ';';
return static::db()->query( $insert_sql ); // no params so no need for `prepare`.
}
/**
* update
*
* Updates data in the table, based on where conditionals
* @param array<string, mixed> $data Optional. Array of column => (raw) values to be updated.
* Defaults to an empty array.
* @param array<string, mixed> $where Optional. Array of column => (raw) values as a group of AND
* WHERE conditionals for the UPDATE statement. Defaults to an empty array.
*
* @return false|int The numbers of rows affected, or FALSE on error
*/
public static function update( array $data = [], array $where = [] ) {
return static::db()->update( static::table_name(), $data, $where );
}
/**
* delete
*
* Delete rows from this table based on optional where conditions.
*
* @param array<string, mixed> $where Optional. And array of column => (raw) values
* as a group of AND conditions for the DELETE statement. Defaults to an empty array.
*
* @return false|int The number of rows updated, or false on error.
*/
public static function delete( array $where = [] ) {
return static::db()->delete( static::table_name(), $where );
}
/**
* query
*
* Execute any SQL query on the database.
* It is best used when there is a need for specific,
* custom, or otherwise complex SQL queries.
* @param string $query The query to be executed. Defaults to an empty string
*
* @return false|int Boolean true for CREATE, ALTER, TRUNCATE and DROP queries.
* Number of rows affected/selected for all other queries. Boolean false on error.
*/
public static function query( string $query = '' ) {
return static::db()->query( $query );
}
/**
* get_class_name
*
* Returns the name of this /Table/ class (or its derivative)
* @return string - The name of the current class
*/
public static function get_class_name(): string {
return get_called_class();
}
}