Merged in feature/314-dev-dev01 (pull request #24)

auto-patch  314-dev-dev01-2024-01-25T04_09_02

* auto-patch  314-dev-dev01-2024-01-25T04_09_02
This commit is contained in:
Tony Volpe
2024-01-25 04:11:47 +00:00
parent 6b67473553
commit 68dbe860e9
540 changed files with 3445 additions and 2131 deletions

View File

@@ -17,56 +17,56 @@ class WPSEO_Addon_Manager {
*
* @var string
*/
const SITE_INFORMATION_TRANSIENT = 'wpseo_site_information';
public const SITE_INFORMATION_TRANSIENT = 'wpseo_site_information';
/**
* Holds the name of the transient.
*
* @var string
*/
const SITE_INFORMATION_TRANSIENT_QUICK = 'wpseo_site_information_quick';
public const SITE_INFORMATION_TRANSIENT_QUICK = 'wpseo_site_information_quick';
/**
* Holds the slug for YoastSEO free.
*
* @var string
*/
const FREE_SLUG = 'yoast-seo-wordpress';
public const FREE_SLUG = 'yoast-seo-wordpress';
/**
* Holds the slug for YoastSEO Premium.
*
* @var string
*/
const PREMIUM_SLUG = 'yoast-seo-wordpress-premium';
public const PREMIUM_SLUG = 'yoast-seo-wordpress-premium';
/**
* Holds the slug for Yoast News.
*
* @var string
*/
const NEWS_SLUG = 'yoast-seo-news';
public const NEWS_SLUG = 'yoast-seo-news';
/**
* Holds the slug for Video.
*
* @var string
*/
const VIDEO_SLUG = 'yoast-seo-video';
public const VIDEO_SLUG = 'yoast-seo-video';
/**
* Holds the slug for WooCommerce.
*
* @var string
*/
const WOOCOMMERCE_SLUG = 'yoast-seo-woocommerce';
public const WOOCOMMERCE_SLUG = 'yoast-seo-woocommerce';
/**
* Holds the slug for Local.
*
* @var string
*/
const LOCAL_SLUG = 'yoast-seo-local';
public const LOCAL_SLUG = 'yoast-seo-local';
/**
* The expected addon data.
@@ -396,6 +396,8 @@ class WPSEO_Addon_Manager {
* If the plugin is lacking an active subscription, throw a warning.
*
* @param array $plugin_data The data for the plugin in this row.
*
* @return void
*/
public function expired_subscription_warning( $plugin_data ) {
$subscription = $this->get_subscription( $plugin_data['slug'] );
@@ -411,16 +413,16 @@ class WPSEO_Addon_Manager {
);
}
echo '<br><br>';
echo '<strong><span class="yoast-dashicons-notice warning dashicons dashicons-warning"></span> ' .
sprintf(
echo '<strong><span class="yoast-dashicons-notice warning dashicons dashicons-warning"></span> '
. sprintf(
/* translators: %1$s is the plugin name, %2$s and %3$s are a link. */
esc_html__( '%1$s can\'t be updated because your product subscription is expired. %2$sRenew your product subscription%3$s to get updates again and use all the features of %1$s.', 'wordpress-seo' ),
esc_html( $plugin_data['name'] ),
'<a href="' . esc_url( WPSEO_Shortlinker::get( $addon_link ) ) . '">',
'</a>'
) .
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output is escaped above.
$sale_copy
)
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output is escaped above.
. $sale_copy
. '</strong>';
}
}
@@ -461,6 +463,8 @@ class WPSEO_Addon_Manager {
/**
* Validates the addons and show a notice for the ones that are invalid.
*
* @return void
*/
public function validate_addons() {
$notification_center = Yoast_Notification_Center::get();
@@ -579,7 +583,7 @@ class WPSEO_Addon_Manager {
'banners' => $this->get_banners( $subscription->product->slug ),
// If we have extracted Yoast Free's data before, use that. If not, resort to the defaults.
'tested' => YOAST_SEO_WP_TESTED,
'requires' => isset( $yoast_free_data->requires ) ? $yoast_free_data->requires : $defaults['requires'],
'requires' => ( $yoast_free_data->requires ?? $defaults['requires'] ),
'requires_php' => YOAST_SEO_PHP_REQUIRED,
];
}
@@ -726,7 +730,7 @@ class WPSEO_Addon_Manager {
$current_page = null;
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: We are not processing form information.
if ( isset( $_GET['page'] ) && is_string( $_GET['page'] ) ) {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Reason: We are not processing form information, We are only strictly comparing and thus no need to sanitize.
// phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Reason: We are not processing form information, We are only strictly comparing and thus no need to sanitize.
$current_page = wp_unslash( $_GET['page'] );
}
@@ -833,7 +837,7 @@ class WPSEO_Addon_Manager {
'last_updated' => $subscription->product->lastUpdated,
'store_url' => $subscription->product->storeUrl,
// Ternary operator is necessary because download can be undefined.
'download' => isset( $subscription->product->download ) ? $subscription->product->download : null,
'download' => ( $subscription->product->download ?? null ),
'changelog' => $subscription->product->changelog,
],
];

View File

@@ -28,6 +28,8 @@ class WPSEO_Rewrite {
* Trigger a rewrite_rule flush on shutdown.
*
* @since 1.2.8
*
* @return void
*/
public function schedule_flush() {
add_action( 'shutdown', 'flush_rewrite_rules' );

View File

@@ -50,6 +50,8 @@ class WPSEO_Upgrade_History {
* @param string $old_version The version we are upgrading from.
* @param string $new_version The version we are upgrading to.
* @param array $option_names The options that need to be stored.
*
* @return void
*/
public function add( $old_version, $new_version, array $option_names ) {
$option_data = [];

View File

@@ -8,6 +8,7 @@
use Yoast\WP\Lib\Model;
use Yoast\WP\SEO\Helpers\Taxonomy_Helper;
use Yoast\WP\SEO\Integrations\Cleanup_Integration;
use Yoast\WP\SEO\Integrations\Watchers\Addon_Update_Watcher;
/**
* This code handles the option upgrades.
@@ -108,7 +109,7 @@ class WPSEO_Upgrade {
/**
* Filter: 'wpseo_run_upgrade' - Runs the upgrade hook which are dependent on Yoast SEO.
*
* @api string - The current version of Yoast SEO
* @param string $version The current version of Yoast SEO
*/
do_action( 'wpseo_run_upgrade', $version );
@@ -135,6 +136,8 @@ class WPSEO_Upgrade {
*
* @param string $current_version The old version from which we are upgrading.
* @param string $new_version The version we are upgrading to.
*
* @return void
*/
protected function add_upgrade_history( $current_version, $new_version ) {
$upgrade_history = new WPSEO_Upgrade_History();
@@ -168,6 +171,8 @@ class WPSEO_Upgrade {
* Run the Yoast SEO 1.5 upgrade routine.
*
* @param string $version Current plugin version.
*
* @return void
*/
private function upgrade_15( $version ) {
// Clean up options and meta.
@@ -177,6 +182,8 @@ class WPSEO_Upgrade {
/**
* Moves options that moved position in WPSEO 2.0.
*
* @return void
*/
private function upgrade_20() {
/**
@@ -194,6 +201,8 @@ class WPSEO_Upgrade {
/**
* Detects if taxonomy terms were split and updates the corresponding taxonomy meta's accordingly.
*
* @return void
*/
private function upgrade_21() {
$taxonomies = get_option( 'wpseo_taxonomy_meta', [] );
@@ -217,6 +226,8 @@ class WPSEO_Upgrade {
/**
* Performs upgrade functions to Yoast SEO 2.2.
*
* @return void
*/
private function upgrade_22() {
// Unschedule our tracking.
@@ -227,6 +238,8 @@ class WPSEO_Upgrade {
/**
* Schedules upgrade function to Yoast SEO 2.3.
*
* @return void
*/
private function upgrade_23() {
add_action( 'wp', [ $this, 'upgrade_23_query' ], 90 );
@@ -235,6 +248,8 @@ class WPSEO_Upgrade {
/**
* Performs upgrade query to Yoast SEO 2.3.
*
* @return void
*/
public function upgrade_23_query() {
$wp_query = new WP_Query( 'post_type=any&meta_key=_yoast_wpseo_sitemap-include&meta_value=never&order=ASC' );
@@ -266,6 +281,8 @@ class WPSEO_Upgrade {
/**
* Performs upgrade functions to Yoast SEO 3.0.
*
* @return void
*/
private function upgrade_30() {
// Remove the meta fields for sitemap prio.
@@ -274,6 +291,8 @@ class WPSEO_Upgrade {
/**
* Performs upgrade functions to Yoast SEO 3.3.
*
* @return void
*/
private function upgrade_33() {
// Notification dismissals have been moved to User Meta instead of global option.
@@ -282,6 +301,8 @@ class WPSEO_Upgrade {
/**
* Performs upgrade functions to Yoast SEO 3.6.
*
* @return void
*/
private function upgrade_36() {
global $wpdb;
@@ -292,6 +313,8 @@ class WPSEO_Upgrade {
/**
* Removes the about notice when its still in the database.
*
* @return void
*/
private function upgrade_40() {
$center = Yoast_Notification_Center::get();
@@ -300,6 +323,8 @@ class WPSEO_Upgrade {
/**
* Moves the content-analysis-active and keyword-analysis-acive options from wpseo-titles to wpseo.
*
* @return void
*/
private function upgrade_44() {
$wpseo_titles = $this->get_option_from_database( 'wpseo_titles' );
@@ -313,6 +338,8 @@ class WPSEO_Upgrade {
/**
* Renames the meta name for the cornerstone content. It was a public meta field and it has to be private.
*
* @return void
*/
private function upgrade_47() {
global $wpdb;
@@ -328,6 +355,8 @@ class WPSEO_Upgrade {
/**
* Removes the 'wpseo-dismiss-about' notice for every user that still has it.
*
* @return void
*/
private function upgrade_49() {
global $wpdb;
@@ -391,6 +420,8 @@ class WPSEO_Upgrade {
/**
* Adds the yoast_seo_links table to the database.
*
* @return void
*/
private function upgrade_50() {
global $wpdb;
@@ -401,6 +432,8 @@ class WPSEO_Upgrade {
/**
* Register new capabilities and roles.
*
* @return void
*/
private function upgrade_55() {
// Register roles.
@@ -623,6 +656,8 @@ class WPSEO_Upgrade {
* Performs the 12.3 upgrade.
*
* Removes the about notice when its still in the database.
*
* @return void
*/
private function upgrade_123() {
$plugins = [
@@ -644,6 +679,8 @@ class WPSEO_Upgrade {
* Performs the 12.4 upgrade.
*
* Removes the Google plus defaults from the database.
*
* @return void
*/
private function upgrade_124() {
$this->cleanup_option_data( 'wpseo_social' );
@@ -651,6 +688,8 @@ class WPSEO_Upgrade {
/**
* Performs the 12.5 upgrade.
*
* @return void
*/
public function upgrade_125() {
// Disables the force rewrite title when the theme supports it through WordPress.
@@ -668,6 +707,8 @@ class WPSEO_Upgrade {
/**
* Performs the 12.8 upgrade.
*
* @return void
*/
private function upgrade_128() {
// Re-save wpseo to make sure bf_banner_2019_dismissed key is gone.
@@ -679,6 +720,8 @@ class WPSEO_Upgrade {
/**
* Performs the 13.2 upgrade.
*
* @return void
*/
private function upgrade_132() {
Yoast_Notification_Center::get()->remove_notification_by_id( 'wpseo-dismiss-tagline-notice' );
@@ -715,6 +758,8 @@ class WPSEO_Upgrade {
/**
* Perform the 14.0.3 upgrade.
*
* @return void
*/
private function upgrade_1403() {
WPSEO_Options::set( 'ignore_indexation_warning', false );
@@ -722,6 +767,8 @@ class WPSEO_Upgrade {
/**
* Performs the 14.1 upgrade.
*
* @return void
*/
private function upgrade_141() {
/*
@@ -738,6 +785,8 @@ class WPSEO_Upgrade {
* Performs the 14.2 upgrade.
*
* Removes the yoast-acf-analysis notice when it's still in the database.
*
* @return void
*/
private function upgrade_142() {
add_action( 'init', [ $this, 'remove_acf_notification_for_142' ] );
@@ -745,6 +794,8 @@ class WPSEO_Upgrade {
/**
* Performs the 14.5 upgrade.
*
* @return void
*/
private function upgrade_145() {
add_action( 'init', [ $this, 'set_indexation_completed_option_for_145' ] );
@@ -752,6 +803,8 @@ class WPSEO_Upgrade {
/**
* Performs the 14.9 upgrade.
*
* @return void
*/
private function upgrade_149() {
$version = get_option( 'wpseo_license_server_version', 2 );
@@ -815,19 +868,23 @@ class WPSEO_Upgrade {
/**
* Performs the 15.9.1 upgrade routine.
*
* @return void
*/
private function upgrade_1591() {
$enabled_auto_updates = \get_option( 'auto_update_plugins' );
$addon_update_watcher = YoastSEO()->classes->get( \Yoast\WP\SEO\Integrations\Watchers\Addon_Update_Watcher::class );
$enabled_auto_updates = get_option( 'auto_update_plugins' );
$addon_update_watcher = YoastSEO()->classes->get( Addon_Update_Watcher::class );
$addon_update_watcher->toggle_auto_updates_for_add_ons( 'auto_update_plugins', [], $enabled_auto_updates );
}
/**
* Performs the 16.2 upgrade routine.
*
* @return void
*/
private function upgrade_162() {
$enabled_auto_updates = \get_site_option( 'auto_update_plugins' );
$addon_update_watcher = YoastSEO()->classes->get( \Yoast\WP\SEO\Integrations\Watchers\Addon_Update_Watcher::class );
$enabled_auto_updates = get_site_option( 'auto_update_plugins' );
$addon_update_watcher = YoastSEO()->classes->get( Addon_Update_Watcher::class );
$addon_update_watcher->toggle_auto_updates_for_add_ons( 'auto_update_plugins', $enabled_auto_updates, [] );
}
@@ -849,25 +906,29 @@ class WPSEO_Upgrade {
* @return void
*/
private function upgrade_172() {
\wp_unschedule_hook( 'wpseo_cleanup_orphaned_indexables' );
\wp_unschedule_hook( 'wpseo_cleanup_indexables' );
wp_unschedule_hook( 'wpseo_cleanup_orphaned_indexables' );
wp_unschedule_hook( 'wpseo_cleanup_indexables' );
if ( ! \wp_next_scheduled( Cleanup_Integration::START_HOOK ) ) {
\wp_schedule_single_event( ( time() + ( MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK );
if ( ! wp_next_scheduled( Cleanup_Integration::START_HOOK ) ) {
wp_schedule_single_event( ( time() + ( MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK );
}
}
/**
* Performs the 17.7.1 upgrade routine.
*
* @return void
*/
private function upgrade_1771() {
$enabled_auto_updates = \get_site_option( 'auto_update_plugins' );
$addon_update_watcher = YoastSEO()->classes->get( \Yoast\WP\SEO\Integrations\Watchers\Addon_Update_Watcher::class );
$enabled_auto_updates = get_site_option( 'auto_update_plugins' );
$addon_update_watcher = YoastSEO()->classes->get( Addon_Update_Watcher::class );
$addon_update_watcher->toggle_auto_updates_for_add_ons( 'auto_update_plugins', $enabled_auto_updates, [] );
}
/**
* Performs the 17.9 upgrade routine.
*
* @return void
*/
private function upgrade_179() {
WPSEO_Options::set( 'wincher_integration_active', true );
@@ -875,6 +936,8 @@ class WPSEO_Upgrade {
/**
* Performs the 18.3 upgrade routine.
*
* @return void
*/
private function upgrade_183() {
$this->delete_post_meta( 'yoast-structured-data-blocks-images-cache' );
@@ -882,6 +945,8 @@ class WPSEO_Upgrade {
/**
* Performs the 18.6 upgrade routine.
*
* @return void
*/
private function upgrade_186() {
if ( is_multisite() ) {
@@ -891,6 +956,8 @@ class WPSEO_Upgrade {
/**
* Performs the 18.9 upgrade routine.
*
* @return void
*/
private function upgrade_189() {
// Make old users not get the Installation Success page after upgrading.
@@ -912,7 +979,7 @@ class WPSEO_Upgrade {
// Transfer the progress of the old Configuration Workout.
$workout_data = WPSEO_Options::get( 'workouts_data' );
$old_conf_progress = isset( $workout_data['configuration']['finishedSteps'] ) ? $workout_data['configuration']['finishedSteps'] : [];
$old_conf_progress = ( $workout_data['configuration']['finishedSteps'] ?? [] );
if ( in_array( 'optimizeSeoData', $old_conf_progress, true ) && in_array( 'siteRepresentation', $old_conf_progress, true ) ) {
// If completed SEO optimization and Site representation step, we assume the workout was completed.
@@ -927,6 +994,8 @@ class WPSEO_Upgrade {
/**
* Performs the 19.1 upgrade routine.
*
* @return void
*/
private function upgrade_191() {
if ( is_multisite() ) {
@@ -936,6 +1005,8 @@ class WPSEO_Upgrade {
/**
* Performs the 19.3 upgrade routine.
*
* @return void
*/
private function upgrade_193() {
if ( empty( get_option( 'wpseo_premium', [] ) ) ) {
@@ -946,6 +1017,8 @@ class WPSEO_Upgrade {
/**
* Performs the 19.6 upgrade routine.
*
* @return void
*/
private function upgrade_196() {
WPSEO_Options::set( 'ryte_indexability', false );
@@ -955,19 +1028,23 @@ class WPSEO_Upgrade {
/**
* Performs the 19.11 upgrade routine.
*
* @return void
*/
private function upgrade_1911() {
\add_action( 'shutdown', [ $this, 'remove_indexable_rows_for_non_public_post_types' ] );
\add_action( 'shutdown', [ $this, 'remove_indexable_rows_for_non_public_taxonomies' ] );
add_action( 'shutdown', [ $this, 'remove_indexable_rows_for_non_public_post_types' ] );
add_action( 'shutdown', [ $this, 'remove_indexable_rows_for_non_public_taxonomies' ] );
$this->deduplicate_unindexed_indexable_rows();
$this->remove_indexable_rows_for_disabled_authors_archive();
if ( ! \wp_next_scheduled( Cleanup_Integration::START_HOOK ) ) {
\wp_schedule_single_event( ( time() + ( MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK );
if ( ! wp_next_scheduled( Cleanup_Integration::START_HOOK ) ) {
wp_schedule_single_event( ( time() + ( MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK );
}
}
/**
* Performs the 20.2 upgrade routine.
*
* @return void
*/
private function upgrade_202() {
if ( WPSEO_Options::get( 'disable-attachment', true ) ) {
@@ -979,18 +1056,20 @@ class WPSEO_Upgrade {
$this->clean_unindexed_indexable_rows_with_no_object_id();
if ( ! \wp_next_scheduled( Cleanup_Integration::START_HOOK ) ) {
if ( ! wp_next_scheduled( Cleanup_Integration::START_HOOK ) ) {
// This schedules the cleanup routine cron again, since in combination of premium cleans up the prominent words table. We also want to cleanup possible orphaned hierarchies from the above cleanups.
\wp_schedule_single_event( ( time() + ( MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK );
wp_schedule_single_event( ( time() + ( MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK );
}
}
/**
* Performs the 20.5 upgrade routine.
*
* @return void
*/
private function upgrade_205() {
if ( ! \wp_next_scheduled( Cleanup_Integration::START_HOOK ) ) {
\wp_schedule_single_event( ( time() + ( MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK );
if ( ! wp_next_scheduled( Cleanup_Integration::START_HOOK ) ) {
wp_schedule_single_event( ( time() + ( MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK );
}
}
@@ -998,6 +1077,8 @@ class WPSEO_Upgrade {
* Performs the 20.7 upgrade routine.
* Removes the metadata related to the settings page introduction modal for all the users.
* Also, schedules another cleanup scheduled action.
*
* @return void
*/
private function upgrade_207() {
add_action( 'shutdown', [ $this, 'delete_user_introduction_meta' ] );
@@ -1006,10 +1087,12 @@ class WPSEO_Upgrade {
/**
* Performs the 20.8 upgrade routine.
* Schedules another cleanup scheduled action.
*
* @return void
*/
private function upgrade_208() {
if ( ! \wp_next_scheduled( Cleanup_Integration::START_HOOK ) ) {
\wp_schedule_single_event( ( time() + ( MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK );
if ( ! wp_next_scheduled( Cleanup_Integration::START_HOOK ) ) {
wp_schedule_single_event( ( time() + ( MINUTE_IN_SECONDS * 5 ) ), Cleanup_Integration::START_HOOK );
}
}
@@ -1041,6 +1124,8 @@ class WPSEO_Upgrade {
* Checks if the indexable indexation is completed.
* If so, sets the `indexables_indexation_completed` option to `true`,
* else to `false`.
*
* @return void
*/
public function set_indexation_completed_option_for_145() {
WPSEO_Options::set( 'indexables_indexation_completed', YoastSEO()->helpers->indexing->get_limited_filtered_unindexed_count( 1 ) === 0 );
@@ -1048,6 +1133,8 @@ class WPSEO_Upgrade {
/**
* Cleans up the private taxonomies from the indexables table for the upgrade routine to 14.1.
*
* @return void
*/
public function clean_up_private_taxonomies_for_141() {
global $wpdb;
@@ -1057,7 +1144,7 @@ class WPSEO_Upgrade {
$wpdb->show_errors = false;
// Clean up indexables of private taxonomies.
$private_taxonomies = \get_taxonomies( [ 'public' => false ], 'names' );
$private_taxonomies = get_taxonomies( [ 'public' => false ], 'names' );
if ( empty( $private_taxonomies ) ) {
return;
@@ -1071,7 +1158,7 @@ class WPSEO_Upgrade {
"DELETE FROM $indexable_table
WHERE object_type = 'term'
AND object_sub_type IN ("
. \implode( ', ', \array_fill( 0, \count( $private_taxonomies ), '%s' ) )
. implode( ', ', array_fill( 0, count( $private_taxonomies ), '%s' ) )
. ')',
$private_taxonomies
);
@@ -1082,6 +1169,8 @@ class WPSEO_Upgrade {
/**
* Resets the permalinks of attachments to `null` in the indexable table for the upgrade routine to 14.1.
*
* @return void
*/
private function reset_permalinks_of_attachments_for_141() {
global $wpdb;
@@ -1422,7 +1511,7 @@ class WPSEO_Upgrade {
$indexable_table = Model::get_table_name( 'Indexable' );
$included_post_types = \YoastSEO()->helpers->post_type->get_indexable_post_types();
$included_post_types = YoastSEO()->helpers->post_type->get_indexable_post_types();
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reason: Too hard to fix.
if ( empty( $included_post_types ) ) {
@@ -1436,7 +1525,7 @@ class WPSEO_Upgrade {
"DELETE FROM $indexable_table
WHERE object_type = 'post'
AND object_sub_type IS NOT NULL
AND object_sub_type NOT IN ( " . \implode( ', ', \array_fill( 0, \count( $included_post_types ), '%s' ) ) . ' )',
AND object_sub_type NOT IN ( " . implode( ', ', array_fill( 0, count( $included_post_types ), '%s' ) ) . ' )',
$included_post_types
);
}
@@ -1466,7 +1555,7 @@ class WPSEO_Upgrade {
$indexable_table = Model::get_table_name( 'Indexable' );
$included_taxonomies = \YoastSEO()->helpers->taxonomy->get_indexable_taxonomies();
$included_taxonomies = YoastSEO()->helpers->taxonomy->get_indexable_taxonomies();
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Reason: Too hard to fix.
if ( empty( $included_taxonomies ) ) {
@@ -1479,7 +1568,7 @@ class WPSEO_Upgrade {
"DELETE FROM $indexable_table
WHERE object_type = 'term'
AND object_sub_type IS NOT NULL
AND object_sub_type NOT IN ( " . \implode( ', ', \array_fill( 0, \count( $included_taxonomies ), '%s' ) ) . ' )',
AND object_sub_type NOT IN ( " . implode( ', ', array_fill( 0, count( $included_taxonomies ), '%s' ) ) . ' )',
$included_taxonomies
);
}
@@ -1592,7 +1681,7 @@ class WPSEO_Upgrade {
private function remove_indexable_rows_for_disabled_authors_archive() {
global $wpdb;
if ( ! \YoastSEO()->helpers->author_archive->are_disabled() ) {
if ( ! YoastSEO()->helpers->author_archive->are_disabled() ) {
return;
}
@@ -1626,7 +1715,7 @@ class WPSEO_Upgrade {
private function get_indexable_deduplication_query_for_type( $object_type, $duplicates, $wpdb ) {
$indexable_table = Model::get_table_name( 'Indexable' );
$filtered_duplicates = \array_filter(
$filtered_duplicates = array_filter(
$duplicates,
static function ( $duplicate ) use ( $object_type ) {
return $duplicate['object_type'] === $object_type;
@@ -1646,8 +1735,8 @@ class WPSEO_Upgrade {
"DELETE FROM
$indexable_table
WHERE
object_id IN ( " . \implode( ', ', \array_fill( 0, \count( $filtered_duplicates ), '%d' ) ) . ' )
AND id NOT IN ( ' . \implode( ', ', \array_fill( 0, \count( $filtered_duplicates ), '%d' ) ) . ' )
object_id IN ( " . implode( ', ', array_fill( 0, count( $filtered_duplicates ), '%d' ) ) . ' )
AND id NOT IN ( ' . implode( ', ', array_fill( 0, count( $filtered_duplicates ), '%d' ) ) . ' )
AND object_type = %s',
array_merge( array_values( $object_ids ), array_values( $newest_indexable_ids ), [ $object_type ] )
);

View File

@@ -23,35 +23,35 @@ class WPSEO_Admin_Bar_Menu implements WPSEO_WordPress_Integration {
*
* @var string
*/
const MENU_IDENTIFIER = 'wpseo-menu';
public const MENU_IDENTIFIER = 'wpseo-menu';
/**
* The identifier used for the Keyword Research submenu.
*
* @var string
*/
const KEYWORD_RESEARCH_SUBMENU_IDENTIFIER = 'wpseo-kwresearch';
public const KEYWORD_RESEARCH_SUBMENU_IDENTIFIER = 'wpseo-kwresearch';
/**
* The identifier used for the Analysis submenu.
*
* @var string
*/
const ANALYSIS_SUBMENU_IDENTIFIER = 'wpseo-analysis';
public const ANALYSIS_SUBMENU_IDENTIFIER = 'wpseo-analysis';
/**
* The identifier used for the Settings submenu.
*
* @var string
*/
const SETTINGS_SUBMENU_IDENTIFIER = 'wpseo-settings';
public const SETTINGS_SUBMENU_IDENTIFIER = 'wpseo-settings';
/**
* The identifier used for the Network Settings submenu.
*
* @var string
*/
const NETWORK_SETTINGS_SUBMENU_IDENTIFIER = 'wpseo-network-settings';
public const NETWORK_SETTINGS_SUBMENU_IDENTIFIER = 'wpseo-network-settings';
/**
* Asset manager instance.
@@ -119,11 +119,11 @@ class WPSEO_Admin_Bar_Menu implements WPSEO_WordPress_Integration {
* @param WPSEO_Shortlinker|null $shortlinker The shortlinker.
*/
public function __construct(
WPSEO_Admin_Asset_Manager $asset_manager = null,
Indexable_Repository $indexable_repository = null,
Score_Icon_Helper $score_icon_helper = null,
Product_Helper $product_helper = null,
WPSEO_Shortlinker $shortlinker = null
?WPSEO_Admin_Asset_Manager $asset_manager = null,
?Indexable_Repository $indexable_repository = null,
?Score_Icon_Helper $score_icon_helper = null,
?Product_Helper $product_helper = null,
?WPSEO_Shortlinker $shortlinker = null
) {
if ( ! $asset_manager ) {
$asset_manager = new WPSEO_Admin_Asset_Manager();
@@ -753,7 +753,7 @@ class WPSEO_Admin_Bar_Menu implements WPSEO_WordPress_Integration {
/**
* Filter: 'wpseo_use_page_analysis' Determines if the analysis should be enabled.
*
* @api bool Determines if the analysis should be enabled.
* @param bool $enabled Determines if the analysis should be enabled.
*/
if ( apply_filters( 'wpseo_use_page_analysis', true ) !== true ) {
return '';

View File

@@ -13,8 +13,8 @@ class WPSEO_Content_Images {
/**
* Retrieves images from the post content.
*
* @param int $post_id The post ID.
* @param \WP_Post|null $post The post object.
* @param int $post_id The post ID.
* @param WP_Post|null $post The post object.
*
* @return array An array of images found in this post.
*/
@@ -98,7 +98,8 @@ class WPSEO_Content_Images {
/**
* Filter: 'wpseo_pre_analysis_post_content' - Allow filtering the content before analysis.
*
* @api string $post_content The Post content string.
* @param string $post_content The Post content string.
* @param WP_Post $post The current post.
*/
$content = apply_filters( 'wpseo_pre_analysis_post_content', $post->post_content, $post );

View File

@@ -148,7 +148,7 @@ class WPSEO_Image_Utils {
*
* Elements with keys not listed in the section will be discarded.
*
* @api array {
* @param array $image_data {
* Array of image data
*
* @type int id Image's ID as an attachment.
@@ -162,7 +162,7 @@ class WPSEO_Image_Utils {
* @type string url Image's URL.
* @type int filesize The file size in bytes, if already set.
* }
* @api int Attachment ID.
* @param int $attachment_id Attachment ID.
*/
$image = apply_filters( 'wpseo_image_data', $image, $attachment_id );
@@ -186,7 +186,7 @@ class WPSEO_Image_Utils {
* Filter: 'wpseo_image_image_weight_limit' - Determines what the maximum weight
* (in bytes) of an image is allowed to be, default is 2 MB.
*
* @api int - The maximum weight (in bytes) of an image.
* @param int $max_bytes The maximum weight (in bytes) of an image.
*/
$max_size = apply_filters( 'wpseo_image_image_weight_limit', 2097152 );
@@ -404,7 +404,7 @@ class WPSEO_Image_Utils {
/**
* Filter: 'wpseo_image_sizes' - Determines which image sizes we'll loop through to get an appropriate image.
*
* @api array - The array of image sizes to loop through.
* @param array<string> $sizes The array of image sizes to loop through.
*/
return apply_filters( 'wpseo_image_sizes', [ 'full', 'large', 'medium_large' ] );
}

View File

@@ -34,6 +34,8 @@ class WPSEO_Installation {
/**
* Sets the options on first install for showing the installation notice and disabling of the settings pages.
*
* @return void
*/
public function set_first_install_options() {
$options = get_option( 'wpseo' );

View File

@@ -304,7 +304,7 @@ class WPSEO_Meta {
register_meta(
'post',
self::$meta_prefix . $key,
[ 'sanitize_callback' => [ __CLASS__, 'sanitize_post_meta' ] ]
[ 'sanitize_callback' => [ self::class, 'sanitize_post_meta' ] ]
);
// Set the $fields_index property for efficiency.
@@ -327,8 +327,8 @@ class WPSEO_Meta {
self::filter_schema_article_types();
add_filter( 'update_post_metadata', [ __CLASS__, 'remove_meta_if_default' ], 10, 5 );
add_filter( 'add_post_metadata', [ __CLASS__, 'dont_save_meta_if_default' ], 10, 4 );
add_filter( 'update_post_metadata', [ self::class, 'remove_meta_if_default' ], 10, 5 );
add_filter( 'add_post_metadata', [ self::class, 'dont_save_meta_if_default' ], 10, 4 );
}
/**
@@ -402,7 +402,7 @@ class WPSEO_Meta {
/** This filter is documented in inc/options/class-wpseo-option-titles.php */
$allowed_article_types = apply_filters( 'wpseo_schema_article_types', Schema_Types::ARTICLE_TYPES );
if ( ! \array_key_exists( $default_schema_article_type, $allowed_article_types ) ) {
if ( ! array_key_exists( $default_schema_article_type, $allowed_article_types ) ) {
$default_schema_article_type = WPSEO_Options::get_default( 'wpseo_titles', 'schema-article-type-' . $post_type );
}
$field_defs['schema_article_type']['default'] = $default_schema_article_type;

View File

@@ -61,6 +61,8 @@ class WPSEO_Primary_Term {
* Sets the new primary term ID.
*
* @param int $new_primary_term New primary term ID.
*
* @return void
*/
public function set_primary_term( $new_primary_term ) {
update_post_meta( $this->post_ID, WPSEO_Meta::$meta_prefix . 'primary_' . $this->taxonomy_name, $new_primary_term );

View File

@@ -15,35 +15,35 @@ class WPSEO_Rank {
*
* @var string
*/
const BAD = 'bad';
public const BAD = 'bad';
/**
* Constant used for determining an OK SEO rating.
*
* @var string
*/
const OK = 'ok';
public const OK = 'ok';
/**
* Constant used for determining a good SEO rating.
*
* @var string
*/
const GOOD = 'good';
public const GOOD = 'good';
/**
* Constant used for determining that no focus keyphrase is set.
*
* @var string
*/
const NO_FOCUS = 'na';
public const NO_FOCUS = 'na';
/**
* Constant used for determining that this content is not indexed.
*
* @var string
*/
const NO_INDEX = 'noindex';
public const NO_INDEX = 'noindex';
/**
* All possible ranks.

View File

@@ -63,6 +63,8 @@ class WPSEO_Replace_Vars {
/**
* Setup the help texts and external replacements as statics so they will be available to all instances.
*
* @return void
*/
public static function setup_statics_once() {
if ( self::$help_texts === [] ) {
@@ -107,7 +109,7 @@ class WPSEO_Replace_Vars {
elseif ( strpos( $var_to_replace, 'cf_' ) === 0 || strpos( $var_to_replace, 'ct_' ) === 0 ) {
trigger_error( esc_html__( 'A replacement variable can not start with "%%cf_" or "%%ct_" as these are reserved for the WPSEO standard variable variables for custom fields and custom taxonomies. Try making your variable name unique.', 'wordpress-seo' ), E_USER_WARNING );
}
elseif ( ! method_exists( __CLASS__, 'retrieve_' . $var_to_replace ) ) {
elseif ( ! method_exists( self::class, 'retrieve_' . $var_to_replace ) ) {
if ( $var_to_replace !== '' && ! isset( self::$external_replacements[ $var_to_replace ] ) ) {
self::$external_replacements[ $var_to_replace ] = $replace_function;
$replacement_variable = new WPSEO_Replacement_Variable( $var_to_replace, $var_to_replace, $help_text );
@@ -156,7 +158,7 @@ class WPSEO_Replace_Vars {
// Clean $omit array.
if ( is_array( $omit ) && $omit !== [] ) {
$omit = array_map( [ __CLASS__, 'remove_var_delimiter' ], $omit );
$omit = array_map( [ self::class, 'remove_var_delimiter' ], $omit );
}
$replacements = [];
@@ -167,10 +169,9 @@ class WPSEO_Replace_Vars {
/**
* Filter: 'wpseo_replacements' - Allow customization of the replacements before they are applied.
*
* @api array $replacements The replacements.
*
* @param array $args The object some of the replacement values might come from,
* could be a post, taxonomy or term.
* @param array $replacements The replacements.
* @param array $args The object some of the replacement values might come from,
* could be a post, taxonomy or term.
*/
$replacements = apply_filters( 'wpseo_replacements', $replacements, $this->args );
@@ -190,12 +191,12 @@ class WPSEO_Replace_Vars {
*
* @example <code>add_filter( 'wpseo_replacements_final', '__return_false' );</code>
*
* @api bool $final
* @param bool $final
*/
if ( apply_filters( 'wpseo_replacements_final', true ) === true && ( isset( $matches[1] ) && is_array( $matches[1] ) ) ) {
// Remove non-replaced variables.
$remove = array_diff( $matches[1], $omit ); // Make sure the $omit variables do not get removed.
$remove = array_map( [ __CLASS__, 'add_var_delimiter' ], $remove );
$remove = array_map( [ self::class, 'add_var_delimiter' ], $remove );
$text = str_replace( $remove, '', $text );
}
@@ -366,21 +367,17 @@ class WPSEO_Replace_Vars {
// Returns a string.
$replacement = YoastSEO()->helpers->date->format_translated( $this->args->post_date, get_option( 'date_format' ) );
}
else {
if ( get_query_var( 'day' ) && get_query_var( 'day' ) !== '' ) {
// Returns a string.
$replacement = get_the_date();
}
else {
if ( single_month_title( ' ', false ) && single_month_title( ' ', false ) !== '' ) {
// Returns a string.
$replacement = single_month_title( ' ', false );
}
elseif ( get_query_var( 'year' ) !== '' ) {
// Returns an integer, let's cast to string.
$replacement = (string) get_query_var( 'year' );
}
}
elseif ( get_query_var( 'day' ) && get_query_var( 'day' ) !== '' ) {
// Returns a string.
$replacement = get_the_date();
}
elseif ( single_month_title( ' ', false ) && single_month_title( ' ', false ) !== '' ) {
// Returns a string.
$replacement = single_month_title( ' ', false );
}
elseif ( get_query_var( 'year' ) !== '' ) {
// Returns an integer, let's cast to string.
$replacement = (string) get_query_var( 'year' );
}
return $replacement;
@@ -394,7 +391,7 @@ class WPSEO_Replace_Vars {
*/
private function retrieve_excerpt() {
$replacement = null;
$locale = \get_locale();
$locale = get_locale();
// Japanese doesn't have a jp_JP variant in WP.
$limit = ( $locale === 'ja' ) ? 80 : 156;
@@ -1148,7 +1145,7 @@ class WPSEO_Replace_Vars {
return null;
}
return \get_the_date( 'Y', $this->args->ID );
return get_the_date( 'Y', $this->args->ID );
}
/**
@@ -1161,7 +1158,7 @@ class WPSEO_Replace_Vars {
return null;
}
return \get_the_date( 'F', $this->args->ID );
return get_the_date( 'F', $this->args->ID );
}
/**
@@ -1174,7 +1171,7 @@ class WPSEO_Replace_Vars {
return null;
}
return \get_the_date( 'd', $this->args->ID );
return get_the_date( 'd', $this->args->ID );
}
/**
@@ -1221,7 +1218,7 @@ class WPSEO_Replace_Vars {
return null;
}
return \get_permalink( $this->args->ID );
return get_permalink( $this->args->ID );
}
/**
@@ -1280,6 +1277,8 @@ class WPSEO_Replace_Vars {
*
* @param string $type Type of variable: 'basic' or 'advanced'.
* @param WPSEO_Replacement_Variable $replacement_variable The replacement variable to register.
*
* @return void
*/
private static function register_help_text( $type, WPSEO_Replacement_Variable $replacement_variable ) {
$identifier = $replacement_variable->get_variable();
@@ -1455,6 +1454,8 @@ class WPSEO_Replace_Vars {
/**
* Set/translate the help texts for the WPSEO standard basic variables.
*
* @return void
*/
private static function set_basic_help_texts() {
/* translators: %s: wp_title() function. */
@@ -1505,6 +1506,8 @@ class WPSEO_Replace_Vars {
/**
* Set/translate the help texts for the WPSEO standard advanced variables.
*
* @return void
*/
private static function set_advanced_help_texts() {
$replacement_variables = [
@@ -1591,8 +1594,8 @@ class WPSEO_Replace_Vars {
* Allows filtering of the terms list used to replace %%category%%, %%tag%%
* and %%ct_<custom-tax-name>%% variables.
*
* @api string $output Comma-delimited string containing the terms.
* @api string $taxonomy The taxonomy of the terms.
* @param string $output Comma-delimited string containing the terms.
* @param string $taxonomy The taxonomy of the terms.
*/
return apply_filters( 'wpseo_terms', $output, $taxonomy );
}

View File

@@ -36,6 +36,8 @@ class WPSEO_Shortlinker {
* Echoes a version of the URL with a utm_content with the current version.
*
* @param string $url The URL to build upon.
*
* @return void
*/
public static function show( $url ) {
YoastSEO()->helpers->short_link->show( $url );

View File

@@ -43,7 +43,7 @@ class WPSEO_Utils {
* Filter: 'wpseo_allow_system_file_edit' - Allow developers to change whether the editing of
* .htaccess and robots.txt is allowed.
*
* @api bool $allowed Whether file editing is allowed.
* @param bool $allowed Whether file editing is allowed.
*/
return apply_filters( 'wpseo_allow_system_file_edit', $allowed );
}
@@ -110,7 +110,7 @@ class WPSEO_Utils {
$value = trim( $value );
}
elseif ( is_array( $value ) ) {
$value = array_map( [ __CLASS__, 'trim_recursive' ], $value );
$value = array_map( [ self::class, 'trim_recursive' ], $value );
}
return $value;
@@ -232,7 +232,7 @@ class WPSEO_Utils {
if ( strpos( $url, '%' ) !== false ) {
$url = preg_replace_callback(
'`%[a-fA-F0-9]{2}`',
static function( $octects ) {
static function ( $octects ) {
return strtolower( $octects[0] );
},
$url
@@ -253,7 +253,7 @@ class WPSEO_Utils {
*/
public static function sanitize_encoded_text_field( $value ) {
if ( is_array( $value ) ) {
return array_map( [ __CLASS__, 'sanitize_encoded_text_field' ], $value );
return array_map( [ self::class, 'sanitize_encoded_text_field' ], $value );
}
return rawurlencode( sanitize_text_field( rawurldecode( $value ) ) );
@@ -381,7 +381,7 @@ class WPSEO_Utils {
return $value;
}
elseif ( is_float( $value ) ) {
// phpcs:ignore WordPress.PHP.StrictComparisons -- Purposeful loose comparison.
// phpcs:ignore Universal.Operators.StrictComparisons -- Purposeful loose comparison.
if ( (int) $value == $value && ! is_nan( $value ) ) {
return (int) $value;
}
@@ -412,6 +412,8 @@ class WPSEO_Utils {
* Clears the WP or W3TC cache depending on which is used.
*
* @since 1.8.0
*
* @return void
*/
public static function clear_cache() {
if ( function_exists( 'w3tc_pgcache_flush' ) ) {
@@ -426,6 +428,8 @@ class WPSEO_Utils {
* Clear rewrite rules.
*
* @since 1.8.0
*
* @return void
*/
public static function clear_rewrites() {
update_option( 'rewrite_rules', '' );
@@ -506,7 +510,7 @@ class WPSEO_Utils {
if ( $bc ) {
$result = bcdiv( $number1, $number2, $precision ); // String, or NULL if right_operand is 0.
}
elseif ( $number2 != 0 ) { // phpcs:ignore WordPress.PHP.StrictComparisons -- Purposeful loose comparison.
elseif ( $number2 != 0 ) { // phpcs:ignore Universal.Operators.StrictComparisons -- Purposeful loose comparison.
$result = ( $number1 / $number2 );
}
@@ -521,7 +525,7 @@ class WPSEO_Utils {
if ( $bc ) {
$result = bcmod( $number1, $number2 ); // String, or NULL if modulus is 0.
}
elseif ( $number2 != 0 ) { // phpcs:ignore WordPress.PHP.StrictComparisons -- Purposeful loose comparison.
elseif ( $number2 != 0 ) { // phpcs:ignore Universal.Operators.StrictComparisons -- Purposeful loose comparison.
$result = ( $number1 % $number2 );
}
@@ -538,7 +542,7 @@ class WPSEO_Utils {
$result = bccomp( $number1, $number2, $precision ); // Returns int 0, 1 or -1.
}
else {
// phpcs:ignore WordPress.PHP.StrictComparisons -- Purposeful loose comparison.
// phpcs:ignore Universal.Operators.StrictComparisons -- Purposeful loose comparison.
$result = ( $number1 == $number2 ) ? 0 : ( ( $number1 > $number2 ) ? 1 : -1 );
}
break;
@@ -553,7 +557,7 @@ class WPSEO_Utils {
}
}
else {
// phpcs:ignore WordPress.PHP.StrictComparisons -- Purposeful loose comparison.
// phpcs:ignore Universal.Operators.StrictComparisons -- Purposeful loose comparison.
$result = ( intval( $result ) == $result ) ? intval( $result ) : floatval( $result );
}
}
@@ -802,7 +806,7 @@ class WPSEO_Utils {
* @return string The post type, or an empty string.
*/
public static function get_post_type() {
$wp_screen = \get_current_screen();
$wp_screen = get_current_screen();
if ( $wp_screen !== null && ! empty( $wp_screen->post_type ) ) {
return $wp_screen->post_type;
@@ -843,7 +847,7 @@ class WPSEO_Utils {
else {
$label_object = WPSEO_Taxonomy::get_labels();
$wp_screen = \get_current_screen();
$wp_screen = get_current_screen();
if ( $wp_screen !== null && ! empty( $wp_screen->taxonomy ) ) {
$taxonomy_slug = $wp_screen->taxonomy;
@@ -920,12 +924,12 @@ class WPSEO_Utils {
/**
* Filter the Yoast SEO development mode.
*
* @api array $data Allows filtering of the JSON data for debug purposes.
* @param array $data Allows filtering of the JSON data for debug purposes.
*/
$data = apply_filters( 'wpseo_debug_json_data', $data );
}
// phpcs:ignore Yoast.Yoast.AlternativeFunctions.json_encode_wp_json_encodeWithAdditionalParams -- This is the definition of format_json_encode.
// phpcs:ignore Yoast.Yoast.JsonEncodeAlternative.FoundWithAdditionalParams -- This is the definition of format_json_encode.
return wp_json_encode( $data, $flags );
}
@@ -1095,30 +1099,4 @@ class WPSEO_Utils {
$feature_flag_integration = YoastSEO()->classes->get( Feature_Flag_Integration::class );
return $feature_flag_integration->get_enabled_features();
}
/* ********************* DEPRECATED METHODS ********************* */
/**
* Translates a decimal analysis score into a textual one.
*
* @since 1.8.0
* @deprecated 19.5
* @codeCoverageIgnore
*
* @param int $val The decimal score to translate.
* @param bool $css_value Whether to return the i18n translated score or the CSS class value.
*
* @return string
*/
public static function translate_score( $val, $css_value = true ) {
_deprecated_function( __METHOD__, 'Yoast SEO 19.5', 'YoastSEO()->helpers->score_icon' );
$seo_rank = WPSEO_Rank::from_numeric_score( $val );
if ( $css_value ) {
return $seo_rank->get_css_class();
}
return $seo_rank->get_label();
}
}

View File

@@ -0,0 +1,178 @@
<?php
/**
* WPSEO plugin file.
*
* @package WPSEO\Internals
*/
/**
* Class containing an alternative rewrite rules API for handling them dynamically without requiring flushing rules.
*/
class Yoast_Dynamic_Rewrites implements WPSEO_WordPress_Integration {
/**
* Additional rewrite rules with high priority.
*
* @var array
*/
protected $extra_rules_top = [];
/**
* Additional rewrite rules with low priority.
*
* @var array
*/
protected $extra_rules_bottom = [];
/**
* Main instance holder.
*
* @var self|null
*/
protected static $instance = null;
/**
* WP_Rewrite instance to use.
*
* @var WP_Rewrite
*/
public $wp_rewrite;
/**
* Gets the main instance of the class.
*
* @return self Dynamic rewrites main instance.
*/
public static function instance() {
if ( self::$instance === null ) {
self::$instance = new self();
self::$instance->register_hooks();
}
return self::$instance;
}
/**
* Constructor.
*
* Sets the WP_Rewrite instance to use.
*
* @param WP_Rewrite|null $rewrite Optional. WP_Rewrite instance to use. Default is the $wp_rewrite global.
* @throws RuntimeException Throws an exception if the $wp_rewrite global is not set.
*/
public function __construct( $rewrite = null ) {
if ( ! $rewrite ) {
if ( empty( $GLOBALS['wp_rewrite'] ) ) {
/* translators: 1: PHP class name, 2: PHP variable name */
throw new RuntimeException( sprintf( __( 'The %1$s class must not be instantiated before the %2$s global is set.', 'wordpress-seo' ), self::class, '$wp_rewrite' ) );
}
$rewrite = $GLOBALS['wp_rewrite'];
}
$this->wp_rewrite = $rewrite;
}
/**
* Registers all necessary hooks with WordPress.
*
* @return void
*/
public function register_hooks() {
add_action( 'init', [ $this, 'trigger_dynamic_rewrite_rules_hook' ], 1 );
add_filter( 'option_rewrite_rules', [ $this, 'filter_rewrite_rules_option' ] );
add_filter( 'sanitize_option_rewrite_rules', [ $this, 'sanitize_rewrite_rules_option' ] );
}
/**
* Adds a dynamic rewrite rule that transforms a URL structure to a set of query vars.
*
* Rules registered with this method are applied dynamically and do not require the rewrite rules
* to be flushed in order to become active, which is a benefit over the regular WordPress core API.
* Note however that the dynamic application only works for rules that correspond to index.php.
* Non-WordPress rewrite rules still require flushing.
*
* Any value in the $after parameter that isn't 'bottom' will result in the rule
* being placed at the top of the rewrite rules.
*
* @param string $regex Regular expression to match request against.
* @param string|array $query The corresponding query vars for this rewrite rule.
* @param string $priority Optional. Priority of the new rule. Accepts 'top'
* or 'bottom'. Default 'bottom'.
*
* @return void
*/
public function add_rule( $regex, $query, $priority = 'bottom' ) {
if ( is_array( $query ) ) {
$query = add_query_arg( $query, 'index.php' );
}
$this->wp_rewrite->add_rule( $regex, $query, $priority );
// Do not further handle external rules.
if ( substr( $query, 0, strlen( $this->wp_rewrite->index . '?' ) ) !== $this->wp_rewrite->index . '?' ) {
return;
}
if ( $priority === 'bottom' ) {
$this->extra_rules_bottom[ $regex ] = $query;
return;
}
$this->extra_rules_top[ $regex ] = $query;
}
/**
* Triggers the hook on which rewrite rules should be added.
*
* This allows for a more specific point in time from the generic `init` hook where this is
* otherwise handled.
*
* @return void
*/
public function trigger_dynamic_rewrite_rules_hook() {
/**
* Fires when the plugin's dynamic rewrite rules should be added.
*
* @param self $dynamic_rewrites Dynamic rewrites handler instance. Use its `add_rule()` method
* to add dynamic rewrite rules.
*/
do_action( 'yoast_add_dynamic_rewrite_rules', $this );
}
/**
* Filters the rewrite rules option to dynamically add additional rewrite rules.
*
* @param array|string $rewrite_rules Array of rewrite rule $regex => $query pairs, or empty string
* if currently not set.
*
* @return array|string Filtered value of $rewrite_rules.
*/
public function filter_rewrite_rules_option( $rewrite_rules ) {
// Do not add extra rewrite rules if the rules need to be flushed.
if ( empty( $rewrite_rules ) ) {
return $rewrite_rules;
}
return array_merge( $this->extra_rules_top, $rewrite_rules, $this->extra_rules_bottom );
}
/**
* Sanitizes the rewrite rules option prior to writing it to the database.
*
* This method ensures that the dynamic rewrite rules do not become part of the actual option.
*
* @param array|string $rewrite_rules Array pf rewrite rule $regex => $query pairs, or empty string
* in order to unset.
*
* @return array|string Filtered value of $rewrite_rules before writing the option.
*/
public function sanitize_rewrite_rules_option( $rewrite_rules ) {
if ( empty( $rewrite_rules ) ) {
return $rewrite_rules;
}
return array_diff_key( $rewrite_rules, $this->extra_rules_top, $this->extra_rules_bottom );
}
}

View File

@@ -182,6 +182,8 @@ class WPSEO_Option_Titles extends WPSEO_Option {
/**
* Make sure we can recognize the right action for the double cleaning.
*
* @return void
*/
public function end_of_init() {
do_action( 'wpseo_double_clean_titles' );
@@ -211,7 +213,7 @@ class WPSEO_Option_Titles extends WPSEO_Option {
/**
* Allow altering the array with separator options.
*
* @api array $separator_options Array with the separator options.
* @param array $separator_options Array with the separator options.
*/
$filtered_separators = apply_filters( 'wpseo_separator_options', $separators );
@@ -234,7 +236,7 @@ class WPSEO_Option_Titles extends WPSEO_Option {
$separator_options = [];
foreach ( $separators as $key => $label ) {
$aria_label = isset( $separator_list[ $key ]['label'] ) ? $separator_list[ $key ]['label'] : '';
$aria_label = ( $separator_list[ $key ]['label'] ?? '' );
$separator_options[ $key ] = [
'label' => $label,
@@ -640,7 +642,7 @@ class WPSEO_Option_Titles extends WPSEO_Option {
*
* Make sure when you filter this to also filter `wpseo_schema_article_types_labels`.
*
* @api array $schema_article_types The available schema article types.
* @param array $schema_article_types The available schema article types.
*/
if ( array_key_exists( $dirty[ $key ], apply_filters( 'wpseo_schema_article_types', Schema_Types::ARTICLE_TYPES ) ) ) {
$clean[ $key ] = $dirty[ $key ];
@@ -845,10 +847,8 @@ class WPSEO_Option_Titles extends WPSEO_Option {
if ( ! isset( $post_type_names[ $tax ] ) && isset( $option_value[ $old_prefix . $tax ] ) ) {
unset( $option_value[ $old_prefix . $tax ] );
}
else {
if ( isset( $post_type_names[ $tax ] ) && ! isset( $option_value[ $old_prefix . $tax ] ) ) {
$option_value[ $old_prefix . $tax ] = $original[ $old_prefix . $tax ];
}
elseif ( isset( $post_type_names[ $tax ] ) && ! isset( $option_value[ $old_prefix . $tax ] ) ) {
$option_value[ $old_prefix . $tax ] = $original[ $old_prefix . $tax ];
}
if ( $old_prefix === 'tax-hideeditbox-' ) {
@@ -929,7 +929,7 @@ class WPSEO_Option_Titles extends WPSEO_Option {
/**
* Allow altering the array with variable array key patterns.
*
* @api array $patterns Array with the variable array key patterns.
* @param array $patterns Array with the variable array key patterns.
*/
$patterns = apply_filters( 'wpseo_option_titles_variable_array_key_patterns', $patterns );
@@ -1020,7 +1020,7 @@ class WPSEO_Option_Titles extends WPSEO_Option {
/**
* Allows altering the separator options array.
*
* @api array $separators Array with the separator options.
* @param array $separators Array with the separator options.
*/
$separator_list = apply_filters( 'wpseo_separator_option_list', $separators );

View File

@@ -219,7 +219,7 @@ class WPSEO_Option_Wpseo extends WPSEO_Option {
/**
* Filter: 'wpseo_enable_tracking' - Enables the data tracking of Yoast SEO Premium.
*
* @api string $is_enabled The enabled state. Default is false.
* @param string $is_enabled The enabled state. Default is false.
*/
$this->defaults['tracking'] = apply_filters( 'wpseo_enable_tracking', false );
@@ -469,7 +469,7 @@ class WPSEO_Option_Wpseo extends WPSEO_Option {
if ( is_array( $items ) ) {
foreach ( $items as $item_key => $item ) {
if ( ! \is_string( $item_key ) || ! \is_numeric( $item ) ) {
if ( ! is_string( $item_key ) || ! is_numeric( $item ) ) {
unset( $items[ $item_key ] );
}
}

View File

@@ -61,7 +61,7 @@ abstract class WPSEO_Option {
*
* @var string
*/
const ALLOW_KEY_PREFIX = 'allow_';
public const ALLOW_KEY_PREFIX = 'allow_';
/**
* Option name - MUST be set in concrete class and set to public.
@@ -186,9 +186,6 @@ abstract class WPSEO_Option {
*/
add_filter( 'sanitize_option_' . $this->option_name, [ $this, 'validate' ] );
// Flushes the rewrite rules when option is updated.
add_action( 'update_option_' . $this->option_name, [ 'WPSEO_Utils', 'clear_rewrites' ] );
/* Register our option for the admin pages */
add_action( 'admin_init', [ $this, 'register_setting' ] );
@@ -296,6 +293,8 @@ abstract class WPSEO_Option {
* @param array $dirty Dirty data with the new values.
* @param array $old Old data.
* @param array $clean Clean data by reference, normally the default values.
*
* @return void
*/
public function validate_verification_string( $key, $dirty, $old, &$clean ) {
if ( isset( $dirty[ $key ] ) && $dirty[ $key ] !== '' ) {
@@ -371,6 +370,8 @@ abstract class WPSEO_Option {
* @param array $dirty Dirty data with the new values.
* @param array $old Old data.
* @param array $clean Clean data by reference, normally the default values.
*
* @return void
*/
public function validate_url( $key, $dirty, $old, &$clean ) {
if ( isset( $dirty[ $key ] ) && $dirty[ $key ] !== '' ) {
@@ -870,7 +871,7 @@ abstract class WPSEO_Option {
/**
* Check whether a given array key conforms to one of the variable array key patterns for this option.
*
* @usedby validate_option() methods for options with variable array keys.
* @used-by validate_option() methods for options with variable array keys.
*
* @param string $key Array key to check.
*

View File

@@ -66,6 +66,8 @@ class WPSEO_Options {
/**
* Register our hooks.
*
* @return void
*/
public function register_hooks() {
add_action( 'registered_taxonomy', [ $this, 'clear_cache' ] );
@@ -91,6 +93,8 @@ class WPSEO_Options {
* Registers an option to the options list.
*
* @param WPSEO_Option $option_instance Instance of the option.
*
* @return void
*/
public static function register_option( WPSEO_Option $option_instance ) {
$option_name = $option_instance->get_option_name();
@@ -200,7 +204,7 @@ class WPSEO_Options {
/**
* Filter: wpseo_options - Allow developers to change the option name to include.
*
* @api array The option names to include in get_all and reset().
* @param array $option_names The option names to include in get_all and reset().
*/
return apply_filters( 'wpseo_options', $option_names );
}
@@ -283,6 +287,8 @@ class WPSEO_Options {
/**
* Resets the cache to null.
*
* @return void
*/
public static function clear_cache() {
static::$option_values = null;
@@ -290,6 +296,8 @@ class WPSEO_Options {
/**
* Primes our cache.
*
* @return void
*/
private static function prime_cache() {
static::$option_values = static::get_all();

View File

@@ -119,6 +119,8 @@ class WPSEO_Taxonomy_Meta extends WPSEO_Option {
/**
* Add extra default options received from a filter.
*
* @return void
*/
public function enrich_defaults() {
$extra_defaults_per_term = apply_filters( 'wpseo_add_extra_taxmeta_term_defaults', [] );
@@ -291,7 +293,7 @@ class WPSEO_Taxonomy_Meta extends WPSEO_Option {
break;
}
$clean[ $key ] = apply_filters( 'wpseo_sanitize_tax_meta_' . $key, $clean[ $key ], ( isset( $meta_data[ $key ] ) ? $meta_data[ $key ] : null ), ( isset( $old_meta[ $key ] ) ? $old_meta[ $key ] : null ) );
$clean[ $key ] = apply_filters( 'wpseo_sanitize_tax_meta_' . $key, $clean[ $key ], ( $meta_data[ $key ] ?? null ), ( $old_meta[ $key ] ?? null ) );
}
// Only save the non-default values.
@@ -438,6 +440,8 @@ class WPSEO_Taxonomy_Meta extends WPSEO_Option {
* @param int $term_id ID of the term to save data for.
* @param string $taxonomy The taxonomy the term belongs to.
* @param array $meta_values The values that will be saved.
*
* @return void
*/
public static function set_values( $term_id, $taxonomy, array $meta_values ) {
/* Validate the post values */
@@ -454,6 +458,8 @@ class WPSEO_Taxonomy_Meta extends WPSEO_Option {
* @param string $taxonomy The taxonomy the term belongs to.
* @param string $meta_key The target meta key to store the value in.
* @param string $meta_value The value of the target meta key.
*
* @return void
*/
public static function set_value( $term_id, $taxonomy, $meta_key, $meta_value ) {
@@ -496,6 +502,8 @@ class WPSEO_Taxonomy_Meta extends WPSEO_Option {
* @param int $term_id ID of the term to save data for.
* @param string $taxonomy The taxonomy the term belongs to.
* @param array $clean Array with clean values.
*
* @return void
*/
private static function save_clean_values( $term_id, $taxonomy, array $clean ) {
$tax_meta = self::get_tax_meta();
@@ -530,6 +538,8 @@ class WPSEO_Taxonomy_Meta extends WPSEO_Option {
* Saving the tax meta values to the database.
*
* @param array $tax_meta Array with the meta values for taxonomy.
*
* @return void
*/
private static function save_tax_meta( $tax_meta ) {
update_option( self::$name, $tax_meta );

View File

@@ -115,32 +115,7 @@ class WPSEO_Post_Type_Sitemap_Provider implements WPSEO_Sitemap_Provider {
$all_dates = [];
if ( $max_pages > 1 ) {
$post_statuses = array_map( 'esc_sql', WPSEO_Sitemaps::get_post_statuses( $post_type ) );
if ( version_compare( $wpdb->db_version(), '8.0', '>=' ) ) {
$sql = "
WITH ordering AS (SELECT ROW_NUMBER() OVER (ORDER BY post_modified_gmt) AS n, post_modified_gmt
FROM {$wpdb->posts} USE INDEX ( type_status_date )
WHERE post_status IN ('" . implode( "','", $post_statuses ) . "')
AND post_type = %s
ORDER BY post_modified_gmt)
SELECT post_modified_gmt
FROM ordering
WHERE MOD(n, %d) = 0;";
}
else {
$sql = "
SELECT post_modified_gmt
FROM ( SELECT @rownum:=0 ) init
JOIN {$wpdb->posts} USE INDEX( type_status_date )
WHERE post_status IN ('" . implode( "','", $post_statuses ) . "')
AND post_type = %s
AND ( @rownum:=@rownum+1 ) %% %d = 0
ORDER BY post_modified_gmt ASC
";
}
$all_dates = $wpdb->get_col( $wpdb->prepare( $sql, $post_type, $max_entries ) );
$all_dates = version_compare( $wpdb->db_version(), '8.0', '>=' ) ? $this->get_all_dates_using_with_clause( $post_type, $max_entries ) : $this->get_all_dates( $post_type, $max_entries );
}
for ( $page_counter = 0; $page_counter < $max_pages; $page_counter++ ) {
@@ -175,8 +150,9 @@ class WPSEO_Post_Type_Sitemap_Provider implements WPSEO_Sitemap_Provider {
* @param int $max_entries Entries per sitemap.
* @param int $current_page Current page of the sitemap.
*
* @throws OutOfBoundsException When an invalid page is requested.
* @return array
*
* @throws OutOfBoundsException When an invalid page is requested.
*/
public function get_sitemap_links( $type, $max_entries, $current_page ) {
@@ -262,6 +238,8 @@ class WPSEO_Post_Type_Sitemap_Provider implements WPSEO_Sitemap_Provider {
* Check for relevant post type before invalidation.
*
* @param int $post_id Post ID to possibly invalidate for.
*
* @return void
*/
public function save_post( $post_id ) {
@@ -313,7 +291,7 @@ class WPSEO_Post_Type_Sitemap_Provider implements WPSEO_Sitemap_Provider {
/**
* Filter: 'wpseo_exclude_from_sitemap_by_post_ids' - Allow extending and modifying the posts to exclude.
*
* @api array $posts_to_exclude The posts to exclude.
* @param array $posts_to_exclude The posts to exclude.
*/
$excluded_posts_ids = apply_filters( 'wpseo_exclude_from_sitemap_by_post_ids', $excluded_posts_ids );
if ( ! is_array( $excluded_posts_ids ) ) {
@@ -401,6 +379,19 @@ class WPSEO_Post_Type_Sitemap_Provider implements WPSEO_Sitemap_Provider {
$front_page['chf'] = 'daily';
$front_page['pri'] = 1;
$images = [];
/**
* Filter images to be included for the term in XML sitemap.
*
* @param array $images Array of image items.
* @return array $image_list Array of image items.
*/
$image_list = apply_filters( 'wpseo_sitemap_urlimages_front_page', $images );
if ( isset( $image_list ) && is_array( $image_list ) ) {
$front_page['images'] = $image_list;
}
$links[] = $front_page;
}
elseif ( $post_type !== 'page' ) {
@@ -675,4 +666,101 @@ class WPSEO_Post_Type_Sitemap_Provider implements WPSEO_Sitemap_Provider {
return $url;
}
/**
* Get all dates for a post type by using the WITH clause for performance.
*
* @param string $post_type Post type to retrieve dates for.
* @param int $max_entries Maximum number of entries to retrieve.
*
* @return array Array of dates.
*/
private function get_all_dates_using_with_clause( $post_type, $max_entries ) {
global $wpdb;
$post_statuses = array_map( 'esc_sql', WPSEO_Sitemaps::get_post_statuses( $post_type ) );
$replacements = array_merge(
[
'ordering',
'post_modified_gmt',
$wpdb->posts,
'type_status_date',
'post_status',
],
$post_statuses,
[
'post_type',
$post_type,
'post_modified_gmt',
'post_modified_gmt',
'ordering',
$max_entries,
]
);
//phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- We need to use a direct query here.
//phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: No relevant caches.
return $wpdb->get_col(
//phpcs:disable WordPress.DB.PreparedSQLPlaceholders -- %i placeholder is still not recognized.
$wpdb->prepare(
'
WITH %i AS (SELECT ROW_NUMBER() OVER (ORDER BY %i) AS n, post_modified_gmt
FROM %i USE INDEX ( %i )
WHERE %i IN (' . implode( ', ', array_fill( 0, count( $post_statuses ), '%s' ) ) . ')
AND %i = %s
ORDER BY %i)
SELECT %i
FROM %i
WHERE MOD(n, %d) = 0;
',
$replacements
)
);
}
/**
* Get all dates for a post type.
*
* @param string $post_type Post type to retrieve dates for.
* @param int $max_entries Maximum number of entries to retrieve.
*
* @return array Array of dates.
*/
private function get_all_dates( $post_type, $max_entries ) {
global $wpdb;
$post_statuses = array_map( 'esc_sql', WPSEO_Sitemaps::get_post_statuses( $post_type ) );
$replacements = array_merge(
[
'post_modified_gmt',
$wpdb->posts,
'type_status_date',
'post_status',
],
$post_statuses,
[
'post_type',
$post_type,
$max_entries,
'post_modified_gmt',
]
);
return $wpdb->get_col(
//phpcs:disable WordPress.DB.PreparedSQLPlaceholders -- %i placeholder is still not recognized.
$wpdb->prepare(
'
SELECT %i
FROM ( SELECT @rownum:=0 ) init
JOIN %i USE INDEX( %i )
WHERE %i IN (' . implode( ', ', array_fill( 0, count( $post_statuses ), '%s' ) ) . ')
AND %i = %s
AND ( @rownum:=@rownum+1 ) %% %d = 0
ORDER BY %i ASC
',
$replacements
)
);
}
}

View File

@@ -28,6 +28,8 @@ class WPSEO_Sitemap_Cache_Data implements Serializable, WPSEO_Sitemap_Cache_Data
* Set the sitemap XML data
*
* @param string $sitemap XML Content of the sitemap.
*
* @return void
*/
public function set_sitemap( $sitemap ) {

View File

@@ -124,7 +124,10 @@ class WPSEO_Sitemap_Image_Parser {
* @param array $images Array of image items.
* @param int $post_id ID of the post.
*/
$images = apply_filters( 'wpseo_sitemap_urlimages', $images, $post->ID );
$image_list = apply_filters( 'wpseo_sitemap_urlimages', $images, $post->ID );
if ( isset( $image_list ) && is_array( $image_list ) ) {
$images = $image_list;
}
return $images;
}
@@ -147,6 +150,17 @@ class WPSEO_Sitemap_Image_Parser {
];
}
/**
* Filter images to be included for the term in XML sitemap.
*
* @param array $image_list Array of image items.
* @param int $term_id ID of the post.
*/
$image_list = apply_filters( 'wpseo_sitemap_urlimages_term', $images, $term->term_id );
if ( isset( $image_list ) && is_array( $image_list ) ) {
$images = $image_list;
}
return $images;
}

View File

@@ -33,9 +33,11 @@ class WPSEO_Sitemaps_Admin {
* if the post is being published, is a post type that a sitemap is built for
* and is a post that is included in sitemaps.
*
* @param string $new_status New post status.
* @param string $old_status Old post status.
* @param \WP_Post $post Post object.
* @param string $new_status New post status.
* @param string $old_status Old post status.
* @param WP_Post $post Post object.
*
* @return void
*/
public function status_transition( $new_status, $old_status, $post ) {
if ( $new_status !== 'publish' ) {
@@ -71,6 +73,8 @@ class WPSEO_Sitemaps_Admin {
/**
* Notify Google of the updated sitemap.
*
* @return void
*/
public function ping_search_engines() {
@@ -81,7 +85,7 @@ class WPSEO_Sitemaps_Admin {
/**
* Filter: 'wpseo_allow_xml_sitemap_ping' - Check if pinging is not allowed (allowed by default).
*
* @api boolean $allow_ping The boolean that is set to true by default.
* @param bool $allow_ping The boolean that is set to true by default.
*/
if ( apply_filters( 'wpseo_allow_xml_sitemap_ping', true ) === false ) {
return;
@@ -103,9 +107,11 @@ class WPSEO_Sitemaps_Admin {
* When importing is done, if we have a post_type that is saved in the sitemap
* try to ping the search engines.
*
* @param string $new_status New post status.
* @param string $old_status Old post status.
* @param \WP_Post $post Post object.
* @param string $new_status New post status.
* @param string $old_status Old post status.
* @param WP_Post $post Post object.
*
* @return void
*/
private function status_transition_bulk( $new_status, $old_status, $post ) {
$this->importing_post_types[] = get_post_type( $post );
@@ -114,6 +120,8 @@ class WPSEO_Sitemaps_Admin {
/**
* After import finished, walk through imported post_types and update info.
*
* @return void
*/
public function status_transition_bulk_finished() {
if ( ! defined( 'WP_IMPORTING' ) ) {

View File

@@ -17,21 +17,21 @@ class WPSEO_Sitemaps_Cache_Validator {
*
* @var string
*/
const STORAGE_KEY_PREFIX = 'yst_sm_';
public const STORAGE_KEY_PREFIX = 'yst_sm_';
/**
* Name of the option that holds the global validation value.
*
* @var string
*/
const VALIDATION_GLOBAL_KEY = 'wpseo_sitemap_cache_validator_global';
public const VALIDATION_GLOBAL_KEY = 'wpseo_sitemap_cache_validator_global';
/**
* The format which creates the key of the option that holds the type validation value.
*
* @var string
*/
const VALIDATION_TYPE_KEY_FORMAT = 'wpseo_sitemap_%s_cache_validator';
public const VALIDATION_TYPE_KEY_FORMAT = 'wpseo_sitemap_%s_cache_validator';
/**
* Get the cache key for a certain type and page.
@@ -189,8 +189,15 @@ class WPSEO_Sitemaps_Cache_Validator {
$where[] = sprintf( "option_name LIKE '%s'", addcslashes( '_transient_timeout_' . $like, '_' ) );
// Delete transients.
$query = sprintf( 'DELETE FROM %1$s WHERE %2$s', $wpdb->options, implode( ' OR ', $where ) );
$wpdb->query( $query );
//phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- We need to use a direct query here.
//phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: No relevant caches.
$wpdb->query(
$wpdb->prepare(
//phpcs:disable WordPress.DB.PreparedSQLPlaceholders -- %i placeholder is still not recognized.
'DELETE FROM %i WHERE ' . implode( ' OR', array_fill( 0, count( $where ), '%s' ) ),
array_merge( [ $wpdb->options ], $where )
)
);
wp_cache_delete( 'alloptions', 'options' );
}

View File

@@ -47,22 +47,24 @@ class WPSEO_Sitemaps_Cache {
add_action( 'init', [ $this, 'init' ] );
add_action( 'deleted_term_relationships', [ __CLASS__, 'invalidate' ] );
add_action( 'deleted_term_relationships', [ self::class, 'invalidate' ] );
add_action( 'update_option', [ __CLASS__, 'clear_on_option_update' ] );
add_action( 'update_option', [ self::class, 'clear_on_option_update' ] );
add_action( 'edited_terms', [ __CLASS__, 'invalidate_helper' ], 10, 2 );
add_action( 'clean_term_cache', [ __CLASS__, 'invalidate_helper' ], 10, 2 );
add_action( 'clean_object_term_cache', [ __CLASS__, 'invalidate_helper' ], 10, 2 );
add_action( 'edited_terms', [ self::class, 'invalidate_helper' ], 10, 2 );
add_action( 'clean_term_cache', [ self::class, 'invalidate_helper' ], 10, 2 );
add_action( 'clean_object_term_cache', [ self::class, 'invalidate_helper' ], 10, 2 );
add_action( 'user_register', [ __CLASS__, 'invalidate_author' ] );
add_action( 'delete_user', [ __CLASS__, 'invalidate_author' ] );
add_action( 'user_register', [ self::class, 'invalidate_author' ] );
add_action( 'delete_user', [ self::class, 'invalidate_author' ] );
add_action( 'shutdown', [ __CLASS__, 'clear_queued' ] );
add_action( 'shutdown', [ self::class, 'clear_queued' ] );
}
/**
* Setup context for static calls.
*
* @return void
*/
public function init() {
@@ -294,6 +296,8 @@ class WPSEO_Sitemaps_Cache {
/**
* Invalidate storage for cache types queued to clear.
*
* @return void
*/
public static function clear_queued() {
@@ -320,6 +324,8 @@ class WPSEO_Sitemaps_Cache {
*
* @param string $option Option name.
* @param string $type Sitemap type.
*
* @return void
*/
public static function register_clear_on_option_update( $option, $type = '' ) {

View File

@@ -103,7 +103,7 @@ class WPSEO_Sitemaps_Renderer {
/**
* Filters the `urlset` for a sitemap by type.
*
* @api string $urlset The output for the sitemap's `urlset`.
* @param string $urlset The output for the sitemap's `urlset`.
*/
$xml = apply_filters( "wpseo_sitemap_{$type}_urlset", $urlset );
@@ -166,6 +166,8 @@ class WPSEO_Sitemaps_Renderer {
* Set a custom stylesheet for this sitemap. Set to empty to just remove the default stylesheet.
*
* @param string $stylesheet Full XML-stylesheet declaration.
*
* @return void
*/
public function set_stylesheet( $stylesheet ) {
$this->stylesheet = $stylesheet;
@@ -239,9 +241,8 @@ class WPSEO_Sitemaps_Renderer {
/**
* Filters the output for the sitemap URL tag.
*
* @api string $output The output for the sitemap url tag.
*
* @param array $url The sitemap URL array on which the output is based.
* @param string $output The output for the sitemap url tag.
* @param array $url The sitemap URL array on which the output is based.
*/
return apply_filters( 'wpseo_sitemap_url', $output, $url );
}

View File

@@ -21,24 +21,51 @@ class WPSEO_Sitemaps_Router {
return;
}
add_action( 'init', [ $this, 'init' ], 1 );
add_action( 'yoast_add_dynamic_rewrite_rules', [ $this, 'add_rewrite_rules' ] );
add_filter( 'query_vars', [ $this, 'add_query_vars' ] );
add_filter( 'redirect_canonical', [ $this, 'redirect_canonical' ] );
add_action( 'template_redirect', [ $this, 'template_redirect' ], 0 );
}
/**
* Adds rewrite routes for sitemaps.
*
* @param Yoast_Dynamic_Rewrites $dynamic_rewrites Dynamic rewrites handler instance.
*
* @return void
*/
public function add_rewrite_rules( $dynamic_rewrites ) {
$dynamic_rewrites->add_rule( 'sitemap_index\.xml$', 'index.php?sitemap=1', 'top' );
$dynamic_rewrites->add_rule( '([^/]+?)-sitemap([0-9]+)?\.xml$', 'index.php?sitemap=$matches[1]&sitemap_n=$matches[2]', 'top' );
$dynamic_rewrites->add_rule( '([a-z]+)?-?sitemap\.xsl$', 'index.php?yoast-sitemap-xsl=$matches[1]', 'top' );
}
/**
* Adds query variables for sitemaps.
*
* @param array $query_vars List of query variables to filter.
*
* @return array Filtered query variables.
*/
public function add_query_vars( $query_vars ) {
$query_vars[] = 'sitemap';
$query_vars[] = 'sitemap_n';
$query_vars[] = 'yoast-sitemap-xsl';
return $query_vars;
}
/**
* Sets up rewrite rules.
*
* @deprecated 21.8
* @codeCoverageIgnore
*
* @return void
*/
public function init() {
global $wp;
$wp->add_query_var( 'sitemap' );
$wp->add_query_var( 'sitemap_n' );
$wp->add_query_var( 'yoast-sitemap-xsl' );
add_rewrite_rule( 'sitemap_index\.xml$', 'index.php?sitemap=1', 'top' );
add_rewrite_rule( '([^/]+?)-sitemap([0-9]+)?\.xml$', 'index.php?sitemap=$matches[1]&sitemap_n=$matches[2]', 'top' );
add_rewrite_rule( '([a-z]+)?-?sitemap\.xsl$', 'index.php?yoast-sitemap-xsl=$matches[1]', 'top' );
_deprecated_function( __METHOD__, 'Yoast SEO 21.8' );
}
/**
@@ -59,14 +86,15 @@ class WPSEO_Sitemaps_Router {
/**
* Redirects sitemap.xml to sitemap_index.xml.
*
* @return void
*/
public function template_redirect() {
if ( ! $this->needs_sitemap_index_redirect() ) {
return;
}
wp_safe_redirect( home_url( '/sitemap_index.xml' ), 301, 'Yoast SEO' );
exit;
YoastSEO()->helpers->redirect->do_safe_redirect( home_url( '/sitemap_index.xml' ), 301, 'Yoast SEO' );
}
/**

View File

@@ -17,7 +17,7 @@ class WPSEO_Sitemaps {
*
* @var string
*/
const SITEMAP_INDEX_TYPE = '1';
public const SITEMAP_INDEX_TYPE = '1';
/**
* Content of the sitemap to output.
@@ -115,6 +115,8 @@ class WPSEO_Sitemaps {
* Initialize sitemap providers classes.
*
* @since 5.3
*
* @return void
*/
public function init_sitemaps_providers() {
@@ -135,6 +137,8 @@ class WPSEO_Sitemaps {
/**
* Check the current request URI, if we can determine it's probably an XML sitemap, kill loading the widgets.
*
* @return void
*/
public function reduce_query_load() {
if ( ! isset( $_SERVER['REQUEST_URI'] ) ) {
@@ -153,11 +157,13 @@ class WPSEO_Sitemaps {
* @param string $name The name of the sitemap.
* @param callback $building_function Function to build your sitemap.
* @param string $rewrite Optional. Regular expression to match your sitemap with.
*
* @return void
*/
public function register_sitemap( $name, $building_function, $rewrite = '' ) {
add_action( 'wpseo_do_sitemap_' . $name, $building_function );
if ( ! empty( $rewrite ) ) {
add_rewrite_rule( $rewrite, 'index.php?sitemap=' . $name, 'top' );
if ( $rewrite ) {
Yoast_Dynamic_Rewrites::instance()->add_rule( $rewrite, 'index.php?sitemap=' . $name, 'top' );
}
}
@@ -169,11 +175,13 @@ class WPSEO_Sitemaps {
* @param string $name The name of the XSL file.
* @param callback $building_function Function to build your XSL file.
* @param string $rewrite Optional. Regular expression to match your sitemap with.
*
* @return void
*/
public function register_xsl( $name, $building_function, $rewrite = '' ) {
add_action( 'wpseo_xsl_' . $name, $building_function );
if ( ! empty( $rewrite ) ) {
add_rewrite_rule( $rewrite, 'index.php?yoast-sitemap-xsl=' . $name, 'top' );
if ( $rewrite ) {
Yoast_Dynamic_Rewrites::instance()->add_rule( $rewrite, 'index.php?yoast-sitemap-xsl=' . $name, 'top' );
}
}
@@ -182,6 +190,8 @@ class WPSEO_Sitemaps {
* in a one-off process.
*
* @param int $current_page The part that should be generated.
*
* @return void
*/
public function set_n( $current_page ) {
if ( is_scalar( $current_page ) && intval( $current_page ) > 0 ) {
@@ -193,6 +203,8 @@ class WPSEO_Sitemaps {
* Set the sitemap content to display after you have generated it.
*
* @param string $sitemap The generated sitemap to output.
*
* @return void
*/
public function set_sitemap( $sitemap ) {
$this->sitemap = $sitemap;
@@ -202,6 +214,8 @@ class WPSEO_Sitemaps {
* Set as true to make the request 404. Used stop the display of empty sitemaps or invalid requests.
*
* @param bool $is_bad Is this a bad request. True or false.
*
* @return void
*/
public function set_bad_sitemap( $is_bad ) {
$this->bad_sitemap = (bool) $is_bad;
@@ -211,6 +225,8 @@ class WPSEO_Sitemaps {
* Prevent stupid plugins from running shutdown scripts when we're obviously not outputting HTML.
*
* @since 1.4.16
*
* @return void
*/
public function sitemap_close() {
remove_all_actions( 'wp_footer' );
@@ -220,7 +236,9 @@ class WPSEO_Sitemaps {
/**
* Hijack requests for potential sitemaps and XSL files.
*
* @param \WP_Query $query Main query instance.
* @param WP_Query $query Main query instance.
*
* @return void
*/
public function redirect( $query ) {
@@ -332,6 +350,8 @@ class WPSEO_Sitemaps {
* Sets $bad_sitemap if this isn't for the root sitemap, a post type or taxonomy.
*
* @param string $type The requested sitemap's identifier.
*
* @return void
*/
public function build_sitemap( $type ) {
@@ -382,6 +402,8 @@ class WPSEO_Sitemaps {
/**
* Build the root sitemap (example.com/sitemap_index.xml) which lists sub-sitemaps for other content types.
*
* @return void
*/
public function build_root_map() {
@@ -415,6 +437,8 @@ class WPSEO_Sitemaps {
* @since 1.4.13
*
* @param string $type Type to output.
*
* @return void
*/
public function xsl_output( $type ) {
@@ -445,6 +469,8 @@ class WPSEO_Sitemaps {
/**
* Spit out the generated sitemap.
*
* @return void
*/
public function output() {
$this->send_headers();
@@ -499,18 +525,41 @@ class WPSEO_Sitemaps {
if ( ! empty( $post_type_names ) ) {
$post_statuses = array_map( 'esc_sql', self::get_post_statuses() );
$replacements = array_merge(
[
'post_type',
'post_modified_gmt',
'date',
$wpdb->posts,
'post_status',
],
$post_statuses,
[ 'post_type' ],
array_keys( $post_type_names ),
[
'post_type',
'date',
]
);
$sql = "
SELECT post_type, MAX(post_modified_gmt) AS date
FROM $wpdb->posts
WHERE post_status IN ('" . implode( "','", $post_statuses ) . "')
AND post_type IN ('" . implode( "','", $post_type_names ) . "')
GROUP BY post_type
ORDER BY date DESC
";
//phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- We need to use a direct query here.
//phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: No relevant caches.
$dates = $wpdb->get_results(
//phpcs:disable WordPress.DB.PreparedSQLPlaceholders -- %i placeholder is still not recognized.
$wpdb->prepare(
'
SELECT %i, MAX(%i) AS %i
FROM %i
WHERE %i IN (' . implode( ', ', array_fill( 0, count( $post_statuses ), '%s' ) ) . ')
AND %i IN (' . implode( ', ', array_fill( 0, count( $post_type_names ), '%s' ) ) . ')
GROUP BY %i
ORDER BY %i DESC
',
$replacements
)
);
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- They are prepared on the lines above and a direct query is required.
foreach ( $wpdb->get_results( $sql ) as $obj ) {
foreach ( $dates as $obj ) {
$post_type_dates[ $obj->post_type ] = $obj->date;
}
}
@@ -592,6 +641,8 @@ class WPSEO_Sitemaps {
/**
* Sends all the required HTTP Headers.
*
* @return void
*/
private function send_headers() {
if ( headers_sent() ) {

View File

@@ -94,10 +94,11 @@ class WPSEO_Taxonomy_Sitemap_Provider implements WPSEO_Sitemap_Provider {
$hide_empty_tax = apply_filters( 'wpseo_sitemap_exclude_empty_terms_taxonomy', $hide_empty, $taxonomy_name );
$term_args = [
'taxonomy' => $taxonomy_name,
'hide_empty' => $hide_empty_tax,
'fields' => 'ids',
];
$taxonomy_terms = get_terms( $taxonomy_name, $term_args );
$taxonomy_terms = get_terms( $term_args );
if ( count( $taxonomy_terms ) > 0 ) {
$all_taxonomies[ $taxonomy_name ] = $taxonomy_terms;
@@ -211,24 +212,28 @@ class WPSEO_Taxonomy_Sitemap_Provider implements WPSEO_Sitemap_Provider {
$post_statuses = array_map( 'esc_sql', WPSEO_Sitemaps::get_post_statuses() );
// Grab last modified date.
$sql = "
SELECT MAX(p.post_modified_gmt) AS lastmod
FROM $wpdb->posts AS p
INNER JOIN $wpdb->term_relationships AS term_rel
ON term_rel.object_id = p.ID
INNER JOIN $wpdb->term_taxonomy AS term_tax
ON term_tax.term_taxonomy_id = term_rel.term_taxonomy_id
AND term_tax.taxonomy = %s
AND term_tax.term_id = %d
WHERE p.post_status IN ('" . implode( "','", $post_statuses ) . "')
AND p.post_password = ''
";
$replacements = array_merge(
[
'post_modified_gmt',
$wpdb->posts,
$wpdb->term_relationships,
'object_id',
'ID',
$wpdb->term_taxonomy,
'term_taxonomy_id',
'term_taxonomy_id',
'taxonomy',
'term_id',
'post_status',
],
$post_statuses,
[ 'post_password' ]
);
/**
* Filter: 'wpseo_exclude_from_sitemap_by_term_ids' - Allow excluding terms by ID.
*
* @api array $terms_to_exclude The terms to exclude.
* @param array $terms_to_exclude The terms to exclude.
*/
$terms_to_exclude = apply_filters( 'wpseo_exclude_from_sitemap_by_term_ids', [] );
@@ -253,7 +258,30 @@ class WPSEO_Taxonomy_Sitemap_Provider implements WPSEO_Sitemap_Provider {
continue;
}
$url['mod'] = $wpdb->get_var( $wpdb->prepare( $sql, $term->taxonomy, $term->term_id ) );
$current_replacements = $replacements;
array_splice( $current_replacements, 9, 0, $term->taxonomy );
array_splice( $current_replacements, 11, 0, $term->term_id );
//phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- We need to use a direct query here.
//phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: No relevant caches.
$url['mod'] = $wpdb->get_var(
//phpcs:disable WordPress.DB.PreparedSQLPlaceholders -- %i placeholder is still not recognized.
$wpdb->prepare(
'
SELECT MAX(p.%i) AS lastmod
FROM %i AS p
INNER JOIN %i AS term_rel
ON term_rel.%i = p.%i
INNER JOIN %i AS term_tax
ON term_tax.%i = term_rel.%i
AND term_tax.%i = %s
AND term_tax.%i = %d
WHERE p.%i IN (' . implode( ', ', array_fill( 0, count( $post_statuses ), '%s' ) ) . ")
AND p.%i = ''
",
$current_replacements
)
);
if ( $this->include_images ) {
$url['images'] = $this->get_image_parser()->get_term_images( $term );

View File

@@ -15,21 +15,21 @@ interface WPSEO_Sitemap_Cache_Data_Interface {
*
* @var string
*/
const OK = 'ok';
public const OK = 'ok';
/**
* Status for unusable sitemap.
*
* @var string
*/
const ERROR = 'error';
public const ERROR = 'error';
/**
* Status for unusable sitemap because it cannot be identified.
*
* @var string
*/
const UNKNOWN = 'unknown';
public const UNKNOWN = 'unknown';
/**
* Set the content of the sitemap.

View File

@@ -4,4 +4,3 @@
*
* @package WPSEO\Deprecated
*/

View File

@@ -210,6 +210,8 @@ if ( ! function_exists( 'ctype_digit' ) ) {
* @param string $new_term_id New term id of the taxonomy term that was splitted.
* @param string $term_taxonomy_id Term taxonomy id for the taxonomy that was affected.
* @param string $taxonomy The taxonomy that the taxonomy term was splitted for.
*
* @return void
*/
function wpseo_split_shared_term( $old_term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
$tax_meta = get_option( 'wpseo_taxonomy_meta', [] );