From 336a08db6e15e06a057ab041de38d427c7d21585 Mon Sep 17 00:00:00 2001 From: Shea Bunge Date: Mon, 14 Sep 2026 20:47:27 +1000 Subject: [PATCH 1/2] Merge changes from pro-beta branch. --- .gitignore | 7 + CHANGELOG.md | 296 ++++++---- config/webpack/webpack-js.ts | 2 +- package-lock.json | 532 +++++++++++++----- package.json | 5 +- scripts/test-setup-playwright.ts | 20 +- src/code-snippets.php | 6 +- src/css/admin-bar.scss | 14 + src/css/common/_badges.scss | 1 + src/css/common/_buttons.scss | 32 ++ src/css/common/_list-table.scss | 27 + src/css/common/_modal.scss | 14 + src/css/common/_page-subtitle.scss | 13 + src/css/common/_subnav.scss | 5 +- src/css/common/_theme.scss | 34 ++ src/css/common/_toolbar.scss | 70 ++- src/css/common/_tooltips.scss | 1 + src/css/common/_wp-admin.scss | 2 + src/css/common/list-table/_layout.scss | 23 +- src/css/common/list-table/_responsive.scss | 5 +- src/css/edit.scss | 3 +- src/css/edit/_conditions.scss | 5 +- src/css/edit/_form.scss | 3 +- src/css/edit/_gpt.scss | 28 - src/css/edit/_sidebar.scss | 145 +++-- src/css/import.scss | 1 + src/css/insights.scss | 1 + src/css/manage.scss | 12 +- src/css/manage/_ai-agent.scss | 46 +- src/css/manage/_blueprints.scss | 3 + src/css/manage/_cloud-community.scss | 8 +- src/css/manage/_snippets-table.scss | 109 +++- src/css/manage/blueprints/_detail.scss | 38 +- src/css/manage/blueprints/_form-layout.scss | 2 +- src/css/settings.scss | 4 +- .../ConditionModal/ConditionModalButton.tsx | 6 +- .../EditMenu/EditorSidebar/EditorSidebar.tsx | 11 +- .../EditorSidebar/actions/ExportButtons.tsx | 12 +- .../EditorSidebar/controls/LockControl.tsx | 1 + .../ManageMenu/CommunityCloud/CloudSearch.tsx | 85 +-- .../CommunityCloud/WithCloudSearchContext.tsx | 15 +- .../SnippetsTable/ManageSnippetCard.tsx | 38 +- .../ManageMenu/SnippetsTable/RowActions.tsx | 7 +- .../SnippetsTable/SnippetsTable.tsx | 6 +- .../ManageMenu/SnippetsTable/TableColumns.tsx | 42 +- .../WithFilteredSnippetsContext.tsx | 15 +- .../common/ListTable/TableNavigation.tsx | 2 +- .../common/LoadingStatusNotices.tsx | 5 +- src/js/components/common/SubnavTabs.tsx | 78 ++- src/js/components/common/Toolbar.tsx | 2 +- .../cloud/CloudSnippetCard.tsx} | 37 +- .../cloud/CloudSnippetDownloadButton.tsx | 4 +- .../common/icons/CloudUpdateIcon.tsx | 13 - .../common/snippets/ConfirmDeleteDialog.tsx | 17 +- .../common/snippets/SnippetPreviewModal.tsx | 29 +- src/js/hooks/useSnippetsAPI.tsx | 6 +- src/js/services/settings/tabs.ts | 12 +- src/js/types/Snippet.ts | 8 + src/js/types/schema/SnippetSchema.ts | 11 +- src/js/utils/errors.ts | 10 +- src/js/utils/restAPI.ts | 11 + src/js/utils/screen.ts | 3 + src/js/utils/snippets/objects.ts | 19 +- src/js/utils/snippets/snippets.ts | 2 +- src/js/utils/urls.ts | 12 +- src/php/Admin/Feedback_Panel.php | 2 +- src/php/Admin/Menus/Admin_Menu.php | 17 +- src/php/Admin/Menus/Edit_Menu.php | 4 +- .../Admin/Menus/Insights/Insights_Summary.php | 2 +- src/php/Admin/Menus/Manage/Manage_Menu.php | 9 +- .../Admin/Menus/Manage/Manage_Menu_Assets.php | 4 + .../Manage/Manage_Menu_Screen_Options.php | 17 +- src/php/Admin/Menus/Settings_Menu.php | 32 +- src/php/Client/Feedback_Client.php | 6 +- src/php/Core/DB.php | 39 +- src/php/Core/Uninstaller.php | 3 +- src/php/Core/load.php | 13 +- .../Handlers/Functions_Snippet_Handler.php | 10 +- src/php/Flat_Files/Snippet_Files.php | 10 +- src/php/Integration/Admin_Bar.php | 48 +- src/php/Integration/Evaluate_Content.php | 72 ++- src/php/Integration/Evaluate_Functions.php | 42 +- src/php/Integration/Shortcodes.php | 58 +- src/php/Model/Basic_Cloud_Connection.php | 3 +- src/php/Model/Cloud_Snippets.php | 21 +- src/php/Model/Feedback_Connection.php | 2 + src/php/Model/Model.php | 2 +- src/php/Model/Snippet.php | 7 + src/php/Plugin.php | 26 +- .../Cloud/Cloud_Snippets_REST_Controller.php | 35 +- .../Feedback/Feedback_REST_Controller.php | 2 +- .../Demos_Seen_REST_Controller.php | 2 +- .../Snippet_View_REST_Controller.php | 2 +- .../Snippets/Snippets_REST_Controller.php | 45 +- src/php/Settings/Setting_Field.php | 15 +- src/php/Settings/Settings_Fields.php | 42 +- src/php/Settings/Settings_Layout.php | 17 +- src/php/Settings/settings.php | 17 +- src/php/Utils/Validator.php | 4 +- src/php/Utils/editor.php | 2 +- src/php/Utils/options.php | 26 +- src/php/snippet-ops.php | 74 ++- src/readme.txt | 9 - tests/e2e/code-snippets-evaluation.spec.ts | 144 +++++ tests/e2e/code-snippets-list.spec.ts | 62 ++ tests/e2e/helpers/SnippetsTestHelper.ts | 117 ++++ tests/e2e/helpers/constants.ts | 6 +- tests/unit/Admin/Admin_Bar_Test.php | 14 +- tests/unit/Admin/Feedback_Panel_Test.php | 2 +- .../Menus/Manage/Manage_Menu_Assets_Test.php | 2 +- .../Manage/Manage_Menu_Demo_Reset_Test.php | 9 +- tests/unit/Admin/Notice_Filter_Test.php | 2 + tests/unit/Authorship_Test.php | 144 +++++ tests/unit/Model/Cloud_Snippets_Test.php | 53 ++ tests/unit/Plugin_Test.php | 6 +- .../Cloud_Snippets_REST_Controller_Test.php} | 85 ++- ...PI_Snippets_Shared_Network_Toggle_Test.php | 2 +- .../{ => Snippets}/REST_API_Snippets_Test.php | 2 +- 118 files changed, 2574 insertions(+), 853 deletions(-) create mode 100644 src/css/common/_buttons.scss create mode 100644 src/css/common/_page-subtitle.scss create mode 100644 src/css/manage/_blueprints.scss rename src/js/components/{ManageMenu/CommunityCloud/SearchResult.tsx => common/cloud/CloudSnippetCard.tsx} (75%) delete mode 100644 src/js/components/common/icons/CloudUpdateIcon.tsx create mode 100644 tests/unit/Authorship_Test.php rename tests/unit/REST_API/{REST_API_Cloud_Test.php => Cloud/Cloud_Snippets_REST_Controller_Test.php} (80%) rename tests/unit/REST_API/{ => Snippets}/REST_API_Snippets_Shared_Network_Toggle_Test.php (99%) rename tests/unit/REST_API/{ => Snippets}/REST_API_Snippets_Test.php (99%) diff --git a/.gitignore b/.gitignore index 453a38177..d52c8fce4 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,10 @@ tmp /.env .superpowers/ docs/superpowers/ +/docs/ + +# Local dev only (wp-env mu-plugin mappings, staging access) +/dev/ + +# Local wp-env overrides — may contain credentials, never commit +.wp-env.override.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 73d4e8faa..e94b17f42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,22 +3,83 @@ ## [4.0.0] (UPCOMING) ### Added -* AI Agent demo: a guided, scripted walkthrough of the Pro AI Agent that plans, builds, and refines a welcome banner snippet named after your site. Runs entirely inside the plugin — no data leaves your site and no snippets are added to your library. -* Blueprints demo: a guided, scripted walkthrough of Pro Blueprints that steps through the "Create a Shortcode" blueprint and confirms the snippet it would generate. Runs entirely inside the plugin — no code is generated and nothing is saved. -* Cloud Library demo: a guided, scripted walkthrough of the Pro Cloud Library, showing how a cloud snippet is previewed, downloaded inactive, and then kept in sync. Runs entirely inside the plugin — the snippets shown are examples and nothing is downloaded. -* "New" badges on the AI Agent, Blueprints, and Cloud Library toolbar tabs, which soften once each demo walkthrough has been watched. +* AI Agent for building snippets from a description: it proposes a plan you can refine or approve before any code is + written, and can revise the snippets it created. (PRO) +* Snippet revisions, with a history of past versions, a side-by-side diff against the current code, and one-click + restore. (PRO) +* Display conditions for controlling where and when a snippet runs, without writing the checks by hand. (PRO) +* Per-role snippet permissions, so you can decide which roles may view, edit, activate, or delete snippets. (PRO) +* Blueprints for setting up a site from a saved collection of snippets and settings. (PRO) +* Flat file storage, for keeping snippets as files so they can be version-controlled alongside the rest of a site. (PRO) +* "Ran on this page" tracking, showing which snippets actually executed on the page you are viewing. (PRO) +* Natural-language search in Community Cloud, so you can describe what you need instead of guessing keywords. (PRO) +* Snippet deployment from Code Snippets Cloud to connected sites, including deploying several snippets under one shared + display condition. (PRO) +* Installing a cloud bundle onto a connected site as a standalone plugin. (PRO) +* Updating Code Snippets Pro on a connected site from the cloud dashboard. (PRO) +* Drift detection, which reports when a snippet on the site no longer matches the copy stored in the cloud. (PRO) +* New admin interface for managing snippets, with a cleaner layout, faster interactions, and a more consistent + experience across plugin screens. (PRO) +* Card view for browsing snippets, with a view switcher on the snippets table and Community Cloud. (PRO) +* Snippet preview modal for viewing snippet code from the snippets table without opening the editor. (PRO) +* Automatic hiding of unrelated admin notices from other plugins on Code Snippets screens. (PRO) +* Admin bar snippet drawer, based on the Deckerweb Snippets workflow, for quick access to snippets and Safe Mode from + the WordPress admin bar. (PRO) +* Snippet locking to help prevent accidental edits or deletion of important snippets. Props + to https://github.com/mgiannopoulos24. (PRO) +* Improved screen options on the main snippets table, including controls for visible columns and truncating long snippet + names or descriptions. (PRO) +* Bulk actions and bulk code download support in the redesigned snippets table. (PRO) +* Featured snippets and improved browsing in Community Cloud. (PRO) +* WordPress modern theme admin styling compatibility. (PRO) +* Clearer accessibility labels, headings, tab markup, table checkboxes, sort buttons, copy buttons, and drag-and-drop + upload controls. (PRO) +* Feedback reporter for sending bug reports, feature requests and general feedback from the plugin screens, with an + optional summary of the site environment so the team can reproduce the problem. (PRO) + +### Changed +* Redesigned the main snippets table with improved search, filtering, sorting, pagination, row actions, and bulk + selection. (PRO) +* Improved the snippet import and migration experience, including clearer file upload handling and third-party plugin + migration flows. (PRO) +* Improved snippet error handling so activation failures, validation errors, and stack traces are easier to understand. + (PRO) +* Improved Community Cloud search and filtering, including server-side filters, better result loading, and clearer empty + states. (PRO) +* Updated the welcome screen, toolbar, import screen, and cloud screens to match the new admin experience. (PRO) +* Updated internal plugin architecture to a cleaner PSR-4 structure for better long-term maintainability. (PRO) +* Improved accessibility across the snippets table, import screen, migration flow, Community Cloud, welcome screen, + toolbar, dialogs, tooltips, and code editor. (PRO) +* Improved colour contrast and reduced-motion support across admin screens. (PRO) +* Faster loading of large code vaults, which are now fetched a page at a time instead of all at once. (PRO) + +### Fixed +* Fixed AI conversations from one connected site being visible from another. (PRO) +* Fixed a snippet list stored in Code Snippets Cloud being emptied when the site was temporarily unable to read its own + snippets. (PRO) +* Fixed REST API server error responses on missing snippets. (PRO) +* Fixed redundant frontend logic, improving overall performance. (PRO) +* Fixed Community Cloud search results and pagination to respect WordPress screen options. (PRO) +* Fixed snippet saving and activation feedback to improve validation and runtime error display. (PRO) +* Fixed downloaded Community Cloud snippets appearing as not downloaded after a page reload. (PRO) +* Fixed network snippet lookups using the wrong database table on multisite. (PRO) +* Fixed the inactive snippets count including trashed snippets. (PRO) +* Fixed featured Community Cloud snippets failing to load with some cloud API responses. (PRO) +* Fixed bulk actions in Community Cloud running against an empty selection, so selected snippets were never downloaded. + (PRO) ## [3.10.2] (2026-09-01) ### Added -* Added a confirmation flow for run-once snippet execution and hardened the handler to prevent failed or confusing actions. +* Added a confirmation flow for run-once snippet execution and hardened the handler to prevent failed or confusing + actions. ### Changed * Snippet names now respect the row truncation Screen Option in the admin list for better readability. * Version switching AJAX requests now validate the correct nonce, improving reliability when updating snippet versions. ### Fixed -* Fixed safe mode fatal errors caused by an undefined wp_get_current_user() call. +* Fixed safe mode fatal errors caused by an undefined wp_get_current_user () call. * Fixed PHP validation being triggered incorrectly when activating snippets in bulk. * Fixed saving issues after a user session expires. * Fixed warnings caused by aliased field names when reading modified snippet fields. @@ -33,7 +94,8 @@ ### Fixed * Fixed a fatal error affecting snippets that use a `namespace` or `declare` statement. * Fixed the snippets page rendering blank when another plugin's screen settings filter returned an invalid value. -* Fixed snippet saving on hosts that block REST API `PUT` and `PATCH` requests, by sending writes as `POST` with a method override. +* Fixed snippet saving on hosts that block REST API `PUT` and `PATCH` requests, by sending writes as `POST` with a + method override. * Fixed the Snippets List Order setting not being applied to the snippets list. * Fixed admin bar snippet scripts failing to load on the free version, including on the site front end. * Fixed snippet modified dates being sent without the correct UTC offset. @@ -44,26 +106,35 @@ ## [3.10.0] (2026-08-24) ### Added -* New admin interface for managing snippets, with a cleaner layout, faster interactions, and a more consistent experience across plugin screens. +* New admin interface for managing snippets, with a cleaner layout, faster interactions, and a more consistent + experience across plugin screens. * Card view for browsing snippets, with a view switcher on the snippets table and Community Cloud. * Snippet preview modal for viewing snippet code from the snippets table without opening the editor. * Automatic hiding of unrelated admin notices from other plugins on Code Snippets screens. -* Admin bar snippet drawer, based on the Deckerweb Snippets workflow, for quick access to snippets and Safe Mode from the WordPress admin bar. -* Snippet locking to help prevent accidental edits or deletion of important snippets. Props to https://github.com/mgiannopoulos24. -* Improved screen options on the main snippets table, including controls for visible columns and truncating long snippet names or descriptions. +* Admin bar snippet drawer, based on the Deckerweb Snippets workflow, for quick access to snippets and Safe Mode from + the WordPress admin bar. +* Snippet locking to help prevent accidental edits or deletion of important snippets. Props + to https://github.com/mgiannopoulos24. +* Improved screen options on the main snippets table, including controls for visible columns and truncating long snippet + names or descriptions. * Bulk actions and bulk code download support in the redesigned snippets table. * Featured snippets and improved browsing in Community Cloud. * WordPress modern theme admin styling compatibility. -* Clearer accessibility labels, headings, tab markup, table checkboxes, sort buttons, copy buttons, and drag-and-drop upload controls. +* Clearer accessibility labels, headings, tab markup, table checkboxes, sort buttons, copy buttons, and drag-and-drop + upload controls. ### Changed -* Redesigned the main snippets table with improved search, filtering, sorting, pagination, row actions, and bulk selection. -* Improved the snippet import and migration experience, including clearer file upload handling and third-party plugin migration flows. +* Redesigned the main snippets table with improved search, filtering, sorting, pagination, row actions, and bulk + selection. +* Improved the snippet import and migration experience, including clearer file upload handling and third-party plugin + migration flows. * Improved snippet error handling so activation failures, validation errors, and stack traces are easier to understand. -* Improved Community Cloud search and filtering, including server-side filters, better result loading, and clearer empty states. +* Improved Community Cloud search and filtering, including server-side filters, better result loading, and clearer empty + states. * Updated the welcome screen, toolbar, import screen, and cloud screens to match the new admin experience. * Updated internal plugin architecture to a cleaner PSR-4 structure for better long-term maintainability. -* Improved accessibility across the snippets table, import screen, migration flow, Community Cloud, welcome screen, toolbar, dialogs, tooltips, and code editor. +* Improved accessibility across the snippets table, import screen, migration flow, Community Cloud, welcome screen, + toolbar, dialogs, tooltips, and code editor. * Improved colour contrast and reduced-motion support across admin screens. ### Fixed @@ -91,7 +162,8 @@ ### Added * New import functionality to migrate snippets from file uploads with drag-and-drop interface. -* Support for importing snippets from other popular plugins (Header Footer Code Manager, Insert Headers and Footers, Insert PHP Code Snippet). +* Support for importing snippets from other popular plugins (Header Footer Code Manager, Insert Headers and Footers, + Insert PHP Code Snippet). * Enhanced file based execution support with improved multisite mode compatibility. ### Fixed @@ -102,7 +174,8 @@ ## [3.9.3] (2025-12-03) ### Added -* End-to-end tests to verify the toggle visual state in the snippets list page, improving UI verification and test reliability. +* End-to-end tests to verify the toggle visual state in the snippets list page, improving UI verification and test + reliability. ### Fixed * Restored missing styles styling and direction-aware layout from Manage menu. @@ -139,7 +212,8 @@ * Expanded Multisite Sharing settings for clearer control over network-wide snippet sharing ### Changed -* Modernized browser support targets and polished admin UI (clearer row-action badges, improved Pro badge hover, refined active snippet name styling) +* Modernized browser support targets and polished admin UI (clearer row-action badges, improved Pro badge hover, refined + active snippet name styling) ### Fixed * Fixed REST API pagination to return correct results and page counts @@ -251,14 +325,16 @@ * Improved UX of snippet activation toggle. ### Fixed -* Fetching active snippets on a multisite network now respects the 'priority' field above all else when ordering snippets. +* Fetching active snippets on a multisite network now respects the 'priority' field above all else when ordering + snippets. * Cloud search appears correctly and allows downloading snippets in the free version of Code Snippets. * Improved performance of loading admin menu icon. ## [3.6.9] (2025-02-17) ### Changed -* Updated `Cloud_API::get_bundles()` to properly check bundle data and return an empty array if no valid bundles are present. +* Updated `Cloud_API::get_bundles()` to properly check bundle data and return an empty array if no valid bundles are + present. * Refactored `Cloud_List_Table::fetch_snippets()` to always return a valid `Cloud_Snippets` instance. * Cleaned up bundle iteration code and improved translation handling in the bundles view. @@ -274,7 +350,8 @@ * Updated Freemius SDK to the latest version. (PRO) ### Removed -* Functionality allowing `[code_snippet]` shortcodes to be embedded recursively – it will be re-added in a future version. +* Functionality allowing `[code_snippet]` shortcodes to be embedded recursively – it will be re-added in a future + version. ### Fixed * Shortcodes embedded within `[code_snippet]` shortcodes not evaluating correctly. @@ -287,15 +364,19 @@ ### Added * Generated snippet shortcode tags will include the snippet name, for easier identification. -* Admin notices will dismiss automatically after five seconds. ([#208](https://github.com/codesnippetspro/code-snippets/issues/208)) +* Admin notices will dismiss automatically after five seconds. + ([#208](https://github.com/codesnippetspro/code-snippets/issues/208)) ### Changed * Updated CSS to use latest Sass features. -* Moved theme selector to just above editor preview on settings page (thanks to [brandonjp]). ([#206](https://github.com/codesnippetspro/code-snippets/issues/206)) -* `[code_snippet]` shortcodes can now be nested within each other. ([#198](https://github.com/codesnippetspro/code-snippets/issues/198)) +* Moved theme selector to just above editor preview on settings page (thanks to [brandonjp]). + ([#206](https://github.com/codesnippetspro/code-snippets/issues/206)) +* `[code_snippet]` shortcodes can now be nested within each other. + ([#198](https://github.com/codesnippetspro/code-snippets/issues/198)) ### Fixed -* Save buttons above editor did not follow usual validation process in Pro. (PRO) ([#197](https://github.com/codesnippetspro/code-snippets/issues/197)) +* Save buttons above editor did not follow usual validation process in Pro. (PRO) + ([#197](https://github.com/codesnippetspro/code-snippets/issues/197)) * Minor inconsistencies in consistent UI elements between Core and Pro. * Tags input not allowing input. ([#211](https://github.com/codesnippetspro/code-snippets/issues/211)) * Issue with Elementor source code widget. (PRO) ([#205](https://github.com/codesnippetspro/code-snippets/issues/205)) @@ -421,13 +502,16 @@ * Scroll new notices into view on edit menu. ### Fixed -* Error when attempting to update network shared snippets after saving. [[#](https://wordpress.org/support/topic/activating-snippets-breaks-on-wordpress-6-3/)] +* Error when attempting to update network shared snippets after + saving. [[#](https://wordpress.org/support/topic/activating-snippets-breaks-on-wordpress-6-3/)] ## [3.4.2] (2023-07-05) ### Fixed -* Issue causing export process to fail with fatal error. [[#](https://wordpress.org/support/topic/critical-error-on-exporting-snippets/)] -* Type issue on `the_posts` filter when no posts available. [[#](https://wordpress.org/support/topic/collision-with-plugin-xml-sitemap-google-news/)] +* Issue causing export process to fail with fatal + error. [[#](https://wordpress.org/support/topic/critical-error-on-exporting-snippets/)] +* Type issue on `the_posts` filter when no posts + available. [[#](https://wordpress.org/support/topic/collision-with-plugin-xml-sitemap-google-news/)] ## [3.4.1] (2023-06-29) @@ -435,14 +519,18 @@ * Added better debugging when calling REST API methods from the edit menu. ### Changed -* Escape special characters when sending snippet code through AJAX to avoid false-positives from security modules. [[#](https://wordpress.org/support/topic/latest-3-4-0-ajax-bug-cannot-save-snippets-403-error/)] +* Escape special characters when sending snippet code through AJAX to avoid false-positives from security + modules. [[#](https://wordpress.org/support/topic/latest-3-4-0-ajax-bug-cannot-save-snippets-403-error/)] * Only display the latest update or error notice on the edit page, instead of allowing them to stack. ### Fixed -* Undefined array key error. [[#](https://wordpress.org/support/topic/after-updating-occasionally-getting-undefined-array-key-query/)] -* Potential type issue when loading Prism. [[#](https://wordpress.org/support/topic/code-snippets-fatal-error-breaking-xml-sitemaps/)] +* Undefined array key + error. [[#](https://wordpress.org/support/topic/after-updating-occasionally-getting-undefined-array-key-query/)] +* Potential type issue when loading + Prism. [[#](https://wordpress.org/support/topic/code-snippets-fatal-error-breaking-xml-sitemaps/)] * Potential type issue when sorting snippets. [[#](https://github.com/codesnippetspro/code-snippets/issues/166)] -* Issue preventing asset revision numbers from updating correctly. (PRO) [[#](https://github.com/codesnippetspro/code-snippets/issues/166)] +* Issue preventing asset revision numbers from updating correctly. + (PRO) [[#](https://github.com/codesnippetspro/code-snippets/issues/166)] ## [3.4.0] (2023-05-17) @@ -453,10 +541,10 @@ ### Changed * Better compatibility with modern versions of PHP (7.0+). * Converted Edit/Add New Snippet page to use React: - - Converted action buttons to asynchronously use REST API endpoints through AJAX. - - Load page components dynamically through React. - - Added action notice queue system - - Replaced native alert dialog with proper React modal. + - Converted action buttons to asynchronously use REST API endpoints through AJAX. + - Load page components dynamically through React. + - Added action notice queue system + - Replaced native alert dialog with proper React modal. * Catch snippet execution errors to prevent site from crashing. * Display recent snippet errors in admin dashboard instead. * Updated editor block to use new REST API endpoints. (PRO) @@ -476,7 +564,8 @@ ### Added * Added additional editor shortcuts to list in tooltip. -* Filter for changing Snippets admin menu position. [See this help article for more information.](https://codesnippets.pro/doc/snippets-menu-location/) +* Filter for changing Snippets admin menu + position. [See this help article for more information.](https://codesnippets.pro/doc/snippets-menu-location/) * Ability to filter shortcode output. Thanks to contributions from [Jack Szwergold](https://github.com/JackSzwergold). ### Fixed @@ -493,10 +582,12 @@ ### Added * `Ctrl`+`/` or `Cmd`+`/` as shortcut for commenting out code in the snippet editor. -* Additional hooks to various snippet actions, thanks to contributions made by [ancient-spirit](https://github.com/ancient-spirit). +* Additional hooks to various snippet actions, thanks to contributions made + by [ancient-spirit](https://github.com/ancient-spirit). * Fold markers, additional keyboard shortcuts and keymap options to snippet editor, thanks to contributions made by [Amaral Krichman](https://github.com/karmaral). -* WP-CLI commands for retrieving, activating, deactivating, deleting, creating, updating, exporting and importing snippets. +* WP-CLI commands for retrieving, activating, deactivating, deleting, creating, updating, exporting and importing + snippets. ### Changed * Removed duplicate tables exist query. ([#](https://wordpress.org/support/topic/duplicate-queries-21)). @@ -515,7 +606,8 @@ * Support for multiple code styles in the source code Gutenberg editor block. (PRO) * Admin notice announcing release of Code Snippets Pro. * Button for copying shortcode text to clipboard. -* Option to choose from 44 different themes for the Prism code highlighter in the source editor block and Elementor widget. (PRO) +* Option to choose from 44 different themes for the Prism code highlighter in the source editor block and Elementor + widget. (PRO) ### Changed * Include Code Snippets CSS and JS source code in distributed package. @@ -634,15 +726,16 @@ ## [2.14.3] (2021-12-10) ### Fixed -* Potential security issue outputting snippets-safe-mode query variable value as-is. Thanks to Krzysztof Zając for reporting. +* Potential security issue outputting snippets-safe-mode query variable value as-is. Thanks to Krzysztof Zając for + reporting. ## [2.14.2] (2021-09-09) ### Added * Added translations: - - Spanish by [Ibidem Group](https://www.ibidemgroup.com) - - Urdu by [Samuel Badree](https://mobilemall.pk/) - - Greek by [Toni Bishop from Jrop](https://www.jrop.com/) + - Spanish by [Ibidem Group](https://www.ibidemgroup.com) + - Urdu by [Samuel Badree](https://mobilemall.pk/) + - Greek by [Toni Bishop from Jrop](https://www.jrop.com/) * Support for `:class` syntax to the code validator. * PHP8 support to the code linter. * Color picker feature to the code editor. @@ -665,7 +758,8 @@ * Code validator now supports `function_exists` and `class_exists` checks. * Code validator now supports anonymous functions. * Issue with saving the hidden columns setting. -* Replaced the outdated tag-it library with [tagger](https://github.com/jcubic/tagger) for powering the snippet tags editor. +* Replaced the outdated tag-it library with [tagger](https://github.com/jcubic/tagger) for powering the snippet tags + editor. ## [2.14.0] (2020-01-26) @@ -686,7 +780,8 @@ * Fixed a bug preventing the editor theme from being set to default. * Ensure that imported snippets are always inactive. * Check the referer on the import menu to prevent CSRF attacks. - Thanks to [Chloe with the Wordfence Threat Intelligence team](https://www.wordfence.com/blog/author/wfchloe/) for reporting. + Thanks to [Chloe with the Wordfence Threat Intelligence team](https://www.wordfence.com/blog/author/wfchloe/) for + reporting. * Ensure that individual snippet action links use proper verification. ## [2.13.3] (2019-03-13) @@ -733,7 +828,8 @@ ## [2.13.0] (2018-12-17) ### Added -* Search/replace functionality to the snippet editor. [See here for a list of keyboard shortcuts.](https://codemirror.net/demo/search.html) [[#](https://wordpress.org/support/topic/feature-request-codemirror-search-and-replace/)] +* Search/replace functionality to the snippet + editor. [See here for a list of keyboard shortcuts.](https://codemirror.net/demo/search.html) [[#](https://wordpress.org/support/topic/feature-request-codemirror-search-and-replace/)] * Option to make admin menu more compact. * Added additional styles to editor settings preview. * PHP linter to code editor. @@ -753,7 +849,8 @@ * CodeMirror updated to version 5.41.0. * Attempt to create database columns that might be missing after a table upgrade. * Streamlined upgrade process. -* Made search box appear at top of page on mobile. [[#](https://wordpress.org/support/topic/small-modification-for-mobile-ux/)] +* Made search box appear at top of page on + mobile. [[#](https://wordpress.org/support/topic/small-modification-for-mobile-ux/)] * Updated screenshots. ### Fixed @@ -810,7 +907,7 @@ ### Fixed * Prevent errors when trying to export no snippets. -* Use wp_json_encode() to encode export data. +* Use wp_json_encode () to encode export data. * Check both the file extension and MIME type of uploaded import files. ## [2.10.0] (2018-01-18) @@ -882,7 +979,7 @@ ### Changed * Moved code to disable snippet execution into a filter hook. -* execute_active_snippets() function updated with improved efficiency. +* execute_active_snippets () function updated with improved efficiency. * Renamed Snippet class to avoid name collisions with other plugins. * Don't hide output when executing a snippet. @@ -900,8 +997,10 @@ ## [2.8.6] (2017-05-14) ### Fixed -* Fixed snippet description field alias not mapping correctly, causing snippet descriptions to not be displayed in the table or when editing a snippet. -* Ensured that get_snippets() function retrieves snippets with the correct 'network' setting. Fixes snippet edit links in network admin. +* Fixed snippet description field alias not mapping correctly, causing snippet descriptions to not be displayed in the + table or when editing a snippet. +* Ensured that get_snippets () function retrieves snippets with the correct 'network' setting. Fixes snippet edit links + in network admin. ## [2.8.5] (2017-05-13) @@ -945,7 +1044,8 @@ ### Fixed * Fixed admin menu items not translating. * Corrected editor alignment on RTL sites. ([#](https://wordpress.org/support/topic/suggestion-css-fix-for-rtl-sites/)) -* Fixed bulk actions running when Filter button is clicked. ([#](https://wordpress.org/support/topic/bug-with-filtering-action-buttons/)) +* Fixed bulk actions running when Filter button is clicked. + ([#](https://wordpress.org/support/topic/bug-with-filtering-action-buttons/)) ## [2.8.0] (2016-12-14) @@ -984,7 +1084,8 @@ * Updated CodeMirror to version 5.19.0. ### Security -* Ensured that the editor theme setting is properly validated. Thanks to [Netsparker](https://www.netsparker.com) for reporting. +* Ensured that the editor theme setting is properly validated. Thanks to [Netsparker](https://www.netsparker.com) for + reporting. * Ensured that snippet tags are properly escaped. Thanks to [Netsparker](https://www.netsparker.com) for reporting. ## [2.7.0] (2016-07-23) @@ -1000,9 +1101,11 @@ ### Fixed * Fixed plugin translations being loaded. * Fixed description field not being imported. -* Fixed issue with CodeMirror rubyblue theme. [[#](https://wordpress.org/support/topic/a-problem-with-the-cursor-color-and-the-fix-that-worked-for-me)] +* Fixed issue with CodeMirror rubyblue + theme. [[#](https://wordpress.org/support/topic/a-problem-with-the-cursor-color-and-the-fix-that-worked-for-me)] * Fixed snippet fields not importing. -* Fixed a minor XSS vulnerability discovered by Burak Kelebek. [[#](https://wordpress.org/support/topic/security-vulnerability-20)] +* Fixed a minor XSS vulnerability discovered by Burak + Kelebek. [[#](https://wordpress.org/support/topic/security-vulnerability-20)] ## [2.6.1] (2016-02-10) @@ -1064,7 +1167,8 @@ ## [2.4.1] (2015-09-17) ### Fixed -* Fixed CodeMirror themes not being detected on settings page [[#](https://wordpress.org/support/topic/updated-to-240-now-i-cant-switch-theme)] +* Fixed CodeMirror themes not being detected on settings + page [[#](https://wordpress.org/support/topic/updated-to-240-now-i-cant-switch-theme)] ## [2.4.0] (2015-09-17) @@ -1090,7 +1194,8 @@ ### Added * Added icons for admin and front-end snippets to manage table. -* Added filter switch to prevent a snippet from executing. ([#25](https://github.com/codesnippetspro/code-snippets/issues/25)) +* Added filter switch to prevent a snippet from executing. + ([#25](https://github.com/codesnippetspro/code-snippets/issues/25)) ### Changed * Improved settings retrieval by caching settings. @@ -1126,7 +1231,7 @@ ### Fixed * Resolved JavaScript error on edit snippet pages. -* Added polyfill for array_replace_recursive() function for PHP 5.2. +* Added polyfill for array_replace_recursive () function for PHP 5.2. ## [2.2.1] (2015-05-10) @@ -1199,7 +1304,8 @@ * Added Russian translation by Alexander Samsonov. * Added Slovak translation by [Ján Fajčák] from [WordPress Slovakia](https://wp.sk). * Added setting to always save and activate snippets by default. -* Added braces to single-line conditionals in line with [new coding standards](https://make.wordpress.org/core/2013/11/13/proposed-coding-standards-change-always-require-braces/). +* Added braces to single-line conditionals in line + with [new coding standards](https://make.wordpress.org/core/2013/11/13/proposed-coding-standards-change-always-require-braces/). ### Changed * Improved plugin file structure. @@ -1241,7 +1347,8 @@ ### Added * Added French translation thanks to translator [oWEB](http://office-web.net). -* Added 'Save & Deactivate' button to the edit snippet page. ([#](https://wordpress.org/support/topic/deactivate-button-in-edit-snippet-page)) +* Added 'Save & Deactivate' button to the edit snippet page. + ([#](https://wordpress.org/support/topic/deactivate-button-in-edit-snippet-page)) * Added nonce to edit snippet page. * Added a fallback MP6 icon. @@ -1251,8 +1358,10 @@ * Updated CodeMirror to version 3.19. * Updated WordPress.org plugin banner. * Add and remove network capabilities as super admins are added and removed. -* Replaced buggy trim `` functionality with a much more reliable regex method. ([#](https://wordpress.org/support/topic/character-gets-cut)) -* Make the title of each snippet on the manage page a clickable link to edit the snippet ([#](https://wordpress.org/support/topic/deactivate-button-in-edit-snippet-page?replies=9#post-4682757)) +* Replaced buggy trim `` functionality with a much more reliable regex method. + ([#](https://wordpress.org/support/topic/character-gets-cut)) +* Make the title of each snippet on the manage page a clickable link to edit the snippet + ([#](https://wordpress.org/support/topic/deactivate-button-in-edit-snippet-page?replies=9#post-4682757)) * Hide row actions on manage snippet page by default. * Use the proper WordPress database APIs consistently. * Rewritten export functionality. @@ -1263,7 +1372,9 @@ * Removed CodeMirror bundled with plugin. ### Fixed -* Fixed snippet failing to save when code contains `%` character, props to [nikan06](https://wordpress.org/support/profile/nikan06). ([#](https://wordpress.org/support/topic/percent-sign-bug)) +* Fixed snippet failing to save when code contains `%` character, props + to [nikan06](https://wordpress.org/support/profile/nikan06). + ([#](https://wordpress.org/support/topic/percent-sign-bug)) * Fixed HTML breaking in export files. ([#](https://wordpress.org/support/topic/import-problem-7)) * Fixed incorrect export filename. * Fixed CodeMirror incompatibility with the WP Editor plugin. @@ -1289,7 +1400,9 @@ * Added error message handling for import snippets page. ### Changed -* Improved database table creation method: on a single-site install, the snippets table will always be created. On a multisite install, the network snippets table will always be created; the site-specific table will always be created for the main site; for sub-sites the snippets table will only be created on a visit to a snippets admin page. +* Improved database table creation method: on a single-site install, the snippets table will always be created. On a + multisite install, the network snippets table will always be created; the site-specific table will always be created + for the main site; for sub-sites the snippets table will only be created on a visit to a snippets admin page. * Updated to CodeMirror 3.14. * Allow no snippet name or code to be set. * Prevented an error on fresh multisite installations. @@ -1315,7 +1428,8 @@ ### Added * Added German translation thanks to [David Decker](https://deckerweb.de) -* Allow or deny site administrators access to snippet admin menus. Set your preference in the **Enable Administration Menus** setting under the *Settings > Network Settings* network admin menu. +* Allow or deny site administrators access to snippet admin menus. Set your preference in the **Enable Administration + Menus** setting under the *Settings > Network Settings* network admin menu. ### Changed * Updated PHP Documentation completely. [[View online](https://bungeshea.github.io/code-snippets/api)] @@ -1330,7 +1444,8 @@ ### Added * Added icon for the new MP6 admin UI ([#](https://wordpress.org/support/topic/icon-disappears-with-mp6)) -* Allow plugin to be activated on individual sites on multisite ([#](https://wordpress.org/support/topic/dont-work-at-multisite)) +* Allow plugin to be activated on individual sites on multisite + ([#](https://wordpress.org/support/topic/dont-work-at-multisite)) * Strip PHP tags from the beginning and end of a snippet on save ([#](https://wordpress.org/support/topic/php-tags)) * Change label in admin menu when editing a snippet. @@ -1346,12 +1461,14 @@ * Removed HTML, CSS and JavaScript CodeMirror modes that were messing things up. ### Fixed -* Fixed a bug with saving snippets per page option ([#](https://wordpress.org/support/topic/plugin-code-snippets-snippets-per-page-does-not-work#post-3710991)) +* Fixed a bug with saving snippets per page option + ([#](https://wordpress.org/support/topic/plugin-code-snippets-snippets-per-page-does-not-work#post-3710991)) ## [1.6.1] (2012-12-29) ### Fixed -* Fixed a bug with permissions not being applied on install ([#](https://wordpress.org/support/topic/permissions-problem-after-install)) +* Fixed a bug with permissions not being applied on install + ([#](https://wordpress.org/support/topic/permissions-problem-after-install)) * Fixed a bug in the uninstall method ([#](https://wordpress.org/support/topic/bug-in-delete-script)) ## [1.6.0] (2012-12-22) @@ -1378,19 +1495,22 @@ ### Added * Added custom capabilities. -* Added 'Export to PHP' feature. ([#](https://wordpress.org/support/topic/plugin-code-snippets-suggestion-bulk-export-to-php)) +* Added 'Export to PHP' feature. + ([#](https://wordpress.org/support/topic/plugin-code-snippets-suggestion-bulk-export-to-php)) * Added i18n. ### Changed * Updated CodeMirror to version 2.33. * Updated the 'Manage Snippets' page to use the WP_List_Table class: - - Added 'Screen Options' tab to 'Manage Snippets' page. - - Added search capability to 'Manage Snippets' page. - - Added views to easily filter activated, deactivated and recently activated snippets. - - Added ID column to 'Manage Snippets' page. - - Added sortable name and ID column on 'Manage Snippets' page ([#](https://wordpress.org/support/topic/plugin-code-snippets-suggestion-sort-by-snippet-name)) + - Added 'Screen Options' tab to 'Manage Snippets' page. + - Added search capability to 'Manage Snippets' page. + - Added views to easily filter activated, deactivated and recently activated snippets. + - Added ID column to 'Manage Snippets' page. + - Added sortable name and ID column on 'Manage Snippets' page + ([#](https://wordpress.org/support/topic/plugin-code-snippets-suggestion-sort-by-snippet-name)) * Improved API. -* Lengthened snippet name field to 64 characters. ([#](https://wordpress.org/support/topic/plugin-code-snippets-snippet-title-limited-to-36-characters)) +* Lengthened snippet name field to 64 characters. + ([#](https://wordpress.org/support/topic/plugin-code-snippets-snippet-title-limited-to-36-characters)) ## [1.4.0] (2012-08-20) @@ -1434,9 +1554,11 @@ ## [1.1.0] (2012-06-24) ### Fixed -* Fixed a permissions bug with `DISALLOW_FILE_EDIT` being set to true. ([#](https://wordpress.org/support/topic/plugin-code-snippets-cant-add-new)) +* Fixed a permissions bug with `DISALLOW_FILE_EDIT` being set to true. + ([#](https://wordpress.org/support/topic/plugin-code-snippets-cant-add-new)) * Fixed a bug with the page title reading 'Add New Snippet' on the 'Edit Snippets' page. -* Fixed a bug not allowing the plugin to be Network Activated. ([#](https://wordpress.org/support/topic/plugin-code-snippets-network-activate-does-not-create-snippets-tables)) +* Fixed a bug not allowing the plugin to be Network Activated. + ([#](https://wordpress.org/support/topic/plugin-code-snippets-network-activate-does-not-create-snippets-tables)) ## [1.0.0] (2012-06-13) @@ -1446,22 +1568,6 @@ [brandonjp]: https://github.com/brandonjp [unreleased]: https://github.com/codesnippetspro/code-snippets/tree/core -[3.10.0]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.10.0 -[3.9.6]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.9.6 -[3.9.5]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.9.5 -[3.9.4]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.9.4 -[3.9.3]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.9.3 -[3.9.2]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.9.2 -[3.9.1]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.9.1 -[3.9.0]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.9.0 -[3.9.0-beta.2]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.9.0-beta.2 -[3.9.0-beta.1]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.9.0-beta.1 -[3.8.2]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.8.2 -[3.8.1]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.8.1 -[3.8.0]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.8.0 -[3.7.1-beta.3]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.7.1-beta.3 -[3.7.1-beta.2]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.7.1-beta.2 -[3.7.1-beta.1]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.7.1-beta.1 [3.7.0]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.7.0 [3.6.7]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.6.7 [3.6.6.1]: https://github.com/codesnippetspro/code-snippets/releases/tag/v3.6.6.1 diff --git a/config/webpack/webpack-js.ts b/config/webpack/webpack-js.ts index 62981acea..6c51a3ce5 100644 --- a/config/webpack/webpack-js.ts +++ b/config/webpack/webpack-js.ts @@ -24,7 +24,6 @@ const babelConfig = { export const jsWebpackConfig: Configuration = { entry: { - 'admin-bar': `${SOURCE_DIR}/admin-bar.ts`, 'edit': { import: `${SOURCE_DIR}/edit.ts`, dependOn: 'editor' }, 'editor': `${SOURCE_DIR}/editor.ts`, 'feedback': `${SOURCE_DIR}/feedback.ts`, @@ -35,6 +34,7 @@ export const jsWebpackConfig: Configuration = { 'mce': `${SOURCE_DIR}/mce.ts`, 'prism': `${SOURCE_DIR}/prism.ts`, 'settings': { import: `${SOURCE_DIR}/settings.ts`, dependOn: 'editor' }, + 'admin-bar': `${SOURCE_DIR}/admin-bar.ts`, 'welcome': `${SOURCE_DIR}/welcome.ts` }, output: { diff --git a/package-lock.json b/package-lock.json index 9f98a02e3..8e437da30 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "code-snippets", - "version": "4.0.0-beta.1", + "version": "4.0.0-beta.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "code-snippets", - "version": "4.0.0-beta.1", + "version": "4.0.0-beta.12", "license": "GPL-2.0-or-later", "dependencies": { "@codemirror/fold": "^0.19.4", @@ -23,7 +23,8 @@ "prismjs": "^1.29.0", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-select": "^5.10.0" + "react-select": "^5.10.0", + "uuid": "^11.1.0" }, "devDependencies": { "@axe-core/playwright": "^4.11.2", @@ -99,15 +100,23 @@ "node": ">=6.0.0" } }, - "node_modules/@ariakit/core": { - "version": "0.4.14", - "license": "MIT" + "node_modules/@ariakit/components": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/@ariakit/components/-/components-0.1.9.tgz", + "integrity": "sha512-Rmj5gcdfNQ4r4z5FzHHeC9OFRu9HSCVXDCDz8ak/vNHBrGmjeZ6Q3LOup61Eh+/GsT6cc2TDIQ6i8X1aB6y0BA==", + "license": "MIT", + "dependencies": { + "@ariakit/store": "0.1.7", + "@ariakit/utils": "0.1.5" + } }, "node_modules/@ariakit/react": { - "version": "0.4.15", + "version": "0.4.36", + "resolved": "https://registry.npmjs.org/@ariakit/react/-/react-0.4.36.tgz", + "integrity": "sha512-QKxSc6KvTHObB9khmaQlr6XOvjKyZSHr4JWnZTDwRFDgUAzz79a+p2vApCHFlqadqV1QeGezap5cxHrOysoNOg==", "license": "MIT", "dependencies": { - "@ariakit/react-core": "0.4.15" + "@ariakit/react-components": "0.4.0" }, "funding": { "type": "opencollective", @@ -118,19 +127,67 @@ "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/@ariakit/react-core": { - "version": "0.4.15", + "node_modules/@ariakit/react-components": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@ariakit/react-components/-/react-components-0.4.0.tgz", + "integrity": "sha512-dYymiYvAbyu6a/ehqYN2ZeieiMSYt0CMAj2BnDRUI/dZ9vLF32cv9PQMcgXXyqn0ILpqu79PQs53vVEZ+Z+0rQ==", "license": "MIT", "dependencies": { - "@ariakit/core": "0.4.14", - "@floating-ui/dom": "^1.0.0", - "use-sync-external-store": "^1.2.0" + "@ariakit/components": "0.1.9", + "@ariakit/react-store": "0.1.8", + "@ariakit/react-utils": "0.2.3", + "@ariakit/store": "0.1.7", + "@ariakit/utils": "0.1.5", + "@floating-ui/dom": "^1.0.0" }, "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/@ariakit/react-store": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@ariakit/react-store/-/react-store-0.1.8.tgz", + "integrity": "sha512-VYZ1LTUVMrNUi4jP37Npvhe3mcAzKdznqnBSVeh1Jjsbcgw0JlN88oy6UpdoJPvLKWOZHVYr62Sqn7xE0GrsqQ==", + "license": "MIT", + "dependencies": { + "@ariakit/react-utils": "0.2.3", + "@ariakit/store": "0.1.7", + "@ariakit/utils": "0.1.5", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@ariakit/react-utils": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@ariakit/react-utils/-/react-utils-0.2.3.tgz", + "integrity": "sha512-fDaheb/7QEusanZb2oRT7mO55GTpQUyBOdjvQF5RPh3/CM15lm0TejLKN5bl1obmU5HRuByvckQmQvSyr8n/dw==", + "license": "MIT", + "dependencies": { + "@ariakit/store": "0.1.7", + "@ariakit/utils": "0.1.5" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@ariakit/store": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@ariakit/store/-/store-0.1.7.tgz", + "integrity": "sha512-/GcxscA9QTo2F+IFbFPvoyj1N8hzXBnaYsQt9UxRiJgCFPQ2jIe4i6QgPXdOZEZUuqYdyuvjcQrg7MDm9vpvCA==", + "license": "MIT", + "dependencies": { + "@ariakit/utils": "0.1.5" + } + }, + "node_modules/@ariakit/utils": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@ariakit/utils/-/utils-0.1.5.tgz", + "integrity": "sha512-BQebYH9nV1VZttZwoq/fsxcxIJjc8oW2bNV6yJDHLZ8OF8UtM15drFN0JOL8Jwn7jeeD7Ev+tIC8pUijJEditQ==", + "license": "MIT" + }, "node_modules/@axe-core/playwright": { "version": "4.11.3", "resolved": "https://registry.npmjs.org/@axe-core/playwright/-/playwright-4.11.3.tgz", @@ -1994,14 +2051,16 @@ } }, "node_modules/@emotion/css": { - "version": "11.11.2", + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/css/-/css-11.13.5.tgz", + "integrity": "sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==", "license": "MIT", "dependencies": { - "@emotion/babel-plugin": "^11.11.0", - "@emotion/cache": "^11.11.0", - "@emotion/serialize": "^1.1.2", - "@emotion/sheet": "^1.2.2", - "@emotion/utils": "^1.2.1" + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.13.5", + "@emotion/serialize": "^1.3.3", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2" } }, "node_modules/@emotion/hash": { @@ -2057,7 +2116,9 @@ "license": "MIT" }, "node_modules/@emotion/styled": { - "version": "11.14.0", + "version": "11.14.1", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", + "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.18.3", @@ -2263,25 +2324,31 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.5.0", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz", + "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==", "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.1.3" + "@floating-ui/utils": "^0.2.12" } }, "node_modules/@floating-ui/dom": { - "version": "1.5.3", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz", + "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==", "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.4.2", - "@floating-ui/utils": "^0.1.3" + "@floating-ui/core": "^1.8.0", + "@floating-ui/utils": "^0.2.12" } }, "node_modules/@floating-ui/react-dom": { - "version": "2.1.1", + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.9.tgz", + "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==", "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.0.0" + "@floating-ui/dom": "^1.8.0" }, "peerDependencies": { "react": ">=16.8.0", @@ -2289,7 +2356,9 @@ } }, "node_modules/@floating-ui/utils": { - "version": "0.1.6", + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz", + "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==", "license": "MIT" }, "node_modules/@humanfs/core": { @@ -4146,13 +4215,13 @@ } }, "node_modules/@wordpress/a11y": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@wordpress/a11y/-/a11y-4.40.0.tgz", - "integrity": "sha512-WhBuBgJTvanbBMNeflgCvwQLOU9ToITdYSzOvWg0kzz1i/e138NlCxrVpcXGUc6MQulduKhOWOtjizSdotaQRA==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/a11y/-/a11y-4.52.0.tgz", + "integrity": "sha512-0KlDa/vSASriu84+z+a/XA2teaau6t6rCH6PEqMXoW5a6EbP2e/REpZRumbu0VzV5MRO5kpxfD+fVYNYz9BdlA==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/dom-ready": "^4.40.0", - "@wordpress/i18n": "^6.13.0" + "@wordpress/dom-ready": "^4.52.0", + "@wordpress/i18n": "^6.25.0" }, "engines": { "node": ">=18.12.0", @@ -4160,15 +4229,14 @@ } }, "node_modules/@wordpress/a11y/node_modules/@wordpress/i18n": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-6.13.0.tgz", - "integrity": "sha512-Yx882uFxcg6QpB13fv8UhvM6k5NwMQGfNXKB9SVSNL/APvDWn2m/n4n+5GZYi+wOV+KJLojQZbdRpHWCnX/jFg==", + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-6.25.0.tgz", + "integrity": "sha512-UcyUT8CJgEkhjzEGTVV6kw0Qi4OraF0I9J9FBLmTda/1Wi1o6rLAXZBm2aJrP740ezFxPneHH92aQF4Z5xZqcQ==", "license": "GPL-2.0-or-later", "dependencies": { "@tannin/sprintf": "^1.3.2", - "@wordpress/hooks": "^4.40.0", + "@wordpress/hooks": "^4.52.0", "gettext-parser": "^1.3.1", - "memize": "^2.1.0", "tannin": "^1.2.0" }, "bin": { @@ -4275,6 +4343,20 @@ "react-dom": "^18.0.0" } }, + "node_modules/@wordpress/components/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/@wordpress/compose": { "version": "7.40.0", "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-7.40.0.tgz", @@ -4303,19 +4385,19 @@ } }, "node_modules/@wordpress/data": { - "version": "10.40.0", - "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-10.40.0.tgz", - "integrity": "sha512-wwqkMc9iLteRO1zNxL/R3COWnijsdC5TIjenmd2JivReUmdA4ulAN3Tq7QiHkhwOV4jzZkuWW7DgR2ynxf55lw==", + "version": "10.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-10.52.0.tgz", + "integrity": "sha512-7Nx66TfUkYZDdXL4wn2/DjIJOYRsKdi8Gvv24Warv9rZ1pwTNoFXFDagvc3UoCOjn0pM8+pFNbd7a9TJH8oQzg==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/compose": "^7.40.0", - "@wordpress/deprecated": "^4.40.0", - "@wordpress/element": "^6.40.0", - "@wordpress/is-shallow-equal": "^5.40.0", - "@wordpress/priority-queue": "^3.40.0", - "@wordpress/private-apis": "^1.40.0", - "@wordpress/redux-routine": "^5.40.0", - "deepmerge": "^4.3.0", + "@wordpress/compose": "^8.5.0", + "@wordpress/deprecated": "^4.52.0", + "@wordpress/element": "^8.4.0", + "@wordpress/is-shallow-equal": "^5.52.0", + "@wordpress/priority-queue": "^3.52.0", + "@wordpress/private-apis": "^1.52.0", + "@wordpress/redux-routine": "^5.52.0", + "deepmerge": "^4.3.1", "equivalent-key-map": "^0.2.2", "is-plain-object": "^5.0.0", "is-promise": "^4.0.0", @@ -4328,16 +4410,75 @@ "npm": ">=8.19.2" }, "peerDependencies": { - "react": "^18.0.0" + "@types/react": "^18 || ^19", + "react": "^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@wordpress/data/node_modules/@wordpress/compose": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-8.5.0.tgz", + "integrity": "sha512-giYS22Tbhtr3Lj4lK6lxzGqV6EkM2QeVBiP7+c9r2F9rnQN3F6A8cN4gQM5sVGdgIOlps9tw+dsn9OHzIFVwIg==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@types/mousetrap": "^1.6.8", + "@wordpress/deprecated": "^4.52.0", + "@wordpress/dom": "^4.52.0", + "@wordpress/element": "^8.4.0", + "@wordpress/is-shallow-equal": "^5.52.0", + "@wordpress/keycodes": "^4.52.0", + "@wordpress/priority-queue": "^3.52.0", + "@wordpress/private-apis": "^1.52.0", + "@wordpress/undo-manager": "^1.52.0", + "change-case": "^4.1.2", + "mousetrap": "^1.6.5", + "use-memo-one": "^1.1.1" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "@types/react": "^18 || ^19", + "react": "^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@wordpress/data/node_modules/@wordpress/element": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-8.4.0.tgz", + "integrity": "sha512-/LzW+0MpSmKfYiESoXUQtjBPqOPyvqUm17GigQR5c0Z8Wj2NiklP72x4XaF02uSkau1ru1Z9lP8NWEGjwBwLsA==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@types/react": "^18.3.27", + "@types/react-dom": "^18.3.1", + "@wordpress/deprecated": "^4.52.0", + "@wordpress/escape-html": "^3.52.0", + "change-case": "^4.1.2", + "is-plain-object": "^5.0.0", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" } }, "node_modules/@wordpress/date": { - "version": "5.43.0", - "resolved": "https://registry.npmjs.org/@wordpress/date/-/date-5.43.0.tgz", - "integrity": "sha512-8DiFlE7YzP7F/P59Hr6h5fWJxJlvt6eZgU1C7huM9XhANh8Y3dZfepsySL6K7h1yE66SQDSq07cEefFQgJW31g==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/date/-/date-5.52.0.tgz", + "integrity": "sha512-JRAXv2CQwUiJq9k2n/iUqblo9rX3LUFJ03lA4zRy4+bxcSiMdpXvYrpZfUTp3W4I1Oc/fPZIYQY0HB3XNyjUWw==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/deprecated": "^4.43.0", + "@wordpress/deprecated": "^4.52.0", "moment": "^2.29.4", "moment-timezone": "^0.5.40" }, @@ -4347,12 +4488,12 @@ } }, "node_modules/@wordpress/deprecated": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@wordpress/deprecated/-/deprecated-4.43.0.tgz", - "integrity": "sha512-Pxn+nUmCVAaKBiZun2tEVweVdevMvWFWyCRqIqsAKdWCLsD8Uk6o27EwXc1u8BlO65VmK8D2zF9uWKGKfdZbCw==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/deprecated/-/deprecated-4.52.0.tgz", + "integrity": "sha512-94oHBKPty4pp6L5510LWDwJwNqFhikxLfwN6VUcDOQzj3itkc0MQ4ZQhmsfBy3Y6IRxSGx+p2bjSQvA4D+M96A==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/hooks": "^4.43.0" + "@wordpress/hooks": "^4.52.0" }, "engines": { "node": ">=18.12.0", @@ -4360,12 +4501,12 @@ } }, "node_modules/@wordpress/dom": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@wordpress/dom/-/dom-4.40.0.tgz", - "integrity": "sha512-JBF1sRjJMFgLn0pet0tmPzO1kNaa35/DwAAtG81zzjikctR1PzE3EK8o6ZGPtUY1sTa9l7aB1Lxfcum/eroyRg==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/dom/-/dom-4.52.0.tgz", + "integrity": "sha512-LUY9nI9h6blk4xBuG83KgyfTnx7PMs/g6ZVzY/SOaCcOc2P3zOfzacADq/vxQydbZpcwtLM6juzgnNta6AX95w==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/deprecated": "^4.40.0" + "@wordpress/deprecated": "^4.52.0" }, "engines": { "node": ">=18.12.0", @@ -4373,9 +4514,9 @@ } }, "node_modules/@wordpress/dom-ready": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-4.40.0.tgz", - "integrity": "sha512-mHVy4P6yc0XLmGgnccxptMKg83TwcbYKfYrQH8pTcIu43P24zONTd44eZFjkfz7c/b+RLJg1Kj+d5mKh1xqH1A==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-4.52.0.tgz", + "integrity": "sha512-dAsch1oeyRV4kwoQuqdr6dXisGAs09OtvGOk09Ke+QC0fTTPzxdKUw+c4M1nk0AmCeyZfqAqYYGCMm4n241QeQ==", "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", @@ -4486,9 +4627,9 @@ } }, "node_modules/@wordpress/escape-html": { - "version": "3.40.0", - "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-3.40.0.tgz", - "integrity": "sha512-DD6xWVbnw4fGGgO6DFDTJiLj52om0OG4cYHLz7ZhuipmOlEUGljPYOcrj8uxtlh5EFrqHCIPkOya+qQXUHUSBw==", + "version": "3.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-3.52.0.tgz", + "integrity": "sha512-sW8X839Xu8aiJlCGF48MM3iYrcXspuiY0By8iTpXKpnUdd2u0SL9HRR0ALSAsOf2ujOeWm/x58ODMSchovRWGw==", "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", @@ -4496,9 +4637,9 @@ } }, "node_modules/@wordpress/hooks": { - "version": "4.43.0", - "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-4.43.0.tgz", - "integrity": "sha512-BY7GPjEwhOlgkavVak40E3RtA8Z9ehydqTZckRoesMRjXYfxKSzr1C1FT4wAPS5uXM1pNlWivfofMaJjVNQu5w==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-4.52.0.tgz", + "integrity": "sha512-EbV/nJTerhqwNW3DLvvGutJfNyXcmBHXuWyJpv1NypzT80k21jPGP79HBE5Z0A2oAI2kIBp6Klaa4O8uEjq/sw==", "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", @@ -4506,9 +4647,9 @@ } }, "node_modules/@wordpress/html-entities": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@wordpress/html-entities/-/html-entities-4.40.0.tgz", - "integrity": "sha512-bsJrwZk22On8gNhUd84yyWKt/nrNZtACNZpXmkpyue/oTlFqNenLfhqRkvTKJzjbLxrrcUPsXlskbPcS7mxwTQ==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/html-entities/-/html-entities-4.52.0.tgz", + "integrity": "sha512-SM0XH+EgCi20Ptqv5WGkM8d2CAlThWRO/BVMeXzu6RLlcHKLMXNQZvW2waXCZtUpto8hlVZT9Dzg8z37sj4OiQ==", "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", @@ -4552,9 +4693,9 @@ } }, "node_modules/@wordpress/is-shallow-equal": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@wordpress/is-shallow-equal/-/is-shallow-equal-5.40.0.tgz", - "integrity": "sha512-IU11xOcHIGqDLxx9X+8RIk4WFo0qqba0bpeLqrVKsQXNGjP7tXSo2ufylxE9K9CEYXFMF0C65k83XpRZtEkA8g==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/is-shallow-equal/-/is-shallow-equal-5.52.0.tgz", + "integrity": "sha512-LMIBLLTZ+vvq0DlYebL4d9XaCu16PNnhPGSn8QqsMPmBzwBYOjO0/btMLpYbs9rRc8k1QKBDWvw8eddvRVsYxA==", "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", @@ -4562,28 +4703,35 @@ } }, "node_modules/@wordpress/keycodes": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.40.0.tgz", - "integrity": "sha512-laLkfjwkhMdreCl/KQdHucBIQAYwSjkyk3BToq/PCrcxFJBwWK2NgEtSl/t1CEw2HJwe0H2ne3FEWtipY4iDrA==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.52.0.tgz", + "integrity": "sha512-KRvwViTTdxUDgikYaCm+qnXSH2UlFuCDjAIvtjjcen8oRviSkeMv6bPn1T2vqFRKcVgt88xTtKlvI8l5U99o2Q==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/i18n": "^6.13.0" + "@wordpress/i18n": "^6.25.0" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" + }, + "peerDependencies": { + "@types/react": "^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, "node_modules/@wordpress/keycodes/node_modules/@wordpress/i18n": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-6.13.0.tgz", - "integrity": "sha512-Yx882uFxcg6QpB13fv8UhvM6k5NwMQGfNXKB9SVSNL/APvDWn2m/n4n+5GZYi+wOV+KJLojQZbdRpHWCnX/jFg==", + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-6.25.0.tgz", + "integrity": "sha512-UcyUT8CJgEkhjzEGTVV6kw0Qi4OraF0I9J9FBLmTda/1Wi1o6rLAXZBm2aJrP740ezFxPneHH92aQF4Z5xZqcQ==", "license": "GPL-2.0-or-later", "dependencies": { "@tannin/sprintf": "^1.3.2", - "@wordpress/hooks": "^4.40.0", + "@wordpress/hooks": "^4.52.0", "gettext-parser": "^1.3.1", - "memize": "^2.1.0", "tannin": "^1.2.0" }, "bin": { @@ -4595,12 +4743,12 @@ } }, "node_modules/@wordpress/primitives": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-4.40.0.tgz", - "integrity": "sha512-0gOw3n3kSUsAPo91xNDS9J4GGTrNXU90XmuWn7mNfXAl5uRAMRnxgkfL+pwd0ng0rmdPtjPqrJpljnP2oy3K2w==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-4.52.0.tgz", + "integrity": "sha512-rgB+Q1i97AY8AECLAEhvV/bGw9sOV6CKtUaY90t7nuv6M+ZgXqwQLRRWVaXWFUsthcZ2y4sTIbKfxwVJV+JQ6g==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/element": "^6.40.0", + "@wordpress/element": "^8.4.0", "clsx": "^2.1.1" }, "engines": { @@ -4608,13 +4756,39 @@ "npm": ">=8.19.2" }, "peerDependencies": { - "react": "^18.0.0" + "@types/react": "^18 || ^19", + "react": "^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@wordpress/primitives/node_modules/@wordpress/element": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-8.4.0.tgz", + "integrity": "sha512-/LzW+0MpSmKfYiESoXUQtjBPqOPyvqUm17GigQR5c0Z8Wj2NiklP72x4XaF02uSkau1ru1Z9lP8NWEGjwBwLsA==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@types/react": "^18.3.27", + "@types/react-dom": "^18.3.1", + "@wordpress/deprecated": "^4.52.0", + "@wordpress/escape-html": "^3.52.0", + "change-case": "^4.1.2", + "is-plain-object": "^5.0.0", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" } }, "node_modules/@wordpress/priority-queue": { - "version": "3.40.0", - "resolved": "https://registry.npmjs.org/@wordpress/priority-queue/-/priority-queue-3.40.0.tgz", - "integrity": "sha512-85km9+I7RWi7P73BU/yom41gpdu0watdQ1GscQhQBel6BjHOXO5qWG6P9i3sEH47bz7EyO248l4LC/h8oHqpfQ==", + "version": "3.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/priority-queue/-/priority-queue-3.52.0.tgz", + "integrity": "sha512-aYnVXxV5j4D73tRld2n1D3G6cKLfSwKWcTnktJ7XlmiswW7xlaAqvn4FyBjwmIe20pZw0A7xLH5xCuQcqOM7nw==", "license": "GPL-2.0-or-later", "dependencies": { "requestidlecallback": "^0.3.0" @@ -4625,9 +4799,9 @@ } }, "node_modules/@wordpress/private-apis": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-1.40.0.tgz", - "integrity": "sha512-68cwZKVq8Xy8GBzKoDRuV4b3pQ4nJFItY689HXp+poc0XXrnAeC4ZhjeSgS1qGRpFo6RVvLjjcaZsN2OrSSMvQ==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-1.52.0.tgz", + "integrity": "sha512-gFcmBXSti73Y4uEx++5qUNDaH/o0/2ijrHEJkY5e/df4RtmxVSQOIVxftRiI4m9thCWfJMoehMMreJxhwx6Qtg==", "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", @@ -4635,9 +4809,9 @@ } }, "node_modules/@wordpress/redux-routine": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@wordpress/redux-routine/-/redux-routine-5.40.0.tgz", - "integrity": "sha512-V+c1yCBl4i7qvRsWtQpGevbFCGtrRlzDe++4bwnrYJUiu79wbSXWRrmiSFr/EQie2KNM680t2MeFcfO7nsDVoA==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/redux-routine/-/redux-routine-5.52.0.tgz", + "integrity": "sha512-MpyNAKpfQAk8IWJ3Cwzc/p1dVEUl/iYxL6GCTX/y7K3c8qYd7csU4o5kuK9lfeqgVVI+d0y6rzBZiTaL2Z6Ojw==", "license": "GPL-2.0-or-later", "dependencies": { "is-plain-object": "^5.0.0", @@ -4653,42 +4827,99 @@ } }, "node_modules/@wordpress/rich-text": { - "version": "7.40.0", - "resolved": "https://registry.npmjs.org/@wordpress/rich-text/-/rich-text-7.40.0.tgz", - "integrity": "sha512-eHImTvzPEg4GWAuzcagyc2tArc6neA2sbqvybpd5JzhEpgv/Q0zcKwLfUKI05kYaaPI/Rg5WXgeXDxjGYpq5hA==", + "version": "7.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/rich-text/-/rich-text-7.52.0.tgz", + "integrity": "sha512-zyd7w4hs8TV+nWrC/hbULg4lKJQyxpd5AolFfOHAJmKM2LrU/Lvlobz9oyGuTrZ/HXdkFs3wzPMwS/VGydSjHw==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/a11y": "^4.40.0", - "@wordpress/compose": "^7.40.0", - "@wordpress/data": "^10.40.0", - "@wordpress/deprecated": "^4.40.0", - "@wordpress/dom": "^4.40.0", - "@wordpress/element": "^6.40.0", - "@wordpress/escape-html": "^3.40.0", - "@wordpress/i18n": "^6.13.0", - "@wordpress/keycodes": "^4.40.0", - "@wordpress/private-apis": "^1.40.0", - "colord": "2.9.3", - "memize": "^2.1.0" + "@wordpress/a11y": "^4.52.0", + "@wordpress/compose": "^8.5.0", + "@wordpress/data": "^10.52.0", + "@wordpress/deprecated": "^4.52.0", + "@wordpress/dom": "^4.52.0", + "@wordpress/element": "^8.4.0", + "@wordpress/escape-html": "^3.52.0", + "@wordpress/i18n": "^6.25.0", + "@wordpress/keycodes": "^4.52.0", + "@wordpress/private-apis": "^1.52.0", + "colord": "^2.9.3" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" }, "peerDependencies": { - "react": "^18.0.0" + "@types/react": "^18 || ^19", + "react": "^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@wordpress/rich-text/node_modules/@wordpress/compose": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-8.5.0.tgz", + "integrity": "sha512-giYS22Tbhtr3Lj4lK6lxzGqV6EkM2QeVBiP7+c9r2F9rnQN3F6A8cN4gQM5sVGdgIOlps9tw+dsn9OHzIFVwIg==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@types/mousetrap": "^1.6.8", + "@wordpress/deprecated": "^4.52.0", + "@wordpress/dom": "^4.52.0", + "@wordpress/element": "^8.4.0", + "@wordpress/is-shallow-equal": "^5.52.0", + "@wordpress/keycodes": "^4.52.0", + "@wordpress/priority-queue": "^3.52.0", + "@wordpress/private-apis": "^1.52.0", + "@wordpress/undo-manager": "^1.52.0", + "change-case": "^4.1.2", + "mousetrap": "^1.6.5", + "use-memo-one": "^1.1.1" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "@types/react": "^18 || ^19", + "react": "^18 || ^19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@wordpress/rich-text/node_modules/@wordpress/element": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-8.4.0.tgz", + "integrity": "sha512-/LzW+0MpSmKfYiESoXUQtjBPqOPyvqUm17GigQR5c0Z8Wj2NiklP72x4XaF02uSkau1ru1Z9lP8NWEGjwBwLsA==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@types/react": "^18.3.27", + "@types/react-dom": "^18.3.1", + "@wordpress/deprecated": "^4.52.0", + "@wordpress/escape-html": "^3.52.0", + "change-case": "^4.1.2", + "is-plain-object": "^5.0.0", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" } }, "node_modules/@wordpress/rich-text/node_modules/@wordpress/i18n": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-6.13.0.tgz", - "integrity": "sha512-Yx882uFxcg6QpB13fv8UhvM6k5NwMQGfNXKB9SVSNL/APvDWn2m/n4n+5GZYi+wOV+KJLojQZbdRpHWCnX/jFg==", + "version": "6.25.0", + "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-6.25.0.tgz", + "integrity": "sha512-UcyUT8CJgEkhjzEGTVV6kw0Qi4OraF0I9J9FBLmTda/1Wi1o6rLAXZBm2aJrP740ezFxPneHH92aQF4Z5xZqcQ==", "license": "GPL-2.0-or-later", "dependencies": { "@tannin/sprintf": "^1.3.2", - "@wordpress/hooks": "^4.40.0", + "@wordpress/hooks": "^4.52.0", "gettext-parser": "^1.3.1", - "memize": "^2.1.0", "tannin": "^1.2.0" }, "bin": { @@ -4700,12 +4931,12 @@ } }, "node_modules/@wordpress/undo-manager": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/@wordpress/undo-manager/-/undo-manager-1.40.0.tgz", - "integrity": "sha512-QvhHke/bVaOSPeaV5mNvsuIQpc2dJFDhXZ7gUnpuzyuNHh74Xk6Ar0vvYcfXiALst4ejKqWCoKOBi7ve1h2ppg==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/undo-manager/-/undo-manager-1.52.0.tgz", + "integrity": "sha512-6hI0WWDOtLLVEkWqQokCoQRz5Pba9UNtgt5MV4hHGe5x0mzsowj+GWHedppf8UCVZ2ex3cde7fThaRKMCackrQ==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/is-shallow-equal": "^5.40.0" + "@wordpress/is-shallow-equal": "^5.52.0" }, "engines": { "node": ">=18.12.0", @@ -4713,9 +4944,9 @@ } }, "node_modules/@wordpress/url": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-4.40.0.tgz", - "integrity": "sha512-DVAJlW7bdocKfQp8G7tS73vnobAC8TBbIHHdxeLQKwzT8mOkG4W/rpzN2KTxkiJKFXUu5in4F8a6T+Cy/Lt1eQ==", + "version": "4.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-4.52.0.tgz", + "integrity": "sha512-4cSo0dUHiOQB2DiiPkoVIqP5aoGJdIj32LD9XgG41yeh7xG6ALdDA1I/883WFRoX2JIYySFj208MzopURDH7Yg==", "license": "GPL-2.0-or-later", "dependencies": { "remove-accents": "^0.5.0" @@ -4726,9 +4957,9 @@ } }, "node_modules/@wordpress/warning": { - "version": "3.40.0", - "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-3.40.0.tgz", - "integrity": "sha512-0l3OFa1Z+UdhWRRHX9JWWKofo7Lbi2MqOFzzzn0MC26HOyfieQycjLVLNVNXaaodIKUhap6uDQq+JXbbHm881A==", + "version": "3.52.0", + "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-3.52.0.tgz", + "integrity": "sha512-BjJ+Jte1g2nMITI1IHq0NwMpm/qlFOV1L+gNe0vFQmGKEcXiQ0DjrHQNtA8hV+Mgt9zSWRNS71Fgonht3r72Ew==", "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", @@ -8036,15 +8267,19 @@ } }, "node_modules/framer-motion": { - "version": "11.3.28", + "version": "11.18.2", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.18.2.tgz", + "integrity": "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==", "license": "MIT", "dependencies": { + "motion-dom": "^11.18.1", + "motion-utils": "^11.18.1", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@emotion/is-prop-valid": { @@ -9873,7 +10108,9 @@ "license": "CC0-1.0" }, "node_modules/memize": { - "version": "2.1.0", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/memize/-/memize-2.1.1.tgz", + "integrity": "sha512-8Nl+i9S5D6KXnruM03Jgjb+LwSupvR13WBr4hJegaaEyobvowCVupi79y2WSiWvO1mzBWxPwEYE5feCe8vyA5w==", "license": "MIT" }, "node_modules/memoize-one": { @@ -10032,6 +10269,21 @@ "node": "*" } }, + "node_modules/motion-dom": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz", + "integrity": "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==", + "license": "MIT", + "dependencies": { + "motion-utils": "^11.18.1" + } + }, + "node_modules/motion-utils": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.18.1.tgz", + "integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==", + "license": "MIT" + }, "node_modules/mousetrap": { "version": "1.6.5", "resolved": "https://registry.npmjs.org/mousetrap/-/mousetrap-1.6.5.tgz", @@ -13713,7 +13965,9 @@ } }, "node_modules/use-sync-external-store": { - "version": "1.4.0", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" @@ -13725,14 +13979,16 @@ "license": "MIT" }, "node_modules/uuid": { - "version": "9.0.1", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", + "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], "license": "MIT", "bin": { - "uuid": "dist/bin/uuid" + "uuid": "dist/esm/bin/uuid" } }, "node_modules/v8-compile-cache-lib": { diff --git a/package.json b/package.json index 4d395c85b..d576992ff 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "code-snippets", "description": "Manage code snippets running on a WordPress-powered site through a graphical interface.", "homepage": "https://codesnippets.pro", - "version": "4.0.0-beta.1", + "version": "4.0.0-beta.12", "main": "src/dist/edit.js", "directories": { "test": "tests" @@ -63,7 +63,8 @@ "prismjs": "^1.29.0", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-select": "^5.10.0" + "react-select": "^5.10.0", + "uuid": "^11.1.0" }, "devDependencies": { "@axe-core/playwright": "^4.11.2", diff --git a/scripts/test-setup-playwright.ts b/scripts/test-setup-playwright.ts index 7ebdcd3b4..18d88b869 100644 --- a/scripts/test-setup-playwright.ts +++ b/scripts/test-setup-playwright.ts @@ -1,7 +1,7 @@ #!/usr/bin/env ts-node import { execFileSync } from 'node:child_process' -import { readFileSync } from 'node:fs' +import { existsSync, readFileSync } from 'node:fs' import { resolve } from 'node:path' const run = (cmd: string, args: readonly string[]) => { @@ -10,6 +10,22 @@ const run = (cmd: string, args: readonly string[]) => { const runWpEnvCli = (args: readonly string[]) => run('npx', ['wp-env', 'run', 'cli', ...args]) +const loadEnvFile = (): void => { + const envPath = resolve(process.cwd(), '.env') + + if (!existsSync(envPath)) { + return + } + + for (const line of readFileSync(envPath, 'utf8').split('\n')) { + const match = /^\s*(?[\w.-]+)\s*=\s*(?.*?)\s*$/u.exec(line) + + if (match?.groups && !(match.groups.key in process.env)) { + process.env[match.groups.key] = match.groups.value.replace(/^["']|["']$/u, '') + } + } +} + const getPluginSlug = (): string => { const prefix = 'wp-content/plugins/' const config = <{ mappings?: Record }>JSON.parse(readFileSync(resolve(process.cwd(), '.wp-env.json'), 'utf8')) @@ -29,6 +45,8 @@ const main = () => { // - force enable_flat_files=false so the Playwright setup test can flip it to true // - delete all DB snippets with an E2E prefix (keeps list clean across runs) + loadEnvFile() + runWpEnvCli(['sh', '-lc', 'rm -rf wp-content/code-snippets']) runWpEnvCli(['wp', 'plugin', 'activate', getPluginSlug()]) diff --git a/src/code-snippets.php b/src/code-snippets.php index 3f78bd0e5..539a75dfe 100644 --- a/src/code-snippets.php +++ b/src/code-snippets.php @@ -8,11 +8,11 @@ * License: GPL-2.0-or-later * License URI: license.txt * Text Domain: code-snippets - * Version: 4.0.0-beta.1 + * Version: 4.0.0-beta.12 * Requires PHP: 7.4 * Requires at least: 5.5 * - * @version 4.0.0-beta.1 + * @version 4.0.0-beta.12 * @package Code_Snippets * @author Shea Bunge * @copyright 2012-2026 Code Snippets Pro @@ -37,7 +37,7 @@ * * @const string */ - define( 'CODE_SNIPPETS_VERSION', '4.0.0-beta.1' ); + define( 'CODE_SNIPPETS_VERSION', '4.0.0-beta.12' ); /** * The full path to the main file of this plugin. diff --git a/src/css/admin-bar.scss b/src/css/admin-bar.scss index f3104e446..1ef7ceec1 100644 --- a/src/css/admin-bar.scss +++ b/src/css/admin-bar.scss @@ -112,8 +112,22 @@ opacity: 1; } + #wp-admin-bar-code-snippets-ran-on-this-page > .ab-sub-wrapper > .ab-submenu, #wp-admin-bar-code-snippets-active-snippets > .ab-sub-wrapper > .ab-submenu, #wp-admin-bar-code-snippets-inactive-snippets > .ab-sub-wrapper > .ab-submenu { padding-block-start: 0; } + + .code-snippets-kind-badge { + display: inline-block; + min-inline-size: 30px; + padding-inline: 5px; + border-radius: 3px; + color: #fff; + font-size: 10px; + font-weight: 600; + line-height: 1.7; + text-align: center; + text-transform: uppercase; + } } diff --git a/src/css/common/_badges.scss b/src/css/common/_badges.scss index 099aa47b3..cd0849693 100644 --- a/src/css/common/_badges.scss +++ b/src/css/common/_badges.scss @@ -77,6 +77,7 @@ $badges: ( cond: #22826f, core: #0ca0a9, pro: #f7e8e3 #df9279, + revisions: #50575e, cloud: #009fb4, bundles: #50575e, cloud_search: #d27c00, diff --git a/src/css/common/_buttons.scss b/src/css/common/_buttons.scss new file mode 100644 index 000000000..cb315d231 --- /dev/null +++ b/src/css/common/_buttons.scss @@ -0,0 +1,32 @@ +// A ` diff --git a/src/js/components/EditMenu/EditorSidebar/actions/ExportButtons.tsx b/src/js/components/EditMenu/EditorSidebar/actions/ExportButtons.tsx index 82d84aa71..a7b167465 100644 --- a/src/js/components/EditMenu/EditorSidebar/actions/ExportButtons.tsx +++ b/src/js/components/EditMenu/EditorSidebar/actions/ExportButtons.tsx @@ -11,10 +11,12 @@ import type { Snippet } from '../../../../types/Snippet' interface ExportButtonProps { name: string label: string + icon: string + title?: string makeRequest: (snippet: Snippet) => Promise } -const ExportButton: React.FC = ({ name, label, makeRequest }) => { +const ExportButton: React.FC = ({ name, label, icon, title, makeRequest }) => { const { snippet, isWorking, setIsWorking, handleRequestError } = useSnippetForm() const handleClick = () => { @@ -28,7 +30,8 @@ const ExportButton: React.FC = ({ name, label, makeRequest }) } return ( - ) @@ -43,13 +46,16 @@ export const ExportButtons: React.FC = () => { {window.CODE_SNIPPETS_EDIT?.enableDownloads && 'cond' !== getSnippetType(snippet) && ( )} diff --git a/src/js/components/EditMenu/EditorSidebar/controls/LockControl.tsx b/src/js/components/EditMenu/EditorSidebar/controls/LockControl.tsx index 84df9dcf1..6ad5800ca 100644 --- a/src/js/components/EditMenu/EditorSidebar/controls/LockControl.tsx +++ b/src/js/components/EditMenu/EditorSidebar/controls/LockControl.tsx @@ -41,6 +41,7 @@ export const LockControl: React.FC = () => { {snippet.locked ? QuickNav Active B', $active_titles[1] ); $_GET['code_snippets_ab_active_page'] = 2; @@ -241,7 +245,7 @@ public function test_snippet_listings_paginate_and_respect_query_arg(): void { $active_titles_page_2 = array_values( array_filter( $active_titles_page_2, static fn( $title ) => false !== strpos( $title, 'QuickNav Active' ) ) ); $this->assertCount( 1, $active_titles_page_2 ); - $this->assertStringContainsString( '(PHP) QuickNav Active C', $active_titles_page_2[0] ); + $this->assertStringContainsString( '>PHP QuickNav Active C', $active_titles_page_2[0] ); $_GET['code_snippets_ab_inactive_page'] = 2; @@ -264,7 +268,7 @@ public function test_snippet_listings_paginate_and_respect_query_arg(): void { ); $this->assertCount( 1, $inactive_titles_page_2 ); - $this->assertStringContainsString( '(HTML) QuickNav Inactive Z HTML', $inactive_titles_page_2[0] ); + $this->assertStringContainsString( '>HTML QuickNav Inactive Z HTML', $inactive_titles_page_2[0] ); } /** diff --git a/tests/unit/Admin/Feedback_Panel_Test.php b/tests/unit/Admin/Feedback_Panel_Test.php index 861a28b06..842bf9623 100644 --- a/tests/unit/Admin/Feedback_Panel_Test.php +++ b/tests/unit/Admin/Feedback_Panel_Test.php @@ -210,7 +210,7 @@ public function test_the_search_url_is_localised(): void { $this->assertStringContainsString( sprintf( '"searchUrl":"%s"', rest_url( Feedback_REST_Controller::get_base_route() . '/search' ) ), - (string) $data + stripslashes( $data ) ); } diff --git a/tests/unit/Admin/Menus/Manage/Manage_Menu_Assets_Test.php b/tests/unit/Admin/Menus/Manage/Manage_Menu_Assets_Test.php index 00d1be7e9..507b000e3 100644 --- a/tests/unit/Admin/Menus/Manage/Manage_Menu_Assets_Test.php +++ b/tests/unit/Admin/Menus/Manage/Manage_Menu_Assets_Test.php @@ -61,7 +61,7 @@ public function test_enqueue_localizes_manage_data(): void { } /** - * The AI Agent demo receives the site name it personalises its snippet with. + * The AI Agent demo receives the site name it personalizes its snippet with. * * @return void */ diff --git a/tests/unit/Admin/Menus/Manage/Manage_Menu_Demo_Reset_Test.php b/tests/unit/Admin/Menus/Manage/Manage_Menu_Demo_Reset_Test.php index 587b9532c..6491186fd 100644 --- a/tests/unit/Admin/Menus/Manage/Manage_Menu_Demo_Reset_Test.php +++ b/tests/unit/Admin/Menus/Manage/Manage_Menu_Demo_Reset_Test.php @@ -4,6 +4,7 @@ use Code_Snippets\REST_API\Preferences\Demos_Seen_REST_Controller; use Code_Snippets\UnitTestCase; +use ReflectionException; use ReflectionMethod; use RuntimeException; @@ -63,6 +64,8 @@ public function capture_redirect( string $location ) { * @param string $nonce Nonce to present. * * @return bool Whether the handler redirected, which it only does after resetting. + * + * @throws ReflectionException Uses reflection to access a private method. */ private function reset_request( string $nonce ): bool { $_GET[ Manage_Menu::DEMO_RESET_PARAM ] = '1'; @@ -70,8 +73,12 @@ private function reset_request( string $nonce ): bool { // The admin bootstrap does not run under PHPUnit, so the menu is built here. $menu = new Manage_Menu(); + $method = new ReflectionMethod( $menu, 'maybe_reset_demos' ); - $method->setAccessible( true ); + + if ( version_compare( PHP_VERSION, '8.1', '<' ) ) { + $method->setAccessible( true ); + } try { $method->invoke( $menu ); diff --git a/tests/unit/Admin/Notice_Filter_Test.php b/tests/unit/Admin/Notice_Filter_Test.php index f0bff06ab..8b2eeb087 100644 --- a/tests/unit/Admin/Notice_Filter_Test.php +++ b/tests/unit/Admin/Notice_Filter_Test.php @@ -3,6 +3,8 @@ namespace Code_Snippets\Admin; use Code_Snippets\AdminUnitTestCase; +use Code_Snippets\Controller\Cloud_Auth_Controller; +use Code_Snippets\Model\Basic_Cloud_Connection; use function Code_Snippets\code_snippets; /** diff --git a/tests/unit/Authorship_Test.php b/tests/unit/Authorship_Test.php new file mode 100644 index 000000000..c461692ca --- /dev/null +++ b/tests/unit/Authorship_Test.php @@ -0,0 +1,144 @@ +user->create( + [ + 'role' => 'administrator', + 'display_name' => 'Ada Author', + ] + ); + self::$editor_id = $factory->user->create( + [ + 'role' => 'administrator', + 'display_name' => 'Ed Editor', + ] + ); + } + + /** + * Start each test with an empty snippets table. + */ + public function set_up() { + parent::set_up(); + + global $wpdb; + $table_name = code_snippets()->db->get_table_name(); + $wpdb->query( "TRUNCATE TABLE $table_name" ); + } + + /** + * Create a snippet as the given user and return the stored copy. + * + * @param int $user_id User to act as. + * @param string $name Snippet name. + * + * @return Snippet + */ + private function save_as( int $user_id, string $name ): Snippet { + wp_set_current_user( $user_id ); + + $snippet = save_snippet( + new Snippet( + [ + 'name' => $name, + 'code' => "echo 'hi';", + ] + ) + ); + + return get_snippet( $snippet->id ); + } + + /** + * Stamps both authorship columns with the current user on insert. + */ + public function test_save_stamps_author_on_insert() { + $stored = $this->save_as( self::$author_id, 'Authored' ); + + $this->assertSame( self::$author_id, $stored->created_by ); + $this->assertSame( self::$author_id, $stored->updated_by ); + } + + /** + * Advances updated_by on a later save by another user while created_by stays fixed. + */ + public function test_updated_by_advances_while_created_by_is_fixed() { + $snippet = $this->save_as( self::$author_id, 'Shared' ); + + wp_set_current_user( self::$editor_id ); + $snippet->name = 'Shared (edited)'; + save_snippet( $snippet ); + + $stored = get_snippet( $snippet->id ); + $this->assertSame( self::$author_id, $stored->created_by, 'created_by is fixed at insert' ); + $this->assertSame( self::$editor_id, $stored->updated_by, 'updated_by follows the latest editor' ); + } + + /** + * Resolves a user ID to a compact display object. + */ + public function test_resolver_returns_display_object() { + $author = get_snippet_author( self::$author_id ); + + $this->assertIsArray( $author ); + $this->assertSame( self::$author_id, $author['id'] ); + $this->assertSame( 'Ada Author', $author['display_name'] ); + $this->assertArrayHasKey( 'avatar_url', $author ); + } + + /** + * Returns null for an empty or unknown user ID. + */ + public function test_resolver_returns_null_for_unknown() { + $this->assertNull( get_snippet_author( 0 ) ); + $this->assertNull( get_snippet_author( 987654 ) ); + } + + /** + * Embeds a nested author object in the snippets REST response, not a raw ID. + */ + public function test_rest_response_embeds_nested_author() { + $stored = $this->save_as( self::$author_id, 'Rest Authored' ); + + $request = new WP_REST_Request( 'GET', '/code-snippets/v1/snippets/' . $stored->id ); + $data = rest_get_server()->response_to_data( rest_do_request( $request ), false ); + + $this->assertIsArray( $data['created_by'] ); + $this->assertSame( self::$author_id, $data['created_by']['id'] ); + $this->assertSame( 'Ada Author', $data['created_by']['display_name'] ); + $this->assertArrayHasKey( 'avatar_url', $data['created_by'] ); + } +} diff --git a/tests/unit/Model/Cloud_Snippets_Test.php b/tests/unit/Model/Cloud_Snippets_Test.php index 05f2b6a53..380d01b76 100644 --- a/tests/unit/Model/Cloud_Snippets_Test.php +++ b/tests/unit/Model/Cloud_Snippets_Test.php @@ -269,4 +269,57 @@ public function test_string_fields_normalise_non_string_values(): void { $this->assertSame( '', $snippet->created ); $this->assertSame( '20260101', $snippet->updated ); } + + /** + * The page size is read from the meta block alongside the other counts. + * + * @return void + */ + public function test_reads_per_page_from_meta(): void { + $result = Cloud_Snippets::unpack_api_response( + [ + 'snippets' => [], + 'meta' => [ + 'total' => 60, + 'total_pages' => 3, + 'page' => 1, + 'per_page' => 20, + ], + ] + ); + + $this->assertSame( 20, $result->per_page ); + } + + /** + * A requested page size wins over the reported one, so callers can compare it + * against a later request even when an older cloud omits it from the meta. + * + * @return void + */ + public function test_requested_per_page_overrides_meta(): void { + $without_meta = Cloud_Snippets::unpack_api_response( [ 'snippets' => [] ], 1, 50 ); + $this->assertSame( 50, $without_meta->per_page ); + + $with_meta = Cloud_Snippets::unpack_api_response( + [ + 'snippets' => [], + 'meta' => [ 'per_page' => 20 ], + ], + 1, + 50 + ); + $this->assertSame( 50, $with_meta->per_page ); + } + + /** + * Page size defaults to zero when neither the response nor the caller states one. + * + * @return void + */ + public function test_per_page_defaults_to_zero(): void { + $result = Cloud_Snippets::unpack_api_response( [ 'snippets' => [] ] ); + + $this->assertSame( 0, $result->per_page ); + } } diff --git a/tests/unit/Plugin_Test.php b/tests/unit/Plugin_Test.php index 16fe57ace..897bebd27 100644 --- a/tests/unit/Plugin_Test.php +++ b/tests/unit/Plugin_Test.php @@ -39,7 +39,11 @@ private function get_elementor_promotion_callbacks(): array { foreach ( $callbacks as $callback ) { $function = $callback['function']; - if ( is_array( $function ) && $function[0] instanceof Elementor_Editor && 'promotion_in_custom_css_section' === $function[1] ) { + if ( + is_array( $function ) + && $function[0] instanceof Elementor_Editor + && 'promotion_in_custom_css_section' === $function[1] + ) { $promotion_callbacks[] = $function; } } diff --git a/tests/unit/REST_API/REST_API_Cloud_Test.php b/tests/unit/REST_API/Cloud/Cloud_Snippets_REST_Controller_Test.php similarity index 80% rename from tests/unit/REST_API/REST_API_Cloud_Test.php rename to tests/unit/REST_API/Cloud/Cloud_Snippets_REST_Controller_Test.php index 3fffcb4f9..329148ce8 100644 --- a/tests/unit/REST_API/REST_API_Cloud_Test.php +++ b/tests/unit/REST_API/Cloud/Cloud_Snippets_REST_Controller_Test.php @@ -1,14 +1,14 @@ requested_url = ''; $this->rest_server = $wp_rest_server ?? null; + delete_user_option( $this->get_user_id(), 'snippets_per_page' ); + add_filter( 'pre_http_request', [ $this, 'mock_cloud_search_request' ], 10, 3 ); } @@ -69,6 +71,7 @@ public function tear_down() { remove_filter( 'pre_http_request', [ $this, 'mock_cloud_search_request' ] ); delete_user_option( $this->get_user_id(), 'snippets_per_page' ); + $wp_rest_server = $this->rest_server; parent::tear_down(); @@ -84,6 +87,30 @@ public function tear_down() { * @return mixed */ public function mock_cloud_search_request( $preempt, array $parsed_args, string $url ) { + if ( false !== strpos( $url, 'private/allsnippets' ) ) { + ++$this->codevault_request_count; + + return [ + 'headers' => [], + 'body' => wp_json_encode( + [ + 'snippets' => [], + 'cloud_id_rev' => [], + 'meta' => [ + 'total' => 0, + 'total_pages' => 0, + 'page' => 1, + ], + ] + ), + 'response' => [ + 'code' => 200, + 'message' => 'OK', + ], + 'cookies' => [], + ]; + } + if ( false === strpos( $url, 'public/search' ) && false === strpos( $url, 'public/featured' ) ) { return $preempt; } @@ -145,17 +172,12 @@ public function mock_cloud_search_request( $preempt, array $parsed_args, string */ private function make_request( array $params, string $route = '' ): WP_REST_Response { global $wp_rest_server; - static $connection; - - if ( ! isset( $connection ) ) { - $connection = new Basic_Cloud_Connection(); - } $wp_rest_server = null; rest_get_server(); $request = new WP_REST_Request( 'GET', $this->endpoint . $route ); - $request->add_header( 'Access-Control', $connection->get_local_token() ); + $request->add_header( 'Access-Control', code_snippets()->cloud_connection->get_local_token() ); foreach ( $params as $key => $value ) { $request->set_param( $key, $value ); @@ -306,4 +328,49 @@ public function test_get_featured_items_reports_local_ids_for_downloaded_snippet $this->assertSame( 200, $response->get_status() ); $this->assertSame( $local->id, wp_list_pluck( $snippets, 'local_id', 'id' )[3] ?? null ); } + + /** + * The AI search method is forwarded to the cloud as s_method=ai. + */ + public function test_search_method_ai_is_forwarded_to_cloud(): void { + $response = $this->make_request( + [ + 'query' => 'make my site more secure', + 'searchMethod' => 'ai', + ] + ); + + parse_str( (string) wp_parse_url( $this->requested_url, PHP_URL_QUERY ), $query_args ); + + $this->assertSame( 200, $response->get_status() ); + $this->assertSame( 'ai', $query_args['s_method'] ?? null ); + } + + /** + * With no method params, the search defaults to keyword matching (term). + */ + public function test_search_method_defaults_to_term(): void { + $this->make_request( [ 'query' => 'test' ] ); + + parse_str( (string) wp_parse_url( $this->requested_url, PHP_URL_QUERY ), $query_args ); + + $this->assertSame( 'term', $query_args['s_method'] ?? null ); + } + + /** + * A codevault search takes precedence over an AI search method. + */ + public function test_codevault_takes_precedence_over_ai(): void { + $this->make_request( + [ + 'query' => 'general', + 'searchByCodevault' => true, + 'searchMethod' => 'ai', + ] + ); + + parse_str( (string) wp_parse_url( $this->requested_url, PHP_URL_QUERY ), $query_args ); + + $this->assertSame( 'codevault', $query_args['s_method'] ?? null ); + } } diff --git a/tests/unit/REST_API/REST_API_Snippets_Shared_Network_Toggle_Test.php b/tests/unit/REST_API/Snippets/REST_API_Snippets_Shared_Network_Toggle_Test.php similarity index 99% rename from tests/unit/REST_API/REST_API_Snippets_Shared_Network_Toggle_Test.php rename to tests/unit/REST_API/Snippets/REST_API_Snippets_Shared_Network_Toggle_Test.php index 703c8eb11..e9f8cb2cd 100644 --- a/tests/unit/REST_API/REST_API_Snippets_Shared_Network_Toggle_Test.php +++ b/tests/unit/REST_API/Snippets/REST_API_Snippets_Shared_Network_Toggle_Test.php @@ -1,6 +1,6 @@ Date: Tue, 15 Sep 2026 19:49:02 +1000 Subject: [PATCH 2/2] Fix broken unit test. --- src/php/REST_API/Cloud/Cloud_Snippets_REST_Controller.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/php/REST_API/Cloud/Cloud_Snippets_REST_Controller.php b/src/php/REST_API/Cloud/Cloud_Snippets_REST_Controller.php index 2b1e4aa30..c8e6e2822 100644 --- a/src/php/REST_API/Cloud/Cloud_Snippets_REST_Controller.php +++ b/src/php/REST_API/Cloud/Cloud_Snippets_REST_Controller.php @@ -237,6 +237,8 @@ private function attach_local_ids( Cloud_Snippets $snippets ): Cloud_Snippets { /** * Determine the search method to use based on request parameters. * + * @param WP_REST_Request $request The request object containing the search parameters. + * * @return string The search method to use. */ private function get_search_method( WP_REST_Request $request ): string {