PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 28.4
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v28.4
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 / actions / indexing / indexable-post-indexation-action.php

indexable-post-indexation-action.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 28.4, at src/actions/indexing/indexable-post-indexation-action.php

210 lines 5.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Yoast\WP\SEO\Actions\Indexing;
4
5 use wpdb;
6 use Yoast\WP\Lib\Model;
7 use Yoast\WP\SEO\Helpers\Post_Helper;
8 use Yoast\WP\SEO\Helpers\Post_Type_Helper;
9 use Yoast\WP\SEO\Models\Indexable;
10 use Yoast\WP\SEO\Repositories\Indexable_Repository;
11 use Yoast\WP\SEO\Values\Indexables\Indexable_Builder_Versions;
12
13 /**
14 * Reindexing action for post indexables.
15 */
16 class Indexable_Post_Indexation_Action extends Abstract_Indexing_Action {
17
18 /**
19 * The transient cache key.
20 *
21 * @var string
22 */
23 public const UNINDEXED_COUNT_TRANSIENT = 'wpseo_total_unindexed_posts';
24
25 /**
26 * The transient cache key for limited counts.
27 *
28 * @var string
29 */
30 public const UNINDEXED_LIMITED_COUNT_TRANSIENT = self::UNINDEXED_COUNT_TRANSIENT . '_limited';
31
32 /**
33 * The post type helper.
34 *
35 * @var Post_Type_Helper
36 */
37 protected $post_type_helper;
38
39 /**
40 * The post helper.
41 *
42 * @var Post_Helper
43 */
44 protected $post_helper;
45
46 /**
47 * The indexable repository.
48 *
49 * @var Indexable_Repository
50 */
51 protected $repository;
52
53 /**
54 * The WordPress database instance.
55 *
56 * @var wpdb
57 */
58 protected $wpdb;
59
60 /**
61 * The latest version of Post Indexables.
62 *
63 * @var int
64 */
65 protected $version;
66
67 /**
68 * Indexable_Post_Indexing_Action constructor
69 *
70 * @param Post_Type_Helper $post_type_helper The post type helper.
71 * @param Indexable_Repository $repository The indexable repository.
72 * @param wpdb $wpdb The WordPress database instance.
73 * @param Indexable_Builder_Versions $builder_versions The latest versions for each Indexable type.
74 * @param Post_Helper $post_helper The post helper.
75 */
76 public function __construct(
77 Post_Type_Helper $post_type_helper,
78 Indexable_Repository $repository,
79 wpdb $wpdb,
80 Indexable_Builder_Versions $builder_versions,
81 Post_Helper $post_helper
82 ) {
83 $this->post_type_helper = $post_type_helper;
84 $this->repository = $repository;
85 $this->wpdb = $wpdb;
86 $this->version = $builder_versions->get_latest_version_for_type( 'post' );
87 $this->post_helper = $post_helper;
88 }
89
90 /**
91 * Creates indexables for unindexed posts.
92 *
93 * @return Indexable[] The created indexables.
94 */
95 public function index() {
96 $query = $this->get_select_query( $this->get_limit() );
97
98 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Function get_select_query returns a prepared query.
99 $post_ids = $this->wpdb->get_col( $query );
100
101 $indexables = $this->repository->find_by_multiple_ids_and_type(
102 \array_map( 'intval', $post_ids ),
103 'post',
104 );
105
106 if ( \count( $indexables ) > 0 ) {
107 \delete_transient( static::UNINDEXED_COUNT_TRANSIENT );
108 \delete_transient( static::UNINDEXED_LIMITED_COUNT_TRANSIENT );
109 }
110
111 return $indexables;
112 }
113
114 /**
115 * Returns the number of posts that will be indexed in a single indexing pass.
116 *
117 * @return int The limit.
118 */
119 public function get_limit() {
120 /**
121 * Filter 'wpseo_post_indexation_limit' - Allow filtering the amount of posts indexed during each indexing pass.
122 *
123 * @param int $limit The maximum number of posts indexed.
124 */
125 $limit = \apply_filters( 'wpseo_post_indexation_limit', 25 );
126
127 if ( ! \is_int( $limit ) || $limit < 1 ) {
128 $limit = 25;
129 }
130
131 return $limit;
132 }
133
134 /**
135 * Builds a query for counting the number of unindexed posts.
136 *
137 * @return string The prepared query string.
138 */
139 protected function get_count_query() {
140 $indexable_table = Model::get_table_name( 'Indexable' );
141
142 $post_types = $this->post_type_helper->get_indexable_post_types();
143 $excluded_post_statuses = $this->post_helper->get_excluded_post_statuses();
144 $replacements = \array_merge(
145 $post_types,
146 $excluded_post_statuses,
147 );
148
149 $replacements[] = $this->version;
150
151 // Warning: If this query is changed, makes sure to update the query in get_select_query as well.
152 // @phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber
153 return $this->wpdb->prepare(
154 "
155 SELECT COUNT(P.ID)
156 FROM {$this->wpdb->posts} AS P
157 WHERE P.post_type IN (" . \implode( ', ', \array_fill( 0, \count( $post_types ), '%s' ) ) . ')
158 AND P.post_status NOT IN (' . \implode( ', ', \array_fill( 0, \count( $excluded_post_statuses ), '%s' ) ) . ")
159 AND NOT EXISTS (
160 SELECT 1 FROM $indexable_table AS I
161 WHERE I.object_id = P.ID
162 AND I.object_type = 'post'
163 AND I.version = %d )",
164 $replacements,
165 );
166 }
167
168 /**
169 * Builds a query for selecting the ID's of unindexed posts.
170 *
171 * @param bool $limit The maximum number of post IDs to return.
172 *
173 * @return string The prepared query string.
174 */
175 protected function get_select_query( $limit = false ) {
176 $indexable_table = Model::get_table_name( 'Indexable' );
177
178 $post_types = $this->post_type_helper->get_indexable_post_types();
179 $excluded_post_statuses = $this->post_helper->get_excluded_post_statuses();
180 $replacements = \array_merge(
181 $post_types,
182 $excluded_post_statuses,
183 );
184 $replacements[] = $this->version;
185
186 $limit_query = '';
187 if ( $limit ) {
188 $limit_query = 'LIMIT %d';
189 $replacements[] = $limit;
190 }
191
192 // Warning: If this query is changed, makes sure to update the query in get_count_query as well.
193 // @phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber
194 return $this->wpdb->prepare(
195 "
196 SELECT P.ID
197 FROM {$this->wpdb->posts} AS P
198 WHERE P.post_type IN (" . \implode( ', ', \array_fill( 0, \count( $post_types ), '%s' ) ) . ')
199 AND P.post_status NOT IN (' . \implode( ', ', \array_fill( 0, \count( $excluded_post_statuses ), '%s' ) ) . ")
200 AND NOT EXISTS (
201 SELECT 1 FROM $indexable_table AS I
202 WHERE I.object_id = P.ID
203 AND I.object_type = 'post'
204 AND I.version = %d )
205 $limit_query",
206 $replacements,
207 );
208 }
209 }
210