diff --git a/CHANGELOG.md b/CHANGELOG.md index fcf87bef..4a71c25b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,152 +2,158 @@ ## Unreleased +## v2.6.2 - 04/22/2025 + +- Security: Escaped `[content_control]` `message` attribute. +- Fix: Misc JS bugs in admin. +- Developer: Added new `content_control/pre_restrict_content` & `content_control/pre_restrict_excerpt` filters to allow overloading/short curcuiting the default restriction application. + ## v2.6.1 - 03/15/2025 -* Improvement: Only fetch titles & ids when loading posts/taxonomy for the Restriction Editor. Reducing request overhead. -* Improvement: Ensure taxonomies are also removed from search appropriately. -* Improvement: Reduce memory footprint of overloaded object handling. -* Tweak: Adjust rest intent when using search endpoint or arg for better detection. -* Fix: Prevent undefined post type or taxonomy `public` arg from generating warning notices. -* Fix: Prvent warnings due to translations being loaded too early. +- Improvement: Only fetch titles & ids when loading posts/taxonomy for the Restriction Editor. Reducing request overhead. +- Improvement: Ensure taxonomies are also removed from search appropriately. +- Improvement: Reduce memory footprint of overloaded object handling. +- Tweak: Adjust rest intent when using search endpoint or arg for better detection. +- Fix: Prevent undefined post type or taxonomy `public` arg from generating warning notices. +- Fix: Prvent warnings due to translations being loaded too early. ## v2.6.0 - 03/11/2025 -* Feature: Added new setting to control restricted content visibility in search results. - * Site owners can now choose to completely hide restricted content from search results. - * Includes detailed security guidance when enabling search visibility. - * Helps prevent unintended exposure of sensitive information through search. - * Resolves concerns addressed in CVE-2024-11153 by default, now requiring explicit admin consent to show items in search results. -* Performance: Improved asset minification. +- Feature: Added new setting to control restricted content visibility in search results. + - Site owners can now choose to completely hide restricted content from search results. + - Includes detailed security guidance when enabling search visibility. + - Helps prevent unintended exposure of sensitive information through search. + - Resolves concerns addressed in CVE-2024-11153 by default, now requiring explicit admin consent to show items in search results. +- Performance: Improved asset minification. ## v2.5.0 - 08/18/2024 -* Improvement: Change rule processing to be more explicit for each context/rule type, improving performance & reliability of how rules are handled in some edge cases. -* Improvement: Update `content_control_known_blockTypes` option to not be autoloaded. -* Improvement: Update QueryMonitor output to differentiate between terms & posts. -* Fix: Error due to invalid return value variable name. +- Improvement: Change rule processing to be more explicit for each context/rule type, improving performance & reliability of how rules are handled in some edge cases. +- Improvement: Update `content_control_known_blockTypes` option to not be autoloaded. +- Improvement: Update QueryMonitor output to differentiate between terms & posts. +- Fix: Error due to invalid return value variable name. ## v2.4.0 - 06/21/2024 -* Improvement: Optimized the order we determine if we can skip checking restrictions for any givem content type. Thanks to PolyLang team for the suggestion. -* Improvement: Better coverage for taxonomy query detection & filtering. -* Improvement: Added inertnal function caches to drastically reduce overhead of checking restrictions. This may result in a significant performance increase for large sites or sites with many restrictions. -* Improvement: Only generate list of page template types for rules when in the admin, saving potential DB query. -* Tweak: Explicitly bail on rule checks for unknown Rest API endpoints as we don't currently fully support them. Filter below added to allow modifying this behavior. -* Tweak: Remove upsell message when pro version is active. -* Fix: Bug with restricting logged in users from content when the user had post_edit permissions for the post. -* Developer: Added new internal globals variable handler instead of using `global $vars` directly. Set of helper functions available to get/set/push/pop global variables. -* Developer: Made controllers more efficient by conditionally loading them only when needed. -* Developer: Added new filter `content_control/determine_uknonwn_rest_api_intent` to allow 3rd party plugins to modify the REST API intent used in rule checks specifically for unknown intents. -* Developer: Added new filter `content_control/request_is_excluded_rest_endpoint` to allow 3rd party plugins to exclude/include custom REST API endpoints from restriction checks. -* Developer: Added new filter `'content_control/pre_query_can_be_ignored` allowing early return for known ignorable queries. -* Developer: Added second paramter to the`content_control/get_rest_api_intent` filter pass the `$rest_route`. +- Improvement: Optimized the order we determine if we can skip checking restrictions for any givem content type. Thanks to PolyLang team for the suggestion. +- Improvement: Better coverage for taxonomy query detection & filtering. +- Improvement: Added inertnal function caches to drastically reduce overhead of checking restrictions. This may result in a significant performance increase for large sites or sites with many restrictions. +- Improvement: Only generate list of page template types for rules when in the admin, saving potential DB query. +- Tweak: Explicitly bail on rule checks for unknown Rest API endpoints as we don't currently fully support them. Filter below added to allow modifying this behavior. +- Tweak: Remove upsell message when pro version is active. +- Fix: Bug with restricting logged in users from content when the user had post_edit permissions for the post. +- Developer: Added new internal globals variable handler instead of using `global $vars` directly. Set of helper functions available to get/set/push/pop global variables. +- Developer: Made controllers more efficient by conditionally loading them only when needed. +- Developer: Added new filter `content_control/determine_uknonwn_rest_api_intent` to allow 3rd party plugins to modify the REST API intent used in rule checks specifically for unknown intents. +- Developer: Added new filter `content_control/request_is_excluded_rest_endpoint` to allow 3rd party plugins to exclude/include custom REST API endpoints from restriction checks. +- Developer: Added new filter `'content_control/pre_query_can_be_ignored` allowing early return for known ignorable queries. +- Developer: Added second paramter to the`content_control/get_rest_api_intent` filter pass the `$rest_route`. ## v2.3.0 - 05/23/2024 -* Improvement: Added more full coverage of all query types for for restriction handling. This helps catch more custom/3rd party AJAX search queries that were not being filtered. -* Improvement: Added better handling for excluding queries and admin views from restrictions. -* Improvement: Added filters for easier compatibility fixes with 3rd party plugins. -* Improvement: Added support/fixes for BetterDocs custom AJAX searching. -* Improvement: Added support/fixes for Blocksy theme custom AJAX searching. -* Fix: Bug where $post->ID was used without checking if $post was set. -* Developer: Added new filter `content_control/get_rest_api_intent` to allow 3rd party plugins to modify the REST API intent used in rule checks. +- Improvement: Added more full coverage of all query types for for restriction handling. This helps catch more custom/3rd party AJAX search queries that were not being filtered. +- Improvement: Added better handling for excluding queries and admin views from restrictions. +- Improvement: Added filters for easier compatibility fixes with 3rd party plugins. +- Improvement: Added support/fixes for BetterDocs custom AJAX searching. +- Improvement: Added support/fixes for Blocksy theme custom AJAX searching. +- Fix: Bug where $post->ID was used without checking if $post was set. +- Developer: Added new filter `content_control/get_rest_api_intent` to allow 3rd party plugins to modify the REST API intent used in rule checks. ## v2.2.8 - 05/07/2024 -* Fix: Issue causing some non-admin AJAX requests to the REST API from being run through protection checks. -* Fix: Error when using page template rules & global $post is not set properly. +- Fix: Issue causing some non-admin AJAX requests to the REST API from being run through protection checks. +- Fix: Error when using page template rules & global $post is not set properly. ## v2.2.7 - 03/20/2024 -* Improvement: Fix plugin preview blueprint file location. +- Improvement: Fix plugin preview blueprint file location. ## v2.2.6 - 03/20/2024 -* Improvement: Add plugin preview blueprint support. +- Improvement: Add plugin preview blueprint support. ## v2.2.5 - 03/20/2024 -* Improvement: Logic for protection being disabled was improved to be more efficient. -* Fix: Bug with The Events Calendar showing blank screen when using Redirect restriction. -* Fix: Bug where redirect based restrictions failed on The Events Calendar pages. -* Fix: Typo in order of widget REST API check conditionals. +- Improvement: Logic for protection being disabled was improved to be more efficient. +- Fix: Bug with The Events Calendar showing blank screen when using Redirect restriction. +- Fix: Bug where redirect based restrictions failed on The Events Calendar pages. +- Fix: Typo in order of widget REST API check conditionals. ## v2.2.4 - 03/20/2024 -* Fix: Enforced strict versioning in autoload build tool that recently auto updated causing the autoloader to suddenly leak unprefixed classes. This was causing random issues in combination with [incompatible autoloading by other plugins](https://pressidium.com/blog/wordpress-plugin-conflicts-how-to-prevent-composer-dependency-hell/). +- Fix: Enforced strict versioning in autoload build tool that recently auto updated causing the autoloader to suddenly leak unprefixed classes. This was causing random issues in combination with [incompatible autoloading by other plugins](https://pressidium.com/blog/wordpress-plugin-conflicts-how-to-prevent-composer-dependency-hell/). ## v2.2.3 - 03/19/2024 -* Fix: Recurssion error with taxonomy queries due to calling setup_post during get_terms query. WooCommerce then setup global $product, which called another taxonomy query, and so on. -* Fix: Bug when modified WP_Term_Query->terms arrays of ints were passed instead of epxected term objects. +- Fix: Recurssion error with taxonomy queries due to calling setup_post during get_terms query. WooCommerce then setup global $product, which called another taxonomy query, and so on. +- Fix: Bug when modified WP_Term_Query->terms arrays of ints were passed instead of epxected term objects. ## v2.2.2 - 03/19/2024 -* Fix: Bug with new taxonomy query filter. For now this is limited to the REST API only. +- Fix: Bug with new taxonomy query filter. For now this is limited to the REST API only. ## v2.2.1 - 03/18/2024 -* Fix: Bug where the plugin had errors on taxonomy pages or queries. -* Fix: Error when Term query taxonomy arg was not an array. +- Fix: Bug where the plugin had errors on taxonomy pages or queries. +- Fix: Error when Term query taxonomy arg was not an array. ## v2.2.0 - 03/17/2024 -* Feature: Add support for [restricing content in the REST API](https://contentcontrolplugin.com/features/rest-api/). -* Feature: Add support for terms in WP term queries. -* Fix: Nav Menu Link user rule not working properly. -* Fix: Prevent "Required Upgrade" notices on new installs. -* Tweak: Only show "Required Upgrade" notices to admins with plugin management permissions. -* Dev:: Added new field type `userselect` for choosing users with search. +- Feature: Add support for [restricing content in the REST API](https://contentcontrolplugin.com/features/rest-api/). +- Feature: Add support for terms in WP term queries. +- Fix: Nav Menu Link user rule not working properly. +- Fix: Prevent "Required Upgrade" notices on new installs. +- Tweak: Only show "Required Upgrade" notices to admins with plugin management permissions. +- Dev:: Added new field type `userselect` for choosing users with search. ## v2.1.0 - 12/08/2023 NOTE: Plugin now requires PHP 7.4+ & WP 6.2+. The plugin may still work on older versions, but it is no longer tested or supported. -* Improvement: Preloaded plugin settings on admin pages to decrease delay before settings are available to JS. This should help settings not showing up in the editor when first loading the page. -* Tweak: Changed `'content_control/get_block_control_classes'` filter to include the $controls found in the block. -* Tweak: Various style improvements to admin pages for consistency. -* Fix: Typo in fetching of taxonomy labels for rule generation. This could have led to rule search results not being shown with proper labels (or empty labels). -* Fix: Block scanner running for all users, not just admins, triggered AJAX events that were denied every time author entered block editor. -* Fix: Styling issues with WP 6.4 checkbox changes. -* Fix: Bug when filtering restrictions in the list view and no results remained, causing the filters to not work properly witoout a page refresh. -* Developer: Core plugin class now is extendible to allow addons to get full access to plugin internals. -* Developer: Added useFields api which will be used in future versions of the plugin to allow 3rd party plugins to add their own fields to the restriction editor. -* Developer: Added multiple new components for field organization and layout: `FieldRow`, `FieldPanel`. -* Developer: Added new `'content-control.data.registry'` hook in JavaScript to allow addons to register their own data stores for use in the editor & settings pages. -* Developer: Added new `'content_control/restriction/bypass_user_requirements'` PHP filter to allow addons to bypass user requirements for more specific restrictions. +- Improvement: Preloaded plugin settings on admin pages to decrease delay before settings are available to JS. This should help settings not showing up in the editor when first loading the page. +- Tweak: Changed `'content_control/get_block_control_classes'` filter to include the $controls found in the block. +- Tweak: Various style improvements to admin pages for consistency. +- Fix: Typo in fetching of taxonomy labels for rule generation. This could have led to rule search results not being shown with proper labels (or empty labels). +- Fix: Block scanner running for all users, not just admins, triggered AJAX events that were denied every time author entered block editor. +- Fix: Styling issues with WP 6.4 checkbox changes. +- Fix: Bug when filtering restrictions in the list view and no results remained, causing the filters to not work properly witoout a page refresh. +- Developer: Core plugin class now is extendible to allow addons to get full access to plugin internals. +- Developer: Added useFields api which will be used in future versions of the plugin to allow 3rd party plugins to add their own fields to the restriction editor. +- Developer: Added multiple new components for field organization and layout: `FieldRow`, `FieldPanel`. +- Developer: Added new `'content-control.data.registry'` hook in JavaScript to allow addons to register their own data stores for use in the editor & settings pages. +- Developer: Added new `'content_control/restriction/bypass_user_requirements'` PHP filter to allow addons to bypass user requirements for more specific restrictions. ## v2.0.12 - 10/26/2023 -* Fix: Prevent extra 301 redirect due to missing trailing slash on some URLs. -* Fix: Issue with Custom Message replacement not always working on pages built with Elementor. +- Fix: Prevent extra 301 redirect due to missing trailing slash on some URLs. +- Fix: Issue with Custom Message replacement not always working on pages built with Elementor. ## v2.0.11 - 10/04/2023 -* Improvement: Query Monitor integration to show which restrictions are active on a page. - * Shows global settings that may be affecting the page. - * Shows which restrictions are active on the page. - * Shows which posts are being filtered out of queries and by which restriction. -* Tweak: Ensure upgrade stream doesn't send headers if they were already sent. -* Tweak: Make second arg on get_the_excerpt filter optional to prevent errors with some plugins. -* Fix: Bug when using `content_control/check_all_restrictions` filter that caused rules to not compare properly. +- Improvement: Query Monitor integration to show which restrictions are active on a page. + - Shows global settings that may be affecting the page. + - Shows which restrictions are active on the page. + - Shows which posts are being filtered out of queries and by which restriction. +- Tweak: Ensure upgrade stream doesn't send headers if they were already sent. +- Tweak: Make second arg on get_the_excerpt filter optional to prevent errors with some plugins. +- Fix: Bug when using `content_control/check_all_restrictions` filter that caused rules to not compare properly. ## v2.0.10 - 10/01/2023 -* Improvement: If no v1 global restrictions existed, skip the migration step entirely. -* Improvement: Default to late init of post query filtering until after plugins_loaded should be finished. This should prevent help prevent random errors due to restrictions being checked before plugins have had a chance to register their post types, and thus restrictions won't properly match those post type rules. -* Improvement: Add check to prevent restriction checks for **WP CLI** requests. -* Improvement: Add notice to indicate is when waiting for post/page search results in the restriction editor fields. -* Tweak: Fix issue in build that caused autoloader to not fully use optimized classmap, should result in improved performance. -* Fix: Ensure `$wp_rewrite` is available before calling `is_rest()` -> `get_rest_url()`. This should prevent errors when using the plugin with **WP CLI** and when plugins make `WP_Query` calls during `plugins_loaded`. -* Fix: Don't attempt to initialize side query filtering until after_theme_setup hook. This should prevent errors when plugins make `WP_Query` calls during `plugins_loaded`, and allow further delaying initialization if needed from themes `functions.php` file. -* Fix: Backward compatibility issue with WP versions <6.2 that made settings page not render. -* Fix: Bug where Block Controls didn't work on WooCommerce pages. This was filtering `pre_render_block` but not returning a value. Now we run our check after theirs to ensure that bug has no effect on our plugin. [Report](https://github.com/woocommerce/woocommerce-blocks/issues/11077) +- Improvement: If no v1 global restrictions existed, skip the migration step entirely. +- Improvement: Default to late init of post query filtering until after plugins_loaded should be finished. This should prevent help prevent random errors due to restrictions being checked before plugins have had a chance to register their post types, and thus restrictions won't properly match those post type rules. +- Improvement: Add check to prevent restriction checks for **WP CLI** requests. +- Improvement: Add notice to indicate is when waiting for post/page search results in the restriction editor fields. +- Tweak: Fix issue in build that caused autoloader to not fully use optimized classmap, should result in improved performance. +- Fix: Ensure `$wp_rewrite` is available before calling `is_rest()` -> `get_rest_url()`. This should prevent errors when using the plugin with **WP CLI** and when plugins make `WP_Query` calls during `plugins_loaded`. +- Fix: Don't attempt to initialize side query filtering until after_theme_setup hook. This should prevent errors when plugins make `WP_Query` calls during `plugins_loaded`, and allow further delaying initialization if needed from themes `functions.php` file. +- Fix: Backward compatibility issue with WP versions <6.2 that made settings page not render. +- Fix: Bug where Block Controls didn't work on WooCommerce pages. This was filtering `pre_render_block` but not returning a value. Now we run our check after theirs to ensure that bug has no effect on our plugin. [Report](https://github.com/woocommerce/woocommerce-blocks/issues/11077) ## v2.0.9 - 09/24/2023 -* Improvement: Better handling of restriction titles & content. Admins with priv can insert any content into the restriction messages. -* Improvement: Added new filter `content_control/query_filter_init_hook` to allow delaying query filtering for compatibility with plugins that make custom queries before `template_redirect` action. +- Improvement: Better handling of restriction titles & content. Admins with priv can insert any content into the restriction messages. +- Improvement: Added new filter `content_control/query_filter_init_hook` to allow delaying query filtering for compatibility with plugins that make custom queries before `template_redirect` action. ```php add_filter( 'content_control/query_filter_init_hook', function () { @@ -155,150 +161,150 @@ add_filter( 'content_control/query_filter_init_hook', function () { } ); ``` -* Tweak: Ensure our restriction checks work within a nested post loop. -* Tweak: Change how restriction title & descriptions were sent/received over Rest API. -* Fix: Bug that caused some shortcodes to not render properly. -* Fix: Bug where override message wasn't used. -* Fix: Bug where Elementor Post loop would render incorrectly when using ACF fields in the loop template. +- Tweak: Ensure our restriction checks work within a nested post loop. +- Tweak: Change how restriction title & descriptions were sent/received over Rest API. +- Fix: Bug that caused some shortcodes to not render properly. +- Fix: Bug where override message wasn't used. +- Fix: Bug where Elementor Post loop would render incorrectly when using ACF fields in the loop template. ## v2.0.8 - 09/22/2023 -* Tweak: Ignore many Elementor queries from being restricted. -* Fix: Error when required upgrade was marked as complete. -* Fix: Bug that caused secondary queries to be handled like main queries. +- Tweak: Ignore many Elementor queries from being restricted. +- Fix: Error when required upgrade was marked as complete. +- Fix: Bug that caused secondary queries to be handled like main queries. ## v2.0.7 - 09/21/2023 -* Tweak: Only log each unique plugin debug notice once to prevent filling log files quickly. -* Tweak: Replace usage of `wp_upload_dir` with `wp_get_upload_dir` which is more performant. -* Fix: Error in upgrades when no data is found to migrate. -* Fix: Error when function is called early & global $wp_query is not yet available. -* Fix: Conditional check that could always return false. -* Developer: Implemented PHP Static Analysis to catch more bugs before they happen. Currently clean on lvl 6. +- Tweak: Only log each unique plugin debug notice once to prevent filling log files quickly. +- Tweak: Replace usage of `wp_upload_dir` with `wp_get_upload_dir` which is more performant. +- Fix: Error in upgrades when no data is found to migrate. +- Fix: Error when function is called early & global $wp_query is not yet available. +- Fix: Conditional check that could always return false. +- Developer: Implemented PHP Static Analysis to catch more bugs before they happen. Currently clean on lvl 6. ## v2.0.6 - 09/19/2023 -* Improvement: Added data backup step to upgrade process that stores json export in the media library. -* Improvement: Better error handling in the data upgrade process. -* Fix: Fix bug in data upgrade process that caused it to never finish. -* Fix: Possible error when no restriction match found in some custom` queries. +- Improvement: Added data backup step to upgrade process that stores json export in the media library. +- Improvement: Better error handling in the data upgrade process. +- Fix: Fix bug in data upgrade process that caused it to never finish. +- Fix: Possible error when no restriction match found in some custom` queries. ## v2.0.5 - 09/18/2023 -* Fix: Fix errors on some sites with custom conditions due to registering all rules too early. +- Fix: Fix errors on some sites with custom conditions due to registering all rules too early. ## v2.0.4 - 09/18/2023 -* Fix: Error when WP Query vars include anonymous function closures. +- Fix: Error when WP Query vars include anonymous function closures. ## v2.0.3 - 09/18/2023 -* Fix: Log errors instead of throwing exceptions to prevent uncaught exceptions turning into fatal errors. +- Fix: Log errors instead of throwing exceptions to prevent uncaught exceptions turning into fatal errors. ## v2.0.2 - 09/18/2023 -* Fix: Fatal error from error logger on systems without write access. +- Fix: Fatal error from error logger on systems without write access. ## v2.0.1 - 09/17/2023 -* Fix: Fatal error from unregistered or unknown rule types from 3rd party plugins/themes or custom code. Now they are logged in plugin settings page. +- Fix: Fatal error from unregistered or unknown rule types from 3rd party plugins/themes or custom code. Now they are logged in plugin settings page. ## v2.0.0 - 09/17/2023 -* Feature: Restrict individual blocks in the Gutenberg editor. -* Feature: Restrict individual blocks in the Full Site Editor. -* Feature: Use a custom page template for restricted content. -* Feature: Restrict blocks by device type with customizable breakpoints. -* Feature: Restrict blocks by user status & role. -* Feature: Global restrictions now offer more control over how restricted content is handled. - * Choose to redirect or replace content with a custom page. - * Filter or hide posts in archives or custom loops. - * Secondary controls for posts if found in an archive. -* Improvement: Match or exclude specific roles. -* Improvement: Updated interface with intuitive and responsive controls. -* Improvement: Boolean editor improvements. -* Improvement: Control who can modify plugin settings. -* Improvement: Upgraded tooling & Code quality improvements. +- Feature: Restrict individual blocks in the Gutenberg editor. +- Feature: Restrict individual blocks in the Full Site Editor. +- Feature: Use a custom page template for restricted content. +- Feature: Restrict blocks by device type with customizable breakpoints. +- Feature: Restrict blocks by user status & role. +- Feature: Global restrictions now offer more control over how restricted content is handled. + - Choose to redirect or replace content with a custom page. + - Filter or hide posts in archives or custom loops. + - Secondary controls for posts if found in an archive. +- Improvement: Match or exclude specific roles. +- Improvement: Updated interface with intuitive and responsive controls. +- Improvement: Boolean editor improvements. +- Improvement: Control who can modify plugin settings. +- Improvement: Upgraded tooling & Code quality improvements. ## v1.18.2 - 07/03/2023 -* Fix: WP 4.9 missing `wp_get_environment_type` function notices +- Fix: WP 4.9 missing `wp_get_environment_type` function notices ## v1.18.1 - 03/08/2023 -* Improvement: Add nonce to asset cache purging for admins. -* Fix: PHP 8.2 Deprecated notices. -* Fix: Bug in asset caching causing assets to falsly determine they couldn't be writtien. -* Fix: Add backcompat fix for WP >5.3 `wp_date` errors. +- Improvement: Add nonce to asset cache purging for admins. +- Fix: PHP 8.2 Deprecated notices. +- Fix: Bug in asset caching causing assets to falsly determine they couldn't be writtien. +- Fix: Add backcompat fix for WP >5.3 `wp_date` errors. ## v1.1.10 - 12/28/2022 = -* Security: Fix unescaped output for CSS classname in the [contentcontrol] shortcode allowing users with the ability to edit posts to inject code into the page. +- Security: Fix unescaped output for CSS classname in the [contentcontrol] shortcode allowing users with the ability to edit posts to inject code into the page. ## v1.1.9 - 09/30/2021 = -* Fix: Error when using Gutenberg Preview. +- Fix: Error when using Gutenberg Preview. ## v1.1.8 - 07/17/2021 = -* Fix: Error when Elementor instance preview proptery was null. +- Fix: Error when Elementor instance preview proptery was null. ## v1.1.7 - 07/17/2021 = -* Fix: Prevent warning if widget settings don't exist in options table. -* Fix: Arbitrary limit of 10 on current items listed in Restriction Editor due to WP query default args. -* Fix: Prevent restrictions from activating when using the Elementor page builder. +- Fix: Prevent warning if widget settings don't exist in options table. +- Fix: Arbitrary limit of 10 on current items listed in Restriction Editor due to WP query default args. +- Fix: Prevent restrictions from activating when using the Elementor page builder. ## v1.1.6 - 03/21/2021 = -* Fix: Nonce validation was preventing 3rd party plugin from saving widget settings when it failed. Thanks @jacobmischka -* Fix: Prevent corrupted options from preventing saving of settings. +- Fix: Nonce validation was preventing 3rd party plugin from saving widget settings when it failed. Thanks @jacobmischka +- Fix: Prevent corrupted options from preventing saving of settings. ## v1.1.5 - 02/22/2021 = -* Fix: Issue where roles with `-` would not save when checked. +- Fix: Issue where roles with `-` would not save when checked. ## v1.1.4 - 03/24/2020 = -* Improvement: Added gettext handling for several strings that were not translatable. -* Tweak: Process shortcodes in default denial message contents. -* Tweak: Various improvements in form reliability & user experience. -* Fix: Issues with ajax search fields not retaining their values after save. -* Fix: Issue where only would show 10 pages. -* Fix: PHP 7.4 compatibility fixes. +- Improvement: Added gettext handling for several strings that were not translatable. +- Tweak: Process shortcodes in default denial message contents. +- Tweak: Various improvements in form reliability & user experience. +- Fix: Issues with ajax search fields not retaining their values after save. +- Fix: Issue where only would show 10 pages. +- Fix: PHP 7.4 compatibility fixes. ## v1.1.3 - 12/03/2019 = -* Fix: Custom post type conditions were not always registered. +- Fix: Custom post type conditions were not always registered. ## v1.1.2 - 11/10/2019 = -* Tweak: Remove erroneous console.log messages in admin. -* Fix: Fatal error when empty shortcode used. +- Tweak: Remove erroneous console.log messages in admin. +- Fix: Fatal error when empty shortcode used. ## v1.1.1 - 10/15/2019 = -* Fix: Bugs where variables were not always the expected type. +- Fix: Bugs where variables were not always the expected type. ## v1.1.0 = -* Improvement: Added default denial message to shortcode. -* Improvement: Render nested shortcodes in the [content_control] shortcode. -* Fix: Bug where multiple roles checked together in restriction editor. +- Improvement: Added default denial message to shortcode. +- Improvement: Render nested shortcodes in the [content_control] shortcode. +- Fix: Bug where multiple roles checked together in restriction editor. ## v1.0.3 = -* Fix: Minor notice on activation. +- Fix: Minor notice on activation. ## v1.0.2 = -* Fix: Call to undefined function. +- Fix: Call to undefined function. ## v1.0.1 = -* Fix: Non static method called statically -* Fix: Bug when using invalid variable type. +- Fix: Non static method called statically +- Fix: Bug when using invalid variable type. ## v1.0.0 = -* Initial Release +- Initial Release diff --git a/bin/update-changelog.js b/bin/update-changelog.js new file mode 100644 index 00000000..0a84d5ac --- /dev/null +++ b/bin/update-changelog.js @@ -0,0 +1,112 @@ +const fs = require( 'fs' ); + +// Read the current version number from package.json +const newVersion = process.argv[ 2 ]; +// --- Format Date as MM/DD/YYYY --- +const today = new Date(); +const month = String( today.getMonth() + 1 ).padStart( 2, '0' ); // Months are 0-indexed +const day = String( today.getDate() ).padStart( 2, '0' ); +const year = today.getFullYear(); +const releaseDate = `${ month }/${ day }/${ year }`; // Format as MM/DD/YYYY +// --- End Date Formatting --- + +if ( ! newVersion ) { + console.error( 'Please provide the new version number as an argument.' ); + process.exit( 1 ); +} + +// Check if --verbose or -v is passed +const isVerbose = + process.argv.includes( '--verbose' ) || process.argv.includes( '-v' ); + +// Read and process CHANGELOG.md +const changelogFilePath = 'CHANGELOG.md'; +const readmeFilePath = 'readme.txt'; + +let changelogContent = fs.readFileSync( changelogFilePath, 'utf8' ); + +// Improved pattern to capture unreleased changes +const unreleasedPattern = /^## Unreleased\s([\s\S]*?)(?=\n## |\n$)/m; +const unreleasedMatch = changelogContent.match( unreleasedPattern ); + +if ( ! unreleasedMatch ) { + console.error( 'No unreleased changes found in CHANGELOG.md.' ); + process.exit( 1 ); +} + +const unreleasedChanges = unreleasedMatch[ 1 ] + .trim() + .split( '\n' ) + .filter( ( line ) => line.trim() !== '' ); +const changeCount = unreleasedChanges.length; + +// Format unreleased changes into a numbered list if verbose option is used +if ( isVerbose ) { + const formattedConsoleChanges = unreleasedChanges + .map( + ( change, index ) => + `${ index + 1 }. ${ change.replace( /^\-\s*/, '' ) }` + ) + .join( '\n' ); + console.log( 'Unreleased Changes:\n' + formattedConsoleChanges ); +} + +// --- Format for CHANGELOG.md --- +// The captured lines already have the correct '- ' format. +// Just join them together. +const formattedChangelogChanges = unreleasedChanges.join( '\n' ); + +// Update CHANGELOG.md with new version using the original lines +const updatedChangelog = changelogContent.replace( + unreleasedPattern, + `## Unreleased\n\n## v${ newVersion } - ${ releaseDate }\n\n${ formattedChangelogChanges }` // Use the joined original lines +); + +fs.writeFileSync( changelogFilePath, updatedChangelog, 'utf8' ); + +// --- Format for readme.txt --- +const readmeContent = fs.readFileSync( readmeFilePath, 'utf8' ); + +// Pattern to find the changelog header and any immediate following whitespace +const changelogPattern = /(== Changelog ==\s*)/s; + +if ( !changelogPattern.test( readmeContent ) ) { + console.error( 'Could not find "== Changelog ==" section in readme.txt' ); + process.exit( 1 ); +} + +// Format unreleased changes: replace '- ' with '* ' +const formattedReadmeChanges = unreleasedChanges + .map( ( change ) => `* ${ change.replace( /^\-\s*/, '' ).trim() }` ) // Replace '- ...' with '* ...' and trim potential leading space after replace + .join( '\n' ); + +// Create the new version entry using '*' +const newReadmeVersionEntry = `= v${ newVersion } - ${ releaseDate } =\n\n${ formattedReadmeChanges }\n\n`; + +// Replace the matched header and whitespace with itself followed by the new entry +const newReadmeContent = readmeContent.replace( + changelogPattern, + `$1${ newReadmeVersionEntry }` +); + +// Remove the debugging code if it's no longer needed, or keep it for now +// --- Debugging Start --- +console.log( '--- Debug readme.txt ---' ); +console.log( 'Pattern:', changelogPattern ); +const matchResult = readmeContent.match( changelogPattern ); +console.log( 'Match found:', matchResult ? 'Yes' : 'No' ); +if ( matchResult ) { + console.log( 'Matched text ($1):', JSON.stringify( matchResult[ 1 ] ) ); +} +console.log( 'New entry:\n', newReadmeVersionEntry ); +console.log( '--- Attempting to write new readme content (first 500 chars): ---' ); +console.log( newReadmeContent.substring( 0, 500 ) ); +console.log( '--- End Debug ---' ); +// --- Debugging End --- + +fs.writeFileSync( readmeFilePath, newReadmeContent.trim(), 'utf8' ); + +// Output the count of changes +console.log( + `Changelog updated successfully with ${ changeCount } change(s).` +); diff --git a/bin/update-versions.js b/bin/update-versions.js new file mode 100644 index 00000000..766cc87c --- /dev/null +++ b/bin/update-versions.js @@ -0,0 +1,188 @@ +/** + * Replaces version numbers in files. + * + * Usage: + * node replace-versions.js + * + * Parameters: + * The version number to replace. + * --dry-run Prints the files that would be modified without actually modifying them. + * --plugin Replaces the version in plugin files. + * --docblock Replaces the version in docblocks. + * --comment Replaces the version in comments. + * --all Replaces the version in all files. + */ + +const fs = require('fs'); +const path = require('path'); +const glob = require('glob'); +const minimist = require('minimist'); + +const argv = minimist(process.argv.slice(2)); + +const version = argv._[0]; + +if (!version) { + console.error('Please provide a version number.'); + process.exit(1); +} + +const dryRun = argv['dry-run']; + +let replaceType = 'all'; + +if (argv['plugin']) { + replaceType = 'plugin'; +} else if (argv['docblock']) { + replaceType = 'docblock'; +} + +const excludedDirs = [ + 'node_modules/**', + 'vendor/**', + 'vendor-prefixed/**', + 'bin/**', +]; + +const versionPatterns = [ + // Plugin file header. + { + regex: /^([\t ]*\*[\t ]*Version:[\t ]*)(.*)/gm, + replacement: (newVersion) => `$1${newVersion}`, + }, + // Plugin main class version. + { + regex: /^(.*public[\t ]+static[\t ]+\$VER[\t ]*=[\t ]*['"])(.*)(['"];\s*)$/gm, + replacement: (newVersion) => `$1${newVersion}$3`, + }, + // Plugin config array. + { + regex: /^([\t ]*'version'[\t ]*=>[\t ]*['"])(.*)(['"],)$/gm, + replacement: (newVersion) => `$1${newVersion}$3`, + }, + // Plugin readme. + { + regex: /^(Stable tag:[\t ]*)(.*)/gm, + replacement: (newVersion) => `$1${newVersion}`, + }, + // Plugin composer & package json. + { + regex: /(\s*"version":\s*")(\d+\.\d+\.\d+)(")/gm, + replacement: (newVersion) => `$1${newVersion}$3`, + }, +]; + +const docblockPatterns = [ + { + // Only match if the version is currently X.X.X exactly (the string "@deprecated X.X.X"). + regex: /((@deprecated|@since|@version)\s+)X.X.X/gm, + replacement: (newVersion) => (_match, tag) => { + return `${tag}${newVersion}`; + }, + }, +]; + +const commentPatterns = [ + { + // Match // single line comments with X.X.X + regex: /(\/\/.*\s+)X.X.X/gm, + replacement: (newVersion) => (_match, prefix) => { + return `${prefix}${newVersion}`; + }, + }, + { + // Match /* single line comments with X.X.X */ + regex: /(\/\*.*\s+)X.X.X/gm, + replacement: (newVersion) => (_match, prefix) => { + return `${prefix}${newVersion}`; + }, + }, + { + // Match /** multi line comments (start with *\s) + regex: /(\s+\*.*\s+)X.X.X/gm, + replacement: (newVersion) => (_match, prefix) => { + return `${prefix}${newVersion}`; + }, + }, +]; + +/** + * Update version in specified files with the given patterns. + * + * @param {string} filePath - Path to the file. + * @param {string} newVersion - The new version number. + * @param {boolean} dryRun - Indicate if this is a dry run. + * @param {Array} patterns - Array of regex patterns to match and replace. + */ +function updateVersionInFile(filePath, newVersion, dryRun, patterns) { + if (fs.existsSync(filePath)) { + const contents = fs.readFileSync(filePath, 'utf8'); + let newContents = contents; + + patterns.forEach((pattern) => { + newContents = newContents.replace( + pattern.regex, + pattern.replacement(newVersion) + ); + }); + + if (newContents !== contents) { + if (dryRun) { + console.log(`${filePath}:`); + console.log(newContents); + } else { + fs.writeFileSync(filePath, newContents, 'utf8'); + } + } + } else { + console.log(`No file found at ${filePath}`); + } +} + +if (replaceType === 'all' || replaceType === 'plugin') { + const pluginSlug = path.basename(process.cwd()); + const pluginFile = process.cwd() + '/' + pluginSlug + '.php'; + const boostrapFile = process.cwd() + '/bootstrap.php'; + const readmeFile = process.cwd() + '/readme.txt'; + const packageJsonFile = process.cwd() + '/' + 'package.json'; + const composerJsonFile = process.cwd() + '/' + 'composer.json'; + + if (fs.existsSync(pluginFile)) { + updateVersionInFile(pluginFile, version, dryRun, versionPatterns); + } + + if (fs.existsSync(boostrapFile)) { + updateVersionInFile(boostrapFile, version, dryRun, versionPatterns); + } + + if (fs.existsSync(readmeFile)) { + updateVersionInFile(readmeFile, version, dryRun, versionPatterns); + } + + if (fs.existsSync(packageJsonFile)) { + updateVersionInFile(packageJsonFile, version, dryRun, versionPatterns); + } + + if (fs.existsSync(composerJsonFile)) { + updateVersionInFile(composerJsonFile, version, dryRun, versionPatterns); + } +} + +if ( + replaceType === 'all' || + replaceType === 'docblock' || + replaceType === 'comment' +) { + const files = glob.sync('**/*.php', { ignore: excludedDirs }); + + // One loop reduces the number of file system calls. + files.forEach((file) => { + if (replaceType === 'all' || replaceType === 'docblock') { + updateVersionInFile(file, version, dryRun, docblockPatterns); + } + + if (replaceType === 'all' || replaceType === 'comment') { + updateVersionInFile(file, version, dryRun, commentPatterns); + } + }); +} diff --git a/classes/Controllers/Frontend/Restrictions/PostContent.php b/classes/Controllers/Frontend/Restrictions/PostContent.php index 269322e5..a026f87d 100644 --- a/classes/Controllers/Frontend/Restrictions/PostContent.php +++ b/classes/Controllers/Frontend/Restrictions/PostContent.php @@ -98,6 +98,22 @@ public function filter_the_content_if_restricted( $content ) { return $content; } + /** + * Prevent the default restriction message from being shown by returning a custom + * message or content. + * + * @param null|string $pre_restrict_content The content to display. + * @param string $content The content. + * @param \ContentControl\Models\Restriction $restriction The restriction. + * + * @return string + */ + $pre_restrict_content = apply_filters( 'content_control/pre_restrict_content', null, $content, $restriction ); + + if ( null !== $pre_restrict_content ) { + return $pre_restrict_content; + } + $message = \ContentControl\get_default_denial_message(); /** @@ -118,8 +134,8 @@ public function filter_the_content_if_restricted( $content ) { /** * Filter the message to display when a post is restricted. * - * @param string $message Message to display. - * @param object $restriction Restriction object. + * @param string $message Message to display. + * @param \ContentControl\Models\Restriction $restriction The restriction. * * @return string */ @@ -155,12 +171,27 @@ public function filter_the_excerpt_if_restricted( $post_excerpt, $post = null ) return $post_excerpt; } - $restriction = get_applicable_restriction(); + $restriction = get_applicable_restriction( $post->ID ); if ( false === $restriction ) { return $post_excerpt; } + /** + * Filter to bypass the default restriction message for excerpts. + * + * @since 2.0.0 + * + * @param null|string $pre_excerpt Return a non-null value to bypass. + * @param string $post_excerpt The original excerpt. + * @param \ContentControl\Models\Restriction $restriction The restriction object. + */ + $pre_excerpt = apply_filters( 'content_control/pre_restrict_excerpt', null, $post_excerpt, $restriction ); + + if ( null !== $pre_excerpt ) { + return $pre_excerpt; + } + /** * Filter the excerpt to display when a post is restricted. * diff --git a/classes/Controllers/Shortcodes.php b/classes/Controllers/Shortcodes.php index 7c8c38de..8402ebc9 100644 --- a/classes/Controllers/Shortcodes.php +++ b/classes/Controllers/Shortcodes.php @@ -93,7 +93,14 @@ public function content_control( $atts, $content = '' ) { $classes = implode( ' ', $classes ); - return sprintf( $container, esc_attr( $classes ), do_shortcode( $content ), do_shortcode( $atts['message'] ) ); + return sprintf( + $container, + esc_attr( $classes ), + // Sanitize the content output, allowing safe HTML and processed shortcodes. + wp_kses_post( do_shortcode( $content ) ), + // Sanitize the message output, allowing safe HTML and processed shortcodes. + wp_kses_post( do_shortcode( $atts['message'] ) ) + ); } /** diff --git a/composer.json b/composer.json index 244924e9..b8956111 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "code-atlantic/content-control", - "version": "2.6.1", + "version": "2.6.2", "type": "wordpress-plugin", "license": "GPL-2.0-or-later", "homepage": "https://contentcontrolplugin.com/", @@ -9,20 +9,20 @@ }, "minimum-stability": "dev", "require": { - "composer/installers": "v2.3.0", - "pimple/pimple": "v3.5.0", - "trustedlogin/client": "v1.9.0" + "composer/installers": "2.3.0", + "pimple/pimple": "3.5.0", + "trustedlogin/client": "1.9.0" }, "require-dev": { "code-atlantic/coding-standards": "^1.1.0", "dealerdirect/phpcodesniffer-composer-installer": "^1.0.0", "phpstan/phpstan": "^1.10.62", - "szepeviktor/phpstan-wordpress": "v1.3.3", + "szepeviktor/phpstan-wordpress": "1.3.3", "phpstan/extension-installer": "^1.3.1", "phpunit/phpunit": "10.4.0", "mockery/mockery": "^1.6.6", "brain/monkey": "^2.6.1", - "php-stubs/woocommerce-stubs": "v8.6.1", + "php-stubs/woocommerce-stubs": "8.6.1", "php-stubs/generator": "^0.8.4" }, "autoload": { diff --git a/composer.lock b/composer.lock index f5e9617b..e2e2c9f0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3caeeb2096468f7f7a6bae712d979445", + "content-hash": "2590a902ca8d302f546143f2cb997562", "packages": [ { "name": "composer/installers", @@ -742,25 +742,27 @@ }, { "name": "nikic/php-parser", - "version": "v4.19.4", + "version": "v5.4.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2" + "reference": "447a020a1f875a434d62f2a401f53b82a396e494" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/715f4d25e225bc47b293a8b997fe6ce99bf987d2", - "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494", "shasum": "" }, "require": { + "ext-ctype": "*", + "ext-json": "*", "ext-tokenizer": "*", - "php": ">=7.1" + "php": ">=7.4" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^9.0" }, "bin": [ "bin/php-parse" @@ -768,7 +770,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -792,9 +794,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.4" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" }, - "time": "2024-09-29T15:01:53+00:00" + "time": "2024-12-30T11:07:19+00:00" }, { "name": "phar-io/manifest", @@ -916,29 +918,29 @@ }, { "name": "php-stubs/generator", - "version": "v0.8.4", + "version": "v0.8.5", "source": { "type": "git", "url": "https://github.com/php-stubs/generator.git", - "reference": "bf758105124218225d59e698913ac852ee7d79c7" + "reference": "820db587692dfc9cabdb2aacda00fc16e896702f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-stubs/generator/zipball/bf758105124218225d59e698913ac852ee7d79c7", - "reference": "bf758105124218225d59e698913ac852ee7d79c7", + "url": "https://api.github.com/repos/php-stubs/generator/zipball/820db587692dfc9cabdb2aacda00fc16e896702f", + "reference": "820db587692dfc9cabdb2aacda00fc16e896702f", "shasum": "" }, "require": { - "nikic/php-parser": "^4.10", + "nikic/php-parser": "^4.10 || ^5.1", "php": "^7.3 || ^8.0", - "symfony/console": "^5.1 || ^6.0", - "symfony/filesystem": "^5.0 || ^6.0", - "symfony/finder": "^5.0 || ^6.0" + "symfony/console": "^5.1 || ^6.0 || ^7.0", + "symfony/filesystem": "^5.0 || ^6.0 || ^7.0", + "symfony/finder": "^5.0 || ^6.0 || ^7.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.16 || ^3.12", - "phpunit/phpunit": "^9.4", - "vimeo/psalm": "^4.1" + "friendsofphp/php-cs-fixer": "3.4.0 || ^3.12", + "phpstan/phpstan": "^1.0 || ^2.0", + "phpunit/phpunit": "^9.4" }, "bin": [ "bin/generate-stubs" @@ -967,9 +969,9 @@ ], "support": { "issues": "https://github.com/php-stubs/generator/issues", - "source": "https://github.com/php-stubs/generator/tree/v0.8.4" + "source": "https://github.com/php-stubs/generator/tree/v0.8.5" }, - "time": "2023-07-24T16:33:51+00:00" + "time": "2025-04-18T03:44:11+00:00" }, { "name": "php-stubs/woocommerce-stubs", @@ -1017,25 +1019,28 @@ }, { "name": "php-stubs/wordpress-stubs", - "version": "v6.7.2", + "version": "v6.8.0", "source": { "type": "git", "url": "https://github.com/php-stubs/wordpress-stubs.git", - "reference": "c04f96cb232fab12a3cbcccf5a47767f0665c3f4" + "reference": "1824db4d1d00d32c0119175d2369d9425dbc4953" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-stubs/wordpress-stubs/zipball/c04f96cb232fab12a3cbcccf5a47767f0665c3f4", - "reference": "c04f96cb232fab12a3cbcccf5a47767f0665c3f4", + "url": "https://api.github.com/repos/php-stubs/wordpress-stubs/zipball/1824db4d1d00d32c0119175d2369d9425dbc4953", + "reference": "1824db4d1d00d32c0119175d2369d9425dbc4953", "shasum": "" }, + "conflict": { + "phpdocumentor/reflection-docblock": "5.6.1" + }, "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "^1.0", "nikic/php-parser": "^4.13", "php": "^7.4 || ^8.0", "php-stubs/generator": "^0.8.3", "phpdocumentor/reflection-docblock": "^5.4.1", - "phpstan/phpstan": "^1.11", + "phpstan/phpstan": "^2.1", "phpunit/phpunit": "^9.5", "szepeviktor/phpcs-psr-12-neutron-hybrid-ruleset": "^1.1.1", "wp-coding-standards/wpcs": "3.1.0 as 2.3.0" @@ -1059,9 +1064,9 @@ ], "support": { "issues": "https://github.com/php-stubs/wordpress-stubs/issues", - "source": "https://github.com/php-stubs/wordpress-stubs/tree/v6.7.2" + "source": "https://github.com/php-stubs/wordpress-stubs/tree/v6.8.0" }, - "time": "2025-02-12T04:51:58+00:00" + "time": "2025-04-17T15:13:53+00:00" }, { "name": "phpcompatibility/php-compatibility", @@ -1269,22 +1274,22 @@ }, { "name": "phpcsstandards/phpcsextra", - "version": "1.2.1", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHPCSExtra.git", - "reference": "11d387c6642b6e4acaf0bd9bf5203b8cca1ec489" + "reference": "46d08eb86eec622b96c466adec3063adfed280dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/11d387c6642b6e4acaf0bd9bf5203b8cca1ec489", - "reference": "11d387c6642b6e4acaf0bd9bf5203b8cca1ec489", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/46d08eb86eec622b96c466adec3063adfed280dd", + "reference": "46d08eb86eec622b96c466adec3063adfed280dd", "shasum": "" }, "require": { "php": ">=5.4", "phpcsstandards/phpcsutils": "^1.0.9", - "squizlabs/php_codesniffer": "^3.8.0" + "squizlabs/php_codesniffer": "^3.12.1" }, "require-dev": { "php-parallel-lint/php-console-highlighter": "^1.0", @@ -1341,9 +1346,13 @@ { "url": "https://opencollective.com/php_codesniffer", "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" } ], - "time": "2023-12-08T16:49:07+00:00" + "time": "2025-04-20T23:35:32+00:00" }, { "name": "phpcsstandards/phpcsutils", @@ -1483,16 +1492,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.12.21", + "version": "1.12.24", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "14276fdef70575106a3392a4ed553c06a984df28" + "reference": "338b92068f58d9f8035b76aed6cf2b9e5624c025" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/14276fdef70575106a3392a4ed553c06a984df28", - "reference": "14276fdef70575106a3392a4ed553c06a984df28", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/338b92068f58d9f8035b76aed6cf2b9e5624c025", + "reference": "338b92068f58d9f8035b76aed6cf2b9e5624c025", "shasum": "" }, "require": { @@ -1537,7 +1546,7 @@ "type": "github" } ], - "time": "2025-03-09T09:24:50+00:00" + "time": "2025-04-16T13:01:53+00:00" }, { "name": "phpunit/php-code-coverage", @@ -2879,16 +2888,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.11.3", + "version": "3.12.2", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "ba05f990e79cbe69b9f35c8c1ac8dca7eecc3a10" + "reference": "6d4cf6032d4b718f168c90a96e36c7d0eaacb2aa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/ba05f990e79cbe69b9f35c8c1ac8dca7eecc3a10", - "reference": "ba05f990e79cbe69b9f35c8c1ac8dca7eecc3a10", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/6d4cf6032d4b718f168c90a96e36c7d0eaacb2aa", + "reference": "6d4cf6032d4b718f168c90a96e36c7d0eaacb2aa", "shasum": "" }, "require": { @@ -2955,55 +2964,54 @@ "type": "open_collective" }, { - "url": "https://thanks.dev/phpcsstandards", + "url": "https://thanks.dev/u/gh/phpcsstandards", "type": "thanks_dev" } ], - "time": "2025-01-23T17:04:15+00:00" + "time": "2025-04-13T04:10:18+00:00" }, { "name": "symfony/console", - "version": "v6.4.17", + "version": "v7.2.5", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "799445db3f15768ecc382ac5699e6da0520a0a04" + "reference": "e51498ea18570c062e7df29d05a7003585b19b88" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/799445db3f15768ecc382ac5699e6da0520a0a04", - "reference": "799445db3f15768ecc382ac5699e6da0520a0a04", + "url": "https://api.github.com/repos/symfony/console/zipball/e51498ea18570c062e7df29d05a7003585b19b88", + "reference": "e51498ea18570c062e7df29d05a7003585b19b88", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3", + "php": ">=8.2", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^5.4|^6.0|^7.0" + "symfony/string": "^6.4|^7.0" }, "conflict": { - "symfony/dependency-injection": "<5.4", - "symfony/dotenv": "<5.4", - "symfony/event-dispatcher": "<5.4", - "symfony/lock": "<5.4", - "symfony/process": "<5.4" + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", "symfony/http-foundation": "^6.4|^7.0", "symfony/http-kernel": "^6.4|^7.0", - "symfony/lock": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/stopwatch": "^5.4|^6.0|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/lock": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -3037,7 +3045,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.17" + "source": "https://github.com/symfony/console/tree/v7.2.5" }, "funding": [ { @@ -3053,7 +3061,7 @@ "type": "tidelift" } ], - "time": "2024-12-07T12:07:30+00:00" + "time": "2025-03-12T08:11:12+00:00" }, { "name": "symfony/deprecation-contracts", @@ -3124,25 +3132,25 @@ }, { "name": "symfony/filesystem", - "version": "v6.4.13", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3" + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/4856c9cf585d5a0313d8d35afd681a526f038dd3", - "reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, "require-dev": { - "symfony/process": "^5.4|^6.4|^7.0" + "symfony/process": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -3170,7 +3178,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.13" + "source": "https://github.com/symfony/filesystem/tree/v7.2.0" }, "funding": [ { @@ -3186,27 +3194,27 @@ "type": "tidelift" } ], - "time": "2024-10-25T15:07:50+00:00" + "time": "2024-10-25T15:15:23+00:00" }, { "name": "symfony/finder", - "version": "v6.4.17", + "version": "v7.2.2", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "1d0e8266248c5d9ab6a87e3789e6dc482af3c9c7" + "reference": "87a71856f2f56e4100373e92529eed3171695cfb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/1d0e8266248c5d9ab6a87e3789e6dc482af3c9c7", - "reference": "1d0e8266248c5d9ab6a87e3789e6dc482af3c9c7", + "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "symfony/filesystem": "^6.0|^7.0" + "symfony/filesystem": "^6.4|^7.0" }, "type": "library", "autoload": { @@ -3234,7 +3242,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.4.17" + "source": "https://github.com/symfony/finder/tree/v7.2.2" }, "funding": [ { @@ -3250,7 +3258,7 @@ "type": "tidelift" } ], - "time": "2024-12-29T13:51:37+00:00" + "time": "2024-12-30T19:00:17+00:00" }, { "name": "symfony/polyfill-ctype", diff --git a/content-control.php b/content-control.php index f6bef5e4..6b637229 100644 --- a/content-control.php +++ b/content-control.php @@ -3,7 +3,7 @@ * Plugin Name: Content Control * Plugin URI: https://contentcontrolplugin.com/?utm_campaign=plugin-info&utm_source=php-file-header&utm_medium=plugin-ui&utm_content=plugin-uri * Description: Restrict content to logged in/out users or specific user roles. Restrict access to certain parts of a page/post. Control the visibility of widgets. - * Version: 2.6.1 + * Version: 2.6.2 * Author: Code Atlantic * Author URI: https://code-atlantic.com/?utm_campaign=plugin-info&utm_source=php-file-header&utm_medium=plugin-ui&utm_content=author-uri * Donate link: https://code-atlantic.com/donate/?utm_campaign=donations&utm_source=php-file-header&utm_medium=plugin-ui&utm_content=donate-link @@ -30,7 +30,7 @@ function get_plugin_config() { return [ 'name' => 'Content Control', 'slug' => 'content-control', - 'version' => '2.6.1', + 'version' => '2.6.2', 'option_prefix' => 'content_control', // Maybe remove this and simply prefix `name` with `'Popup Maker'`. 'text_domain' => 'content-control', diff --git a/package-lock.json b/package-lock.json index 3c52cb46..4cf68916 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "content-control", - "version": "2.6.0", + "version": "2.6.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "content-control", - "version": "2.6.0", + "version": "2.6.1", "license": "GPL-2.0-or-later", "workspaces": [ "./packages/*" diff --git a/package.json b/package.json index a404528a..98a95ad6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "content-control", - "version": "2.6.1", + "version": "2.6.2", "description": "", "author": "Code Atlantic LLC", "license": "GPL-2.0-or-later", @@ -100,7 +100,9 @@ "release:zip": "mv build content-control && zip -r content-control_$(node -p \"require('./package.json').version\").zip content-control && rm -rf content-control", "release:start": "git flow release start", "release:finish": "git flow release finish", - "release:publish": "git push origin master --tags && git push origin master" + "release:publish": "git push origin master --tags && git push origin master", + "update-version": "node bin/update-versions.js", + "update-changelog": "node bin/update-changelog.js" }, "babel": {}, "workspaces": [ diff --git a/packages/settings-page/src/index.tsx b/packages/settings-page/src/index.tsx index aae1f21f..fe8a501c 100644 --- a/packages/settings-page/src/index.tsx +++ b/packages/settings-page/src/index.tsx @@ -44,6 +44,8 @@ declare global { }; } +export type { EditTabProps } from './restrictions-view/edit'; + const { wpVersion } = contentControlSettingsPage; const renderer = () => { diff --git a/packages/settings-page/src/restrictions-view/edit/index.tsx b/packages/settings-page/src/restrictions-view/edit/index.tsx index 8422f28a..09516a40 100644 --- a/packages/settings-page/src/restrictions-view/edit/index.tsx +++ b/packages/settings-page/src/restrictions-view/edit/index.tsx @@ -247,7 +247,8 @@ const Edit = ( { onSave = noop, onClose = noop }: EditProps ) => { title: __( 'Content', 'content-control' ), comp: () => , }, - ] + ], + componentProps ) as TabComponent[]; if ( typeof errorMessage === 'object' && errorMessage?.tabName?.length ) { diff --git a/packages/settings-page/src/restrictions-view/edit/protection.tsx b/packages/settings-page/src/restrictions-view/edit/protection.tsx index 7bf034bf..f5813ba2 100644 --- a/packages/settings-page/src/restrictions-view/edit/protection.tsx +++ b/packages/settings-page/src/restrictions-view/edit/protection.tsx @@ -448,120 +448,101 @@ const SearchWarning = ( { settings, updateSettings }: SearchWarningProps ) => { <> -

- { __( - 'When enabled, restricted items will appear in search results but with a restricted access message. Disable to completely hide from search.', - 'content-control' - ) } -

- { settings.showInSearch && ( + help={ __( + 'When enabled, restricted items will appear in search results but with a restricted access message. Disable to completely hide from search.', + 'content-control' + ) } + checked={ settings.showInSearch } + onChange={ ( showInSearch ) => + updateSettings( { showInSearch } ) + } + /> + { settings.showInSearch && ( +
setIsPopoverVisible( true ) } + onMouseLeave={ () => setIsPopoverVisible( false ) } + > + + ⚠️{ ' ' } + { __( + 'Warning: Enabling this option may expose restricted content', + 'content-control' + ) } + + { isPopoverVisible && ( +
- setIsPopoverVisible( true ) - } - onMouseLeave={ () => - setIsPopoverVisible( false ) - } > - - ⚠️{ ' ' } - { __( - 'Warning: Enabling this option may expose restricted content', - 'content-control' - ) } - - { isPopoverVisible && ( - + Security Consideration + +

+ Only enable this if you fully understand the + risks or have properly mitigated them. +

+

+ WordPress search can reveal parts of your + protected content through simple trial and + error searching. +

+

+ For example: If your protected post contains + "Annual Revenue: $500,000", + someone could discover this by searching for + "An", then "Ann", then + "Annu", and so on. Each successful + search confirms more of the content, even if + they cannot access the full post. +

+

+ With simple scripts a bot can discover + restricted content in seconds if there is no + brute force protection in place such as rate + limiting. +

+

+ The issue can be mitigated, but not fully + eliminated with rate limiting and/or + blocking IPs with an active firewall. +

+

+ Learn more in{ ' ' } + -

-

- Security Consideration -

-

- Only enable this if you fully - understand the risks or have - properly mitigated them. -

-

- WordPress search can reveal - parts of your protected content - through simple trial and error - searching. -

-

- For example: If your protected - post contains "Annual - Revenue: $500,000", someone - could discover this by searching - for "An", then - "Ann", then - "Annu", and so on. - Each successful search confirms - more of the content, even if - they cannot access the full - post. -

-

- With simple scripts a bot can - discover restricted content in - seconds if there is no brute - force protection in place such - as rate limiting. -

-

- The issue can be mitigated, but - not fully eliminated with rate - limiting and/or blocking IPs - with an active firewall. -

-

- Learn more in{ ' ' } - - our documentation - -

-
-
- ) } + our documentation + +

- ) } -
- } - checked={ settings.showInSearch } - onChange={ ( showInSearch ) => - updateSettings( { showInSearch } ) - } - /> + + ) } + + ) } ); }; diff --git a/readme.txt b/readme.txt index d6209e16..c786b362 100644 --- a/readme.txt +++ b/readme.txt @@ -6,7 +6,7 @@ Donate link: https://code-atlantic.com/donate/?utm_campaign=donations&utm_source Tags: membership, access control, members only, content restriction, maintenance mode Requires at least: 6.2 Tested up to: 6.7.2 -Stable tag: 2.6.1 +Stable tag: 2.6.2 Requires PHP: 7.4 License: GPLv3 (or later) @@ -110,6 +110,12 @@ Bugs can be reported either in our support forum or we are happy to accept PRs o == Changelog == += v2.6.2 - 04/22/2025 = + +* Security: Escaped `[content_control]` `message` attribute. +* Fix: Misc JS bugs in admin. +* Developer: Added new `content_control/pre_restrict_content` & `content_control/pre_restrict_excerpt` filters to allow overloading/short curcuiting the default restriction application. + = v2.6.1 - 03/15/2025 = * Improvement: Only fetch titles & ids when loading posts/taxonomy for the Restriction Editor. Reducing request overhead. @@ -399,4 +405,4 @@ add_filter( 'content_control/query_filter_init_hook', function () { = v1.0.0 = -- Initial Release +- Initial Release \ No newline at end of file