← All changes
|
includes/admin/importers/class-rankmath-exporter.php
+169
-27
1.26.0
→
2.14.0
View file →
| @@ -5,9 +5,9 @@ | ||
| 5 | 5 | * |
| 6 | 6 | * Reads Rank Math data from postmeta/termmeta/options and normalizes |
| 7 | 7 | * into the canonical snapshot format. |
| 8 | 8 | * |
| 9 | - * CRITICAL: rank_math_robots is a serialized array — use maybe_unserialize() | |
| 9 | + * CRITICAL: rank_math_robots is a serialized array — use Safe_Unserializer | |
| 10 | 10 | * then in_array() to check for 'noindex'/'nofollow'. |
| 11 | 11 | * |
| 12 | 12 | * @package ThinkRank\Admin\Importers |
| 13 | 13 | * @since 2.0.0 |
| @@ -182,8 +182,17 @@ | ||
| 182 | 182 | if ($log_count > 0) { |
| 183 | 183 | $types['404_logs'] = $log_count; |
| 184 | 184 | } |
| 185 | 185 | |
| 186 | + // FAQ / HowTo blocks live in post_content, not in any meta table, so | |
| 187 | + // they are invisible to every count above. Without this type they were | |
| 188 | + // never migrated at all and simply broke when Rank Math went away | |
| 189 | + // (#777). | |
| 190 | + $block_count = Block_Converter::count_posts(); | |
| 191 | + if ($block_count > 0) { | |
| 192 | + $types[Block_Converter::TYPE] = $block_count; | |
| 193 | + } | |
| 194 | + | |
| 186 | 195 | foreach ($this->option_keys as $key) { |
| 187 | 196 | if (get_option($key, null) !== null) { |
| 188 | 197 | $types['settings'] = 1; |
| 189 | 198 | break; |
| @@ -253,10 +262,10 @@ | ||
| 253 | 262 | 'object_id' => $post_id, |
| 254 | 263 | 'object_type' => 'post', |
| 255 | 264 | 'source_plugin' => $this->plugin_slug, |
| 256 | 265 | 'data' => [ |
| 257 | - 'seo_title' => $this->convert_template_variables($meta['rank_math_title'] ?? '', $post_id), | |
| 258 | - 'meta_description' => $this->convert_template_variables($meta['rank_math_description'] ?? '', $post_id), | |
| 266 | + 'seo_title' => $this->convert_post_value($meta['rank_math_title'] ?? '', $post_id), | |
| 267 | + 'meta_description' => $this->convert_post_value($meta['rank_math_description'] ?? '', $post_id), | |
| 259 | 268 | 'focus_keyword' => $primary_keyword, |
| 260 | 269 | // Full keyword list; the migrator dedupes, drops empties and |
| 261 | 270 | // caps at the ThinkRank maximum via Focus_Keywords. |
| 262 | 271 | 'focus_keywords' => $focus_keywords, |
| @@ -268,16 +277,22 @@ | ||
| 268 | 277 | 'nosnippet' => isset($robots_flags['nosnippet']) ? 1 : 0, |
| 269 | 278 | 'max_snippet' => $this->advanced_robot_int($advanced_robots, 'max-snippet'), |
| 270 | 279 | 'max_video_preview' => $this->advanced_robot_int($advanced_robots, 'max-video-preview'), |
| 271 | 280 | 'max_image_preview' => $this->advanced_robot_string($advanced_robots, 'max-image-preview'), |
| 272 | - 'og_title' => $this->convert_template_variables($meta['rank_math_facebook_title'] ?? '', $post_id), | |
| 273 | - 'og_description' => $this->convert_template_variables($meta['rank_math_facebook_description'] ?? '', $post_id), | |
| 281 | + 'og_title' => $this->convert_post_value($meta['rank_math_facebook_title'] ?? '', $post_id), | |
| 282 | + 'og_description' => $this->convert_post_value($meta['rank_math_facebook_description'] ?? '', $post_id), | |
| 274 | 283 | 'og_image' => $meta['rank_math_facebook_image'] ?? '', |
| 275 | - 'twitter_title' => $this->convert_template_variables($meta['rank_math_twitter_title'] ?? '', $post_id), | |
| 276 | - 'twitter_description' => $this->convert_template_variables($meta['rank_math_twitter_description'] ?? '', $post_id), | |
| 284 | + 'twitter_title' => $this->convert_post_value($meta['rank_math_twitter_title'] ?? '', $post_id), | |
| 285 | + 'twitter_description' => $this->convert_post_value($meta['rank_math_twitter_description'] ?? '', $post_id), | |
| 277 | 286 | 'twitter_image' => $meta['rank_math_twitter_image'] ?? '', |
| 278 | 287 | 'primary_category' => (int) ($meta['rank_math_primary_category'] ?? 0), |
| 279 | 288 | 'schema_type' => $this->resolve_schema_type($meta), |
| 289 | + // WooCommerce product identifier. Rank Math keeps it in its | |
| 290 | + // own per-post meta; ThinkRank Pro reads the canonical field | |
| 291 | + // this maps to, so a migrating store keeps the identifier | |
| 292 | + // Google asks for instead of collecting a "missing | |
| 293 | + // identifier" warning on every product (#715). | |
| 294 | + 'product_identifier' => (string) ($meta['rank_math_gtin_code'] ?? ''), | |
| 280 | 295 | // Rank Math pillar content maps directly to ThinkRank pillar content. |
| 281 | 296 | 'pillar_content' => $this->normalize_pillar_content($meta['rank_math_pillar_content'] ?? ''), |
| 282 | 297 | ], |
| 283 | 298 | 'extended' => [ |
| @@ -334,16 +349,16 @@ | ||
| 334 | 349 | 'object_id' => $term_id, |
| 335 | 350 | 'object_type' => 'term', |
| 336 | 351 | 'source_plugin' => $this->plugin_slug, |
| 337 | 352 | 'data' => [ |
| 338 | - 'seo_title' => $this->convert_term_template_variables($meta['rank_math_title'] ?? '', $term_id), | |
| 339 | - 'meta_description' => $this->convert_term_template_variables($meta['rank_math_description'] ?? '', $term_id), | |
| 353 | + 'seo_title' => $this->convert_term_value($meta['rank_math_title'] ?? '', $term_id), | |
| 354 | + 'meta_description' => $this->convert_term_value($meta['rank_math_description'] ?? '', $term_id), | |
| 340 | 355 | 'focus_keyword' => $primary_keyword, |
| 341 | 356 | 'canonical_url' => $meta['rank_math_canonical_url'] ?? '', |
| 342 | 357 | 'noindex' => $robots['noindex'], |
| 343 | 358 | 'nofollow' => $robots['nofollow'], |
| 344 | - 'og_title' => $this->convert_term_template_variables($meta['rank_math_facebook_title'] ?? '', $term_id), | |
| 345 | - 'og_description' => $this->convert_term_template_variables($meta['rank_math_facebook_description'] ?? '', $term_id), | |
| 359 | + 'og_title' => $this->convert_term_value($meta['rank_math_facebook_title'] ?? '', $term_id), | |
| 360 | + 'og_description' => $this->convert_term_value($meta['rank_math_facebook_description'] ?? '', $term_id), | |
| 346 | 361 | ], |
| 347 | 362 | 'extended' => [ |
| 348 | 363 | 'og_image' => $meta['rank_math_facebook_image'] ?? '', |
| 349 | 364 | 'twitter_title' => $meta['rank_math_twitter_title'] ?? '', |
| @@ -681,8 +696,9 @@ | ||
| 681 | 696 | |
| 682 | 697 | $offset = ($page - 1) * $this->chunk_size; |
| 683 | 698 | |
| 684 | 699 | $rows = $wpdb->get_results( |
| 700 | + // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- table name is $wpdb->prefix plus a literal, and every value is passed as a placeholder replacement. | |
| 685 | 701 | $wpdb->prepare( |
| 686 | 702 | "SELECT * FROM {$table_name} ORDER BY id ASC LIMIT %d OFFSET %d", |
| 687 | 703 | $this->chunk_size, |
| 688 | 704 | $offset |
| @@ -688,8 +704,9 @@ | ||
| 688 | 704 | $offset |
| 689 | 705 | ), |
| 690 | 706 | ARRAY_A |
| 691 | 707 | ); |
| 708 | + // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared | |
| 692 | 709 | |
| 693 | 710 | // One rule can fan out into several records, so pagination must key off |
| 694 | 711 | // the number of ROWS fetched, not the number of records emitted. |
| 695 | 712 | $this->last_page_row_count = is_array($rows) ? count($rows) : 0; |
| @@ -705,9 +722,9 @@ | ||
| 705 | 722 | // rows — ONE rule can match many source URLs. ThinkRank's redirect |
| 706 | 723 | // table is one row per source, so fan each source out into its own |
| 707 | 724 | // record rather than keeping only the first (which silently dropped |
| 708 | 725 | // every additional source). |
| 709 | - $sources = maybe_unserialize($row['sources'] ?? ''); | |
| 726 | + $sources = Safe_Unserializer::unserialize($row['sources'] ?? ''); | |
| 710 | 727 | if (!is_array($sources) || empty($sources)) { |
| 711 | 728 | continue; |
| 712 | 729 | } |
| 713 | 730 | |
| @@ -748,8 +765,40 @@ | ||
| 748 | 765 | |
| 749 | 766 | /** |
| 750 | 767 | * {@inheritDoc} |
| 751 | 768 | * |
| 769 | + * `content_blocks` records carry post ids only. The blocks themselves stay | |
| 770 | + * in `post_content` and are rewritten in place at migrate time — copying | |
| 771 | + * the content into the snapshot would mean holding a second copy of every | |
| 772 | + * FAQ page in `wp_options`, which is where snapshots live. | |
| 773 | + */ | |
| 774 | + protected function export_custom_type_page(string $type, int $page): array { | |
| 775 | + if (Block_Converter::TYPE !== $type) { | |
| 776 | + return parent::export_custom_type_page($type, $page); | |
| 777 | + } | |
| 778 | + | |
| 779 | + $post_ids = Block_Converter::get_post_ids($page, $this->chunk_size); | |
| 780 | + | |
| 781 | + // export_chunk() decides whether another page follows from the number | |
| 782 | + // of rows the query returned, so report it even when nothing is emitted. | |
| 783 | + $this->last_page_row_count = count($post_ids); | |
| 784 | + | |
| 785 | + $records = []; | |
| 786 | + foreach ($post_ids as $post_id) { | |
| 787 | + $records[] = [ | |
| 788 | + 'object_id' => $post_id, | |
| 789 | + 'object_type' => 'post', | |
| 790 | + 'source_plugin' => $this->plugin_slug, | |
| 791 | + 'data' => ['post_id' => $post_id], | |
| 792 | + ]; | |
| 793 | + } | |
| 794 | + | |
| 795 | + return $records; | |
| 796 | + } | |
| 797 | + | |
| 798 | + /** | |
| 799 | + * {@inheritDoc} | |
| 800 | + * | |
| 752 | 801 | * Rank Math's 404 monitor keeps one row per URI in `rank_math_404_logs`, |
| 753 | 802 | * which lines up with ThinkRank Pro's `thinkrank_404_logs`. |
| 754 | 803 | */ |
| 755 | 804 | protected function export_404_logs_page(int $page): array { |
| @@ -765,8 +814,9 @@ | ||
| 765 | 814 | $offset = ($page - 1) * $this->chunk_size; |
| 766 | 815 | |
| 767 | 816 | // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.InterpolatedNotPrepared |
| 768 | 817 | $rows = $wpdb->get_results( |
| 818 | + // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- table name is $wpdb->prefix plus a literal, and every value is passed as a placeholder replacement. | |
| 769 | 819 | $wpdb->prepare( |
| 770 | 820 | "SELECT * FROM {$table_name} ORDER BY id ASC LIMIT %d OFFSET %d", |
| 771 | 821 | $this->chunk_size, |
| 772 | 822 | $offset |
| @@ -772,8 +822,9 @@ | ||
| 772 | 822 | $offset |
| 773 | 823 | ), |
| 774 | 824 | ARRAY_A |
| 775 | 825 | ); |
| 826 | + // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared | |
| 776 | 827 | |
| 777 | 828 | $this->last_page_row_count = is_array($rows) ? count($rows) : 0; |
| 778 | 829 | |
| 779 | 830 | if (empty($rows)) { |
| @@ -901,9 +952,9 @@ | ||
| 901 | 952 | if (strpos($key, 'rank_math_schema_') !== 0) { |
| 902 | 953 | continue; |
| 903 | 954 | } |
| 904 | 955 | |
| 905 | - $schema = maybe_unserialize($value); | |
| 956 | + $schema = Safe_Unserializer::unserialize($value); | |
| 906 | 957 | if (!is_array($schema)) { |
| 907 | 958 | continue; |
| 908 | 959 | } |
| 909 | 960 | |
| @@ -945,18 +996,80 @@ | ||
| 945 | 996 | return self::MODERN_SCHEMA_TYPE_MAP[$key] ?? ''; |
| 946 | 997 | } |
| 947 | 998 | |
| 948 | 999 | /** |
| 1000 | + * Rank Math per-post tokens ThinkRank resolves per request (#886): kept | |
| 1001 | + * as tags rather than frozen into text. Same vocabulary as | |
| 1002 | + * convert_template_tokens(). | |
| 1003 | + */ | |
| 1004 | + private const POST_TOKENS = [ | |
| 1005 | + '%title%' => '%title%', | |
| 1006 | + '%sitename%' => '%sitename%', | |
| 1007 | + '%sep%' => '%sep%', | |
| 1008 | + '%excerpt%' => '%excerpt%', | |
| 1009 | + '%date%' => '%date%', | |
| 1010 | + '%modified%' => '%modified%', | |
| 1011 | + '%name%' => '%author%', | |
| 1012 | + '%category%' => '%category%', | |
| 1013 | + '%wc_price%' => '%price%', | |
| 1014 | + '%wc_sku%' => '%sku%', | |
| 1015 | + '%wc_shortdesc%' => '%short_description%', | |
| 1016 | + '%wc_brand%' => '%brand%', | |
| 1017 | + ]; | |
| 1018 | + | |
| 1019 | + /** | |
| 1020 | + * Rank Math per-term tokens ThinkRank resolves on a term archive. | |
| 1021 | + */ | |
| 1022 | + private const TERM_TOKENS = [ | |
| 1023 | + '%term%' => '%term%', | |
| 1024 | + '%term_description%' => '%excerpt%', | |
| 1025 | + '%sitename%' => '%sitename%', | |
| 1026 | + '%sep%' => '%sep%', | |
| 1027 | + ]; | |
| 1028 | + | |
| 1029 | + /** | |
| 1030 | + * A per-post Rank Math value: mapped tokens as ThinkRank tags, the rest literal. | |
| 1031 | + * | |
| 1032 | + * @param mixed $value Raw Rank Math value | |
| 1033 | + * @param int $post_id Post ID | |
| 1034 | + * @return string | |
| 1035 | + */ | |
| 1036 | + private function convert_post_value($value, int $post_id): string { | |
| 1037 | + return $this->tokenize_object_template( | |
| 1038 | + $this->stringify_template_value($value), | |
| 1039 | + self::literal_token_patterns(self::POST_TOKENS), | |
| 1040 | + fn(string $rest): string => $this->convert_template_variables($rest, $post_id) | |
| 1041 | + ); | |
| 1042 | + } | |
| 1043 | + | |
| 1044 | + /** | |
| 1045 | + * A per-term Rank Math value: mapped tokens as ThinkRank tags, the rest literal. | |
| 1046 | + * | |
| 1047 | + * @param mixed $value Raw Rank Math value | |
| 1048 | + * @param int $term_id Term ID | |
| 1049 | + * @return string | |
| 1050 | + */ | |
| 1051 | + private function convert_term_value($value, int $term_id): string { | |
| 1052 | + return $this->tokenize_object_template( | |
| 1053 | + $this->stringify_template_value($value), | |
| 1054 | + self::literal_token_patterns(self::TERM_TOKENS), | |
| 1055 | + fn(string $rest): string => $this->convert_term_template_variables($rest, $term_id) | |
| 1056 | + ); | |
| 1057 | + } | |
| 1058 | + | |
| 1059 | + /** | |
| 949 | 1060 | * Resolve a Rank Math TERM title/description value, replacing the |
| 950 | 1061 | * term-context tokens (%term%, %term_description%) Rank Math uses for term |
| 951 | 1062 | * archives before delegating to the shared variable resolver. Without this |
| 952 | 1063 | * the term name is stripped and titles render as "Archives - Site". |
| 953 | 1064 | * |
| 954 | - * @param string $value Raw Rank Math term meta value | |
| 955 | - * @param int $term_id Term ID for context | |
| 1065 | + * @param mixed $value Raw Rank Math term meta value | |
| 1066 | + * @param int $term_id Term ID for context | |
| 956 | 1067 | * @return string Resolved value |
| 957 | 1068 | */ |
| 958 | - private function convert_term_template_variables(string $value, int $term_id): string { | |
| 1069 | + private function convert_term_template_variables($value, int $term_id): string { | |
| 1070 | + // Same foreign-data rule as convert_template_variables (see abstract). | |
| 1071 | + $value = $this->stringify_template_value($value); | |
| 959 | 1072 | if ($value === '' || strpos($value, '%') === false) { |
| 960 | 1073 | return $value; |
| 961 | 1074 | } |
| 962 | 1075 | |
| @@ -972,9 +1085,13 @@ | ||
| 972 | 1085 | // Collapse whitespace left where a token (e.g. %page%) resolved to ''. |
| 973 | 1086 | return trim((string) preg_replace('/\s{2,}/', ' ', $this->convert_template_variables($value))); |
| 974 | 1087 | } |
| 975 | 1088 | |
| 976 | - protected function convert_template_variables(string $value, ?int $post_id = null): string { | |
| 1089 | + protected function convert_template_variables($value, ?int $post_id = null): string { | |
| 1090 | + // Foreign data first: booleans/arrays in the source plugin's options | |
| 1091 | + // must degrade to '' here, not fatal the migration (see abstract). | |
| 1092 | + $value = $this->stringify_template_value($value); | |
| 1093 | + | |
| 977 | 1094 | if (empty($value) || strpos($value, '%') === false) { |
| 978 | 1095 | return $value; |
| 979 | 1096 | } |
| 980 | 1097 | |
| @@ -992,9 +1109,12 @@ | ||
| 992 | 1109 | if ($post_id) { |
| 993 | 1110 | $post = get_post($post_id); |
| 994 | 1111 | if ($post) { |
| 995 | 1112 | $replacements['%title%'] = $post->post_title; |
| 996 | - $replacements['%excerpt%'] = wp_trim_words($post->post_excerpt ?: wp_trim_words(wp_strip_all_tags($post->post_content), 55), 55); | |
| 1113 | + $replacements['%excerpt%'] = \ThinkRank\Core\Seo_Text::trim_words( | |
| 1114 | + $post->post_excerpt ?: \ThinkRank\Core\Seo_Text::trim_words(wp_strip_all_tags($post->post_content), 55), | |
| 1115 | + 55 | |
| 1116 | + ); | |
| 997 | 1117 | $replacements['%date%'] = get_the_date('', $post); |
| 998 | 1118 | $replacements['%modified%'] = get_the_modified_date('', $post); |
| 999 | 1119 | $replacements['%id%'] = (string) $post_id; |
| 1000 | 1120 | $replacements['%name%'] = get_the_author_meta('display_name', (int) $post->post_author); |
| @@ -1032,12 +1152,16 @@ | ||
| 1032 | 1152 | * a direct equivalent are renamed; tokens ThinkRank cannot resolve (e.g. |
| 1033 | 1153 | * %page%, %pt_single%, %currentyear%) are stripped so they never render |
| 1034 | 1154 | * literally on the frontend. |
| 1035 | 1155 | * |
| 1036 | - * @param string $template Raw Rank Math template | |
| 1156 | + * @param mixed $template Raw Rank Math template | |
| 1037 | 1157 | * @return string ThinkRank-compatible template |
| 1038 | 1158 | */ |
| 1039 | - private function convert_template_tokens(string $template): string { | |
| 1159 | + private function convert_template_tokens($template): string { | |
| 1160 | + // Foreign data first: booleans/arrays in the source plugin's options | |
| 1161 | + // must degrade to '' here, not fatal the migration (see abstract). | |
| 1162 | + $template = $this->stringify_template_value($template); | |
| 1163 | + | |
| 1040 | 1164 | if (empty($template) || strpos($template, '%') === false) { |
| 1041 | 1165 | return $template; |
| 1042 | 1166 | } |
| 1043 | 1167 | |
| @@ -1043,13 +1167,25 @@ | ||
| 1043 | 1167 | |
| 1044 | 1168 | // Rank Math token => ThinkRank Global SEO token (structure preserved). |
| 1045 | 1169 | $token_map = [ |
| 1046 | 1170 | '%name%' => '%author%', // Rank Math author display name token |
| 1171 | + // WooCommerce product variables. Rank Math lets a product title or | |
| 1172 | + // description carry the price, SKU and stock status; every one of | |
| 1173 | + // them used to be stripped by the pass below, so "Buy %title% for | |
| 1174 | + // %wc_price%" imported as "Buy %title% for" (#715). | |
| 1175 | + '%wc_price%' => '%price%', | |
| 1176 | + '%wc_sku%' => '%sku%', | |
| 1177 | + '%wc_shortdesc%' => '%short_description%', | |
| 1178 | + '%wc_brand%' => '%brand%', | |
| 1047 | 1179 | ]; |
| 1048 | 1180 | $template = str_replace(array_keys($token_map), array_values($token_map), $template); |
| 1049 | 1181 | |
| 1050 | 1182 | // Tokens ThinkRank's Global SEO engine resolves natively — keep as-is. |
| 1051 | - $supported = ['%title%', '%sitename%', '%sep%', '%excerpt%', '%date%', '%modified%', '%author%', '%category%']; | |
| 1183 | + $supported = [ | |
| 1184 | + '%title%', '%sitename%', '%sep%', '%excerpt%', '%date%', '%modified%', '%author%', '%category%', | |
| 1185 | + // Resolved by Pattern_Resolver on a product, empty elsewhere. | |
| 1186 | + '%price%', '%sale_price%', '%sku%', '%stock_status%', '%short_description%', '%brand%', | |
| 1187 | + ]; | |
| 1052 | 1188 | |
| 1053 | 1189 | // Strip any token ThinkRank cannot resolve so it does not render literally. |
| 1054 | 1190 | $template = preg_replace_callback( |
| 1055 | 1191 | '/%[a-z0-9_]+%/i', |
| @@ -1076,9 +1212,13 @@ | ||
| 1076 | 1212 | * |
| 1077 | 1213 | * @param string $format Raw Rank Math image format |
| 1078 | 1214 | * @return string ThinkRank-compatible image format |
| 1079 | 1215 | */ |
| 1080 | - private function convert_image_tokens(string $format): string { | |
| 1216 | + private function convert_image_tokens($format): string { | |
| 1217 | + // Foreign data first: booleans/arrays in the source plugin's options | |
| 1218 | + // must degrade to '' here, not fatal the migration (see abstract). | |
| 1219 | + $format = $this->stringify_template_value($format); | |
| 1220 | + | |
| 1081 | 1221 | if ($format === '' || strpos($format, '%') === false) { |
| 1082 | 1222 | return $format; |
| 1083 | 1223 | } |
| 1084 | 1224 | |
| @@ -1111,9 +1251,11 @@ | ||
| 1111 | 1251 | |
| 1112 | 1252 | foreach ($meta as $key => $value) { |
| 1113 | 1253 | if (strpos($key, 'rank_math_schema_') === 0) { |
| 1114 | 1254 | $schema_key = str_replace('rank_math_schema_', '', $key); |
| 1115 | - $details[$schema_key] = maybe_unserialize($value); | |
| 1255 | + // Schema blocks are always arrays; anything else is malformed | |
| 1256 | + // source data and must not travel further into the migrator. | |
| 1257 | + $details[$schema_key] = Safe_Unserializer::to_array($value); | |
| 1116 | 1258 | } |
| 1117 | 1259 | } |
| 1118 | 1260 | |
| 1119 | 1261 | return $details; |
| @@ -1169,9 +1311,9 @@ | ||
| 1169 | 1311 | foreach ($meta as $key => $value) { |
| 1170 | 1312 | if (strpos($key, 'rank_math_schema_') !== 0) { |
| 1171 | 1313 | continue; |
| 1172 | 1314 | } |
| 1173 | - $schema = maybe_unserialize($value); | |
| 1315 | + $schema = Safe_Unserializer::unserialize($value); | |
| 1174 | 1316 | if (!is_array($schema)) { |
| 1175 | 1317 | continue; |
| 1176 | 1318 | } |
| 1177 | 1319 | $type = strtolower((string) ($schema['@type'] ?? substr($key, strlen('rank_math_schema_')))); |
| @@ -1232,9 +1374,9 @@ | ||
| 1232 | 1374 | * @param mixed $robots_raw Raw (serialized) rank_math_robots value |
| 1233 | 1375 | * @return array Map of present flag => true (noarchive/noimageindex/nosnippet) |
| 1234 | 1376 | */ |
| 1235 | 1377 | private function extract_robots_flags($robots_raw): array { |
| 1236 | - $robots = maybe_unserialize($robots_raw); | |
| 1378 | + $robots = Safe_Unserializer::unserialize($robots_raw); | |
| 1237 | 1379 | if (!is_array($robots)) { |
| 1238 | 1380 | return []; |
| 1239 | 1381 | } |
| 1240 | 1382 | |
| @@ -1273,9 +1415,9 @@ | ||
| 1273 | 1415 | * @param mixed $raw Raw (serialized) meta value |
| 1274 | 1416 | * @return array Associative directive => value map (empty when unset) |
| 1275 | 1417 | */ |
| 1276 | 1418 | private function parse_advanced_robots_meta($raw): array { |
| 1277 | - $advanced = maybe_unserialize($raw); | |
| 1419 | + $advanced = Safe_Unserializer::unserialize($raw); | |
| 1278 | 1420 | return is_array($advanced) ? $advanced : []; |
| 1279 | 1421 | } |
| 1280 | 1422 | |
| 1281 | 1423 | /** |
| @@ -1700,9 +1842,9 @@ | ||
| 1700 | 1842 | if (isset($titles["pt_{$pt}_description"])) { |
| 1701 | 1843 | $pt_settings['description_template'] = $this->convert_template_tokens($titles["pt_{$pt}_description"]); |
| 1702 | 1844 | } |
| 1703 | 1845 | if (isset($titles["pt_{$pt}_robots"])) { |
| 1704 | - $pt_settings['robots'] = maybe_unserialize($titles["pt_{$pt}_robots"]); | |
| 1846 | + $pt_settings['robots'] = Safe_Unserializer::to_array($titles["pt_{$pt}_robots"]); | |
| 1705 | 1847 | } |
| 1706 | 1848 | // Rank Math's per-type Link Suggestions toggle maps onto ThinkRank's |
| 1707 | 1849 | // global-SEO `link_suggestions` (which gates the Pillar Content column |
| 1708 | 1850 | // and post-list filter). Only captured when Rank Math stored a value. |