← All changes
|
includes/admin/importers/class-import-controller.php
+42
-2
2.4.0
→
2.8.0
View file →
| @@ -41,9 +41,9 @@ | ||
| 41 | 41 | * Kept separate from ALLOWED_PLUGINS because cleanup() deletes the source |
| 42 | 42 | * plugin's live data: the native ThinkRank slug must never reach it, or the |
| 43 | 43 | * endpoint gains a path that wipes our own meta and options. |
| 44 | 44 | */ |
| 45 | - private const SOURCE_PLUGINS = ['yoast', 'rankmath', 'seopress', 'aioseo']; | |
| 45 | + private const SOURCE_PLUGINS = ['yoast', 'rankmath', 'seopress', 'aioseo', 'squirrly']; | |
| 46 | 46 | |
| 47 | 47 | /** |
| 48 | 48 | * Snapshot slug for ThinkRank's own data (export / backup / restore). |
| 49 | 49 | */ |
| @@ -52,9 +52,9 @@ | ||
| 52 | 52 | /** |
| 53 | 53 | * Allowed plugin slugs for the snapshot endpoints (export, migrate, |
| 54 | 54 | * snapshot delete). Includes the native slug; cleanup uses SOURCE_PLUGINS. |
| 55 | 55 | */ |
| 56 | - private const ALLOWED_PLUGINS = ['yoast', 'rankmath', 'seopress', 'aioseo', 'thinkrank']; | |
| 56 | + private const ALLOWED_PLUGINS = ['yoast', 'rankmath', 'seopress', 'aioseo', 'squirrly', 'thinkrank']; | |
| 57 | 57 | |
| 58 | 58 | /** |
| 59 | 59 | * Allowed export/migrate types. Must cover every type the exporters and |
| 60 | 60 | * the frontend workflow (useImportWorkflow.js EXPORT_TYPES) can send — |
| @@ -89,8 +89,16 @@ | ||
| 89 | 89 | [ |
| 90 | 90 | 'methods' => \WP_REST_Server::READABLE, |
| 91 | 91 | 'callback' => [$this, 'detect'], |
| 92 | 92 | 'permission_callback' => [$this, 'check_permissions'], |
| 93 | + 'args' => [ | |
| 94 | + 'refresh' => [ | |
| 95 | + 'type' => 'boolean', | |
| 96 | + 'default' => false, | |
| 97 | + 'sanitize_callback' => 'rest_sanitize_boolean', | |
| 98 | + 'description' => __('Discard the cached scan and re-read the database. Set by the Re-scan button; the screen\'s own load leaves it off so repeat navigation stays instant.', 'thinkrank'), | |
| 99 | + ], | |
| 100 | + ], | |
| 93 | 101 | ], |
| 94 | 102 | ]); |
| 95 | 103 | |
| 96 | 104 | register_rest_route($this->namespace, '/' . $this->rest_base . '/export', [ |
| @@ -172,13 +180,22 @@ | ||
| 172 | 180 | /** |
| 173 | 181 | * GET /import/detect — Detect source plugins, ThinkRank's own exportable |
| 174 | 182 | * data, and existing snapshots |
| 175 | 183 | * |
| 184 | + * `refresh` drops the hour-long detection transient before scanning. Without | |
| 185 | + * it the Re-scan button could not do the one thing it exists for: pick up a | |
| 186 | + * source plugin the user just installed, activated or added data to. | |
| 187 | + * | |
| 176 | 188 | * @param \WP_REST_Request $request Request object |
| 177 | 189 | * @return \WP_REST_Response |
| 178 | 190 | */ |
| 179 | 191 | public function detect(\WP_REST_Request $request): \WP_REST_Response { |
| 180 | 192 | $detector = new Import_Detector(); |
| 193 | + | |
| 194 | + if ($request->get_param('refresh')) { | |
| 195 | + $detector->clear_cache(); | |
| 196 | + } | |
| 197 | + | |
| 181 | 198 | $detected = $detector->detect(); |
| 182 | 199 | $snapshots = Snapshot_Store::get_available_snapshots(); |
| 183 | 200 | |
| 184 | 201 | return new \WP_REST_Response([ |
| @@ -326,8 +343,9 @@ | ||
| 326 | 343 | 'yoast' => '_yoast_wpseo_', |
| 327 | 344 | 'rankmath' => 'rank_math_', |
| 328 | 345 | 'seopress' => '_seopress_', |
| 329 | 346 | 'aioseo' => null, // Custom table |
| 347 | + 'squirrly' => '_sq_', // Fallback meta only; the SEO is in the qss table below | |
| 330 | 348 | ]; |
| 331 | 349 | |
| 332 | 350 | $prefix = $prefix_map[$plugin] ?? null; |
| 333 | 351 | |
| @@ -354,8 +372,9 @@ | ||
| 354 | 372 | $usermeta_prefix_map = [ |
| 355 | 373 | 'yoast' => 'wpseo_', |
| 356 | 374 | 'rankmath' => 'rank_math_', |
| 357 | 375 | 'seopress' => '_seopress_', |
| 376 | + 'squirrly' => '_sq_', | |
| 358 | 377 | ]; |
| 359 | 378 | $usermeta_prefix = $usermeta_prefix_map[$plugin] ?? $prefix; |
| 360 | 379 | $deleted += (int) $wpdb->query( |
| 361 | 380 | $wpdb->prepare( |
| @@ -370,8 +389,9 @@ | ||
| 370 | 389 | $option_keys_map = [ |
| 371 | 390 | 'yoast' => ['wpseo', 'wpseo_titles', 'wpseo_social', 'wpseo_taxonomy_meta'], |
| 372 | 391 | 'rankmath' => ['rank-math-options-general', 'rank-math-options-titles', 'rank-math-options-sitemap', 'rank-math-options-instant-indexing'], |
| 373 | 392 | 'seopress' => ['seopress_titles_option_name', 'seopress_social_option_name', 'seopress_advanced_option_name', 'seopress_xml_sitemap_option_name', 'seopress_instant_indexing_option_name'], |
| 393 | + 'squirrly' => ['sq_options'], | |
| 374 | 394 | ]; |
| 375 | 395 | foreach ($option_keys_map[$plugin] ?? [] as $option_name) { |
| 376 | 396 | if (delete_option($option_name)) { |
| 377 | 397 | $deleted++; |
| @@ -378,8 +398,26 @@ | ||
| 378 | 398 | } |
| 379 | 399 | } |
| 380 | 400 | } |
| 381 | 401 | |
| 402 | + if ($plugin === 'squirrly') { | |
| 403 | + // Drop Squirrly's custom tables: per-URL SEO, Advanced Pack | |
| 404 | + // redirects and their logs, reusable JSON-LD templates. | |
| 405 | + foreach (['qss', 'qss_redirects', 'qss_redirects_logs', 'qss_jsonld'] as $suffix) { | |
| 406 | + $table = $wpdb->prefix . $suffix; | |
| 407 | + $table_exists = $wpdb->get_var( | |
| 408 | + $wpdb->prepare("SHOW TABLES LIKE %s", $table) | |
| 409 | + ); | |
| 410 | + if ($table_exists) { | |
| 411 | + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- table name is $wpdb->prefix plus a literal, and every value is passed as a placeholder replacement. | |
| 412 | + $count = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$table}"); | |
| 413 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- table name is $wpdb->prefix plus a literal, and every value is passed as a placeholder replacement. | |
| 414 | + $wpdb->query("DROP TABLE {$table}"); | |
| 415 | + $deleted += $count; | |
| 416 | + } | |
| 417 | + } | |
| 418 | + } | |
| 419 | + | |
| 382 | 420 | if ($plugin === 'aioseo') { |
| 383 | 421 | // Drop the AIOSEO custom tables the exporter reads (posts + Pro terms). |
| 384 | 422 | foreach (['aioseo_posts', 'aioseo_terms'] as $suffix) { |
| 385 | 423 | $table = $wpdb->prefix . $suffix; |
| @@ -455,8 +493,10 @@ | ||
| 455 | 493 | case 'seopress': |
| 456 | 494 | return new SEOPress_Exporter(); |
| 457 | 495 | case 'aioseo': |
| 458 | 496 | return new AIOSEO_Exporter(); |
| 497 | + case Squirrly_Exporter::SLUG: | |
| 498 | + return new Squirrly_Exporter(); | |
| 459 | 499 | case Thinkrank_Exporter::SLUG: |
| 460 | 500 | return new Thinkrank_Exporter(); |
| 461 | 501 | default: |
| 462 | 502 | return new \WP_Error('invalid_plugin', 'Unsupported plugin: ' . $plugin, ['status' => 400]); |