PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 28.2
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v28.2
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
wordpress-seo / src / ai / content-planner / user-interface / content-planner-integration.php

content-planner-integration.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 28.2, at src/ai/content-planner/user-interface/content-planner-integration.php

143 lines 4.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong -- Needed in the folder structure.
4
5 namespace Yoast\WP\SEO\AI\Content_Planner\User_Interface;
6
7 use WPSEO_Admin_Asset_Manager;
8 use Yoast\WP\SEO\AI\Content_Planner\Application\Content_Planner_Endpoints_Repository;
9 use Yoast\WP\SEO\Conditionals\AI_Conditional;
10 use Yoast\WP\SEO\Conditionals\AI_Editor_Conditional;
11 use Yoast\WP\SEO\Helpers\User_Helper;
12 use Yoast\WP\SEO\Integrations\Integration_Interface;
13 use Yoast\WP\SEO\Repositories\Indexable_Repository;
14
15 /**
16 * Content_Planner_Integration class.
17 */
18 class Content_Planner_Integration implements Integration_Interface {
19
20 /**
21 * The minimum number of published posts required for the feature to be available.
22 */
23 public const MIN_PUBLISHED_POSTS = 5;
24
25 /**
26 * Represents the admin asset manager.
27 *
28 * @var WPSEO_Admin_Asset_Manager
29 */
30 private $asset_manager;
31
32 /**
33 * The endpoints repository.
34 *
35 * @var Content_Planner_Endpoints_Repository
36 */
37 private $endpoints_repository;
38
39 /**
40 * The indexable repository.
41 *
42 * @var Indexable_Repository
43 */
44 private $indexable_repository;
45
46 /**
47 * The user helper.
48 *
49 * @var User_Helper
50 */
51 private $user_helper;
52
53 /**
54 * Returns the conditionals based in which this loadable should be active.
55 *
56 * @return array<string>
57 */
58 public static function get_conditionals(): array {
59 return [ AI_Conditional::class, AI_Editor_Conditional::class ];
60 }
61
62 /**
63 * Constructs the class.
64 *
65 * @param WPSEO_Admin_Asset_Manager $asset_manager The admin asset manager.
66 * @param Content_Planner_Endpoints_Repository $endpoints_repository The endpoints repository.
67 * @param Indexable_Repository $indexable_repository The indexable repository.
68 * @param User_Helper $user_helper The user helper.
69 */
70 public function __construct(
71 WPSEO_Admin_Asset_Manager $asset_manager,
72 Content_Planner_Endpoints_Repository $endpoints_repository,
73 Indexable_Repository $indexable_repository,
74 User_Helper $user_helper
75 ) {
76 $this->asset_manager = $asset_manager;
77 $this->endpoints_repository = $endpoints_repository;
78 $this->indexable_repository = $indexable_repository;
79 $this->user_helper = $user_helper;
80 }
81
82 /**
83 * Initializes the integration.
84 *
85 * This is the place to register hooks and filters.
86 *
87 * @return void
88 */
89 public function register_hooks() {
90 \add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
91 // Enqueue after Elementor_Premium integration, which re-registers the assets.
92 \add_action( 'elementor/editor/before_enqueue_scripts', [ $this, 'enqueue_assets' ], 11 );
93 }
94
95 /**
96 * Returns the script data for the content planner.
97 *
98 * @return array{endpoints: array<string, string>, minPostsMet: bool, isBannerPermanentlyDismissed: bool}
99 */
100 public function get_script_data(): array {
101 return [
102 'endpoints' => $this->endpoints_repository->get_all_endpoints()->to_paths_array(),
103 'minPostsMet' => $this->is_minimum_posts_met(),
104 'isBannerPermanentlyDismissed' => $this->is_banner_permanently_dismissed(),
105 ];
106 }
107
108 /**
109 * Localizes the content planner script data.
110 *
111 * @return void
112 */
113 public function enqueue_assets() {
114 $this->asset_manager->enqueue_script( 'ai-content-planner' );
115 $this->asset_manager->localize_script( 'ai-content-planner', 'wpseoContentPlanner', $this->get_script_data() );
116 }
117
118 /**
119 * Determines whether the site has at least the minimum number of published posts.
120 *
121 * Reuses Indexable_Repository::get_recently_modified_posts() with a limit equal to the threshold,
122 * so we never load more rows than necessary just to answer a "≥ N" question.
123 *
124 * @return bool Whether the site has met the minimum-posts threshold.
125 */
126 private function is_minimum_posts_met(): bool {
127 $posts = $this->indexable_repository->get_recently_modified_posts( 'post', self::MIN_PUBLISHED_POSTS, false );
128
129 return \count( $posts ) >= self::MIN_PUBLISHED_POSTS;
130 }
131
132 /**
133 * Determines whether the current user has permanently dismissed the inline banner.
134 *
135 * @return bool Whether the banner is permanently dismissed for this user.
136 */
137 private function is_banner_permanently_dismissed(): bool {
138 $user_id = $this->user_helper->get_current_user_id();
139
140 return (bool) $this->user_helper->get_meta( $user_id, Banner_Permanent_Dismissal_Route::USER_META_KEY, true );
141 }
142 }
143