| @@ -36,8 +36,10 @@ | ||
| 36 | 36 | 'name' => 'Yoast SEO', |
| 37 | 37 | 'class' => 'WPSEO', |
| 38 | 38 | 'function' => 'wpseo_init', |
| 39 | 39 | 'file' => 'wordpress-seo/wp-seo.php', |
| 40 | + 'extra_files' => ['wordpress-seo-premium/wp-seo-premium.php'], | |
| 41 | + 'importable' => true, | |
| 40 | 42 | ], |
| 41 | 43 | 'rankmath' => [ |
| 42 | 44 | 'name' => 'Rank Math', |
| 43 | 45 | 'class' => 'RankMath', |
| @@ -42,8 +44,10 @@ | ||
| 42 | 44 | 'name' => 'Rank Math', |
| 43 | 45 | 'class' => 'RankMath', |
| 44 | 46 | 'function' => 'rank_math', |
| 45 | 47 | 'file' => 'seo-by-rank-math/rank-math.php', |
| 48 | + 'extra_files' => ['seo-by-rank-math-pro/rank-math-pro.php'], | |
| 49 | + 'importable' => true, | |
| 46 | 50 | ], |
| 47 | 51 | 'seopress' => [ |
| 48 | 52 | 'name' => 'SEOPress', |
| 49 | 53 | 'class' => 'SEOPress', |
| @@ -48,8 +52,10 @@ | ||
| 48 | 52 | 'name' => 'SEOPress', |
| 49 | 53 | 'class' => 'SEOPress', |
| 50 | 54 | 'function' => 'seopress_init', |
| 51 | 55 | 'file' => 'wp-seopress/seopress.php', |
| 56 | + 'extra_files' => ['wp-seopress-pro/seopress-pro.php'], | |
| 57 | + 'importable' => true, | |
| 52 | 58 | ], |
| 53 | 59 | 'aioseo' => [ |
| 54 | 60 | 'name' => 'All in One SEO', |
| 55 | 61 | 'class' => 'AIOSEO', |
| @@ -54,8 +60,10 @@ | ||
| 54 | 60 | 'name' => 'All in One SEO', |
| 55 | 61 | 'class' => 'AIOSEO', |
| 56 | 62 | 'function' => 'aioseo', |
| 57 | 63 | 'file' => 'all-in-one-seo-pack/all_in_one_seo_pack.php', |
| 64 | + 'extra_files' => ['all-in-one-seo-pack-pro/all_in_one_seo_pack.php'], | |
| 65 | + 'importable' => true, | |
| 58 | 66 | ], |
| 59 | 67 | 'theseoframework' => [ |
| 60 | 68 | 'name' => 'The SEO Framework', |
| 61 | 69 | 'class' => 'The_SEO_Framework\\Load', |
| @@ -60,8 +68,10 @@ | ||
| 60 | 68 | 'name' => 'The SEO Framework', |
| 61 | 69 | 'class' => 'The_SEO_Framework\\Load', |
| 62 | 70 | 'function' => 'the_seo_framework', |
| 63 | 71 | 'file' => 'autodescription/autodescription.php', |
| 72 | + 'extra_files' => [], | |
| 73 | + 'importable' => false, | |
| 64 | 74 | ], |
| 65 | 75 | ]; |
| 66 | 76 | |
| 67 | 77 | /** |
| @@ -148,25 +158,70 @@ | ||
| 148 | 158 | } |
| 149 | 159 | |
| 150 | 160 | /** |
| 151 | 161 | * Get admin notice message |
| 152 | - * | |
| 162 | + * | |
| 153 | 163 | * @return string Notice message |
| 154 | 164 | */ |
| 155 | 165 | public static function get_notice_message(): string { |
| 156 | - $plugin_names = self::get_plugin_names(); | |
| 157 | - | |
| 158 | - if (empty($plugin_names)) { | |
| 166 | + if (!self::has_seo_plugins()) { | |
| 159 | 167 | return ''; |
| 160 | 168 | } |
| 161 | - | |
| 162 | - $plugin_list = implode(', ', $plugin_names); | |
| 163 | 169 | |
| 164 | - return sprintf( | |
| 165 | - /* translators: %s: comma-separated list of detected SEO plugin names */ | |
| 166 | - __('⚠️ SEO Plugin Detected: %s. ThinkRank will take priority for posts where you generate AI metadata. Consider disabling other SEO plugins for best results.', 'thinkrank'), | |
| 167 | - $plugin_list | |
| 168 | - ); | |
| 170 | + return __('Running more than one SEO plugin can create conflicts — duplicate meta tags, sitemaps, and schema markup that may hurt your search rankings. To avoid any SEO-related conflicts, we recommend deactivating third-party SEO plugins.', 'thinkrank'); | |
| 171 | + } | |
| 172 | + | |
| 173 | + /** | |
| 174 | + * Whether any detected plugin's SEO data can be imported into ThinkRank. | |
| 175 | + * | |
| 176 | + * @return bool True if at least one detected plugin has an importer | |
| 177 | + */ | |
| 178 | + public static function has_importable_plugin(): bool { | |
| 179 | + foreach (self::detect_plugins() as $plugin) { | |
| 180 | + if (!empty($plugin['importable'])) { | |
| 181 | + return true; | |
| 182 | + } | |
| 183 | + } | |
| 184 | + | |
| 185 | + return false; | |
| 186 | + } | |
| 187 | + | |
| 188 | + /** | |
| 189 | + * Get the human-readable name for a known plugin slug. | |
| 190 | + * | |
| 191 | + * Falls back to the slug itself when unknown, so callers always have a | |
| 192 | + * displayable label. | |
| 193 | + * | |
| 194 | + * @param string $slug Plugin slug from KNOWN_PLUGINS | |
| 195 | + * @return string Plugin name (or the slug if unknown) | |
| 196 | + */ | |
| 197 | + public static function get_plugin_name(string $slug): string { | |
| 198 | + return self::KNOWN_PLUGINS[$slug]['name'] ?? $slug; | |
| 199 | + } | |
| 200 | + | |
| 201 | + /** | |
| 202 | + * Get the active plugin files to deactivate for a detected plugin. | |
| 203 | + * | |
| 204 | + * Resolves the plugin file(s) — including premium companions such as | |
| 205 | + * Rank Math Pro — server-side from the known-plugins map, so callers | |
| 206 | + * never pass arbitrary plugin paths to deactivate_plugins(). | |
| 207 | + * | |
| 208 | + * @param string $slug Plugin slug from KNOWN_PLUGINS | |
| 209 | + * @return array Active plugin file paths (may be empty) | |
| 210 | + */ | |
| 211 | + public static function get_deactivatable_files(string $slug): array { | |
| 212 | + if (!isset(self::KNOWN_PLUGINS[$slug]) || !self::is_plugin_detected($slug)) { | |
| 213 | + return []; | |
| 214 | + } | |
| 215 | + | |
| 216 | + if (!function_exists('is_plugin_active')) { | |
| 217 | + require_once ABSPATH . 'wp-admin/includes/plugin.php'; | |
| 218 | + } | |
| 219 | + | |
| 220 | + $plugin = self::KNOWN_PLUGINS[$slug]; | |
| 221 | + $files = array_merge([$plugin['file']], $plugin['extra_files'] ?? []); | |
| 222 | + | |
| 223 | + return array_values(array_filter($files, 'is_plugin_active')); | |
| 169 | 224 | } |
| 170 | 225 | |
| 171 | 226 | /** |
| 172 | 227 | * Should show admin notice |