Changeset 3467961
- Timestamp:
- 02/23/2026 07:14:25 PM (5 weeks ago)
- Location:
- instarank
- Files:
-
- 6 edited
- 1 copied
-
tags/2.0.5 (copied) (copied from instarank/trunk)
-
tags/2.0.5/api/endpoints.php (modified) (6 diffs)
-
tags/2.0.5/instarank.php (modified) (3 diffs)
-
tags/2.0.5/readme.txt (modified) (2 diffs)
-
trunk/api/endpoints.php (modified) (6 diffs)
-
trunk/instarank.php (modified) (3 diffs)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
instarank/tags/2.0.5/api/endpoints.php
r3427377 r3467961 989 989 $limit = intval($request->get_param('limit') ?? 100); 990 990 $offset = intval($request->get_param('offset') ?? 0); 991 $search = $request->get_param('search'); 991 992 992 993 $args = [ … … 999 1000 ]; 1000 1001 1002 if (!empty($search)) { 1003 $args['s'] = sanitize_text_field($search); 1004 } 1005 1001 1006 $query = new WP_Query($args); 1002 1007 $posts = []; … … 1004 1009 foreach ($query->posts as $post) { 1005 1010 $meta = $detector->get_post_meta($post->ID); 1011 $word_count = str_word_count(wp_strip_all_tags($post->post_content)); 1012 1013 // Detect noindex/nofollow from SEO plugin meta 1014 $noindex = false; 1015 $nofollow = false; 1016 if (!empty($meta['robots'])) { 1017 $robots = is_array($meta['robots']) ? implode(',', $meta['robots']) : $meta['robots']; 1018 $noindex = stripos($robots, 'noindex') !== false; 1019 $nofollow = stripos($robots, 'nofollow') !== false; 1020 } 1021 // Also check individual meta flags if set by SEO detector 1022 if (isset($meta['noindex'])) $noindex = (bool)$meta['noindex']; 1023 if (isset($meta['nofollow'])) $nofollow = (bool)$meta['nofollow']; 1006 1024 1007 1025 $posts[] = [ … … 1014 1032 'modified' => $post->post_modified_gmt, 1015 1033 'author' => get_the_author_meta('display_name', $post->post_author), 1034 'word_count' => $word_count, 1016 1035 'seo' => [ 1017 1036 'meta_title' => $meta['title'] ?? '', 1018 1037 'meta_description' => $meta['description'] ?? '', 1019 'focus_keyword' => $meta['focus_keyword'] ?? '' 1038 'focus_keyword' => $meta['focus_keyword'] ?? '', 1039 'noindex' => $noindex, 1040 'nofollow' => $nofollow 1020 1041 ] 1021 1042 ]; … … 2022 2043 // Handle parent page (for hierarchical post types like pages) 2023 2044 $parent_id = isset($params['parent']) ? intval($params['parent']) : 0; 2045 // Parent slug for hierarchical post type URL resolution 2046 $parent_slug_value = isset($params['parent_slug']) ? sanitize_title($params['parent_slug']) : ''; 2024 2047 2025 2048 $post_data = [ … … 2066 2089 ['status' => 500] 2067 2090 ); 2091 } 2092 2093 // Save parent slug meta for hierarchical post type URL resolution 2094 if (!empty($parent_slug_value)) { 2095 update_post_meta($post_id, '_instarank_parent_slug', $parent_slug_value); 2068 2096 } 2069 2097 -
instarank/tags/2.0.5/instarank.php
r3427377 r3467961 4 4 * Plugin URI: https://instarank.com/wordpress-plugin 5 5 * Description: Connect your WordPress site to InstaRank for AI-powered SEO optimization, schema markup generation, and programmatic SEO. Create and sync custom post types, automatically apply SEO improvements, and generate structured data with InstaRank's AI engine. 6 * Version: 2.0. 46 * Version: 2.0.5 7 7 * Author: InstaRank 8 8 * Author URI: https://instarank.com … … 18 18 19 19 // Define plugin constants 20 define('INSTARANK_VERSION', '2.0. 4');20 define('INSTARANK_VERSION', '2.0.5'); 21 21 define('INSTARANK_PLUGIN_DIR', plugin_dir_path(__FILE__)); 22 22 define('INSTARANK_PLUGIN_URL', plugin_dir_url(__FILE__)); … … 1112 1112 foreach ($stored_post_types as $slug => $data) { 1113 1113 if (isset($data['config']) && !post_type_exists($slug)) { 1114 register_post_type($slug, $data['config']); 1114 $config = $data['config']; 1115 1116 // Handle parent post type rewrite chains 1117 // If config has parent_post_type, set up rewrite with parent slug token 1118 if (!empty($config['parent_post_type'])) { 1119 $parent_slug = $config['parent_post_type']; 1120 // Add a rewrite tag for the parent slug so WordPress can parse it 1121 add_rewrite_tag('%' . $parent_slug . '%', '([^/]+)'); 1122 } 1123 1124 register_post_type($slug, $config); 1125 } 1126 } 1127 1128 // Add custom rewrite rules for parent-child post type chains 1129 foreach ($stored_post_types as $slug => $data) { 1130 if (!empty($data['config']['parent_post_type'])) { 1131 $config = $data['config']; 1132 $parent_slug = $config['parent_post_type']; 1133 $rewrite_slug = isset($config['rewrite']['slug']) ? $config['rewrite']['slug'] : $slug; 1134 1135 // Check if the rewrite slug contains the parent token pattern 1136 if (strpos($rewrite_slug, '%' . $parent_slug . '%') !== false) { 1137 // Build regex from the rewrite slug by replacing the token 1138 $regex_base = str_replace('%' . $parent_slug . '%', '([^/]+)', preg_quote($rewrite_slug, '#')); 1139 1140 // Single post: /{parent_slug}/{parent-item}/{child_slug}/{child-item}/ 1141 add_rewrite_rule( 1142 '^' . $regex_base . '/([^/]+)/?$', 1143 'index.php?post_type=' . $slug . '&' . $slug . '=$matches[2]&' . $parent_slug . '=$matches[1]', 1144 'top' 1145 ); 1146 1147 // Pagination: /{parent_slug}/{parent-item}/{child_slug}/{child-item}/page/2/ 1148 add_rewrite_rule( 1149 '^' . $regex_base . '/([^/]+)/page/([0-9]+)/?$', 1150 'index.php?post_type=' . $slug . '&' . $slug . '=$matches[2]&' . $parent_slug . '=$matches[1]&paged=$matches[3]', 1151 'top' 1152 ); 1153 1154 // Archive: /{parent_slug}/{parent-item}/{child_slug}/ 1155 add_rewrite_rule( 1156 '^' . $regex_base . '/?$', 1157 'index.php?post_type=' . $slug . '&' . $parent_slug . '=$matches[1]', 1158 'top' 1159 ); 1160 } 1115 1161 } 1116 1162 } 1117 1163 }, 5); // Priority 5 to run before default post types 1164 1165 /** 1166 * Add parent post type query vars so WordPress recognizes them 1167 */ 1168 add_filter('query_vars', function($vars) { 1169 $stored_post_types = get_option('instarank_custom_post_types', []); 1170 foreach ($stored_post_types as $slug => $data) { 1171 if (!empty($data['config']['parent_post_type'])) { 1172 $parent_slug = $data['config']['parent_post_type']; 1173 if (!in_array($parent_slug, $vars)) { 1174 $vars[] = $parent_slug; 1175 } 1176 } 1177 } 1178 return $vars; 1179 }); 1180 1181 /** 1182 * Filter post type link to replace parent slug token in URLs 1183 */ 1184 add_filter('post_type_link', function($post_link, $post) { 1185 $stored_post_types = get_option('instarank_custom_post_types', []); 1186 1187 if (isset($stored_post_types[$post->post_type])) { 1188 $config = $stored_post_types[$post->post_type]['config']; 1189 1190 if (!empty($config['parent_post_type'])) { 1191 $parent_slug = $config['parent_post_type']; 1192 $token = '%' . $parent_slug . '%'; 1193 1194 if (strpos($post_link, $token) !== false) { 1195 // Find the parent post via post meta or parent resolution 1196 $parent_value = get_post_meta($post->ID, '_instarank_parent_slug', true); 1197 1198 if (!$parent_value && $post->post_parent) { 1199 // Try to get parent post's slug 1200 $parent_post = get_post($post->post_parent); 1201 if ($parent_post) { 1202 $parent_value = $parent_post->post_name; 1203 } 1204 } 1205 1206 // Fallback: try to find parent value from resolution config meta 1207 if (!$parent_value) { 1208 $parent_config = isset($config['parent_resolution_config']) ? $config['parent_resolution_config'] : null; 1209 if ($parent_config && !empty($parent_config['column_name'])) { 1210 $col = $parent_config['column_name']; 1211 $val = get_post_meta($post->ID, $col, true); 1212 if ($val) { 1213 $parent_value = sanitize_title($val); 1214 } 1215 } 1216 } 1217 1218 // Final fallback: use "uncategorized" to avoid duplicating the post type slug in the URL 1219 if (!$parent_value) { 1220 $parent_value = 'uncategorized'; 1221 } 1222 1223 $post_link = str_replace($token, $parent_value, $post_link); 1224 } 1225 } 1226 } 1227 1228 return $post_link; 1229 }, 10, 2); 1118 1230 1119 1231 /** -
instarank/tags/2.0.5/readme.txt
r3427377 r3467961 4 4 Requires at least: 5.6 5 5 Tested up to: 6.9 6 Stable tag: 2.0. 46 Stable tag: 2.0.5 7 7 Requires PHP: 7.4 8 8 License: GPLv2 or later … … 169 169 170 170 == Changelog == 171 172 = 2.0.5 = 173 * Feature: Hierarchical post type URL support with parent-child rewrite rules 174 * Feature: Search parameter for post listing API endpoint 175 * Feature: Word count and noindex/nofollow detection in post SEO data 176 * Feature: Parent slug resolution for custom post type URL chains 177 * Enhancement: Moved robots.txt, sitemap, and LLMs.txt settings management to SaaS dashboard 178 * Enhancement: Improved agent retry handling and error recovery 171 179 172 180 = 2.0.4 = -
instarank/trunk/api/endpoints.php
r3427377 r3467961 989 989 $limit = intval($request->get_param('limit') ?? 100); 990 990 $offset = intval($request->get_param('offset') ?? 0); 991 $search = $request->get_param('search'); 991 992 992 993 $args = [ … … 999 1000 ]; 1000 1001 1002 if (!empty($search)) { 1003 $args['s'] = sanitize_text_field($search); 1004 } 1005 1001 1006 $query = new WP_Query($args); 1002 1007 $posts = []; … … 1004 1009 foreach ($query->posts as $post) { 1005 1010 $meta = $detector->get_post_meta($post->ID); 1011 $word_count = str_word_count(wp_strip_all_tags($post->post_content)); 1012 1013 // Detect noindex/nofollow from SEO plugin meta 1014 $noindex = false; 1015 $nofollow = false; 1016 if (!empty($meta['robots'])) { 1017 $robots = is_array($meta['robots']) ? implode(',', $meta['robots']) : $meta['robots']; 1018 $noindex = stripos($robots, 'noindex') !== false; 1019 $nofollow = stripos($robots, 'nofollow') !== false; 1020 } 1021 // Also check individual meta flags if set by SEO detector 1022 if (isset($meta['noindex'])) $noindex = (bool)$meta['noindex']; 1023 if (isset($meta['nofollow'])) $nofollow = (bool)$meta['nofollow']; 1006 1024 1007 1025 $posts[] = [ … … 1014 1032 'modified' => $post->post_modified_gmt, 1015 1033 'author' => get_the_author_meta('display_name', $post->post_author), 1034 'word_count' => $word_count, 1016 1035 'seo' => [ 1017 1036 'meta_title' => $meta['title'] ?? '', 1018 1037 'meta_description' => $meta['description'] ?? '', 1019 'focus_keyword' => $meta['focus_keyword'] ?? '' 1038 'focus_keyword' => $meta['focus_keyword'] ?? '', 1039 'noindex' => $noindex, 1040 'nofollow' => $nofollow 1020 1041 ] 1021 1042 ]; … … 2022 2043 // Handle parent page (for hierarchical post types like pages) 2023 2044 $parent_id = isset($params['parent']) ? intval($params['parent']) : 0; 2045 // Parent slug for hierarchical post type URL resolution 2046 $parent_slug_value = isset($params['parent_slug']) ? sanitize_title($params['parent_slug']) : ''; 2024 2047 2025 2048 $post_data = [ … … 2066 2089 ['status' => 500] 2067 2090 ); 2091 } 2092 2093 // Save parent slug meta for hierarchical post type URL resolution 2094 if (!empty($parent_slug_value)) { 2095 update_post_meta($post_id, '_instarank_parent_slug', $parent_slug_value); 2068 2096 } 2069 2097 -
instarank/trunk/instarank.php
r3427377 r3467961 4 4 * Plugin URI: https://instarank.com/wordpress-plugin 5 5 * Description: Connect your WordPress site to InstaRank for AI-powered SEO optimization, schema markup generation, and programmatic SEO. Create and sync custom post types, automatically apply SEO improvements, and generate structured data with InstaRank's AI engine. 6 * Version: 2.0. 46 * Version: 2.0.5 7 7 * Author: InstaRank 8 8 * Author URI: https://instarank.com … … 18 18 19 19 // Define plugin constants 20 define('INSTARANK_VERSION', '2.0. 4');20 define('INSTARANK_VERSION', '2.0.5'); 21 21 define('INSTARANK_PLUGIN_DIR', plugin_dir_path(__FILE__)); 22 22 define('INSTARANK_PLUGIN_URL', plugin_dir_url(__FILE__)); … … 1112 1112 foreach ($stored_post_types as $slug => $data) { 1113 1113 if (isset($data['config']) && !post_type_exists($slug)) { 1114 register_post_type($slug, $data['config']); 1114 $config = $data['config']; 1115 1116 // Handle parent post type rewrite chains 1117 // If config has parent_post_type, set up rewrite with parent slug token 1118 if (!empty($config['parent_post_type'])) { 1119 $parent_slug = $config['parent_post_type']; 1120 // Add a rewrite tag for the parent slug so WordPress can parse it 1121 add_rewrite_tag('%' . $parent_slug . '%', '([^/]+)'); 1122 } 1123 1124 register_post_type($slug, $config); 1125 } 1126 } 1127 1128 // Add custom rewrite rules for parent-child post type chains 1129 foreach ($stored_post_types as $slug => $data) { 1130 if (!empty($data['config']['parent_post_type'])) { 1131 $config = $data['config']; 1132 $parent_slug = $config['parent_post_type']; 1133 $rewrite_slug = isset($config['rewrite']['slug']) ? $config['rewrite']['slug'] : $slug; 1134 1135 // Check if the rewrite slug contains the parent token pattern 1136 if (strpos($rewrite_slug, '%' . $parent_slug . '%') !== false) { 1137 // Build regex from the rewrite slug by replacing the token 1138 $regex_base = str_replace('%' . $parent_slug . '%', '([^/]+)', preg_quote($rewrite_slug, '#')); 1139 1140 // Single post: /{parent_slug}/{parent-item}/{child_slug}/{child-item}/ 1141 add_rewrite_rule( 1142 '^' . $regex_base . '/([^/]+)/?$', 1143 'index.php?post_type=' . $slug . '&' . $slug . '=$matches[2]&' . $parent_slug . '=$matches[1]', 1144 'top' 1145 ); 1146 1147 // Pagination: /{parent_slug}/{parent-item}/{child_slug}/{child-item}/page/2/ 1148 add_rewrite_rule( 1149 '^' . $regex_base . '/([^/]+)/page/([0-9]+)/?$', 1150 'index.php?post_type=' . $slug . '&' . $slug . '=$matches[2]&' . $parent_slug . '=$matches[1]&paged=$matches[3]', 1151 'top' 1152 ); 1153 1154 // Archive: /{parent_slug}/{parent-item}/{child_slug}/ 1155 add_rewrite_rule( 1156 '^' . $regex_base . '/?$', 1157 'index.php?post_type=' . $slug . '&' . $parent_slug . '=$matches[1]', 1158 'top' 1159 ); 1160 } 1115 1161 } 1116 1162 } 1117 1163 }, 5); // Priority 5 to run before default post types 1164 1165 /** 1166 * Add parent post type query vars so WordPress recognizes them 1167 */ 1168 add_filter('query_vars', function($vars) { 1169 $stored_post_types = get_option('instarank_custom_post_types', []); 1170 foreach ($stored_post_types as $slug => $data) { 1171 if (!empty($data['config']['parent_post_type'])) { 1172 $parent_slug = $data['config']['parent_post_type']; 1173 if (!in_array($parent_slug, $vars)) { 1174 $vars[] = $parent_slug; 1175 } 1176 } 1177 } 1178 return $vars; 1179 }); 1180 1181 /** 1182 * Filter post type link to replace parent slug token in URLs 1183 */ 1184 add_filter('post_type_link', function($post_link, $post) { 1185 $stored_post_types = get_option('instarank_custom_post_types', []); 1186 1187 if (isset($stored_post_types[$post->post_type])) { 1188 $config = $stored_post_types[$post->post_type]['config']; 1189 1190 if (!empty($config['parent_post_type'])) { 1191 $parent_slug = $config['parent_post_type']; 1192 $token = '%' . $parent_slug . '%'; 1193 1194 if (strpos($post_link, $token) !== false) { 1195 // Find the parent post via post meta or parent resolution 1196 $parent_value = get_post_meta($post->ID, '_instarank_parent_slug', true); 1197 1198 if (!$parent_value && $post->post_parent) { 1199 // Try to get parent post's slug 1200 $parent_post = get_post($post->post_parent); 1201 if ($parent_post) { 1202 $parent_value = $parent_post->post_name; 1203 } 1204 } 1205 1206 // Fallback: try to find parent value from resolution config meta 1207 if (!$parent_value) { 1208 $parent_config = isset($config['parent_resolution_config']) ? $config['parent_resolution_config'] : null; 1209 if ($parent_config && !empty($parent_config['column_name'])) { 1210 $col = $parent_config['column_name']; 1211 $val = get_post_meta($post->ID, $col, true); 1212 if ($val) { 1213 $parent_value = sanitize_title($val); 1214 } 1215 } 1216 } 1217 1218 // Final fallback: use "uncategorized" to avoid duplicating the post type slug in the URL 1219 if (!$parent_value) { 1220 $parent_value = 'uncategorized'; 1221 } 1222 1223 $post_link = str_replace($token, $parent_value, $post_link); 1224 } 1225 } 1226 } 1227 1228 return $post_link; 1229 }, 10, 2); 1118 1230 1119 1231 /** -
instarank/trunk/readme.txt
r3427377 r3467961 4 4 Requires at least: 5.6 5 5 Tested up to: 6.9 6 Stable tag: 2.0. 46 Stable tag: 2.0.5 7 7 Requires PHP: 7.4 8 8 License: GPLv2 or later … … 169 169 170 170 == Changelog == 171 172 = 2.0.5 = 173 * Feature: Hierarchical post type URL support with parent-child rewrite rules 174 * Feature: Search parameter for post listing API endpoint 175 * Feature: Word count and noindex/nofollow detection in post SEO data 176 * Feature: Parent slug resolution for custom post type URL chains 177 * Enhancement: Moved robots.txt, sitemap, and LLMs.txt settings management to SaaS dashboard 178 * Enhancement: Improved agent retry handling and error recovery 171 179 172 180 = 2.0.4 =
Note: See TracChangeset
for help on using the changeset viewer.