PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 28.3
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v28.3
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 / surfaces / meta-surface.php

meta-surface.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 28.3, at src/surfaces/meta-surface.php

383 lines 10.1 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\Surfaces;
4
5 use Yoast\WP\SEO\Context\Meta_Tags_Context;
6 use Yoast\WP\SEO\Helpers\Indexable_Helper;
7 use Yoast\WP\SEO\Memoizers\Meta_Tags_Context_Memoizer;
8 use Yoast\WP\SEO\Models\Indexable;
9 use Yoast\WP\SEO\Repositories\Indexable_Repository;
10 use Yoast\WP\SEO\Surfaces\Values\Meta;
11 use Yoast\WP\SEO\Wrappers\WP_Rewrite_Wrapper;
12 use YoastSEO_Vendor\Symfony\Component\DependencyInjection\ContainerInterface;
13
14 /**
15 * Meta_Surface class.
16 *
17 * Surface for the indexables.
18 */
19 class Meta_Surface {
20
21 /**
22 * The container.
23 *
24 * @var ContainerInterface
25 */
26 private $container;
27
28 /**
29 * The memoizer for the meta tags context.
30 *
31 * @var Meta_Tags_Context_Memoizer
32 */
33 private $context_memoizer;
34
35 /**
36 * The indexable repository.
37 *
38 * @var Indexable_Repository
39 */
40 private $repository;
41
42 /**
43 * Holds the WP rewrite wrapper instance.
44 *
45 * @var WP_Rewrite_Wrapper
46 */
47 private $wp_rewrite_wrapper;
48
49 /**
50 * The indexable helper.
51 *
52 * @var Indexable_Helper
53 */
54 private $indexable_helper;
55
56 /**
57 * Meta_Surface constructor.
58 *
59 * @param ContainerInterface $container The DI container.
60 * @param Meta_Tags_Context_Memoizer $context_memoizer The meta tags context memoizer.
61 * @param Indexable_Repository $indexable_repository The indexable repository.
62 * @param WP_Rewrite_Wrapper $wp_rewrite_wrapper The WP rewrite wrapper.
63 * @param Indexable_Helper $indexable_helper The indexable helper.
64 */
65 public function __construct(
66 ContainerInterface $container,
67 Meta_Tags_Context_Memoizer $context_memoizer,
68 Indexable_Repository $indexable_repository,
69 WP_Rewrite_Wrapper $wp_rewrite_wrapper,
70 Indexable_Helper $indexable_helper
71 ) {
72 $this->container = $container;
73 $this->context_memoizer = $context_memoizer;
74 $this->repository = $indexable_repository;
75 $this->wp_rewrite_wrapper = $wp_rewrite_wrapper;
76 $this->indexable_helper = $indexable_helper;
77 }
78
79 /**
80 * Returns the meta tags context for the current page.
81 *
82 * @return Meta The meta values.
83 */
84 public function for_current_page() {
85 return $this->build_meta( $this->context_memoizer->for_current_page() );
86 }
87
88 /**
89 * Returns the meta tags context for the home page.
90 *
91 * @return Meta|false The meta values. False if none could be found.
92 */
93 public function for_home_page() {
94 $front_page_id = (int) \get_option( 'page_on_front' );
95 if ( \get_option( 'show_on_front' ) === 'page' && $front_page_id !== 0 ) {
96 $indexable = $this->repository->find_by_id_and_type( $front_page_id, 'post' );
97
98 if ( ! $indexable ) {
99 return false;
100 }
101
102 return $this->build_meta( $this->context_memoizer->get( $indexable, 'Static_Home_Page' ) );
103 }
104
105 $indexable = $this->repository->find_for_home_page();
106
107 if ( ! $indexable ) {
108 return false;
109 }
110
111 return $this->build_meta( $this->context_memoizer->get( $indexable, 'Home_Page' ) );
112 }
113
114 /**
115 * Returns the meta tags context for the posts page.
116 *
117 * @return Meta|false The meta values. False if none could be found.
118 */
119 public function for_posts_page() {
120 $posts_page_id = (int) \get_option( 'page_for_posts' );
121 if ( $posts_page_id !== 0 ) {
122 $indexable = $this->repository->find_by_id_and_type( $posts_page_id, 'post' );
123
124 if ( ! $indexable ) {
125 return false;
126 }
127
128 return $this->build_meta( $this->context_memoizer->get( $indexable, 'Static_Posts_Page' ) );
129 }
130
131 $indexable = $this->repository->find_for_home_page();
132
133 if ( ! $indexable ) {
134 return false;
135 }
136
137 return $this->build_meta( $this->context_memoizer->get( $indexable, 'Home_Page' ) );
138 }
139
140 /**
141 * Returns the meta tags context for a post type archive.
142 *
143 * @param string|null $post_type Optional. The post type to get the archive meta for. Defaults to the current post type.
144 *
145 * @return Meta|false The meta values. False if none could be found.
146 */
147 public function for_post_type_archive( $post_type = null ) {
148 $post_type ??= \get_post_type();
149
150 $indexable = $this->repository->find_for_post_type_archive( $post_type );
151
152 if ( ! $indexable ) {
153 return false;
154 }
155
156 return $this->build_meta( $this->context_memoizer->get( $indexable, 'Post_Type_Archive' ) );
157 }
158
159 /**
160 * Returns the meta tags context for the search result page.
161 *
162 * @return Meta|false The meta values. False if none could be found.
163 */
164 public function for_search_result() {
165 $indexable = $this->repository->find_for_system_page( 'search-result' );
166
167 if ( ! $indexable ) {
168 return false;
169 }
170
171 return $this->build_meta( $this->context_memoizer->get( $indexable, 'Search_Result_Page' ) );
172 }
173
174 /**
175 * Returns the meta tags context for the search result page.
176 *
177 * @return Meta|false The meta values. False if none could be found.
178 */
179 public function for_404() {
180 $indexable = $this->repository->find_for_system_page( '404' );
181
182 if ( ! $indexable ) {
183 return false;
184 }
185
186 return $this->build_meta( $this->context_memoizer->get( $indexable, 'Error_Page' ) );
187 }
188
189 /**
190 * Returns the meta tags context for a post.
191 *
192 * @param int $id The ID of the post.
193 *
194 * @return Meta|false The meta values. False if none could be found.
195 */
196 public function for_post( $id ) {
197 $indexable = $this->repository->find_by_id_and_type( $id, 'post' );
198
199 if ( ! $indexable ) {
200 return false;
201 }
202
203 return $this->build_meta( $this->context_memoizer->get( $indexable, 'Post_Type' ) );
204 }
205
206 /**
207 * Returns the meta tags context for a number of posts.
208 *
209 * @param int[] $ids The IDs of the posts.
210 *
211 * @return Meta[]|false The meta values. False if none could be found.
212 */
213 public function for_posts( $ids ) {
214 $indexables = $this->repository->find_by_multiple_ids_and_type( $ids, 'post' );
215
216 if ( empty( $indexables ) ) {
217 return false;
218 }
219
220 // Remove all false values.
221 $indexables = \array_filter( $indexables );
222
223 return \array_map(
224 function ( $indexable ) {
225 return $this->build_meta( $this->context_memoizer->get( $indexable, 'Post_Type' ) );
226 },
227 $indexables,
228 );
229 }
230
231 /**
232 * Returns the meta tags context for a term.
233 *
234 * @param int $id The ID of the term.
235 *
236 * @return Meta|false The meta values. False if none could be found.
237 */
238 public function for_term( $id ) {
239 $indexable = $this->repository->find_by_id_and_type( $id, 'term' );
240
241 if ( ! $indexable ) {
242 return false;
243 }
244
245 return $this->build_meta( $this->context_memoizer->get( $indexable, 'Term_Archive' ) );
246 }
247
248 /**
249 * Returns the meta tags context for an author.
250 *
251 * @param int $id The ID of the author.
252 *
253 * @return Meta|false The meta values. False if none could be found.
254 */
255 public function for_author( $id ) {
256 $indexable = $this->repository->find_by_id_and_type( $id, 'user' );
257
258 if ( ! $indexable ) {
259 return false;
260 }
261
262 return $this->build_meta( $this->context_memoizer->get( $indexable, 'Author_Archive' ) );
263 }
264
265 /**
266 * Returns the meta for an indexable.
267 *
268 * @param Indexable $indexable The indexable.
269 * @param string|null $page_type Optional. The page type if already known.
270 *
271 * @return Meta|false The meta values. False if none could be found.
272 */
273 public function for_indexable( $indexable, $page_type = null ) {
274
275 if ( ! \is_a( $indexable, Indexable::class ) ) {
276 return false;
277 }
278 $page_type ??= $this->indexable_helper->get_page_type_for_indexable( $indexable );
279
280 return $this->build_meta( $this->context_memoizer->get( $indexable, $page_type ) );
281 }
282
283 /**
284 * Returns the meta for an indexable.
285 *
286 * @param Indexable[] $indexables The indexables.
287 * @param string|null $page_type Optional. The page type if already known.
288 *
289 * @return Meta|false The meta values. False if none could be found.
290 */
291 public function for_indexables( $indexables, $page_type = null ) {
292 $closure = function ( $indexable ) use ( $page_type ) {
293 $this_page_type = $page_type;
294 $this_page_type ??= $this->indexable_helper->get_page_type_for_indexable( $indexable );
295
296 return $this->build_meta( $this->context_memoizer->get( $indexable, $this_page_type ) );
297 };
298
299 return \array_map( $closure, $indexables );
300 }
301
302 /**
303 * Returns the meta tags context for a url.
304 *
305 * @param string $url The url of the page. Required to be relative to the site url.
306 *
307 * @return Meta|false The meta values. False if none could be found.
308 */
309 public function for_url( $url ) {
310 $url_parts = \wp_parse_url( $url );
311 $site_parts = \wp_parse_url( \site_url() );
312
313 if ( ( ! \is_array( $url_parts ) || ! \is_array( $site_parts ) )
314 || ! isset( $url_parts['host'], $url_parts['path'], $site_parts['host'], $site_parts['scheme'] )
315 ) {
316 return false;
317 }
318
319 if ( $url_parts['host'] !== $site_parts['host'] ) {
320 return false;
321 }
322 // Ensure the scheme is consistent with values in the DB.
323 $url = $site_parts['scheme'] . '://' . $url_parts['host'] . $url_parts['path'];
324
325 if ( $this->is_date_archive_url( $url ) ) {
326 $indexable = $this->repository->find_for_date_archive();
327 }
328 else {
329 $indexable = $this->repository->find_by_permalink( $url );
330 }
331
332 // If we still don't have an indexable abort, the WP globals could be anything so we can't use the unknown indexable.
333 if ( ! $indexable ) {
334 return false;
335 }
336 $page_type = $this->indexable_helper->get_page_type_for_indexable( $indexable );
337
338 if ( $page_type === false ) {
339 return false;
340 }
341
342 return $this->build_meta( $this->context_memoizer->get( $indexable, $page_type ) );
343 }
344
345 /**
346 * Checks if a given URL is a date archive URL.
347 *
348 * @param string $url The url.
349 *
350 * @return bool
351 */
352 protected function is_date_archive_url( $url ) {
353 $path = \wp_parse_url( $url, \PHP_URL_PATH );
354 if ( $path === null ) {
355 return false;
356 }
357
358 $path = \ltrim( $path, '/' );
359 $wp_rewrite = $this->wp_rewrite_wrapper->get();
360 $date_rewrite = $wp_rewrite->generate_rewrite_rules( $wp_rewrite->get_date_permastruct(), \EP_DATE );
361 $date_rewrite = \apply_filters( 'date_rewrite_rules', $date_rewrite );
362
363 foreach ( (array) $date_rewrite as $match => $query ) {
364 if ( \preg_match( "#^$match#", $path ) ) {
365 return true;
366 }
367 }
368
369 return false;
370 }
371
372 /**
373 * Creates a new meta value object
374 *
375 * @param Meta_Tags_Context $context The meta tags context.
376 *
377 * @return Meta The meta value
378 */
379 protected function build_meta( Meta_Tags_Context $context ) {
380 return new Meta( $context, $this->container );
381 }
382 }
383