| @@ -262,10 +262,16 @@ | ||
| 262 | 262 | add_action('metasync_api_key_changed', array('Metasync_Admin_Navigation', 'invalidate_admin_bar_status_cache'), 10, 0); |
| 263 | 263 | |
| 264 | 264 | add_action('admin_init', array($this, 'initialize_cookie')); |
| 265 | 265 | add_action('admin_init', array($this, 'maybe_redirect_to_wizard')); |
| 266 | - add_action('admin_init', array($this, 'redirect_legacy_instant_indexing_page')); | |
| 267 | 266 | |
| 267 | + // The redirect must run on admin_menu, not admin_init: in current | |
| 268 | + // WordPress the unregistered-page access check in wp-admin/includes/ | |
| 269 | + // menu.php fires from wp-admin/menu.php (required at admin.php:163), | |
| 270 | + // which is BEFORE admin_init (admin.php:180). Hooked on admin_init the | |
| 271 | + // redirect never ran — WP died with a 403 first for the removed slug. | |
| 272 | + add_action('admin_menu', array($this, 'redirect_legacy_instant_indexing_page')); | |
| 273 | + | |
| 268 | 274 | // Add admin_post hooks for form submissions (WordPress standard way - no output buffering needed) |
| 269 | 275 | add_action('admin_post_metasync_clear_all_cache_plugins', array($this, 'handle_clear_all_cache_plugins')); |
| 270 | 276 | add_action('admin_post_metasync_clear_otto_cache_all', array($this, 'handle_clear_otto_cache_all')); |
| 271 | 277 | add_action('admin_post_metasync_clear_otto_cache_url', array($this, 'handle_clear_otto_cache_url')); |
| @@ -388,11 +394,8 @@ | ||
| 388 | 394 | |
| 389 | 395 | # Add AJAX handlers for Bing Instant Indexing (IndexNow) |
| 390 | 396 | add_action('wp_ajax_metasync_send_bing_indexnow', array($this, 'ajax_send_bing_indexnow')); |
| 391 | 397 | |
| 392 | - # Add hooks for instant indexing settings saves | |
| 393 | - add_action('admin_init', array($this, 'save_instant_indexing_settings')); | |
| 394 | - | |
| 395 | 398 | # Add hooks for instant indexing post actions |
| 396 | 399 | add_filter('post_row_actions', array($this, 'add_instant_indexing_post_actions'), 10, 2); |
| 397 | 400 | add_filter('page_row_actions', array($this, 'add_instant_indexing_post_actions'), 10, 2); |
| 398 | 401 | |
| @@ -700,10 +703,8 @@ | ||
| 700 | 703 | */ |
| 701 | 704 | public function maybe_redirect_to_wizard() { |
| 702 | 705 | // Only redirect if wizard should be shown |
| 703 | 706 | if (get_option('metasync_show_wizard') && !isset($_GET['page'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- isset() routing check for a redirect to a fixed admin URL |
| 704 | - delete_option('metasync_show_wizard'); | |
| 705 | - | |
| 706 | 707 | // Don't redirect during AJAX, cron, or bulk activation |
| 707 | 708 | if (wp_doing_ajax() || wp_doing_cron() || isset($_GET['activate-multi'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- isset() routing check for a redirect to a fixed admin URL |
| 708 | 709 | return; |
| 709 | 710 | } |
| @@ -712,8 +713,9 @@ | ||
| 712 | 713 | if (!Metasync::current_user_has_plugin_access()) { |
| 713 | 714 | return; |
| 714 | 715 | } |
| 715 | 716 | |
| 717 | + delete_option('metasync_show_wizard'); | |
| 716 | 718 | wp_safe_redirect(admin_url('admin.php?page=' . self::$page_slug . '-setup-wizard')); |
| 717 | 719 | exit; |
| 718 | 720 | } |
| 719 | 721 | } |
| @@ -723,8 +725,12 @@ | ||
| 723 | 725 | * |
| 724 | 726 | * The menu entry is gone, but bookmarks and external links can still target |
| 725 | 727 | * the old URL. Resolve the current white-label slug rather than assuming |
| 726 | 728 | * "searchatlas". |
| 729 | + * | |
| 730 | + * Hooked on admin_menu (see its registration): the unregistered-page 403 in | |
| 731 | + * wp-admin/includes/menu.php fires before admin_init, so any later hook | |
| 732 | + * would be too late to redirect. | |
| 727 | 733 | */ |
| 728 | 734 | public function redirect_legacy_instant_indexing_page() { |
| 729 | 735 | if (wp_doing_ajax() || wp_doing_cron() || !is_admin() || !isset($_GET['page'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only navigation values for a same-site redirect |
| 730 | 736 | return; |
| @@ -917,10 +923,11 @@ | ||
| 917 | 923 | 'all' |
| 918 | 924 | ); |
| 919 | 925 | } |
| 920 | 926 | |
| 921 | - // Enqueue wizard CSS if on wizard page | |
| 922 | - if (isset($_GET['page']) && strpos(sanitize_key(wp_unslash($_GET['page'])), '-setup-wizard') !== false) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only page check to pick stylesheets | |
| 927 | + // Enqueue wizard CSS on all MetaSync pages because the reusable consent | |
| 928 | + // card is also displayed inside General Settings. | |
| 929 | + if (strpos($current_page, self::$page_slug) === 0 || (isset($_GET['page']) && strpos(sanitize_key(wp_unslash($_GET['page'])), '-setup-wizard') !== false)) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only page check to pick stylesheets | |
| 923 | 930 | wp_enqueue_style( |
| 924 | 931 | $this->plugin_name . '-setup-wizard', |
| 925 | 932 | plugin_dir_url(__FILE__) . 'css/metasync-setup-wizard.css', |
| 926 | 933 | array($this->plugin_name . '-dashboard'), |
| @@ -3357,9 +3364,9 @@ | ||
| 3357 | 3364 | |
| 3358 | 3365 | update_option('metasync_sitemap_settings', $sitemap_settings); |
| 3359 | 3366 | |
| 3360 | 3367 | // Regenerate sitemap with new content settings |
| 3361 | - $result = $sitemap_generator->generate_sitemap(); | |
| 3368 | + $result = $sitemap_generator->generate_sitemap( true ); | |
| 3362 | 3369 | if (is_wp_error($result)) { |
| 3363 | 3370 | echo '<div class="notice notice-error"><p>' . esc_html( |
| 3364 | 3371 | /* translators: %s: error message. */ |
| 3365 | 3372 | sprintf(__('Settings saved but sitemap generation failed: %s', 'metasync'), $result->get_error_message()) |
| @@ -3513,9 +3520,9 @@ | ||
| 3513 | 3520 | gc_collect_cycles(); |
| 3514 | 3521 | } |
| 3515 | 3522 | |
| 3516 | 3523 | // Generate main sitemap (its index will include news/video since they now exist) |
| 3517 | - $result = $sitemap_generator->generate_sitemap(); | |
| 3524 | + $result = $sitemap_generator->generate_sitemap( true ); | |
| 3518 | 3525 | |
| 3519 | 3526 | if (is_wp_error($result)) { |
| 3520 | 3527 | $error_msg = $result->get_error_message(); |
| 3521 | 3528 | error_log('[MetaSync] Sitemap generation failed: ' . $error_msg); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- genuine failure path, bounded, no secrets |
| @@ -3936,9 +3943,9 @@ | ||
| 3936 | 3943 | { |
| 3937 | 3944 | register_rest_route('metasync/v1', '/ping', array( |
| 3938 | 3945 | 'methods' => array('GET', 'POST'), |
| 3939 | 3946 | 'callback' => array($this, 'handle_ping_rest_endpoint'), |
| 3940 | - 'permission_callback' => '__return_true', // Allow public access | |
| 3947 | + 'permission_callback' => '__return_true', | |
| 3941 | 3948 | 'args' => array( |
| 3942 | 3949 | 'test' => array( |
| 3943 | 3950 | 'description' => 'Optional test parameter', |
| 3944 | 3951 | 'type' => 'string', |
| @@ -6468,44 +6475,8 @@ | ||
| 6468 | 6475 | |
| 6469 | 6476 | require_once plugin_dir_path(dirname(__FILE__)) . 'bing-index/class-metasync-bing-instant-index.php'; |
| 6470 | 6477 | $bing_instant_index = new Metasync_Bing_Instant_Index(); |
| 6471 | 6478 | $bing_instant_index->send(); |
| 6472 | - } | |
| 6473 | - | |
| 6474 | - /** | |
| 6475 | - * Save instant indexing settings (Google and Bing) | |
| 6476 | - * | |
| 6477 | - * @since 2.6.0 | |
| 6478 | - * @return void | |
| 6479 | - */ | |
| 6480 | - public function save_instant_indexing_settings() | |
| 6481 | - { | |
| 6482 | - // Check if this is a settings submission | |
| 6483 | - if (!isset($_POST['submit'])) { | |
| 6484 | - return; | |
| 6485 | - } | |
| 6486 | - | |
| 6487 | - // This handler runs on admin_init, which also fires inside | |
| 6488 | - // admin-ajax.php before its login gate, so a bare isset() check let | |
| 6489 | - // any request (including logged-out ones) rewrite the auto-submit | |
| 6490 | - // post types. Require the nonce and plugin access before writing. | |
| 6491 | - if (!isset($_POST['metasync_instant_indexing_nonce']) | |
| 6492 | - || !wp_verify_nonce(sanitize_key(wp_unslash($_POST['metasync_instant_indexing_nonce'])), 'metasync_instant_indexing_settings') | |
| 6493 | - || !Metasync::current_user_has_plugin_access()) { | |
| 6494 | - return; | |
| 6495 | - } | |
| 6496 | - | |
| 6497 | - // Save post types for Google Instant Indexing auto-submit | |
| 6498 | - if (isset($_POST['metasync_post_types'])) { | |
| 6499 | - $post_data = metasync_sanitize_input_array($_POST); | |
| 6500 | - $post_types = is_array($post_data['metasync_post_types']) ? array_map('sanitize_title', $post_data['metasync_post_types']) : []; | |
| 6501 | - | |
| 6502 | - $settings = get_option('metasync_options_instant_indexing', ['post_types' => []]); | |
| 6503 | - $settings['post_types'] = array_values($post_types); | |
| 6504 | - update_option('metasync_options_instant_indexing', $settings); | |
| 6505 | - } | |
| 6506 | - | |
| 6507 | - // Note: Bing Instant Indexing settings are saved via AJAX in save_bing_inline_settings_ajax() | |
| 6508 | 6479 | } |
| 6509 | 6480 | |
| 6510 | 6481 | /** |
| 6511 | 6482 | * Save Bing instant indexing settings from inline form (Indexation Control page) |