From 5128931a10f6aaa2c1f2457d63b19b5e7e8fca88 Mon Sep 17 00:00:00 2001 From: SIMONE FIORAVANTI Date: Thu, 6 Jul 2023 15:10:43 +0200 Subject: [PATCH] Fixes for PHP 8.2 (#156) * Fix dynamic properties declaration * fix spacing * Fix calling trait outside class * More fixes * More fixes * More fixes * More fixes * More fixes * More fixes * Update dependencies * More fixes * Version bump --------- Co-authored-by: xxsimoxx --- classicpress-seo.php | 4 +- composer.lock | 21 +- includes/admin/class-admin.php | 4 +- includes/admin/class-options.php | 1 + includes/class-cmb2.php | 6 +- includes/class-installer.php | 4 +- includes/class-metadata.php | 3 +- includes/class-post.php | 4 +- includes/frontend/class-add-attributes.php | 1 + includes/helpers/class-conditional.php | 28 +- includes/helpers/class-wordpress.php | 2 +- includes/metaboxes/general.php | 2 +- includes/module/class-base.php | 1 + includes/module/class-manager.php | 10 +- .../modules/404-monitor/class-monitor.php | 5 +- includes/modules/redirections/class-admin.php | 6 +- .../redirections/class-redirections.php | 7 +- .../modules/rich-snippet/class-jsonld.php | 6 +- .../rich-snippet/snippets/class-singular.php | 4 +- .../rich-snippet/views/metabox-options.php | 2 +- .../role-manager/class-capability-manager.php | 4 +- .../role-manager/class-role-manager.php | 4 +- includes/modules/sitemap/class-cache.php | 7 +- .../modules/sitemap/class-sitemap-xml.php | 1 + includes/modules/status/class-status.php | 6 +- includes/opengraph/class-image.php | 8 +- includes/replace-variables/class-base.php | 1 + .../class-post-variables.php | 7 +- includes/replace-variables/class-replacer.php | 7 +- readme.txt | 2 +- .../wp-background-processing/.gitignore | 3 +- .../wp-background-processing/README.md | 252 ++++++++++- .../classes/wp-async-request.php | 49 ++- .../classes/wp-background-process.php | 414 ++++++++++++++---- .../wp-background-processing/composer.json | 20 +- .../wp-background-processing.php | 4 +- vendor/composer/autoload_classmap.php | 3 + vendor/composer/autoload_static.php | 3 + vendor/composer/installed.json | 23 +- vendor/composer/installed.php | 10 +- 40 files changed, 731 insertions(+), 218 deletions(-) diff --git a/classicpress-seo.php b/classicpress-seo.php index 949fa8f..63e9f37 100644 --- a/classicpress-seo.php +++ b/classicpress-seo.php @@ -3,7 +3,7 @@ * Plugin Name: Classic SEO * Plugin URI: https://github.com/ClassicPress/classicpress-seo * Description: Classic SEO is the first SEO plugin built specifically to work with ClassicPress. The plugin contains many essential SEO tools to help optimize your website. - * Version: 2.1.3 + * Version: 2.2.0.alpha.0 * Author: ClassicPress * Author URI: https://github.com/ClassicPress * License: GPL v2 or later @@ -34,7 +34,7 @@ class Classic_SEO { * * @var string */ - public $version = '2.1.3'; + public $version = '2.2.0'; /** * Classic SEO database version. diff --git a/composer.lock b/composer.lock index 524622b..a81dd7d 100644 --- a/composer.lock +++ b/composer.lock @@ -8,20 +8,27 @@ "packages": [ { "name": "a5hleyrich/wp-background-processing", - "version": "1.0.2", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/deliciousbrains/wp-background-processing.git", - "reference": "2cbee1abd1b49e1133cd8f611df4d4fc5a8b9800" + "reference": "d5ef95cecba7f792ddca3e3bd70ebfb90dc4996d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/deliciousbrains/wp-background-processing/zipball/2cbee1abd1b49e1133cd8f611df4d4fc5a8b9800", - "reference": "2cbee1abd1b49e1133cd8f611df4d4fc5a8b9800", + "url": "https://api.github.com/repos/deliciousbrains/wp-background-processing/zipball/d5ef95cecba7f792ddca3e3bd70ebfb90dc4996d", + "reference": "d5ef95cecba7f792ddca3e3bd70ebfb90dc4996d", "shasum": "" }, "require": { - "php": ">=5.2" + "php": ">=5.6" + }, + "require-dev": { + "phpcompatibility/phpcompatibility-wp": "*", + "phpunit/phpunit": "^8.0", + "spryker/code-sniffer": "^0.17.18", + "wp-coding-standards/wpcs": "^2.3", + "yoast/phpunit-polyfills": "^1.0" }, "suggest": { "coenjacobs/mozart": "Easily wrap this library with your own prefix, to prevent collisions when multiple plugins use this library" @@ -45,9 +52,9 @@ "description": "WP Background Processing can be used to fire off non-blocking asynchronous requests or as a background processing tool, allowing you to queue tasks.", "support": { "issues": "https://github.com/deliciousbrains/wp-background-processing/issues", - "source": "https://github.com/deliciousbrains/wp-background-processing/tree/1.0.2" + "source": "https://github.com/deliciousbrains/wp-background-processing/tree/1.1.0" }, - "time": "2020-07-31T07:00:11+00:00" + "time": "2023-04-18T12:32:25+00:00" }, { "name": "cmb2/cmb2", diff --git a/includes/admin/class-admin.php b/includes/admin/class-admin.php index a1a1f49..06dc2ba 100644 --- a/includes/admin/class-admin.php +++ b/includes/admin/class-admin.php @@ -27,7 +27,7 @@ */ class Admin implements Runner { - use Hooker, Ajax; + use Hooker, Ajax, Conditional; /** * Register hooks. @@ -113,7 +113,7 @@ public function canonical_check_notice( $post_id ) { $post_type = get_post_type( $post_id ); $is_allowed = in_array( $post_type, Helper::get_allowed_post_types(), true ); - if ( ! $is_allowed || Conditional::is_autosave() || Conditional::is_ajax() || isset( $_REQUEST['bulk_edit'] ) ) { + if ( ! $is_allowed || Admin::is_autosave() || Admin::is_ajax() || isset( $_REQUEST['bulk_edit'] ) ) { return $post_id; } diff --git a/includes/admin/class-options.php b/includes/admin/class-options.php index 5da2cf7..ac3fe3f 100644 --- a/includes/admin/class-options.php +++ b/includes/admin/class-options.php @@ -22,6 +22,7 @@ /** * Options class. */ +#[\AllowDynamicProperties] class Options { use Hooker; diff --git a/includes/class-cmb2.php b/includes/class-cmb2.php index 9e6ffa5..2dc68e7 100644 --- a/includes/class-cmb2.php +++ b/includes/class-cmb2.php @@ -24,6 +24,8 @@ */ class CMB2 { + use Conditional; + /** * Set field arguments based on type. * @@ -99,7 +101,7 @@ public static function current_object_type() { $type = 'term'; } - if ( Conditional::is_ajax() && 'add-tag' === Param::post( 'action' ) ) { + if ( CMB2::is_ajax() && 'add-tag' === Param::post( 'action' ) ) { $type = 'term'; } @@ -313,7 +315,7 @@ public static function sanitize_webmaster_tags( $value ) { return $value; } - + /** * Handles sanitization of advanced robots data. * diff --git a/includes/class-installer.php b/includes/class-installer.php index 17ad796..3a6ae00 100644 --- a/includes/class-installer.php +++ b/includes/class-installer.php @@ -24,7 +24,7 @@ */ class Installer { - use Hooker; + use Hooker, WordPress; /** * Bind all events. @@ -574,7 +574,7 @@ private function get_opening_hours() { * @return array */ private function get_excluded_roles() { - $roles = WordPress::get_roles(); + $roles = Installer::get_roles(); unset( $roles['administrator'], $roles['editor'], $roles['author'] ); return $roles; diff --git a/includes/class-metadata.php b/includes/class-metadata.php index 6fcdbca..fa7034c 100644 --- a/includes/class-metadata.php +++ b/includes/class-metadata.php @@ -14,6 +14,7 @@ /** * Metadata class. */ + #[\AllowDynamicProperties] abstract class Metadata { /** @@ -132,7 +133,7 @@ public function maybe_replace_vars( $key, $value, $object ) { if ( ! in_array( $key, $need_replacements, true ) || ! is_string( $value ) || '' === $value ) { return false; } - + $value = \str_replace( [ '%seo_title%', '%seo_description%' ], [ '%title%', '%excerpt%' ], $value ); return Helper::replace_vars( $value, $object ); diff --git a/includes/class-post.php b/includes/class-post.php index 3e5b17a..88b2331 100644 --- a/includes/class-post.php +++ b/includes/class-post.php @@ -20,6 +20,8 @@ */ class Post extends Metadata { + use Conditional; + /** * Type of object metadata is for (e.g., comment, post, or user). * @@ -168,7 +170,7 @@ public static function is_shop_page() { * @return bool Whether the current page is a WooCommerce page. */ public static function is_woocommerce_page() { - if ( Conditional::is_woocommerce_active() || Conditional::is_classic_commerce_active() ) { + if ( Post::is_woocommerce_active() || Post::is_classic_commerce_active() ) { return \is_cart() || \is_checkout() || \is_account_page(); } diff --git a/includes/frontend/class-add-attributes.php b/includes/frontend/class-add-attributes.php index 8838b42..dabeb61 100644 --- a/includes/frontend/class-add-attributes.php +++ b/includes/frontend/class-add-attributes.php @@ -21,6 +21,7 @@ /** * Add Attributes class. */ +#[\AllowDynamicProperties] class Add_Attributes { use Hooker; diff --git a/includes/helpers/class-conditional.php b/includes/helpers/class-conditional.php index afaa0f6..4d0a25f 100644 --- a/includes/helpers/class-conditional.php +++ b/includes/helpers/class-conditional.php @@ -20,7 +20,9 @@ * Conditional class. */ trait Conditional { - + + use WordPress; + /** * Check if whitelabel filter is active. * @@ -43,7 +45,7 @@ public static function is_whitelabel() { public static function is_ajax() { return function_exists( 'wp_doing_ajax' ) ? wp_doing_ajax() : defined( 'DOING_AJAX' ) && DOING_AJAX; } - + /** * Is CRON request * @@ -52,7 +54,7 @@ public static function is_ajax() { public static function is_cron() { return function_exists( 'wp_doing_cron' ) ? wp_doing_cron() : defined( 'DOING_CRON' ) && DOING_CRON; } - + /** * Is auto-saving * @@ -61,7 +63,7 @@ public static function is_cron() { public static function is_autosave() { return defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE; } - + /** * Is REST request * @@ -103,8 +105,8 @@ public static function is_rest() { 0 === strpos( $current_url['path'], $rest_url['path'], 0 ) ); } - - + + /** * Check if module is active. * @@ -135,7 +137,7 @@ public static function is_configured( $value = null ) { Helper::schedule_flush_rewrite(); update_option( $key, $value ); } - + /** * Check if the site is connected to the Classic SEO API. * @@ -187,7 +189,7 @@ public static function is_score_enabled() { */ return apply_filters( 'cpseo/show_score', true ); } - + /** * Check if the request is heartbeat. * @@ -196,7 +198,7 @@ public static function is_score_enabled() { public static function is_heartbeat() { return 'heartbeat' === Param::post( 'action' ); } - + /** * Check if the request is from frontend. * @@ -215,14 +217,14 @@ public function is_frontend() { */ public static function is_woocommerce_active() { // @codeCoverageIgnoreStart - $wp_filesystem = WordPress::get_filesystem(); - + $wp_filesystem = self::get_filesystem(); + if ( ! function_exists( 'is_plugin_active' ) ) { include_once ABSPATH . 'wp-admin/includes/plugin.php'; } /** - * Check for additional proof that the real WC is installed and not the Classic Commerce compatibility plugin + * Check for additional proof that the real WC is installed and not the Classic Commerce compatibility plugin */ if( $wp_filesystem->exists( WP_PLUGIN_DIR . "/woocommerce/includes/class-woocommerce.php" ) && $wp_filesystem->exists( WP_PLUGIN_DIR . "/woocommerce/includes/admin/class-wc-admin.php" ) ) { // @codeCoverageIgnoreEnd @@ -230,7 +232,7 @@ public static function is_woocommerce_active() { } return false; } - + /** * Is Classic Commerce Installed * diff --git a/includes/helpers/class-wordpress.php b/includes/helpers/class-wordpress.php index d45912c..2f9b174 100644 --- a/includes/helpers/class-wordpress.php +++ b/includes/helpers/class-wordpress.php @@ -344,7 +344,7 @@ private static function get_role_capabilities( $slug, $caps, &$data ) { } } } - + /** * Set capabilities to role. * diff --git a/includes/metaboxes/general.php b/includes/metaboxes/general.php index 28474bc..6c8b3fd 100644 --- a/includes/metaboxes/general.php +++ b/includes/metaboxes/general.php @@ -87,7 +87,7 @@ * @param bool $return True to disable. */ if ( false === $this->do_filter( 'primary_term', false ) ) { - $taxonomies = Helper::get_object_taxonomies( WordPress::get_post_type(), 'objects' ); + $taxonomies = Helper::get_object_taxonomies( ( new class { use Wordpress; } )::get_post_type(), 'objects' ); $taxonomies = wp_filter_object_list( $taxonomies, array( 'hierarchical' => true ), 'and', 'name' ); foreach ( $taxonomies as $taxonomy ) { $cmb->add_field( array( diff --git a/includes/module/class-base.php b/includes/module/class-base.php index 6ab160a..c2fedee 100644 --- a/includes/module/class-base.php +++ b/includes/module/class-base.php @@ -19,6 +19,7 @@ /** * Base class. */ +#[\AllowDynamicProperties] class Base { use Hooker; diff --git a/includes/module/class-manager.php b/includes/module/class-manager.php index 90d5af6..0ae0d74 100644 --- a/includes/module/class-manager.php +++ b/includes/module/class-manager.php @@ -20,7 +20,7 @@ */ class Manager { - use Hooker; + use Hooker, Conditional; /** * Holds modules. @@ -40,7 +40,7 @@ class Manager { * The Constructor. */ public function __construct() { - if ( Conditional::is_heartbeat() ) { + if ( Manager::is_heartbeat() ) { return; } @@ -193,7 +193,7 @@ public function setup_3rd_party( $modules ) { 'disabled_text' => esc_html__( 'Please activate ' . $ecom . ' plugin to use this module.', 'cpseo' ), ]; } - + if ( class_exists( 'ACF' ) ) { $modules['acf'] = [ 'title' => esc_html__( 'ACF', 'cpseo' ), @@ -244,9 +244,9 @@ public function display_form() {
- +

the_link(); ?>

- +
diff --git a/includes/modules/404-monitor/class-monitor.php b/includes/modules/404-monitor/class-monitor.php index 1f75719..256c0ea 100644 --- a/includes/modules/404-monitor/class-monitor.php +++ b/includes/modules/404-monitor/class-monitor.php @@ -23,9 +23,10 @@ /** * Monitor class. */ +#[\AllowDynamicProperties] class Monitor { - use Hooker, Ajax; + use Hooker, Ajax, Conditional; /** * The Constructor. @@ -37,7 +38,7 @@ public function __construct() { $this->admin = new Admin; } - if ( Conditional::is_ajax() ) { + if ( Monitor::is_ajax() ) { $this->ajax( 'delete_log', 'delete_log' ); } diff --git a/includes/modules/redirections/class-admin.php b/includes/modules/redirections/class-admin.php index 7b6d364..695e929 100644 --- a/includes/modules/redirections/class-admin.php +++ b/includes/modules/redirections/class-admin.php @@ -28,7 +28,7 @@ */ class Admin extends Base { - use Ajax, Hooker; + use Ajax, Hooker, Conditional, WordPress; /** * The Constructor. @@ -89,7 +89,7 @@ private function load_metabox() { * Hooks for ajax. */ private function ajax_hooks() { - if ( ! Conditional::is_ajax() ) { + if ( ! Admin::is_ajax() ) { return; } @@ -185,7 +185,7 @@ public function init() { return; } - $action = WordPress::get_request_action(); + $action = Admin::get_request_action(); if ( false === $action || empty( $_REQUEST['redirection'] ) || 'edit' === $action ) { return; } diff --git a/includes/modules/redirections/class-redirections.php b/includes/modules/redirections/class-redirections.php index f3699f0..50383b0 100644 --- a/includes/modules/redirections/class-redirections.php +++ b/includes/modules/redirections/class-redirections.php @@ -20,9 +20,10 @@ * * @codeCoverageIgnore */ +#[\AllowDynamicProperties] class Redirections { - use Hooker; + use Hooker, Conditional; /** * The Constructor. @@ -51,7 +52,7 @@ private function load_admin() { $this->admin = new Admin; } - if ( is_admin() || Conditional::is_rest() ) { + if ( is_admin() || Redirections::is_rest() ) { new Watcher; } } @@ -60,7 +61,7 @@ private function load_admin() { * Do redirection on frontend. */ public function do_redirection() { - if ( is_customize_preview() || Conditional::is_ajax() || ! isset( $_SERVER['REQUEST_URI'] ) || empty( $_SERVER['REQUEST_URI'] ) || $this->is_script_uri_or_http_x() ) { + if ( is_customize_preview() || Redirections::is_ajax() || ! isset( $_SERVER['REQUEST_URI'] ) || empty( $_SERVER['REQUEST_URI'] ) || $this->is_script_uri_or_http_x() ) { return; } diff --git a/includes/modules/rich-snippet/class-jsonld.php b/includes/modules/rich-snippet/class-jsonld.php index a5074b0..cf907ad 100644 --- a/includes/modules/rich-snippet/class-jsonld.php +++ b/includes/modules/rich-snippet/class-jsonld.php @@ -23,7 +23,7 @@ */ class JsonLD { - use Hooker; + use Hooker, Conditional; /** * Hold post object. @@ -128,7 +128,7 @@ private function can_add_breadcrumb() { * @return bool */ private function is_product_page() { - return ( Conditional::is_woocommerce_active() || Conditional::is_classic_commerce_active() ) && ( ( is_tax() && in_array( get_query_var( 'taxonomy' ), get_object_taxonomies( 'product' ), true ) ) || is_shop() ); + return ( JsonLD::is_woocommerce_active() || JsonLD::is_classic_commerce_active() ) && ( ( is_tax() && in_array( get_query_var( 'taxonomy' ), get_object_taxonomies( 'product' ), true ) ) || is_shop() ); } /** @@ -197,7 +197,7 @@ private function add_prop_thumbnail( &$entity ) { ]; } } - + /** * Add aggregateratings to entity. * diff --git a/includes/modules/rich-snippet/snippets/class-singular.php b/includes/modules/rich-snippet/snippets/class-singular.php index 0ab07c3..93b1e0d 100644 --- a/includes/modules/rich-snippet/snippets/class-singular.php +++ b/includes/modules/rich-snippet/snippets/class-singular.php @@ -21,7 +21,7 @@ */ class Singular implements Snippet { - use Hooker; + use Hooker, Conditional; /** * Generate rich snippet. @@ -85,7 +85,7 @@ private function can_add_schema( $jsonld ) { ! metadata_exists( 'post', $jsonld->post_id, 'cpseo_rich_snippet' ) && $schema = Helper::get_settings( "titles.cpseo_pt_{$jsonld->post->post_type}_default_rich_snippet" ) // phpcs:ignore ) { - $schema = ( Conditional::is_woocommerce_active() || Conditional::is_classic_commerce_active() ) && is_product() ? $schema : ( 'article' === $schema ? $schema : '' ); + $schema = ( Singular::is_woocommerce_active() || Singular::is_classic_commerce_active() ) && is_product() ? $schema : ( 'article' === $schema ? $schema : '' ); } return $schema; diff --git a/includes/modules/rich-snippet/views/metabox-options.php b/includes/modules/rich-snippet/views/metabox-options.php index 6b28810..8b73a47 100644 --- a/includes/modules/rich-snippet/views/metabox-options.php +++ b/includes/modules/rich-snippet/views/metabox-options.php @@ -14,7 +14,7 @@ return; } -$post_type = WordPress::get_post_type(); +$post_type = ( new class { use Wordpress; } )::get_post_type(); if ( ( class_exists( 'WooCommerce' ) && 'product' === $post_type ) || ( class_exists( 'Easy_Digital_Downloads' ) && 'download' === $post_type ) ) { diff --git a/includes/modules/role-manager/class-capability-manager.php b/includes/modules/role-manager/class-capability-manager.php index 1ec8e02..176481a 100644 --- a/includes/modules/role-manager/class-capability-manager.php +++ b/includes/modules/role-manager/class-capability-manager.php @@ -23,7 +23,7 @@ */ class Capability_Manager { - use Hooker; + use Hooker, WordPress; /** * Registered capabilities. @@ -94,7 +94,7 @@ public function get_capabilities() { * Add capabilities on install. */ public function create_capabilities() { - foreach ( WordPress::get_roles() as $slug => $role ) { + foreach ( Capability_Manager::get_roles() as $slug => $role ) { $role = get_role( $slug ); if ( ! $role ) { continue; diff --git a/includes/modules/role-manager/class-role-manager.php b/includes/modules/role-manager/class-role-manager.php index 87f8986..f31f827 100644 --- a/includes/modules/role-manager/class-role-manager.php +++ b/includes/modules/role-manager/class-role-manager.php @@ -22,6 +22,8 @@ */ class Role_Manager extends Base { + use Wordpress; + /** * The Constructor. */ @@ -91,7 +93,7 @@ public function register_form() { 'save_fields' => false, ]); - foreach ( WordPress::get_roles() as $role => $label ) { + foreach ( Role_Manager::get_roles() as $role => $label ) { $cmb->add_field([ 'id' => esc_attr( $role ), 'type' => 'multicheck_inline', diff --git a/includes/modules/sitemap/class-cache.php b/includes/modules/sitemap/class-cache.php index 5f4146a..396c341 100644 --- a/includes/modules/sitemap/class-cache.php +++ b/includes/modules/sitemap/class-cache.php @@ -18,8 +18,11 @@ /** * Cache class. */ +#[\AllowDynamicProperties] class Cache { + use WordPress; + /** * Cache mode. * @@ -45,7 +48,7 @@ class Cache { * The Constructor */ public function __construct() { - $this->wp_filesystem = WordPress::get_filesystem(); + $this->wp_filesystem = Cache::get_filesystem(); $this->mode = $this->is_writable() ? 'file' : 'db'; } @@ -189,7 +192,7 @@ public static function cached_files( $value = null, $type = '' ) { */ public static function invalidate_storage( $type = null ) { $directory = self::get_cache_directory(); - $wp_filesystem = WordPress::get_filesystem(); + $wp_filesystem = self::get_filesystem(); if ( is_null( $type ) ) { $wp_filesystem->delete( $directory, true ); diff --git a/includes/modules/sitemap/class-sitemap-xml.php b/includes/modules/sitemap/class-sitemap-xml.php index 41e7724..a6dcc85 100644 --- a/includes/modules/sitemap/class-sitemap-xml.php +++ b/includes/modules/sitemap/class-sitemap-xml.php @@ -18,6 +18,7 @@ /** * Sitemap_XML class. */ +#[\AllowDynamicProperties] class Sitemap_XML extends XML { use Hooker; diff --git a/includes/modules/status/class-status.php b/includes/modules/status/class-status.php index 7723470..acd8506 100644 --- a/includes/modules/status/class-status.php +++ b/includes/modules/status/class-status.php @@ -22,15 +22,17 @@ */ class Status extends Base { + use Conditional; + /** * Class constructor. */ public function __construct() { - if ( Conditional::is_heartbeat() ) { + if ( Status::is_heartbeat() ) { return; } - if ( Conditional::is_rest() ) { + if ( Status::is_rest() ) { $tools = $this->get_page_views(); $tools = new $tools['tools']['class']; $tools->hooks(); diff --git a/includes/opengraph/class-image.php b/includes/opengraph/class-image.php index 81ed47c..9735ec5 100644 --- a/includes/opengraph/class-image.php +++ b/includes/opengraph/class-image.php @@ -22,7 +22,7 @@ */ class Image { - use Hooker; + use Hooker, Attachment; /** * Holds network slug. @@ -179,7 +179,7 @@ public function add_image_by_id( $attachment_id ) { if ( Str::is_non_empty( $attachment ) ) { $attachment = array( 'url' => $attachment ); } - $attachment['alt'] = Attachment::get_alt_tag( $attachment_id ); + $attachment['alt'] = Image::get_alt_tag( $attachment_id ); $this->add_image( $attachment ); } @@ -473,7 +473,7 @@ private function set_content_image( $post ) { } foreach ( $images as $image_url ) { - $attachment_id = Attachment::get_by_url( $image_url ); + $attachment_id = Image::get_by_url( $image_url ); // If image is hosted externally, skip it and continue to the next image. if ( 0 === $attachment_id ) { @@ -579,7 +579,7 @@ private function get_attachment_image( $attachment_id, $size = 'thumbnail' ) { 'width' => $width, 'height' => $height, 'type' => get_post_mime_type( $attachment_id ), - 'alt' => Attachment::get_alt_tag( $attachment_id ), + 'alt' => Image::get_alt_tag( $attachment_id ), ); } diff --git a/includes/replace-variables/class-base.php b/includes/replace-variables/class-base.php index 59d7ef9..04fc4c6 100644 --- a/includes/replace-variables/class-base.php +++ b/includes/replace-variables/class-base.php @@ -19,6 +19,7 @@ /** * Base class. */ +#[\AllowDynamicProperties] class Base { use Hooker; diff --git a/includes/replace-variables/class-post-variables.php b/includes/replace-variables/class-post-variables.php index a274271..6fb83bc 100644 --- a/includes/replace-variables/class-post-variables.php +++ b/includes/replace-variables/class-post-variables.php @@ -71,7 +71,7 @@ public function setup_post_variables() { ], [ $this, 'get_excerpt_only' ] ); - + $this->register_replacement( 'seo_title', [ @@ -242,7 +242,7 @@ public function get_title() { return Str::is_non_empty( $this->args->post_title ) ? stripslashes( $this->args->post_title ) : null; } - + /** * Custom or Generated SEO Title * @@ -289,7 +289,8 @@ public function get_excerpt() { $keywords = Post::get_meta( 'focus_keyword', $object->ID ); $post_content = Paper::should_apply_shortcode() ? do_shortcode( $object->post_content ) : $object->post_content; $post_content = \preg_replace( '//iu', '', $post_content ); - $post_content = wpautop( WordPress::strip_shortcodes( $post_content ) ); + $post_content = strpos( $post_content, '[' ) === false ? $post_content : preg_replace( '~\[\/?.*?\]~s', '', $post_content ); + $post_content = wpautop( $post_content ); $post_content = wp_kses( $post_content, [ 'p' => [] ] ); // 4. Paragraph with the focus keyword. diff --git a/includes/replace-variables/class-replacer.php b/includes/replace-variables/class-replacer.php index f009672..6ac588f 100644 --- a/includes/replace-variables/class-replacer.php +++ b/includes/replace-variables/class-replacer.php @@ -18,8 +18,11 @@ /** * Replacer class. */ +#[\AllowDynamicProperties] class Replacer { + use WordPress; + /** * Default post data. * @@ -96,10 +99,10 @@ private function pre_replace( $args, $exclude ) { // Setup arguments. $this->args = (object) wp_parse_args( $args, self::$defaults ); if ( ! empty( $this->args->post_content ) ) { - $this->args->post_content = WordPress::strip_shortcodes( $this->args->post_content ); + $this->args->post_content = Replacer::strip_shortcodes( $this->args->post_content ); } if ( ! empty( $this->args->post_excerpt ) ) { - $this->args->post_excerpt = WordPress::strip_shortcodes( $this->args->post_excerpt ); + $this->args->post_excerpt = Replacer::strip_shortcodes( $this->args->post_excerpt ); } // Setup exlucusion. diff --git a/readme.txt b/readme.txt index 040aef5..2cbd33e 100644 --- a/readme.txt +++ b/readme.txt @@ -1,7 +1,7 @@ == Classic SEO == Description: Classic SEO is the first SEO plugin built specifically to work with ClassicPress. The plugin contains many essential SEO tools to help optimize your website. -Version: 2.1.3 +Version: 2.2.0.alpha.0 Text Domain: cpseo Domain Path: /languages Requires PHP: 7.0 diff --git a/vendor/a5hleyrich/wp-background-processing/.gitignore b/vendor/a5hleyrich/wp-background-processing/.gitignore index f45219c..23505a9 100644 --- a/vendor/a5hleyrich/wp-background-processing/.gitignore +++ b/vendor/a5hleyrich/wp-background-processing/.gitignore @@ -1,2 +1,3 @@ /vendor/ -/.idea \ No newline at end of file +/.idea +*.cache diff --git a/vendor/a5hleyrich/wp-background-processing/README.md b/vendor/a5hleyrich/wp-background-processing/README.md index fc09783..923e129 100644 --- a/vendor/a5hleyrich/wp-background-processing/README.md +++ b/vendor/a5hleyrich/wp-background-processing/README.md @@ -4,13 +4,13 @@ WP Background Processing can be used to fire off non-blocking asynchronous reque Inspired by [TechCrunch WP Asynchronous Tasks](https://github.com/techcrunch/wp-async-task). -__Requires PHP 5.2+__ +__Requires PHP 5.6+__ ## Install The recommended way to install this library in your project is by loading it through Composer: -``` +```shell composer require deliciousbrains/wp-background-processing ``` @@ -27,88 +27,110 @@ Extend the `WP_Async_Request` class: ```php class WP_Example_Request extends WP_Async_Request { + /** + * @var string + */ + protected $prefix = 'my_plugin'; + /** * @var string */ protected $action = 'example_request'; /** - * Handle + * Handle a dispatched request. * * Override this method to perform any actions required * during the async request. */ protected function handle() { - // Actions to perform + // Actions to perform. } } ``` -##### `protected $action` +#### `protected $prefix` + +Should be set to a unique prefix associated with your plugin, theme, or site's custom function prefix. + +#### `protected $action` Should be set to a unique name. -##### `protected function handle()` +#### `protected function handle()` Should contain any logic to perform during the non-blocking request. The data passed to the request will be accessible via `$_POST`. -##### Dispatching Requests +#### Dispatching Requests Instantiate your request: -`$this->example_request = new WP_Example_Request();` +```php +$this->example_request = new WP_Example_Request(); +``` Add data to the request if required: -`$this->example_request->data( array( 'value1' => $value1, 'value2' => $value2 ) );` +```php +$this->example_request->data( array( 'value1' => $value1, 'value2' => $value2 ) ); +``` Fire off the request: -`$this->example_request->dispatch();` +```php +$this->example_request->dispatch(); +``` Chaining is also supported: -`$this->example_request->data( array( 'data' => $data ) )->dispatch();` +```php +$this->example_request->data( array( 'data' => $data ) )->dispatch(); +``` ### Background Process -Background processes work in a similar fashion to async requests but they allow you to queue tasks. Items pushed onto the queue will be processed in the background once the queue has been dispatched. Queues will also scale based on available server resources, so higher end servers will process more items per batch. Once a batch has completed the next batch will start instantly. +Background processes work in a similar fashion to async requests, but they allow you to queue tasks. Items pushed onto the queue will be processed in the background once the queue has been saved and dispatched. Queues will also scale based on available server resources, so higher end servers will process more items per batch. Once a batch has completed, the next batch will start instantly. Health checks run by default every 5 minutes to ensure the queue is running when queued items exist. If the queue has failed it will be restarted. -Queues work on a first in first out basis, which allows additional items to be pushed to the queue even if it’s already processing. +Queues work on a first in first out basis, which allows additional items to be pushed to the queue even if it’s already processing. Saving a new batch of queued items and dispatching while another background processing instance is already running will result in the dispatch shortcutting out and the existing instance eventually picking up the new items and processing them when it is their turn. Extend the `WP_Background_Process` class: ```php class WP_Example_Process extends WP_Background_Process { + /** + * @var string + */ + protected $prefix = 'my_plugin'; + /** * @var string */ protected $action = 'example_process'; /** - * Task + * Perform task with queued item. * * Override this method to perform any actions required on each * queue item. Return the modified item for further processing * in the next pass through. Or, return false to remove the * item from the queue. * - * @param mixed $item Queue item to iterate over + * @param mixed $item Queue item to iterate over. * * @return mixed */ protected function task( $item ) { - // Actions to perform + // Actions to perform. return false; } /** - * Complete + * Complete processing. * * Override if applicable, but ensure that the below actions are * performed, or, call parent::complete(). @@ -122,23 +144,29 @@ class WP_Example_Process extends WP_Background_Process { } ``` -##### `protected $action` +#### `protected $prefix` + +Should be set to a unique prefix associated with your plugin, theme, or site's custom function prefix. + +#### `protected $action` Should be set to a unique name. -##### `protected function task( $item )` +#### `protected function task( $item )` Should contain any logic to perform on the queued item. Return `false` to remove the item from the queue or return `$item` to push it back onto the queue for further processing. If the item has been modified and is pushed back onto the queue the current state will be saved before the batch is exited. -##### `protected function complete()` +#### `protected function complete()` Optionally contain any logic to perform once the queue has completed. -##### Dispatching Processes +#### Dispatching Processes Instantiate your process: -`$this->example_process = new WP_Example_Process();` +```php +$this->example_process = new WP_Example_Process(); +``` **Note:** You must instantiate your process unconditionally. All requests should do this, even if nothing is pushed to the queue. @@ -152,11 +180,117 @@ foreach ( $items as $item ) { Save and dispatch the queue: -`$this->example_process->save()->dispatch();` +```php +$this->example_process->save()->dispatch(); +``` + +#### Background Process Status + +A background process can be queued, processing, paused, cancelled, or none of the above (not started or has completed). + +##### Queued + +To check whether a background process has queued items use `is_queued()`. + +```php +if ( $this->example_process->is_queued() ) { + // Do something because background process has queued items, e.g. add notice in admin UI. +} +``` + +##### Processing + +To check whether a background process is currently handling a queue of items use `is_processing()`. + +```php +if ( $this->example_process->is_processing() ) { + // Do something because background process is running, e.g. add notice in admin UI. +} +``` + +##### Paused + +You can pause a background process with `pause()`. + +```php +$this->example_process->pause(); +``` + +The currently processing batch will continue until it either completes or reaches the time or memory limit. At that point it'll unlock the process and either complete the batch if the queue is empty, or perform a dispatch that will result in the handler removing the healthcheck cron and firing a "paused" action. + +To check whether a background process is currently paused use `is_paused()`. + +```php +if ( $this->example_process->is_paused() ) { + // Do something because background process is paused, e.g. add notice in admin UI. +} +``` + +You can perform an action in response to background processing being paused by handling the "paused" action for the background process's identifier ($prefix + $action). + +```php +add_action( 'my_plugin_example_process_paused', function() { + // Do something because background process is paused, e.g. add notice in admin UI. +}); +``` + +You can resume a background process with `resume()`. + +```php +$this->example_process->resume(); +``` + +You can perform an action in response to background processing being resumed by handling the "resumed" action for the background process's identifier ($prefix + $action). + +```php +add_action( 'my_plugin_example_process_resumed', function() { + // Do something because background process is resumed, e.g. add notice in admin UI. +}); +``` + +##### Cancelled + +You can cancel a background process with `cancel()`. + +```php +$this->example_process->cancel(); +``` + +The currently processing batch will continue until it either completes or reaches the time or memory limit. At that point it'll unlock the process and either complete the batch if the queue is empty, or perform a dispatch that will result in the handler removing the healthcheck cron, deleting all batches of queued items and firing a "cancelled" action. + +To check whether a background process is currently cancelled use `is_cancelled()`. + +```php +if ( $this->example_process->is_cancelled() ) { + // Do something because background process is cancelled, e.g. add notice in admin UI. +} +``` + +You can perform an action in response to background processing being cancelled by handling the "cancelled" action for the background process's identifier ($prefix + $action). + +```php +add_action( 'my_plugin_example_process_cancelled', function() { + // Do something because background process is paused, e.g. add notice in admin UI. +}); +``` + +The "cancelled" action fires once the queue has been cleared down and cancelled status removed. After which `is_cancelled()` will no longer be true as the background process is now dormant. + +##### Active + +To check whether a background process has queued items, is processing, is paused, or is cancelling, use `is_active()`. + +```php +if ( $this->example_process->is_active() ) { + // Do something because background process is active, e.g. add notice in admin UI. +} +``` + +If a background process is not active, then it either has not had anything queued yet and not started, or has finished processing all queued items. ### BasicAuth -If your site is behind BasicAuth, both async requests and background processes will fail to complete. This is because WP Background Processing relies on the [WordPress HTTP API](http://codex.wordpress.org/HTTP_API), which requires you to attach your BasicAuth credentials to requests. The easiest way to do this is using the following filter: +If your site is behind BasicAuth, both async requests and background processes will fail to complete. This is because WP Background Processing relies on the [WordPress HTTP API](https://developer.wordpress.org/plugins/http-api/), which requires you to attach your BasicAuth credentials to requests. The easiest way to do this is using the following filter: ```php function wpbp_http_request_args( $r, $url ) { @@ -167,6 +301,76 @@ function wpbp_http_request_args( $r, $url ) { add_filter( 'http_request_args', 'wpbp_http_request_args', 10, 2); ``` +## Contributing + +Contributions are welcome via Pull Requests, but please do raise an issue before +working on anything to discuss the change if there isn't already an issue. If there +is an approved issue you'd like to tackle, please post a comment on it to let people know +you're going to have a go at it so that effort isn't wasted through duplicated work. + +### Unit & Style Tests + +When working on the library, please add unit tests to the appropriate file in the +`tests` directory that cover your changes. + +#### Setting Up + +We use the standard WordPress test libraries for running unit tests. + +Please run the following command to set up the libraries: + +```shell +bin/install-wp-tests.sh db_name db_user db_pass +``` + +Substitute `db_name`, `db_user` and `db_pass` as appropriate. + +Please be aware that running the unit tests is a **destructive operation**, *database +tables will be cleared*, so please use a database name dedicated to running unit tests. +The standard database name usually used by the WordPress community is `wordpress_test`, e.g. + +```shell +bin/install-wp-tests.sh wordpress_test root root +``` + +Please refer to the [Initialize the testing environment locally](https://make.wordpress.org/cli/handbook/misc/plugin-unit-tests/#3-initialize-the-testing-environment-locally) +section of the WordPress Handbook's [Plugin Integration Tests](https://make.wordpress.org/cli/handbook/misc/plugin-unit-tests/) +entry should you run into any issues. + +#### Running Unit Tests + +To run the unit tests, simply run: + +```shell +make test-unit +``` + +If the `composer` dependencies aren't in place, they'll be automatically installed first. + +#### Running Style Tests + +It's important that the code in the library use a consistent style to aid in quickly +understanding it, and to avoid some common issues. `PHP_Code_Sniffer` is used with +mostly standard WordPress rules to help check for consistency. + +To run the style tests, simply run: + +```shell +make test-style +``` + +If the `composer` dependencies aren't in place, they'll be automatically installed first. + +#### Running All Tests + +To make things super simple, just run the following to run all tests: + +```shell +make +``` + +If the `composer` dependencies aren't in place, they'll be automatically installed first. + ## License [GPLv2+](http://www.gnu.org/licenses/gpl-2.0.html) diff --git a/vendor/a5hleyrich/wp-background-processing/classes/wp-async-request.php b/vendor/a5hleyrich/wp-background-processing/classes/wp-async-request.php index 7a37dd6..9759ab0 100644 --- a/vendor/a5hleyrich/wp-background-processing/classes/wp-async-request.php +++ b/vendor/a5hleyrich/wp-background-processing/classes/wp-async-request.php @@ -51,7 +51,7 @@ abstract class WP_Async_Request { protected $data = array(); /** - * Initiate new async request + * Initiate new async request. */ public function __construct() { $this->identifier = $this->prefix . '_' . $this->action; @@ -61,7 +61,7 @@ public function __construct() { } /** - * Set data used during the request + * Set data used during the request. * * @param array $data Data. * @@ -74,9 +74,9 @@ public function data( $data ) { } /** - * Dispatch the async request + * Dispatch the async request. * - * @return array|WP_Error + * @return array|WP_Error|false HTTP Response array, WP_Error on failure, or false if not attempted. */ public function dispatch() { $url = add_query_arg( $this->get_query_args(), $this->get_query_url() ); @@ -86,7 +86,7 @@ public function dispatch() { } /** - * Get query args + * Get query args. * * @return array */ @@ -109,7 +109,7 @@ protected function get_query_args() { } /** - * Get query URL + * Get query URL. * * @return string */ @@ -129,7 +129,7 @@ protected function get_query_url() { } /** - * Get post args + * Get post args. * * @return array */ @@ -142,8 +142,8 @@ protected function get_post_args() { 'timeout' => 0.01, 'blocking' => false, 'body' => $this->data, - 'cookies' => $_COOKIE, - 'sslverify' => apply_filters( 'https_local_ssl_verify', false ), + 'cookies' => $_COOKIE, // Passing cookies ensures request is performed as initiating user. + 'sslverify' => apply_filters( 'https_local_ssl_verify', false ), // Local requests, fine to pass false. ); /** @@ -155,27 +155,48 @@ protected function get_post_args() { } /** - * Maybe handle + * Maybe handle a dispatched request. * * Check for correct nonce and pass to handler. + * + * @return void|mixed */ public function maybe_handle() { - // Don't lock up other requests while processing + // Don't lock up other requests while processing. session_write_close(); check_ajax_referer( $this->identifier, 'nonce' ); $this->handle(); - wp_die(); + return $this->maybe_wp_die(); } /** - * Handle + * Should the process exit with wp_die? + * + * @param mixed $return What to return if filter says don't die, default is null. + * + * @return void|mixed + */ + protected function maybe_wp_die( $return = null ) { + /** + * Should wp_die be used? + * + * @return bool + */ + if ( apply_filters( $this->identifier . '_wp_die', true ) ) { + wp_die(); + } + + return $return; + } + + /** + * Handle a dispatched request. * * Override this method to perform any actions required * during the async request. */ abstract protected function handle(); - } diff --git a/vendor/a5hleyrich/wp-background-processing/classes/wp-background-process.php b/vendor/a5hleyrich/wp-background-processing/classes/wp-background-process.php index ce7904a..82a8e63 100644 --- a/vendor/a5hleyrich/wp-background-processing/classes/wp-background-process.php +++ b/vendor/a5hleyrich/wp-background-processing/classes/wp-background-process.php @@ -36,7 +36,7 @@ abstract class WP_Background_Process extends WP_Async_Request { /** * Cron_hook_identifier * - * @var mixed + * @var string * @access protected */ protected $cron_hook_identifier; @@ -44,13 +44,27 @@ abstract class WP_Background_Process extends WP_Async_Request { /** * Cron_interval_identifier * - * @var mixed + * @var string * @access protected */ protected $cron_interval_identifier; /** - * Initiate new background process + * The status set when process is cancelling. + * + * @var int + */ + const STATUS_CANCELLED = 1; + + /** + * The status set when process is paused or pausing. + * + * @var int; + */ + const STATUS_PAUSED = 2; + + /** + * Initiate new background process. */ public function __construct() { parent::__construct(); @@ -63,12 +77,17 @@ public function __construct() { } /** - * Dispatch + * Schedule the cron healthcheck and dispatch an async request to start processing the queue. * * @access public - * @return void + * @return array|WP_Error|false HTTP Response array, WP_Error on failure, or false if not attempted. */ public function dispatch() { + if ( $this->is_processing() ) { + // Process already running. + return false; + } + // Schedule the cron healthcheck. $this->schedule_event(); @@ -77,7 +96,9 @@ public function dispatch() { } /** - * Push to queue + * Push to the queue. + * + * Note, save must be called in order to persist queued items to a batch for processing. * * @param mixed $data Data. * @@ -90,7 +111,7 @@ public function push_to_queue( $data ) { } /** - * Save queue + * Save the queued items for future processing. * * @return $this */ @@ -101,11 +122,14 @@ public function save() { update_site_option( $key, $this->data ); } + // Clean out data so that new data isn't prepended with closed session's data. + $this->data = array(); + return $this; } /** - * Update queue + * Update a batch's queued items. * * @param string $key Key. * @param array $data Data. @@ -121,7 +145,7 @@ public function update( $key, $data ) { } /** - * Delete queue + * Delete a batch of queued items. * * @param string $key Key. * @@ -134,83 +158,215 @@ public function delete( $key ) { } /** - * Generate key + * Delete entire job queue. + */ + public function delete_all() { + $batches = $this->get_batches(); + + foreach ( $batches as $batch ) { + $this->delete( $batch->key ); + } + + delete_site_option( $this->get_status_key() ); + + $this->cancelled(); + } + + /** + * Cancel job on next batch. + */ + public function cancel() { + update_site_option( $this->get_status_key(), self::STATUS_CANCELLED ); + + // Just in case the job was paused at the time. + $this->dispatch(); + } + + /** + * Has the process been cancelled? + * + * @return bool + */ + public function is_cancelled() { + $status = get_site_option( $this->get_status_key(), 0 ); + + if ( absint( $status ) === self::STATUS_CANCELLED ) { + return true; + } + + return false; + } + + /** + * Called when background process has been cancelled. + */ + protected function cancelled() { + do_action( $this->identifier . '_cancelled' ); + } + + /** + * Pause job on next batch. + */ + public function pause() { + update_site_option( $this->get_status_key(), self::STATUS_PAUSED ); + } + + /** + * Is the job paused? + * + * @return bool + */ + public function is_paused() { + $status = get_site_option( $this->get_status_key(), 0 ); + + if ( absint( $status ) === self::STATUS_PAUSED ) { + return true; + } + + return false; + } + + /** + * Called when background process has been paused. + */ + protected function paused() { + do_action( $this->identifier . '_paused' ); + } + + /** + * Resume job. + */ + public function resume() { + delete_site_option( $this->get_status_key() ); + + $this->schedule_event(); + $this->dispatch(); + $this->resumed(); + } + + /** + * Called when background process has been resumed. + */ + protected function resumed() { + do_action( $this->identifier . '_resumed' ); + } + + /** + * Is queued? + * + * @return bool + */ + public function is_queued() { + return ! $this->is_queue_empty(); + } + + /** + * Is the tool currently active, e.g. starting, working, paused or cleaning up? + * + * @return bool + */ + public function is_active() { + return $this->is_queued() || $this->is_processing() || $this->is_paused() || $this->is_cancelled(); + } + + /** + * Generate key for a batch. * * Generates a unique key based on microtime. Queue items are * given a unique key so that they can be merged upon save. * - * @param int $length Length. + * @param int $length Optional max length to trim key to, defaults to 64 characters. + * @param string $key Optional string to append to identifier before hash, defaults to "batch". * * @return string */ - protected function generate_key( $length = 64 ) { - $unique = md5( microtime() . rand() ); - $prepend = $this->identifier . '_batch_'; + protected function generate_key( $length = 64, $key = 'batch' ) { + $unique = md5( microtime() . wp_rand() ); + $prepend = $this->identifier . '_' . $key . '_'; return substr( $prepend . $unique, 0, $length ); } /** - * Maybe process queue + * Get the status key. + * + * @return string + */ + protected function get_status_key() { + return $this->identifier . '_status'; + } + + /** + * Maybe process a batch of queued items. * * Checks whether data exists within the queue and that * the process is not already running. */ public function maybe_handle() { - // Don't lock up other requests while processing + // Don't lock up other requests while processing. session_write_close(); - if ( $this->is_process_running() ) { + if ( $this->is_processing() ) { // Background process already running. - wp_die(); + return $this->maybe_wp_die(); + } + + if ( $this->is_cancelled() ) { + $this->clear_scheduled_event(); + $this->delete_all(); + + return $this->maybe_wp_die(); + } + + if ( $this->is_paused() ) { + $this->clear_scheduled_event(); + $this->paused(); + + return $this->maybe_wp_die(); } if ( $this->is_queue_empty() ) { // No data to process. - wp_die(); + return $this->maybe_wp_die(); } check_ajax_referer( $this->identifier, 'nonce' ); $this->handle(); - wp_die(); + return $this->maybe_wp_die(); } /** - * Is queue empty + * Is queue empty? * * @return bool */ protected function is_queue_empty() { - global $wpdb; - - $table = $wpdb->options; - $column = 'option_name'; - - if ( is_multisite() ) { - $table = $wpdb->sitemeta; - $column = 'meta_key'; - } - - $key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%'; - - $count = $wpdb->get_var( $wpdb->prepare( " - SELECT COUNT(*) - FROM {$table} - WHERE {$column} LIKE %s - ", $key ) ); - - return ( $count > 0 ) ? false : true; + return empty( $this->get_batch() ); } /** - * Is process running + * Is process running? * * Check whether the current process is already running * in a background process. + * + * @return bool + * + * @deprecated 1.1.0 Superseded. + * @see is_processing() */ protected function is_process_running() { + return $this->is_processing(); + } + + /** + * Is the background process currently running? + * + * @return bool + */ + public function is_processing() { if ( get_site_transient( $this->identifier . '_process_lock' ) ) { // Process already running. return true; @@ -220,7 +376,7 @@ protected function is_process_running() { } /** - * Lock process + * Lock process. * * Lock the process so that multiple instances can't run simultaneously. * Override if applicable, but the duration should be greater than that @@ -236,7 +392,7 @@ protected function lock_process() { } /** - * Unlock process + * Unlock process. * * Unlock the process so that other instances can spawn. * @@ -249,13 +405,34 @@ protected function unlock_process() { } /** - * Get batch + * Get batch. * - * @return stdClass Return the first batch from the queue + * @return stdClass Return the first batch of queued items. */ protected function get_batch() { + return array_reduce( + $this->get_batches( 1 ), + function ( $carry, $batch ) { + return $batch; + }, + array() + ); + } + + /** + * Get batches. + * + * @param int $limit Number of batches to return, defaults to all. + * + * @return array of stdClass + */ + public function get_batches( $limit = 0 ) { global $wpdb; + if ( empty( $limit ) || ! is_int( $limit ) ) { + $limit = 0; + } + $table = $wpdb->options; $column = 'option_name'; $key_column = 'option_id'; @@ -270,23 +447,43 @@ protected function get_batch() { $key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%'; - $query = $wpdb->get_row( $wpdb->prepare( " + $sql = ' SELECT * - FROM {$table} - WHERE {$column} LIKE %s - ORDER BY {$key_column} ASC - LIMIT 1 - ", $key ) ); + FROM ' . $table . ' + WHERE ' . $column . ' LIKE %s + ORDER BY ' . $key_column . ' ASC + '; + + $args = array( $key ); + + if ( ! empty( $limit ) ) { + $sql .= ' LIMIT %d'; + + $args[] = $limit; + } + + $items = $wpdb->get_results( $wpdb->prepare( $sql, $args ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + + $batches = array(); - $batch = new stdClass(); - $batch->key = $query->$column; - $batch->data = maybe_unserialize( $query->$value_column ); + if ( ! empty( $items ) ) { + $batches = array_map( + function ( $item ) use ( $column, $value_column ) { + $batch = new stdClass(); + $batch->key = $item->{$column}; + $batch->data = maybe_unserialize( $item->{$value_column} ); + + return $batch; + }, + $items + ); + } - return $batch; + return $batches; } /** - * Handle + * Handle a dispatched request. * * Pass each queue item to the task handler, while remaining * within server memory and time limit constraints. @@ -294,6 +491,22 @@ protected function get_batch() { protected function handle() { $this->lock_process(); + /** + * Number of seconds to sleep between batches. Defaults to 0 seconds, minimum 0. + * + * @param int $seconds + */ + $throttle_seconds = max( + 0, + apply_filters( + $this->identifier . '_seconds_between_batches', + apply_filters( + $this->prefix . '_seconds_between_batches', + 0 + ) + ) + ); + do { $batch = $this->get_batch(); @@ -306,16 +519,22 @@ protected function handle() { unset( $batch->data[ $key ] ); } + // Keep the batch up to date while processing it. + if ( ! empty( $batch->data ) ) { + $this->update( $batch->key, $batch->data ); + } + + // Let the server breathe a little. + sleep( $throttle_seconds ); + if ( $this->time_exceeded() || $this->memory_exceeded() ) { // Batch limits reached. break; } } - // Update or delete current batch. - if ( ! empty( $batch->data ) ) { - $this->update( $batch->key, $batch->data ); - } else { + // Delete current batch if fully processed. + if ( empty( $batch->data ) ) { $this->delete( $batch->key ); } } while ( ! $this->time_exceeded() && ! $this->memory_exceeded() && ! $this->is_queue_empty() ); @@ -329,11 +548,11 @@ protected function handle() { $this->complete(); } - wp_die(); + return $this->maybe_wp_die(); } /** - * Memory exceeded + * Memory exceeded? * * Ensures the batch process never exceeds 90% * of the maximum WordPress memory. @@ -353,7 +572,7 @@ protected function memory_exceeded() { } /** - * Get memory limit + * Get memory limit in bytes. * * @return int */ @@ -365,7 +584,7 @@ protected function get_memory_limit() { $memory_limit = '128M'; } - if ( ! $memory_limit || - 1 === intval( $memory_limit ) ) { + if ( ! $memory_limit || -1 === intval( $memory_limit ) ) { // Unlimited, set to 32GB. $memory_limit = '32000M'; } @@ -374,7 +593,7 @@ protected function get_memory_limit() { } /** - * Time exceeded. + * Time limit exceeded? * * Ensures the batch never exceeds a sensible time limit. * A timeout limit of 30s is common on shared hosting. @@ -393,18 +612,29 @@ protected function time_exceeded() { } /** - * Complete. + * Complete processing. * * Override if applicable, but ensure that the below actions are * performed, or, call parent::complete(). */ protected function complete() { - // Unschedule the cron healthcheck. + delete_site_option( $this->get_status_key() ); + + // Remove the cron healthcheck job from the cron schedule. $this->clear_scheduled_event(); + + $this->completed(); + } + + /** + * Called when background process has completed. + */ + protected function completed() { + do_action( $this->identifier . '_completed' ); } /** - * Schedule cron healthcheck + * Schedule the cron healthcheck job. * * @access public * @@ -413,29 +643,35 @@ protected function complete() { * @return mixed */ public function schedule_cron_healthcheck( $schedules ) { - $interval = apply_filters( $this->identifier . '_cron_interval', 5 ); + $interval = apply_filters( $this->cron_interval_identifier, 5 ); if ( property_exists( $this, 'cron_interval' ) ) { - $interval = apply_filters( $this->identifier . '_cron_interval', $this->cron_interval ); + $interval = apply_filters( $this->cron_interval_identifier, $this->cron_interval ); } - // Adds every 5 minutes to the existing schedules. - $schedules[ $this->identifier . '_cron_interval' ] = array( + if ( 1 === $interval ) { + $display = __( 'Every Minute' ); + } else { + $display = sprintf( __( 'Every %d Minutes' ), $interval ); + } + + // Adds an "Every NNN Minute(s)" schedule to the existing cron schedules. + $schedules[ $this->cron_interval_identifier ] = array( 'interval' => MINUTE_IN_SECONDS * $interval, - 'display' => sprintf( __( 'Every %d Minutes' ), $interval ), + 'display' => $display, ); return $schedules; } /** - * Handle cron healthcheck + * Handle cron healthcheck event. * * Restart the background process if not already running * and data exists in the queue. */ public function handle_cron_healthcheck() { - if ( $this->is_process_running() ) { + if ( $this->is_processing() ) { // Background process already running. exit; } @@ -446,13 +682,11 @@ public function handle_cron_healthcheck() { exit; } - $this->handle(); - - exit; + $this->dispatch(); } /** - * Schedule event + * Schedule the cron healthcheck event. */ protected function schedule_event() { if ( ! wp_next_scheduled( $this->cron_hook_identifier ) ) { @@ -461,7 +695,7 @@ protected function schedule_event() { } /** - * Clear scheduled event + * Clear scheduled cron healthcheck event. */ protected function clear_scheduled_event() { $timestamp = wp_next_scheduled( $this->cron_hook_identifier ); @@ -472,24 +706,19 @@ protected function clear_scheduled_event() { } /** - * Cancel Process + * Cancel the background process. * - * Stop processing queue items, clear cronjob and delete batch. + * Stop processing queue items, clear cron job and delete batch. * + * @deprecated 1.1.0 Superseded. + * @see cancel() */ public function cancel_process() { - if ( ! $this->is_queue_empty() ) { - $batch = $this->get_batch(); - - $this->delete( $batch->key ); - - wp_clear_scheduled_hook( $this->cron_hook_identifier ); - } - + $this->cancel(); } /** - * Task + * Perform task with queued item. * * Override this method to perform any actions required on each * queue item. Return the modified item for further processing @@ -501,5 +730,4 @@ public function cancel_process() { * @return mixed */ abstract protected function task( $item ); - -} \ No newline at end of file +} diff --git a/vendor/a5hleyrich/wp-background-processing/composer.json b/vendor/a5hleyrich/wp-background-processing/composer.json index 9453fe8..5f65733 100644 --- a/vendor/a5hleyrich/wp-background-processing/composer.json +++ b/vendor/a5hleyrich/wp-background-processing/composer.json @@ -3,7 +3,7 @@ "description": "WP Background Processing can be used to fire off non-blocking asynchronous requests or as a background processing tool, allowing you to queue tasks.", "type": "library", "require": { - "php": ">=5.2" + "php": ">=5.6" }, "suggest": { "coenjacobs/mozart": "Easily wrap this library with your own prefix, to prevent collisions when multiple plugins use this library" @@ -16,6 +16,20 @@ } ], "autoload": { - "classmap": [ "classes/" ] + "classmap": [ + "classes/" + ] + }, + "require-dev": { + "phpunit/phpunit": "^8.0", + "yoast/phpunit-polyfills": "^1.0", + "spryker/code-sniffer": "^0.17.18", + "phpcompatibility/phpcompatibility-wp": "*", + "wp-coding-standards/wpcs": "^2.3" + }, + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } } -} \ No newline at end of file +} diff --git a/vendor/a5hleyrich/wp-background-processing/wp-background-processing.php b/vendor/a5hleyrich/wp-background-processing/wp-background-processing.php index c2fc252..6881bcd 100644 --- a/vendor/a5hleyrich/wp-background-processing/wp-background-processing.php +++ b/vendor/a5hleyrich/wp-background-processing/wp-background-processing.php @@ -7,12 +7,12 @@ /* Plugin Name: WP Background Processing -Plugin URI: https://github.com/A5hleyRich/wp-background-processing +Plugin URI: https://github.com/deliciousbrains/wp-background-processing Description: Asynchronous requests and background processing in WordPress. Author: Delicious Brains Inc. Version: 1.0 Author URI: https://deliciousbrains.com/ -GitHub Plugin URI: https://github.com/A5hleyRich/wp-background-processing +GitHub Plugin URI: https://github.com/deliciousbrains/wp-background-processing GitHub Branch: master */ diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index add048b..c75b5fb 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -263,6 +263,7 @@ 'Classic_SEO\\WooCommerce\\Sitemap' => $baseDir . '/includes/modules/woocommerce/class-sitemap.php', 'Classic_SEO\\WooCommerce\\WC_Vars' => $baseDir . '/includes/modules/woocommerce/class-wc-vars.php', 'Classic_SEO\\WooCommerce\\WooCommerce' => $baseDir . '/includes/modules/woocommerce/class-woocommerce.php', + 'Classic_SEO\\updateClientTweaks' => $baseDir . '/includes/class-update-client-tweaks.php', 'ComposerAutoloaderInit531772699595bd84a6a8fd835c733f0b' => $vendorDir . '/composer/autoload_real.php', 'Composer\\Autoload\\ClassLoader' => $vendorDir . '/composer/ClassLoader.php', 'Composer\\Autoload\\ComposerStaticInit531772699595bd84a6a8fd835c733f0b' => $vendorDir . '/composer/autoload_static.php', @@ -380,6 +381,8 @@ 'Psr\\Log\\Test\\DummyTest' => $vendorDir . '/psr/log/Psr/Log/Test/DummyTest.php', 'Psr\\Log\\Test\\LoggerInterfaceTest' => $vendorDir . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php', 'Psr\\Log\\Test\\TestLogger' => $vendorDir . '/psr/log/Psr/Log/Test/TestLogger.php', + 'Test_Setup' => $vendorDir . '/a5hleyrich/wp-background-processing/tests/Test_Setup.php', + 'Test_WP_Background_Process' => $vendorDir . '/a5hleyrich/wp-background-processing/tests/Test_WP_Background_Process.php', 'WP_Async_Request' => $vendorDir . '/a5hleyrich/wp-background-processing/classes/wp-async-request.php', 'WP_Background_Process' => $vendorDir . '/a5hleyrich/wp-background-processing/classes/wp-background-process.php', 'WP_REST_Controller' => $vendorDir . '/cmb2/includes/shim/WP_REST_Controller.php', diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 442bf41..d4b8c59 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -291,6 +291,7 @@ class ComposerStaticInit531772699595bd84a6a8fd835c733f0b 'Classic_SEO\\WooCommerce\\Sitemap' => __DIR__ . '/../..' . '/includes/modules/woocommerce/class-sitemap.php', 'Classic_SEO\\WooCommerce\\WC_Vars' => __DIR__ . '/../..' . '/includes/modules/woocommerce/class-wc-vars.php', 'Classic_SEO\\WooCommerce\\WooCommerce' => __DIR__ . '/../..' . '/includes/modules/woocommerce/class-woocommerce.php', + 'Classic_SEO\\updateClientTweaks' => __DIR__ . '/../..' . '/includes/class-update-client-tweaks.php', 'ComposerAutoloaderInit531772699595bd84a6a8fd835c733f0b' => __DIR__ . '/..' . '/composer/autoload_real.php', 'Composer\\Autoload\\ClassLoader' => __DIR__ . '/..' . '/composer/ClassLoader.php', 'Composer\\Autoload\\ComposerStaticInit531772699595bd84a6a8fd835c733f0b' => __DIR__ . '/..' . '/composer/autoload_static.php', @@ -408,6 +409,8 @@ class ComposerStaticInit531772699595bd84a6a8fd835c733f0b 'Psr\\Log\\Test\\DummyTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/DummyTest.php', 'Psr\\Log\\Test\\LoggerInterfaceTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php', 'Psr\\Log\\Test\\TestLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/TestLogger.php', + 'Test_Setup' => __DIR__ . '/..' . '/a5hleyrich/wp-background-processing/tests/Test_Setup.php', + 'Test_WP_Background_Process' => __DIR__ . '/..' . '/a5hleyrich/wp-background-processing/tests/Test_WP_Background_Process.php', 'WP_Async_Request' => __DIR__ . '/..' . '/a5hleyrich/wp-background-processing/classes/wp-async-request.php', 'WP_Background_Process' => __DIR__ . '/..' . '/a5hleyrich/wp-background-processing/classes/wp-background-process.php', 'WP_REST_Controller' => __DIR__ . '/..' . '/cmb2/includes/shim/WP_REST_Controller.php', diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 3504cf2..f9b6e03 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -2,26 +2,33 @@ "packages": [ { "name": "a5hleyrich/wp-background-processing", - "version": "1.0.2", - "version_normalized": "1.0.2.0", + "version": "1.1.0", + "version_normalized": "1.1.0.0", "source": { "type": "git", "url": "https://github.com/deliciousbrains/wp-background-processing.git", - "reference": "2cbee1abd1b49e1133cd8f611df4d4fc5a8b9800" + "reference": "d5ef95cecba7f792ddca3e3bd70ebfb90dc4996d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/deliciousbrains/wp-background-processing/zipball/2cbee1abd1b49e1133cd8f611df4d4fc5a8b9800", - "reference": "2cbee1abd1b49e1133cd8f611df4d4fc5a8b9800", + "url": "https://api.github.com/repos/deliciousbrains/wp-background-processing/zipball/d5ef95cecba7f792ddca3e3bd70ebfb90dc4996d", + "reference": "d5ef95cecba7f792ddca3e3bd70ebfb90dc4996d", "shasum": "" }, "require": { - "php": ">=5.2" + "php": ">=5.6" + }, + "require-dev": { + "phpcompatibility/phpcompatibility-wp": "*", + "phpunit/phpunit": "^8.0", + "spryker/code-sniffer": "^0.17.18", + "wp-coding-standards/wpcs": "^2.3", + "yoast/phpunit-polyfills": "^1.0" }, "suggest": { "coenjacobs/mozart": "Easily wrap this library with your own prefix, to prevent collisions when multiple plugins use this library" }, - "time": "2020-07-31T07:00:11+00:00", + "time": "2023-04-18T12:32:25+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -42,7 +49,7 @@ "description": "WP Background Processing can be used to fire off non-blocking asynchronous requests or as a background processing tool, allowing you to queue tasks.", "support": { "issues": "https://github.com/deliciousbrains/wp-background-processing/issues", - "source": "https://github.com/deliciousbrains/wp-background-processing/tree/1.0.2" + "source": "https://github.com/deliciousbrains/wp-background-processing/tree/1.1.0" }, "install-path": "../a5hleyrich/wp-background-processing" }, diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 359b914..ffd4a78 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => 'classicpress-plugins/classicpress-seo', 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => '834b5d626c5b2a0f480a3c8cf09cf5fd2be5407c', + 'reference' => '859e1026b85050812661b122c3ccafa162177e55', 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -11,9 +11,9 @@ ), 'versions' => array( 'a5hleyrich/wp-background-processing' => array( - 'pretty_version' => '1.0.2', - 'version' => '1.0.2.0', - 'reference' => '2cbee1abd1b49e1133cd8f611df4d4fc5a8b9800', + 'pretty_version' => '1.1.0', + 'version' => '1.1.0.0', + 'reference' => 'd5ef95cecba7f792ddca3e3bd70ebfb90dc4996d', 'type' => 'library', 'install_path' => __DIR__ . '/../a5hleyrich/wp-background-processing', 'aliases' => array(), @@ -22,7 +22,7 @@ 'classicpress-plugins/classicpress-seo' => array( 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => '834b5d626c5b2a0f480a3c8cf09cf5fd2be5407c', + 'reference' => '859e1026b85050812661b122c3ccafa162177e55', 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(),