PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 1.1.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v1.1.0
2.7.0 2.6.0 2.5.0 2.4.0 2.3.0 2.2.0 2.1.1 2.1.0 2.0.2 2.0.1 2.0.0 1.32.0 1.31.0 1.30.0 1.29.0 1.28.0 1.27.0 1.26.0 1.25.0 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.10.0 All 48 releases
thinkrank / includes / core / class-seo-plugin-detector.php

class-seo-plugin-detector.php in ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO 1.1.0, at includes/core/class-seo-plugin-detector.php

214 lines 5.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * SEO Plugin Detector
4 *
5 * Simple detection of popular SEO plugins
6 *
7 * @package ThinkRank\Core
8 * @since 1.0.0
9 */
10
11 declare(strict_types=1);
12
13 namespace ThinkRank\Core;
14
15 // Prevent direct access
16 if (!defined('ABSPATH')) {
17 exit;
18 }
19
20 /**
21 * SEO Plugin Detector Class
22 *
23 * Single Responsibility: Detect popular SEO plugins
24 *
25 * @since 1.0.0
26 */
27 class SEO_Plugin_Detector {
28
29 /**
30 * Known SEO plugins
31 *
32 * @var array
33 */
34 private const KNOWN_PLUGINS = [
35 'yoast' => [
36 'name' => 'Yoast SEO',
37 'class' => 'WPSEO',
38 'function' => 'wpseo_init',
39 'file' => 'wordpress-seo/wp-seo.php',
40 ],
41 'rankmath' => [
42 'name' => 'Rank Math',
43 'class' => 'RankMath',
44 'function' => 'rank_math',
45 'file' => 'seo-by-rank-math/rank-math.php',
46 ],
47 'seopress' => [
48 'name' => 'SEOPress',
49 'class' => 'SEOPress',
50 'function' => 'seopress_init',
51 'file' => 'wp-seopress/seopress.php',
52 ],
53 'aioseo' => [
54 'name' => 'All in One SEO',
55 'class' => 'AIOSEO',
56 'function' => 'aioseo',
57 'file' => 'all-in-one-seo-pack/all_in_one_seo_pack.php',
58 ],
59 'theseoframework' => [
60 'name' => 'The SEO Framework',
61 'class' => 'The_SEO_Framework\\Load',
62 'function' => 'the_seo_framework',
63 'file' => 'autodescription/autodescription.php',
64 ],
65 ];
66
67 /**
68 * Detected plugins cache
69 *
70 * @var array|null
71 */
72 private static ?array $detected_plugins = null;
73
74 /**
75 * Detect active SEO plugins
76 *
77 * @return array Detected plugins
78 */
79 public static function detect_plugins(): array {
80 if (self::$detected_plugins !== null) {
81 return self::$detected_plugins;
82 }
83
84 self::$detected_plugins = [];
85
86 foreach (self::KNOWN_PLUGINS as $slug => $plugin) {
87 if (self::is_plugin_active($plugin)) {
88 self::$detected_plugins[$slug] = $plugin;
89 }
90 }
91
92 return self::$detected_plugins;
93 }
94
95 /**
96 * Check if any SEO plugins are active
97 *
98 * @return bool True if SEO plugins detected
99 */
100 public static function has_seo_plugins(): bool {
101 return !empty(self::detect_plugins());
102 }
103
104 /**
105 * Get detected plugin names
106 *
107 * @return array Plugin names
108 */
109 public static function get_plugin_names(): array {
110 $detected = self::detect_plugins();
111 return array_column($detected, 'name');
112 }
113
114 /**
115 * Check if a specific plugin is active
116 *
117 * @param string $slug Plugin slug
118 * @return bool True if plugin is active
119 */
120 public static function is_plugin_detected(string $slug): bool {
121 $detected = self::detect_plugins();
122 return isset($detected[$slug]);
123 }
124
125 /**
126 * Check if a plugin is active
127 *
128 * @param array $plugin Plugin configuration
129 * @return bool True if plugin is active
130 */
131 private static function is_plugin_active(array $plugin): bool {
132 // Check by class
133 if (!empty($plugin['class']) && class_exists($plugin['class'])) {
134 return true;
135 }
136
137 // Check by function
138 if (!empty($plugin['function']) && function_exists($plugin['function'])) {
139 return true;
140 }
141
142 // Check by plugin file
143 if (!empty($plugin['file']) && function_exists('is_plugin_active') && is_plugin_active($plugin['file'])) {
144 return true;
145 }
146
147 return false;
148 }
149
150 /**
151 * Get admin notice message
152 *
153 * @return string Notice message
154 */
155 public static function get_notice_message(): string {
156 $plugin_names = self::get_plugin_names();
157
158 if (empty($plugin_names)) {
159 return '';
160 }
161
162 $plugin_list = implode(', ', $plugin_names);
163
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 );
169 }
170
171 /**
172 * Should show admin notice
173 *
174 * @return bool True if should show notice
175 */
176 public static function should_show_notice(): bool {
177 // Only show if SEO plugins detected
178 if (!self::has_seo_plugins()) {
179 return false;
180 }
181
182 // Show on admin pages (not just ThinkRank pages)
183 if (!is_admin()) {
184 return false;
185 }
186
187 // Check if user dismissed the notice
188 $dismissed = get_user_meta(get_current_user_id(), 'thinkrank_seo_notice_dismissed', true);
189 if ($dismissed) {
190 return false;
191 }
192
193 return true;
194 }
195
196 /**
197 * Dismiss notice for current user
198 *
199 * @return void
200 */
201 public static function dismiss_notice(): void {
202 update_user_meta(get_current_user_id(), 'thinkrank_seo_notice_dismissed', true);
203 }
204
205 /**
206 * Reset notice dismissal (for testing)
207 *
208 * @return void
209 */
210 public static function reset_notice(): void {
211 delete_user_meta(get_current_user_id(), 'thinkrank_seo_notice_dismissed');
212 }
213 }
214