PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 1.0.2
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v1.0.2
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 / seo / class-analytics-manager.php

class-analytics-manager.php in ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO 1.0.2, at includes/seo/class-analytics-manager.php

840 lines 29.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Analytics Manager Class
4 *
5 * Coordinates Google API integrations for SEO analytics data collection,
6 * processing, and AI-powered insights generation. Manages Google Analytics,
7 * Search Console, and PageSpeed data with intelligent caching and rate limiting.
8 *
9 * @package ThinkRank
10 * @subpackage SEO
11 * @since 1.0.0
12 */
13
14 declare(strict_types=1);
15
16 namespace ThinkRank\SEO;
17
18 use ThinkRank\Core\Settings_Manager;
19 use ThinkRank\Integrations\Google_Analytics_Client;
20 use ThinkRank\Integrations\Google_Search_Console_Client;
21 use ThinkRank\Integrations\Google_PageSpeed_Client;
22
23 // Prevent direct access
24 if (!defined('ABSPATH')) {
25 exit;
26 }
27
28 /**
29 * Analytics Manager Class
30 *
31 * Single Responsibility: Coordinate Google API data collection and processing
32 * Following ThinkRank manager patterns from AI_Manager and Performance_Monitoring_Manager
33 *
34 * @since 1.0.0
35 */
36 class Analytics_Manager {
37
38 /**
39 * Settings Manager instance
40 *
41 * @var Settings_Manager
42 */
43 private Settings_Manager $settings_manager;
44
45 /**
46 * Google Analytics client
47 *
48 * @var Google_Analytics_Client|null
49 */
50 private ?Google_Analytics_Client $analytics_client = null;
51
52 /**
53 * Google Search Console client
54 *
55 * @var Google_Search_Console_Client|null
56 */
57 private ?Google_Search_Console_Client $search_console_client = null;
58
59 /**
60 * Google PageSpeed client
61 *
62 * @var Google_PageSpeed_Client|null
63 */
64 private ?Google_PageSpeed_Client $pagespeed_client = null;
65
66 /**
67 * Cache duration in seconds
68 *
69 * @var int
70 */
71 private int $cache_duration;
72
73 /**
74 * Constructor
75 *
76 * @param Settings_Manager|null $settings_manager Settings manager instance
77 */
78 public function __construct(?Settings_Manager $settings_manager = null) {
79 $this->settings_manager = $settings_manager ?? new Settings_Manager();
80 $this->cache_duration = (int) $this->get_setting('cache_duration', 3600);
81
82 // Clear any existing cached insights to ensure new logic takes effect
83 $this->clear_insights_cache();
84 }
85
86 /**
87 * Initialize Analytics Manager
88 * Following ThinkRank init patterns
89 *
90 * @return void
91 */
92 public function init(): void {
93 // Initialize Google API clients
94 add_action('init', [$this, 'initialize_clients']);
95
96 // Schedule cache cleanup
97 add_action('thinkrank_daily_cleanup', [$this, 'cleanup_cache']);
98 }
99
100 /**
101 * Initialize Google API clients
102 * Following AI_Manager client initialization pattern
103 *
104 * @return void
105 */
106 public function initialize_clients(): void {
107 try {
108 // Initialize Google Analytics client
109 $ga_api_key = $this->get_setting('google_analytics_api_key');
110 $ga_property_id = $this->get_setting('google_analytics_property_id');
111
112 if (!empty($ga_api_key) && !empty($ga_property_id)) {
113 $timeout = (int) $this->get_setting('api_timeout', 30);
114 $this->analytics_client = new Google_Analytics_Client($ga_api_key, $ga_property_id, $timeout);
115 }
116
117 // Initialize Search Console client
118 $gsc_api_key = $this->get_setting('google_search_console_api_key');
119
120 if (!empty($gsc_api_key)) {
121 $timeout = (int) $this->get_setting('api_timeout', 30);
122 $this->search_console_client = new Google_Search_Console_Client($gsc_api_key, $timeout);
123 }
124
125 // Initialize PageSpeed client
126 $ps_api_key = $this->get_setting('google_pagespeed_api_key');
127
128 if (!empty($ps_api_key)) {
129 $timeout = (int) $this->get_setting('api_timeout', 30);
130 $this->pagespeed_client = new Google_PageSpeed_Client($ps_api_key, $timeout);
131 }
132
133 } catch (\Exception $e) {
134 // Client initialization failed, will be handled later
135 }
136 }
137
138 /**
139 * Test all Google API connections
140 * Following ThinkRank test_connection patterns
141 *
142 * @return array Connection test results
143 */
144 public function test_connections(): array {
145 $results = [
146 'google_analytics' => ['status' => 'not_configured'],
147 'search_console' => ['status' => 'not_configured'],
148 'pagespeed' => ['status' => 'not_configured']
149 ];
150
151 // Test Google Analytics connection
152 if ($this->analytics_client) {
153 try {
154 $test_result = $this->analytics_client->test_connection();
155 $results['google_analytics'] = [
156 'status' => $test_result['success'] ? 'connected' : 'error',
157 'message' => $test_result['message'],
158 'details' => $test_result
159 ];
160 } catch (\Exception $e) {
161 $results['google_analytics'] = [
162 'status' => 'error',
163 'message' => $e->getMessage()
164 ];
165 }
166 }
167
168 // Test Search Console connection
169 if ($this->search_console_client) {
170 try {
171 $test_result = $this->search_console_client->test_connection();
172 $results['search_console'] = [
173 'status' => $test_result['success'] ? 'connected' : 'error',
174 'message' => $test_result['message'],
175 'details' => $test_result
176 ];
177 } catch (\Exception $e) {
178 $results['search_console'] = [
179 'status' => 'error',
180 'message' => $e->getMessage()
181 ];
182 }
183 }
184
185 // Test PageSpeed connection
186 if ($this->pagespeed_client) {
187 try {
188 $test_result = $this->pagespeed_client->test_connection();
189 $results['pagespeed'] = [
190 'status' => $test_result['success'] ? 'connected' : 'error',
191 'message' => $test_result['message'],
192 'details' => $test_result
193 ];
194 } catch (\Exception $e) {
195 $results['pagespeed'] = [
196 'status' => 'error',
197 'message' => $e->getMessage()
198 ];
199 }
200 }
201
202 return $results;
203 }
204
205 /**
206 * Get analytics dashboard data
207 * Combines data from all Google APIs with caching
208 *
209 * @param string $date_range Date range for data
210 * @return array Dashboard data
211 */
212 public function get_dashboard_data(string $date_range = '30d'): array {
213 $cache_key = "analytics_dashboard_{$date_range}";
214 $cached_data = get_transient($cache_key);
215
216 if ($cached_data !== false) {
217 return $cached_data;
218 }
219
220 $dashboard_data = [
221 'traffic' => [],
222 'search_performance' => [],
223 'core_web_vitals' => [],
224 'last_updated' => current_time('mysql'),
225 'date_range' => $date_range
226 ];
227
228 try {
229 // Get Google Analytics traffic data
230 if ($this->analytics_client) {
231 $dashboard_data['traffic'] = $this->analytics_client->get_traffic_data($date_range);
232 $dashboard_data['organic_traffic'] = $this->analytics_client->get_organic_traffic($date_range);
233 $dashboard_data['top_pages'] = $this->analytics_client->get_top_pages(10, $date_range);
234 }
235
236 // Get Search Console data
237 if ($this->search_console_client) {
238 $site_url = $this->get_setting('search_console_property', get_site_url());
239 $dashboard_data['search_performance'] = $this->search_console_client->get_search_performance($site_url, $date_range);
240 $dashboard_data['top_queries'] = $this->search_console_client->get_top_queries($site_url, 10);
241 $dashboard_data['page_performance'] = $this->search_console_client->get_page_performance($site_url, $date_range, 10);
242 }
243
244 // Get Core Web Vitals data
245 if ($this->pagespeed_client) {
246 $site_url = get_site_url();
247 $dashboard_data['core_web_vitals'] = $this->pagespeed_client->get_core_web_vitals($site_url);
248 }
249
250 } catch (\Exception $e) {
251 $dashboard_data['error'] = $e->getMessage();
252 }
253
254 // Cache the results
255 set_transient($cache_key, $dashboard_data, $this->cache_duration);
256
257 return $dashboard_data;
258 }
259
260 /**
261 * Get SEO opportunities using Search Console data
262 *
263 * @param string $date_range Date range for analysis
264 * @return array SEO opportunities
265 */
266 public function get_seo_opportunities(string $date_range = '30d'): array {
267 $cache_key = "seo_opportunities_{$date_range}";
268 $cached_data = get_transient($cache_key);
269
270 if ($cached_data !== false) {
271 return $cached_data;
272 }
273
274 $opportunities = [
275 'keyword_opportunities' => [],
276 'page_opportunities' => [],
277 'device_insights' => [],
278 'last_updated' => current_time('mysql')
279 ];
280
281 try {
282 if ($this->search_console_client) {
283 $site_url = $this->get_setting('search_console_property', get_site_url());
284
285 // Get keyword opportunities
286 $opportunities['keyword_opportunities'] = $this->search_console_client->get_keyword_opportunities($site_url, $date_range);
287
288 // Get device performance insights
289 $opportunities['device_insights'] = $this->search_console_client->get_device_performance($site_url, $date_range);
290
291 // Get search appearance data
292 $opportunities['search_appearance'] = $this->search_console_client->get_search_appearance($site_url, $date_range);
293 }
294
295 } catch (\Exception $e) {
296 $opportunities['error'] = $e->getMessage();
297 }
298
299 // Cache the results
300 set_transient($cache_key, $opportunities, $this->cache_duration);
301
302 return $opportunities;
303 }
304
305 /**
306 * Get setting value from integrations category
307 * Following ThinkRank settings patterns
308 *
309 * @param string $key Setting key
310 * @param mixed $default Default value
311 * @return mixed Setting value
312 */
313 private function get_setting(string $key, $default = '') {
314 $integrations_settings = $this->settings_manager->get_settings('integrations');
315 return $integrations_settings[$key] ?? $default;
316 }
317
318 /**
319 * One-click setup for Google Search Console verification
320 * Following ThinkRank setup patterns
321 *
322 * @param string $site_url Site URL to verify
323 * @return array Setup results
324 */
325 public function setup_search_console_verification(string $site_url): array {
326 try {
327 if (!$this->search_console_client) {
328 return [
329 'success' => false,
330 'message' => 'Search Console API key not configured'
331 ];
332 }
333
334 $verification_result = $this->search_console_client->verify_site($site_url);
335
336 if ($verification_result['success']) {
337 // Update settings with verified site URL
338 $this->settings_manager->update_setting('integrations', 'search_console_property', $site_url);
339 }
340
341 return $verification_result;
342
343 } catch (\Exception $e) {
344 return [
345 'success' => false,
346 'message' => $e->getMessage()
347 ];
348 }
349 }
350
351 /**
352 * Get site indexing status
353 *
354 * @return array Indexing status data
355 */
356 public function get_indexing_status(): array {
357 $cache_key = 'indexing_status';
358 $cached_data = get_transient($cache_key);
359
360 if ($cached_data !== false) {
361 return $cached_data;
362 }
363
364 $indexing_data = [
365 'status' => 'unknown',
366 'last_updated' => current_time('mysql')
367 ];
368
369 try {
370 if ($this->search_console_client) {
371 $site_url = $this->get_setting('search_console_property', get_site_url());
372 $indexing_data = $this->search_console_client->get_indexing_status($site_url);
373 }
374
375 } catch (\Exception $e) {
376 $indexing_data['error'] = $e->getMessage();
377 }
378
379 // Cache for 1 hour
380 set_transient($cache_key, $indexing_data, 3600);
381
382 return $indexing_data;
383 }
384
385 /**
386 * Force refresh of all cached data
387 *
388 * @return array Refresh results
389 */
390 public function refresh_data(): array {
391 // Clear all analytics-related transients
392 $cache_keys = [
393 'analytics_dashboard_7d',
394 'analytics_dashboard_30d',
395 'analytics_dashboard_90d',
396 'seo_opportunities_7d',
397 'seo_opportunities_30d',
398 'seo_opportunities_90d',
399 'seo_insights_7d',
400 'seo_insights_30d',
401 'seo_insights_90d',
402 'indexing_status'
403 ];
404
405 $cleared = 0;
406 foreach ($cache_keys as $key) {
407 if (delete_transient($key)) {
408 $cleared++;
409 }
410 }
411
412 return [
413 'success' => true,
414 'message' => "Cleared {$cleared} cached data entries",
415 'cleared_count' => $cleared,
416 'timestamp' => current_time('mysql')
417 ];
418 }
419
420 /**
421 * Clear insights cache specifically
422 *
423 * @return void
424 */
425 private function clear_insights_cache(): void {
426 $insight_cache_keys = [
427 'seo_insights_7d',
428 'seo_insights_30d',
429 'seo_insights_90d'
430 ];
431
432 foreach ($insight_cache_keys as $key) {
433 delete_transient($key);
434 }
435 }
436
437 /**
438 * Get client status for debugging
439 *
440 * @return array Client status information
441 */
442 public function get_client_status(): array {
443 return [
444 'google_analytics' => [
445 'initialized' => !is_null($this->analytics_client),
446 'api_key_configured' => !empty($this->get_setting('google_analytics_api_key')),
447 'property_id_configured' => !empty($this->get_setting('google_analytics_property_id'))
448 ],
449 'search_console' => [
450 'initialized' => !is_null($this->search_console_client),
451 'api_key_configured' => !empty($this->get_setting('google_search_console_api_key')),
452 'site_url_configured' => !empty($this->get_setting('search_console_property'))
453 ],
454 'pagespeed' => [
455 'initialized' => !is_null($this->pagespeed_client),
456 'api_key_configured' => !empty($this->get_setting('google_pagespeed_api_key'))
457 ],
458 'cache_duration' => $this->cache_duration,
459 'last_checked' => current_time('mysql')
460 ];
461 }
462
463 /**
464 * Cleanup expired cache data
465 * Following ThinkRank cache cleanup patterns
466 *
467 * @return void
468 */
469 public function cleanup_cache(): void {
470 // WordPress handles transient cleanup automatically
471 // This method is for future custom cache cleanup if needed
472 }
473
474 // ========================================
475 // SEO Intelligence Enhancement Methods
476 // ========================================
477
478 /**
479 * Get intelligent dashboard data with trends and insights
480 *
481 * @param string $date_range Date range for analysis
482 * @return array Enhanced dashboard data with intelligence
483 */
484 public function get_intelligent_dashboard_data(string $date_range = '30d'): array {
485 // Get base dashboard data
486 $dashboard_data = $this->get_dashboard_data($date_range);
487
488 // Check if there's an error in the data
489 if (isset($dashboard_data['error'])) {
490 return [
491 'success' => false,
492 'data' => null,
493 'message' => 'Failed to retrieve dashboard data: ' . $dashboard_data['error'],
494 'timestamp' => current_time('mysql')
495 ];
496 }
497
498 // Check if we have real data available
499 if (!$this->has_real_data($dashboard_data)) {
500 return [
501 'success' => false,
502 'data' => null,
503 'message' => 'No analytics data available yet. Please ensure your Google Analytics and Search Console are properly configured and have collected data.',
504 'timestamp' => current_time('mysql')
505 ];
506 }
507
508 // Initialize intelligence classes
509 $trend_analyzer = new SEO_Trend_Analyzer();
510 $scoring_engine = new SEO_Scoring_Engine();
511 $insight_generator = new SEO_Insight_Generator();
512
513 $data = $dashboard_data;
514
515 // Generate trend analysis
516 $current_data = $data;
517 $historical_data = $this->get_historical_data($date_range);
518
519 $trends = [
520 'traffic_trends' => $trend_analyzer->analyze_traffic_trends($current_data, $historical_data),
521 'keyword_trends' => $trend_analyzer->analyze_keyword_trends($data['search_performance'] ?? [], $date_range),
522 'content_trends' => $trend_analyzer->analyze_content_trends($data, $data['search_performance'] ?? [])
523 ];
524
525 // Calculate SEO health score
526 $seo_health = $scoring_engine->calculate_seo_health_score($data, $data['search_performance'] ?? []);
527
528 // Generate insights
529 $insights = [
530 'traffic_insights' => $insight_generator->generate_traffic_insights($trends['traffic_trends']),
531 'keyword_insights' => $insight_generator->generate_keyword_insights($trends['keyword_trends']),
532 'content_insights' => $insight_generator->generate_content_insights($trends['content_trends'])
533 ];
534
535 // Combine all intelligence data
536 $enhanced_data = array_merge($data, [
537 'intelligence' => [
538 'trends' => $trends,
539 'seo_health_score' => $seo_health,
540 'insights' => $insights,
541 'last_analyzed' => current_time('mysql')
542 ]
543 ]);
544
545 return [
546 'success' => true,
547 'data' => $enhanced_data,
548 'message' => 'Intelligent dashboard data retrieved successfully'
549 ];
550 }
551
552 /**
553 * Get intelligent SEO opportunities with prioritization
554 *
555 * @param string $date_range Date range for analysis
556 * @return array Enhanced opportunities with intelligence
557 */
558 public function get_intelligent_seo_opportunities(string $date_range = '30d'): array {
559 // Get base opportunities data
560 $opportunities_data = $this->get_seo_opportunities($date_range);
561
562 // Check if there's an error in the data
563 if (isset($opportunities_data['error'])) {
564 return [
565 'success' => false,
566 'data' => null,
567 'message' => 'Failed to retrieve opportunities data: ' . $opportunities_data['error'],
568 'timestamp' => current_time('mysql')
569 ];
570 }
571
572 // Check if we have real search console data for opportunities
573 $search_performance = $opportunities_data['search_performance'] ?? [];
574 $has_search_data = !empty($search_performance['rows']) ||
575 ($search_performance['total_clicks'] ?? 0) > 0 ||
576 ($search_performance['total_impressions'] ?? 0) > 0;
577
578 if (!$has_search_data) {
579 return [
580 'success' => false,
581 'data' => null,
582 'message' => 'No Search Console data available yet. Please ensure your Search Console is properly configured and has collected data.',
583 'timestamp' => current_time('mysql')
584 ];
585 }
586
587 // Initialize intelligence classes
588 $opportunity_detector = new SEO_Opportunity_Detector();
589 $scoring_engine = new SEO_Scoring_Engine();
590
591 $data = $opportunities_data;
592
593 // Detect intelligent opportunities
594 $search_console_data = $data['search_performance'] ?? [];
595 $analytics_data = $data;
596
597 $intelligent_opportunities = [
598 'quick_wins' => $opportunity_detector->detect_quick_wins($search_console_data, $analytics_data),
599 'content_opportunities' => $opportunity_detector->identify_content_opportunities($search_console_data, $analytics_data),
600 'keyword_opportunities' => $scoring_engine->score_keyword_opportunities($search_console_data)
601 ];
602
603 // Prioritize all opportunities
604 $all_opportunities = array_merge(
605 $intelligent_opportunities['quick_wins']['opportunities'] ?? [],
606 $intelligent_opportunities['content_opportunities']['opportunities'] ?? [],
607 $intelligent_opportunities['keyword_opportunities']['opportunities'] ?? []
608 );
609
610 $prioritized = $opportunity_detector->prioritize_opportunities($all_opportunities);
611 $impact_matrix = $opportunity_detector->calculate_impact_effort_matrix($all_opportunities);
612
613 // Enhance original data with intelligence
614 $enhanced_data = array_merge($data, [
615 'intelligent_opportunities' => $intelligent_opportunities,
616 'prioritized_opportunities' => $prioritized,
617 'impact_effort_matrix' => $impact_matrix,
618 'opportunity_summary' => $this->generate_opportunity_summary($intelligent_opportunities),
619 'last_analyzed' => current_time('mysql')
620 ]);
621
622 return [
623 'success' => true,
624 'data' => $enhanced_data,
625 'message' => 'Intelligent SEO opportunities retrieved successfully'
626 ];
627 }
628
629 /**
630 * Get SEO performance insights
631 *
632 * @param string $date_range Date range for analysis
633 * @return array SEO insights data
634 */
635 public function get_seo_insights(string $date_range = '30d'): array {
636 $cache_key = "seo_insights_{$date_range}";
637 $cached_data = get_transient($cache_key);
638
639 if ($cached_data !== false) {
640 return [
641 'success' => true,
642 'data' => $cached_data,
643 'cached' => true,
644 'message' => 'SEO insights retrieved from cache'
645 ];
646 }
647
648 try {
649 // Get dashboard data for analysis
650 $dashboard_result = $this->get_intelligent_dashboard_data($date_range);
651
652 if (!$dashboard_result['success']) {
653 return $dashboard_result;
654 }
655
656 $dashboard_data = $dashboard_result['data'];
657 $intelligence = $dashboard_data['intelligence'] ?? [];
658
659 // Initialize insight generator
660 $insight_generator = new SEO_Insight_Generator();
661
662 // Collect all insights
663 $all_insights = [];
664
665 if (!empty($intelligence['insights']['traffic_insights']['insights'])) {
666 $all_insights = array_merge($all_insights, $intelligence['insights']['traffic_insights']['insights']);
667 }
668
669 if (!empty($intelligence['insights']['keyword_insights']['insights'])) {
670 $all_insights = array_merge($all_insights, $intelligence['insights']['keyword_insights']['insights']);
671 }
672
673 if (!empty($intelligence['insights']['content_insights']['insights'])) {
674 $all_insights = array_merge($all_insights, $intelligence['insights']['content_insights']['insights']);
675 }
676
677 // Format and prioritize insights
678 $formatted_insights = $insight_generator->format_insights_for_display($all_insights);
679 $prioritized_insights = $insight_generator->prioritize_insights_by_impact($formatted_insights);
680
681 $insights_data = [
682 'insights' => $prioritized_insights['prioritized_insights'],
683 'summary' => [
684 'total_insights' => count($formatted_insights),
685 'high_impact_count' => $prioritized_insights['high_impact_count'],
686 'action_required_count' => $prioritized_insights['action_required_count']
687 ],
688 'seo_health_score' => $intelligence['seo_health_score'] ?? null,
689 'generated_at' => current_time('mysql')
690 ];
691
692 // Cache the results
693 set_transient($cache_key, $insights_data, $this->cache_duration);
694
695 return [
696 'success' => true,
697 'data' => $insights_data,
698 'cached' => false,
699 'message' => 'SEO insights generated successfully'
700 ];
701
702 } catch (Exception $e) {
703 return [
704 'success' => false,
705 'error' => 'Failed to generate SEO insights: ' . $e->getMessage(),
706 'data' => null
707 ];
708 }
709 }
710
711 /**
712 * Check if real analytics data is available
713 *
714 * @param array $dashboard_data Dashboard data to check
715 * @return bool True if real data is available
716 */
717 private function has_real_data(array $dashboard_data): bool {
718 // Check if we have meaningful traffic data
719 $traffic = $dashboard_data['traffic'] ?? [];
720 $search_performance = $dashboard_data['search_performance'] ?? [];
721
722 $has_traffic = !empty($traffic) && (
723 ($traffic['sessions'] ?? 0) > 0 ||
724 ($traffic['pageviews'] ?? 0) > 0 ||
725 ($traffic['active_users'] ?? 0) > 0
726 );
727
728 $has_search_data = !empty($search_performance) && (
729 !empty($search_performance['rows']) ||
730 ($search_performance['total_clicks'] ?? 0) > 0 ||
731 ($search_performance['total_impressions'] ?? 0) > 0
732 );
733
734 return $has_traffic || $has_search_data;
735 }
736
737 /**
738 * Get historical data for trend comparison
739 *
740 * @param string $current_range Current date range
741 * @return array Historical data
742 */
743 private function get_historical_data(string $current_range): array {
744 // Calculate previous period based on current range
745 $previous_range = $this->calculate_previous_period($current_range);
746
747 // Try to get actual historical data from previous period
748 $historical_data = $this->get_dashboard_data($previous_range);
749
750 // Return the actual historical data (may be empty if no real data available)
751 return [
752 'sessions' => $historical_data['traffic']['sessions'] ?? 0,
753 'pageviews' => $historical_data['traffic']['pageviews'] ?? 0,
754 'organic_traffic' => $historical_data['organic_traffic'] ?? ['organic_traffic' => ['sessions' => 0]],
755 'bounce_rate' => $historical_data['traffic']['bounce_rate'] ?? 0,
756 'avg_session_duration' => $historical_data['traffic']['avg_session_duration'] ?? 0
757 ];
758 }
759
760 /**
761 * Calculate previous period for comparison
762 *
763 * @param string $current_range Current range
764 * @return string Previous period range
765 */
766 private function calculate_previous_period(string $current_range): string {
767 // Simple mapping for now - could be enhanced with actual date calculations
768 $period_mapping = [
769 '7d' => '14d',
770 '30d' => '60d',
771 '90d' => '180d'
772 ];
773
774 return $period_mapping[$current_range] ?? '60d';
775 }
776
777 /**
778 * Generate opportunity summary
779 *
780 * @param array $opportunities All opportunities
781 * @return array Opportunity summary
782 */
783 private function generate_opportunity_summary(array $opportunities): array {
784 $quick_wins_count = count($opportunities['quick_wins']['opportunities'] ?? []);
785 $content_opportunities_count = count($opportunities['content_opportunities']['opportunities'] ?? []);
786 $keyword_opportunities_count = count($opportunities['keyword_opportunities']['opportunities'] ?? []);
787
788 $total_opportunities = $quick_wins_count + $content_opportunities_count + $keyword_opportunities_count;
789
790 $potential_clicks = 0;
791 if (!empty($opportunities['quick_wins']['potential_additional_clicks'])) {
792 $potential_clicks = $opportunities['quick_wins']['potential_additional_clicks'];
793 }
794
795 return [
796 'total_opportunities' => $total_opportunities,
797 'quick_wins_count' => $quick_wins_count,
798 'content_opportunities_count' => $content_opportunities_count,
799 'keyword_opportunities_count' => $keyword_opportunities_count,
800 'potential_additional_clicks' => $potential_clicks,
801 'priority_recommendation' => $quick_wins_count > 0 ?
802 'Focus on quick wins first for immediate impact' :
803 'Focus on content optimization for long-term growth'
804 ];
805 }
806
807 /**
808 * Clear intelligence cache
809 *
810 * @return array Clear result
811 */
812 public function clear_intelligence_cache(): array {
813 $intelligence_cache_keys = [
814 'seo_insights_7d',
815 'seo_insights_30d',
816 'seo_insights_90d',
817 'intelligent_dashboard_7d',
818 'intelligent_dashboard_30d',
819 'intelligent_dashboard_90d',
820 'intelligent_opportunities_7d',
821 'intelligent_opportunities_30d',
822 'intelligent_opportunities_90d'
823 ];
824
825 $cleared = 0;
826 foreach ($intelligence_cache_keys as $key) {
827 if (delete_transient($key)) {
828 $cleared++;
829 }
830 }
831
832 return [
833 'success' => true,
834 'message' => "Cleared {$cleared} intelligence cache entries",
835 'cleared_count' => $cleared,
836 'timestamp' => current_time('mysql')
837 ];
838 }
839 }
840