| @@ -176,8 +176,9 @@ | ||
| 176 | 176 | $count = 0; |
| 177 | 177 | |
| 178 | 178 | switch ($plugin) { |
| 179 | 179 | case 'yoast': |
| 180 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 180 | 181 | $count = (int) $wpdb->get_var(" |
| 181 | 182 | SELECT COUNT(DISTINCT post_id) |
| 182 | 183 | FROM {$wpdb->postmeta} |
| 183 | 184 | WHERE meta_key LIKE '_yoast_wpseo_%' |
| @@ -185,22 +186,23 @@ | ||
| 185 | 186 | "); |
| 186 | 187 | break; |
| 187 | 188 | |
| 188 | 189 | case 'rankmath': |
| 189 | - $count = (int) $wpdb->get_var(" | |
| 190 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 191 | + $count = (int) $wpdb->get_var($wpdb->prepare(" | |
| 190 | 192 | SELECT COUNT(DISTINCT post_id) |
| 191 | 193 | FROM {$wpdb->postmeta} |
| 192 | - WHERE meta_key LIKE 'rank_math_%' | |
| 194 | + WHERE meta_key LIKE %s | |
| 193 | 195 | AND post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 194 | - "); | |
| 196 | + ", 'rank_math_%')); | |
| 195 | 197 | break; |
| 196 | 198 | |
| 197 | 199 | case 'aioseo': |
| 198 | 200 | $table = $wpdb->prefix . 'aioseo_posts'; |
| 199 | - if ($wpdb->get_var("SHOW TABLES LIKE '$table'") === $table) { | |
| 201 | + if ($wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->esc_like($table))) === $table) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 200 | 202 | $count = (int) $wpdb->get_var(" |
| 201 | 203 | SELECT COUNT(post_id) |
| 202 | - FROM {$table} | |
| 204 | + FROM {$wpdb->prefix}aioseo_posts | |
| 203 | 205 | WHERE post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 204 | 206 | "); |
| 205 | 207 | } |
| 206 | 208 | break; |
| @@ -222,8 +224,9 @@ | ||
| 222 | 224 | case 'yoast': |
| 223 | 225 | // Check for Yoast schema meta |
| 224 | 226 | // Yoast Premium stores schema type in _yoast_wpseo_schema_article_type |
| 225 | 227 | // Free version may use _yoast_wpseo_schema (JSON) |
| 228 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 226 | 229 | $count = (int) $wpdb->get_var(" |
| 227 | 230 | SELECT COUNT(DISTINCT post_id) |
| 228 | 231 | FROM {$wpdb->postmeta} |
| 229 | 232 | WHERE (meta_key = '_yoast_wpseo_schema' OR meta_key = '_yoast_wpseo_schema_article_type') |
| @@ -234,8 +237,9 @@ | ||
| 234 | 237 | case 'rankmath': |
| 235 | 238 | // Check for Rank Math schema meta (any schema type) |
| 236 | 239 | // Rank Math uses meta keys like: rank_math_schema_Article, rank_math_schema_BlogPosting, rank_math_schema_Product, etc. |
| 237 | 240 | // Exclude shortcode schemas (rank_math_shortcode_schema_*) |
| 241 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 238 | 242 | $count = (int) $wpdb->get_var(" |
| 239 | 243 | SELECT COUNT(DISTINCT post_id) |
| 240 | 244 | FROM {$wpdb->postmeta} |
| 241 | 245 | WHERE meta_key LIKE 'rank_math_schema_%' |
| @@ -246,12 +250,12 @@ | ||
| 246 | 250 | |
| 247 | 251 | case 'aioseo': |
| 248 | 252 | // Check for AIOSEO schema in table |
| 249 | 253 | $table = $wpdb->prefix . 'aioseo_posts'; |
| 250 | - if ($wpdb->get_var("SHOW TABLES LIKE '$table'") === $table) { | |
| 254 | + if ($wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->esc_like($table))) === $table) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 251 | 255 | $count = (int) $wpdb->get_var(" |
| 252 | 256 | SELECT COUNT(post_id) |
| 253 | - FROM {$table} | |
| 257 | + FROM {$wpdb->prefix}aioseo_posts | |
| 254 | 258 | WHERE (schema_type IS NOT NULL AND schema_type != '') |
| 255 | 259 | AND post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 256 | 260 | "); |
| 257 | 261 | } |
| @@ -272,8 +276,9 @@ | ||
| 272 | 276 | |
| 273 | 277 | switch ($plugin) { |
| 274 | 278 | case 'yoast': |
| 275 | 279 | // Check for Yoast SEO title or description |
| 280 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 276 | 281 | $count = (int) $wpdb->get_var(" |
| 277 | 282 | SELECT COUNT(DISTINCT post_id) |
| 278 | 283 | FROM {$wpdb->postmeta} |
| 279 | 284 | WHERE (meta_key = '_yoast_wpseo_title' OR meta_key = '_yoast_wpseo_metadesc') |
| @@ -283,8 +288,9 @@ | ||
| 283 | 288 | break; |
| 284 | 289 | |
| 285 | 290 | case 'rankmath': |
| 286 | 291 | // Check for Rank Math title or description |
| 292 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 287 | 293 | $count = (int) $wpdb->get_var(" |
| 288 | 294 | SELECT COUNT(DISTINCT post_id) |
| 289 | 295 | FROM {$wpdb->postmeta} |
| 290 | 296 | WHERE (meta_key = 'rank_math_title' OR meta_key = 'rank_math_description') |
| @@ -295,12 +301,12 @@ | ||
| 295 | 301 | |
| 296 | 302 | case 'aioseo': |
| 297 | 303 | // Check for AIOSEO title or description in their custom table |
| 298 | 304 | $table = $wpdb->prefix . 'aioseo_posts'; |
| 299 | - if ($wpdb->get_var("SHOW TABLES LIKE '$table'") === $table) { | |
| 305 | + if ($wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->esc_like($table))) === $table) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 300 | 306 | $count = (int) $wpdb->get_var(" |
| 301 | 307 | SELECT COUNT(post_id) |
| 302 | - FROM {$table} | |
| 308 | + FROM {$wpdb->prefix}aioseo_posts | |
| 303 | 309 | WHERE ((title IS NOT NULL AND title != '') OR (description IS NOT NULL AND description != '')) |
| 304 | 310 | AND post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 305 | 311 | "); |
| 306 | 312 | |
| @@ -315,9 +321,9 @@ | ||
| 315 | 321 | if (!empty($templates)) { |
| 316 | 322 | $post_types = array_keys($templates); |
| 317 | 323 | $type_placeholders = implode(', ', array_fill(0, count($post_types), '%s')); |
| 318 | 324 | |
| 319 | - $template_count = (int) $wpdb->get_var($wpdb->prepare( | |
| 325 | + $template_count = (int) $wpdb->get_var($wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 320 | 326 | "SELECT COUNT(*) |
| 321 | 327 | FROM {$wpdb->posts} |
| 322 | 328 | WHERE post_status = 'publish' |
| 323 | 329 | AND post_type IN ({$type_placeholders})", |
| @@ -347,8 +353,9 @@ | ||
| 347 | 353 | $count = 0; |
| 348 | 354 | |
| 349 | 355 | switch ($plugin) { |
| 350 | 356 | case 'yoast': |
| 357 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 351 | 358 | $count = (int) $wpdb->get_var(" |
| 352 | 359 | SELECT COUNT(DISTINCT post_id) |
| 353 | 360 | FROM {$wpdb->postmeta} |
| 354 | 361 | WHERE meta_key = '_yoast_wpseo_primary_category' |
| @@ -357,8 +364,9 @@ | ||
| 357 | 364 | "); |
| 358 | 365 | break; |
| 359 | 366 | |
| 360 | 367 | case 'rankmath': |
| 368 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 361 | 369 | $count = (int) $wpdb->get_var(" |
| 362 | 370 | SELECT COUNT(DISTINCT post_id) |
| 363 | 371 | FROM {$wpdb->postmeta} |
| 364 | 372 | WHERE meta_key = 'rank_math_primary_category' |
| @@ -367,8 +375,9 @@ | ||
| 367 | 375 | "); |
| 368 | 376 | break; |
| 369 | 377 | |
| 370 | 378 | case 'aioseo': |
| 379 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 371 | 380 | $count = (int) $wpdb->get_var(" |
| 372 | 381 | SELECT COUNT(DISTINCT post_id) |
| 373 | 382 | FROM {$wpdb->postmeta} |
| 374 | 383 | WHERE meta_key = '_aioseo_primary_category' |
| @@ -429,8 +438,9 @@ | ||
| 429 | 438 | $batch_size = intval($options['batch_size']); |
| 430 | 439 | $offset = intval($options['offset']); |
| 431 | 440 | $overwrite = (bool) $options['overwrite_existing']; |
| 432 | 441 | |
| 442 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 433 | 443 | $total_posts = (int) $wpdb->get_var(" |
| 434 | 444 | SELECT COUNT(DISTINCT post_id) |
| 435 | 445 | FROM {$wpdb->postmeta} |
| 436 | 446 | WHERE meta_key = '_yoast_wpseo_primary_category' |
| @@ -437,8 +447,9 @@ | ||
| 437 | 447 | AND meta_value != '' |
| 438 | 448 | AND post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 439 | 449 | "); |
| 440 | 450 | |
| 451 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 441 | 452 | $posts = $wpdb->get_results($wpdb->prepare(" |
| 442 | 453 | SELECT DISTINCT post_id |
| 443 | 454 | FROM {$wpdb->postmeta} |
| 444 | 455 | WHERE meta_key = '_yoast_wpseo_primary_category' |
| @@ -492,8 +503,9 @@ | ||
| 492 | 503 | $batch_size = intval($options['batch_size']); |
| 493 | 504 | $offset = intval($options['offset']); |
| 494 | 505 | $overwrite = (bool) $options['overwrite_existing']; |
| 495 | 506 | |
| 507 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 496 | 508 | $total_posts = (int) $wpdb->get_var(" |
| 497 | 509 | SELECT COUNT(DISTINCT post_id) |
| 498 | 510 | FROM {$wpdb->postmeta} |
| 499 | 511 | WHERE meta_key = 'rank_math_primary_category' |
| @@ -500,8 +512,9 @@ | ||
| 500 | 512 | AND meta_value != '' |
| 501 | 513 | AND post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 502 | 514 | "); |
| 503 | 515 | |
| 516 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 504 | 517 | $posts = $wpdb->get_results($wpdb->prepare(" |
| 505 | 518 | SELECT DISTINCT post_id |
| 506 | 519 | FROM {$wpdb->postmeta} |
| 507 | 520 | WHERE meta_key = 'rank_math_primary_category' |
| @@ -555,8 +568,9 @@ | ||
| 555 | 568 | $batch_size = intval($options['batch_size']); |
| 556 | 569 | $offset = intval($options['offset']); |
| 557 | 570 | $overwrite = (bool) $options['overwrite_existing']; |
| 558 | 571 | |
| 572 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 559 | 573 | $total_posts = (int) $wpdb->get_var(" |
| 560 | 574 | SELECT COUNT(DISTINCT post_id) |
| 561 | 575 | FROM {$wpdb->postmeta} |
| 562 | 576 | WHERE meta_key = '_aioseo_primary_category' |
| @@ -563,8 +577,9 @@ | ||
| 563 | 577 | AND meta_value != '' |
| 564 | 578 | AND post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 565 | 579 | "); |
| 566 | 580 | |
| 581 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 567 | 582 | $posts = $wpdb->get_results($wpdb->prepare(" |
| 568 | 583 | SELECT DISTINCT post_id |
| 569 | 584 | FROM {$wpdb->postmeta} |
| 570 | 585 | WHERE meta_key = '_aioseo_primary_category' |
| @@ -762,24 +777,26 @@ | ||
| 762 | 777 | $batch_size = intval($options['batch_size']); |
| 763 | 778 | $offset = intval($options['offset']); |
| 764 | 779 | |
| 765 | 780 | // Get total count (for progress tracking) |
| 766 | - $total = (int) $wpdb->get_var(" | |
| 781 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 782 | + $total = (int) $wpdb->get_var($wpdb->prepare(" | |
| 767 | 783 | SELECT COUNT(DISTINCT post_id) |
| 768 | 784 | FROM {$wpdb->postmeta} |
| 769 | - WHERE meta_key LIKE '_yoast_wpseo_%' | |
| 785 | + WHERE meta_key LIKE %s | |
| 770 | 786 | AND post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 771 | - "); | |
| 787 | + ", '_yoast_wpseo_%')); | |
| 772 | 788 | |
| 773 | 789 | // Get batch of posts with Yoast robots meta |
| 790 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 774 | 791 | $posts = $wpdb->get_results($wpdb->prepare(" |
| 775 | 792 | SELECT DISTINCT post_id |
| 776 | 793 | FROM {$wpdb->postmeta} |
| 777 | - WHERE meta_key LIKE '_yoast_wpseo_%' | |
| 794 | + WHERE meta_key LIKE %s | |
| 778 | 795 | AND post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 779 | 796 | ORDER BY post_id ASC |
| 780 | 797 | LIMIT %d OFFSET %d |
| 781 | - ", $batch_size, $offset)); | |
| 798 | + ", '_yoast_wpseo_%', $batch_size, $offset)); | |
| 782 | 799 | |
| 783 | 800 | foreach ($posts as $post_obj) { |
| 784 | 801 | $post_id = $post_obj->post_id; |
| 785 | 802 | $has_changes = false; |
| @@ -903,24 +920,26 @@ | ||
| 903 | 920 | $batch_size = intval($options['batch_size']); |
| 904 | 921 | $offset = intval($options['offset']); |
| 905 | 922 | |
| 906 | 923 | // Get total count (for progress tracking) |
| 907 | - $total = (int) $wpdb->get_var(" | |
| 924 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 925 | + $total = (int) $wpdb->get_var($wpdb->prepare(" | |
| 908 | 926 | SELECT COUNT(DISTINCT post_id) |
| 909 | 927 | FROM {$wpdb->postmeta} |
| 910 | - WHERE meta_key LIKE 'rank_math_%' | |
| 928 | + WHERE meta_key LIKE %s | |
| 911 | 929 | AND post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 912 | - "); | |
| 930 | + ", 'rank_math_%')); | |
| 913 | 931 | |
| 914 | 932 | // Get batch of posts with Rank Math robots meta |
| 933 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 915 | 934 | $posts = $wpdb->get_results($wpdb->prepare(" |
| 916 | 935 | SELECT DISTINCT post_id |
| 917 | 936 | FROM {$wpdb->postmeta} |
| 918 | - WHERE meta_key LIKE 'rank_math_%' | |
| 937 | + WHERE meta_key LIKE %s | |
| 919 | 938 | AND post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 920 | 939 | ORDER BY post_id ASC |
| 921 | 940 | LIMIT %d OFFSET %d |
| 922 | - ", $batch_size, $offset)); | |
| 941 | + ", 'rank_math_%', $batch_size, $offset)); | |
| 923 | 942 | |
| 924 | 943 | foreach ($posts as $post_obj) { |
| 925 | 944 | $post_id = $post_obj->post_id; |
| 926 | 945 | $has_changes = false; |
| @@ -1043,9 +1062,9 @@ | ||
| 1043 | 1062 | // AIOSEO stores data in a custom table |
| 1044 | 1063 | $aioseo_table = $wpdb->prefix . 'aioseo_posts'; |
| 1045 | 1064 | |
| 1046 | 1065 | // Check if table exists |
| 1047 | - $table_exists = $wpdb->get_var("SHOW TABLES LIKE '$aioseo_table'") === $aioseo_table; | |
| 1066 | + $table_exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->esc_like($aioseo_table))) === $aioseo_table; // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 1048 | 1067 | |
| 1049 | 1068 | if (!$table_exists) { |
| 1050 | 1069 | return ['success' => false, 'message' => 'AIOSEO table not found.']; |
| 1051 | 1070 | } |
| @@ -1050,21 +1069,23 @@ | ||
| 1050 | 1069 | return ['success' => false, 'message' => 'AIOSEO table not found.']; |
| 1051 | 1070 | } |
| 1052 | 1071 | |
| 1053 | 1072 | // Get total count (for progress tracking) |
| 1073 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 1054 | 1074 | $total = (int) $wpdb->get_var(" |
| 1055 | 1075 | SELECT COUNT(*) |
| 1056 | - FROM {$aioseo_table} | |
| 1076 | + FROM {$wpdb->prefix}aioseo_posts | |
| 1057 | 1077 | WHERE post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 1058 | 1078 | "); |
| 1059 | 1079 | |
| 1060 | 1080 | // Get batch of posts with AIOSEO settings |
| 1081 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 1061 | 1082 | $posts = $wpdb->get_results($wpdb->prepare(" |
| 1062 | 1083 | SELECT post_id, robots_default, robots_noindex, robots_nofollow, |
| 1063 | 1084 | robots_noarchive, robots_nosnippet, robots_noimageindex, |
| 1064 | 1085 | robots_max_snippet, robots_max_imagepreview, robots_max_videopreview, |
| 1065 | 1086 | canonical_url |
| 1066 | - FROM {$aioseo_table} | |
| 1087 | + FROM {$wpdb->prefix}aioseo_posts | |
| 1067 | 1088 | WHERE post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 1068 | 1089 | ORDER BY post_id ASC |
| 1069 | 1090 | LIMIT %d OFFSET %d |
| 1070 | 1091 | ", $batch_size, $offset)); |
| @@ -1216,8 +1237,9 @@ | ||
| 1216 | 1237 | global $wpdb; |
| 1217 | 1238 | $imported_count = 0; |
| 1218 | 1239 | |
| 1219 | 1240 | // First, try to import from full schema JSON (free version or old approach) |
| 1241 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 1220 | 1242 | $posts = $wpdb->get_results(" |
| 1221 | 1243 | SELECT post_id, meta_value |
| 1222 | 1244 | FROM {$wpdb->postmeta} |
| 1223 | 1245 | WHERE meta_key = '_yoast_wpseo_schema' |
| @@ -1242,14 +1264,15 @@ | ||
| 1242 | 1264 | // Convert Yoast schema to Metasync format |
| 1243 | 1265 | $metasync_schema = $this->convert_yoast_schema_to_metasync($yoast_schema, $post_id); |
| 1244 | 1266 | |
| 1245 | 1267 | if (!empty($metasync_schema['types'])) { |
| 1246 | - update_post_meta($post_id, 'metasync_schema_markup', $metasync_schema); | |
| 1268 | + update_post_meta($post_id, 'metasync_schema_markup', wp_slash(array_merge(is_array($existing_schema) ? $existing_schema : [], $metasync_schema))); | |
| 1247 | 1269 | $imported_count++; |
| 1248 | 1270 | } |
| 1249 | 1271 | } |
| 1250 | 1272 | |
| 1251 | 1273 | // Second, try to import from schema type (Premium version) |
| 1274 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 1252 | 1275 | $posts = $wpdb->get_results(" |
| 1253 | 1276 | SELECT post_id, meta_value |
| 1254 | 1277 | FROM {$wpdb->postmeta} |
| 1255 | 1278 | WHERE meta_key = '_yoast_wpseo_schema_article_type' |
| @@ -1285,9 +1308,9 @@ | ||
| 1285 | 1308 | ] |
| 1286 | 1309 | ] |
| 1287 | 1310 | ]; |
| 1288 | 1311 | |
| 1289 | - update_post_meta($post_id, 'metasync_schema_markup', $metasync_schema); | |
| 1312 | + update_post_meta($post_id, 'metasync_schema_markup', wp_slash(array_merge(is_array($existing_schema) ? $existing_schema : [], $metasync_schema))); | |
| 1290 | 1313 | $imported_count++; |
| 1291 | 1314 | } |
| 1292 | 1315 | } |
| 1293 | 1316 | |
| @@ -1303,8 +1326,9 @@ | ||
| 1303 | 1326 | $imported_count = 0; |
| 1304 | 1327 | |
| 1305 | 1328 | // Get all posts with any Rank Math schema (dynamically detect schema types) |
| 1306 | 1329 | // Exclude shortcode schemas |
| 1330 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 1307 | 1331 | $posts = $wpdb->get_results(" |
| 1308 | 1332 | SELECT DISTINCT pm.post_id, pm.meta_key, pm.meta_value |
| 1309 | 1333 | FROM {$wpdb->postmeta} pm |
| 1310 | 1334 | WHERE pm.meta_key LIKE 'rank_math_schema_%' |
| @@ -1341,9 +1365,9 @@ | ||
| 1341 | 1365 | // Convert Rank Math schema to Metasync format |
| 1342 | 1366 | $metasync_schema = $this->convert_rankmath_schema_to_metasync($rm_schema, $schema_type, $post_id); |
| 1343 | 1367 | |
| 1344 | 1368 | if (!empty($metasync_schema['types'])) { |
| 1345 | - update_post_meta($post_id, 'metasync_schema_markup', $metasync_schema); | |
| 1369 | + update_post_meta($post_id, 'metasync_schema_markup', wp_slash(array_merge(is_array($existing_schema) ? $existing_schema : [], $metasync_schema))); | |
| 1346 | 1370 | $imported_count++; |
| 1347 | 1371 | $processed_posts[] = $post_id; // Mark post as processed |
| 1348 | 1372 | } |
| 1349 | 1373 | } |
| @@ -1360,16 +1384,17 @@ | ||
| 1360 | 1384 | $imported_count = 0; |
| 1361 | 1385 | |
| 1362 | 1386 | // Check if AIOSEO table exists |
| 1363 | 1387 | $table = $wpdb->prefix . 'aioseo_posts'; |
| 1364 | - if ($wpdb->get_var("SHOW TABLES LIKE '$table'") !== $table) { | |
| 1388 | + if ($wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->esc_like($table))) !== $table) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 1365 | 1389 | return 0; |
| 1366 | 1390 | } |
| 1367 | 1391 | |
| 1368 | 1392 | // Get all posts with AIOSEO schema |
| 1393 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 1369 | 1394 | $posts = $wpdb->get_results(" |
| 1370 | 1395 | SELECT post_id, schema_type, schema_type_options |
| 1371 | - FROM {$table} | |
| 1396 | + FROM {$wpdb->prefix}aioseo_posts | |
| 1372 | 1397 | WHERE (schema_type IS NOT NULL AND schema_type != '') |
| 1373 | 1398 | AND post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 1374 | 1399 | "); |
| 1375 | 1400 | |
| @@ -1395,9 +1420,9 @@ | ||
| 1395 | 1420 | $post_id |
| 1396 | 1421 | ); |
| 1397 | 1422 | |
| 1398 | 1423 | if (!empty($metasync_schema['types'])) { |
| 1399 | - update_post_meta($post_id, 'metasync_schema_markup', $metasync_schema); | |
| 1424 | + update_post_meta($post_id, 'metasync_schema_markup', wp_slash(array_merge(is_array($existing_schema) ? $existing_schema : [], $metasync_schema))); | |
| 1400 | 1425 | $imported_count++; |
| 1401 | 1426 | } |
| 1402 | 1427 | } |
| 1403 | 1428 | |
| @@ -2701,9 +2726,9 @@ | ||
| 2701 | 2726 | 'resolved' => (string) $resolved, |
| 2702 | 2727 | ]; |
| 2703 | 2728 | |
| 2704 | 2729 | if (defined('WP_DEBUG') && WP_DEBUG) { |
| 2705 | - error_log(sprintf( | |
| 2730 | + error_log(sprintf( // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- debug-gated, no secrets | |
| 2706 | 2731 | 'MetaSync importer: unresolved %s placeholder for post %d (%s) — %s', |
| 2707 | 2732 | $plugin, |
| 2708 | 2733 | (int) $post_id, |
| 2709 | 2734 | $meta_key, |
| @@ -3102,22 +3127,23 @@ | ||
| 3102 | 3127 | ]; |
| 3103 | 3128 | } |
| 3104 | 3129 | |
| 3105 | 3130 | // Get total count (for progress tracking) |
| 3106 | - $meta_keys_placeholders = implode(',', array_fill(0, count($meta_keys), '%s')); | |
| 3107 | - $total_posts = (int) $wpdb->get_var($wpdb->prepare(" | |
| 3131 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 3132 | + $total_posts = (int) $wpdb->get_var($wpdb->prepare(' | |
| 3108 | 3133 | SELECT COUNT(DISTINCT post_id) |
| 3109 | - FROM {$wpdb->postmeta} | |
| 3110 | - WHERE meta_key IN ($meta_keys_placeholders) | |
| 3134 | + FROM ' . $wpdb->postmeta . ' | |
| 3135 | + WHERE meta_key IN (' . implode(',', array_fill(0, count($meta_keys), '%s')) . ") | |
| 3111 | 3136 | AND meta_value != '' |
| 3112 | 3137 | AND post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 3113 | 3138 | ", $meta_keys)); |
| 3114 | 3139 | |
| 3115 | 3140 | // Get batch of posts with Yoast data |
| 3116 | - $posts = $wpdb->get_results($wpdb->prepare(" | |
| 3141 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 3142 | + $posts = $wpdb->get_results($wpdb->prepare(' | |
| 3117 | 3143 | SELECT DISTINCT post_id |
| 3118 | - FROM {$wpdb->postmeta} | |
| 3119 | - WHERE meta_key IN ($meta_keys_placeholders) | |
| 3144 | + FROM ' . $wpdb->postmeta . ' | |
| 3145 | + WHERE meta_key IN (' . implode(',', array_fill(0, count($meta_keys), '%s')) . ") | |
| 3120 | 3146 | AND meta_value != '' |
| 3121 | 3147 | AND post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 3122 | 3148 | ORDER BY post_id ASC |
| 3123 | 3149 | LIMIT %d OFFSET %d |
| @@ -3304,22 +3330,23 @@ | ||
| 3304 | 3330 | ]; |
| 3305 | 3331 | } |
| 3306 | 3332 | |
| 3307 | 3333 | // Get total count |
| 3308 | - $meta_keys_placeholders = implode(',', array_fill(0, count($meta_keys), '%s')); | |
| 3309 | - $total_posts = (int) $wpdb->get_var($wpdb->prepare(" | |
| 3334 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 3335 | + $total_posts = (int) $wpdb->get_var($wpdb->prepare(' | |
| 3310 | 3336 | SELECT COUNT(DISTINCT post_id) |
| 3311 | - FROM {$wpdb->postmeta} | |
| 3312 | - WHERE meta_key IN ($meta_keys_placeholders) | |
| 3337 | + FROM ' . $wpdb->postmeta . ' | |
| 3338 | + WHERE meta_key IN (' . implode(',', array_fill(0, count($meta_keys), '%s')) . ") | |
| 3313 | 3339 | AND meta_value != '' |
| 3314 | 3340 | AND post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 3315 | 3341 | ", $meta_keys)); |
| 3316 | 3342 | |
| 3317 | 3343 | // Get batch of posts |
| 3318 | - $posts = $wpdb->get_results($wpdb->prepare(" | |
| 3344 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 3345 | + $posts = $wpdb->get_results($wpdb->prepare(' | |
| 3319 | 3346 | SELECT DISTINCT post_id |
| 3320 | - FROM {$wpdb->postmeta} | |
| 3321 | - WHERE meta_key IN ($meta_keys_placeholders) | |
| 3347 | + FROM ' . $wpdb->postmeta . ' | |
| 3348 | + WHERE meta_key IN (' . implode(',', array_fill(0, count($meta_keys), '%s')) . ") | |
| 3322 | 3349 | AND meta_value != '' |
| 3323 | 3350 | AND post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 3324 | 3351 | ORDER BY post_id ASC |
| 3325 | 3352 | LIMIT %d OFFSET %d |
| @@ -3481,9 +3508,9 @@ | ||
| 3481 | 3508 | $overwrite = (bool) $options['overwrite_existing']; |
| 3482 | 3509 | |
| 3483 | 3510 | // Check if AIOSEO table exists |
| 3484 | 3511 | $table = $wpdb->prefix . 'aioseo_posts'; |
| 3485 | - if ($wpdb->get_var("SHOW TABLES LIKE '$table'") !== $table) { | |
| 3512 | + if ($wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->esc_like($table))) !== $table) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 3486 | 3513 | return [ |
| 3487 | 3514 | 'success' => false, |
| 3488 | 3515 | 'message' => 'AIOSEO database table not found.' |
| 3489 | 3516 | ]; |
| @@ -3573,16 +3600,18 @@ | ||
| 3573 | 3600 | // one registered non-public — can still carry per-post overrides that |
| 3574 | 3601 | // the override-only walk always imported. The second arm keeps every |
| 3575 | 3602 | // row holding real AIOSEO data in scope whatever its post type, so |
| 3576 | 3603 | // adding a template never removes anything from the import. |
| 3604 | + // $joined_has_value is built only from the fixed $value_columns | |
| 3605 | + // allowlist above; table names are inline literals. | |
| 3577 | 3606 | $from_clause = "FROM {$wpdb->posts} p |
| 3578 | - LEFT JOIN {$table} a ON a.post_id = p.ID | |
| 3607 | + LEFT JOIN {$wpdb->prefix}aioseo_posts a ON a.post_id = p.ID | |
| 3579 | 3608 | WHERE p.post_status = 'publish' |
| 3580 | - AND (p.post_type IN ({$type_placeholders}) OR ({$joined_has_value}))"; | |
| 3609 | + AND (p.post_type IN (" . implode(', ', array_fill(0, count($template_post_types), '%s')) . ") OR ({$joined_has_value}))"; | |
| 3581 | 3610 | |
| 3582 | - $total_posts = (int) $wpdb->get_var( | |
| 3583 | - $wpdb->prepare("SELECT COUNT(*) {$from_clause}", $template_post_types) | |
| 3584 | - ); | |
| 3611 | + // Assembled from the literal fragments above; post types bind via prepare(). | |
| 3612 | + $count_query = "SELECT COUNT(*) {$from_clause}"; | |
| 3613 | + $total_posts = (int) $wpdb->get_var($wpdb->prepare($count_query, $template_post_types)); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- fragments built from fixed allowlists, values bound via prepare() | |
| 3585 | 3614 | |
| 3586 | 3615 | $joined_columns = array_map( |
| 3587 | 3616 | function ($column) { |
| 3588 | 3617 | return "a.{$column}"; |
| @@ -3594,15 +3623,14 @@ | ||
| 3594 | 3623 | // least one value column to select. |
| 3595 | 3624 | $joined_select = 'p.ID AS post_id, p.post_type AS post_type, ' |
| 3596 | 3625 | . implode(', ', $joined_columns); |
| 3597 | 3626 | |
| 3598 | - $posts = $wpdb->get_results($wpdb->prepare( | |
| 3599 | - "SELECT {$joined_select} | |
| 3627 | + // Assembled from the literal fragments above; post types bind via prepare(). | |
| 3628 | + $posts_query = "SELECT {$joined_select} | |
| 3600 | 3629 | {$from_clause} |
| 3601 | 3630 | ORDER BY p.ID ASC |
| 3602 | - LIMIT %d OFFSET %d", | |
| 3603 | - array_merge($template_post_types, [$batch_size, $offset]) | |
| 3604 | - )); | |
| 3631 | + LIMIT %d OFFSET %d"; | |
| 3632 | + $posts = $wpdb->get_results($wpdb->prepare($posts_query, array_merge($template_post_types, [$batch_size, $offset]))); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery -- fragments built from fixed allowlists, values bound via prepare() | |
| 3605 | 3633 | } else { |
| 3606 | 3634 | // No usable templates — e.g. only the social options are selected, or |
| 3607 | 3635 | // aioseo_options_dynamic is missing. Fall back to the original |
| 3608 | 3636 | // override-only walk so those sites behave exactly as before. |
| @@ -3607,23 +3635,31 @@ | ||
| 3607 | 3635 | // aioseo_options_dynamic is missing. Fall back to the original |
| 3608 | 3636 | // override-only walk so those sites behave exactly as before. |
| 3609 | 3637 | $select_clause = implode(', ', array_merge(['post_id'], $value_columns)); |
| 3610 | 3638 | |
| 3639 | + // $where_clause / $select_clause are built only from the fixed | |
| 3640 | + // $value_columns allowlist above. | |
| 3641 | + // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $where_clause is built only from the fixed $value_columns allowlist above | |
| 3642 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 3611 | 3643 | $total_posts = (int) $wpdb->get_var(" |
| 3612 | 3644 | SELECT COUNT(post_id) |
| 3613 | - FROM {$table} | |
| 3645 | + FROM {$wpdb->prefix}aioseo_posts | |
| 3614 | 3646 | WHERE ({$where_clause}) |
| 3615 | 3647 | AND post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 3616 | 3648 | "); |
| 3649 | + // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared | |
| 3617 | 3650 | |
| 3651 | + // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $select_clause / $where_clause are built only from the fixed $value_columns allowlist above | |
| 3652 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 3618 | 3653 | $posts = $wpdb->get_results($wpdb->prepare(" |
| 3619 | 3654 | SELECT {$select_clause} |
| 3620 | - FROM {$table} | |
| 3655 | + FROM {$wpdb->prefix}aioseo_posts | |
| 3621 | 3656 | WHERE ({$where_clause}) |
| 3622 | 3657 | AND post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_status = 'publish') |
| 3623 | 3658 | ORDER BY post_id ASC |
| 3624 | 3659 | LIMIT %d OFFSET %d |
| 3625 | 3660 | ", $batch_size, $offset)); |
| 3661 | + // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared | |
| 3626 | 3662 | } |
| 3627 | 3663 | |
| 3628 | 3664 | $imported_count = 0; |
| 3629 | 3665 | $skipped_count = 0; |
| @@ -4097,9 +4133,9 @@ | ||
| 4097 | 4133 | $overwrite = (bool) $options['overwrite_existing']; |
| 4098 | 4134 | |
| 4099 | 4135 | $table = $wpdb->prefix . 'aioseo_terms'; |
| 4100 | 4136 | |
| 4101 | - $table_exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $table)); | |
| 4137 | + $table_exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $table)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 4102 | 4138 | if ($table_exists !== $table) { |
| 4103 | 4139 | return [ |
| 4104 | 4140 | 'success' => false, |
| 4105 | 4141 | 'message' => 'AIOSEO terms table not found.', |
| @@ -4105,11 +4141,11 @@ | ||
| 4105 | 4141 | 'message' => 'AIOSEO terms table not found.', |
| 4106 | 4142 | ]; |
| 4107 | 4143 | } |
| 4108 | 4144 | |
| 4109 | - $rows = $wpdb->get_results($wpdb->prepare( | |
| 4145 | + $rows = $wpdb->get_results($wpdb->prepare( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- one-shot import tool — bulk reads from third-party SEO plugin storage; no bulk WordPress API exists | |
| 4110 | 4146 | "SELECT term_id, title, description, og_title, og_description, canonical_url, robots_noindex |
| 4111 | - FROM {$table} | |
| 4147 | + FROM {$wpdb->prefix}aioseo_terms | |
| 4112 | 4148 | ORDER BY term_id ASC |
| 4113 | 4149 | LIMIT %d OFFSET %d", |
| 4114 | 4150 | $batch_size, |
| 4115 | 4151 | $offset |