PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 27.6
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v27.6
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 / builders / indexable-post-type-archive-builder.php

indexable-post-type-archive-builder.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 27.6, at src/builders/indexable-post-type-archive-builder.php

169 lines 5.2 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\Builders;
4
5 use Yoast\WP\SEO\Exceptions\Indexable\Post_Type_Not_Built_Exception;
6 use Yoast\WP\SEO\Helpers\Options_Helper;
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\Values\Indexables\Indexable_Builder_Versions;
11
12 /**
13 * Post type archive builder for the indexables.
14 *
15 * Formats the post type archive meta to indexable format.
16 */
17 class Indexable_Post_Type_Archive_Builder {
18
19 /**
20 * The options helper.
21 *
22 * @var Options_Helper
23 */
24 protected $options;
25
26 /**
27 * The latest version of the Indexable_Post_Type_Archive_Builder.
28 *
29 * @var int
30 */
31 protected $version;
32
33 /**
34 * Holds the post helper instance.
35 *
36 * @var Post_Helper
37 */
38 protected $post_helper;
39
40 /**
41 * Holds the post type helper instance.
42 *
43 * @var Post_Type_Helper
44 */
45 protected $post_type_helper;
46
47 /**
48 * Indexable_Post_Type_Archive_Builder constructor.
49 *
50 * @param Options_Helper $options The options helper.
51 * @param Indexable_Builder_Versions $versions The latest version of each Indexable builder.
52 * @param Post_Helper $post_helper The post helper.
53 * @param Post_Type_Helper $post_type_helper The post type helper.
54 */
55 public function __construct(
56 Options_Helper $options,
57 Indexable_Builder_Versions $versions,
58 Post_Helper $post_helper,
59 Post_Type_Helper $post_type_helper
60 ) {
61 $this->options = $options;
62 $this->version = $versions->get_latest_version_for_type( 'post-type-archive' );
63 $this->post_helper = $post_helper;
64 $this->post_type_helper = $post_type_helper;
65 }
66
67 /**
68 * Formats the data.
69 *
70 * @param string $post_type The post type to build the indexable for.
71 * @param Indexable $indexable The indexable to format.
72 *
73 * @return Indexable The extended indexable.
74 * @throws Post_Type_Not_Built_Exception Throws exception if the post type is excluded.
75 */
76 public function build( $post_type, Indexable $indexable ) {
77 if ( ! $this->post_type_helper->is_post_type_archive_indexable( $post_type ) ) {
78 throw Post_Type_Not_Built_Exception::because_not_indexable( $post_type );
79 }
80
81 $indexable->object_type = 'post-type-archive';
82 $indexable->object_sub_type = $post_type;
83 $indexable->title = $this->options->get( 'title-ptarchive-' . $post_type );
84 $indexable->description = $this->options->get( 'metadesc-ptarchive-' . $post_type );
85 $indexable->breadcrumb_title = $this->get_breadcrumb_title( $post_type );
86 $indexable->permalink = \get_post_type_archive_link( $post_type );
87 $indexable->is_robots_noindex = $this->options->get( 'noindex-ptarchive-' . $post_type );
88 $indexable->is_public = ( (int) $indexable->is_robots_noindex !== 1 );
89 $indexable->blog_id = \get_current_blog_id();
90 $indexable->version = $this->version;
91
92 $timestamps = $this->get_object_timestamps( $post_type );
93 $indexable->object_published_at = $timestamps->published_at;
94 $indexable->object_last_modified = $timestamps->last_modified;
95
96 return $indexable;
97 }
98
99 /**
100 * Returns the fallback breadcrumb title for a given post.
101 *
102 * @param string $post_type The post type to get the fallback breadcrumb title for.
103 *
104 * @return string
105 */
106 private function get_breadcrumb_title( $post_type ) {
107 $options_breadcrumb_title = $this->options->get( 'bctitle-ptarchive-' . $post_type );
108
109 if ( $options_breadcrumb_title !== '' ) {
110 return $options_breadcrumb_title;
111 }
112
113 $post_type_obj = \get_post_type_object( $post_type );
114
115 if ( ! \is_object( $post_type_obj ) ) {
116 return '';
117 }
118
119 if ( isset( $post_type_obj->label ) && $post_type_obj->label !== '' ) {
120 return $post_type_obj->label;
121 }
122
123 if ( isset( $post_type_obj->labels->menu_name ) && $post_type_obj->labels->menu_name !== '' ) {
124 return $post_type_obj->labels->menu_name;
125 }
126
127 return $post_type_obj->name;
128 }
129
130 /**
131 * Returns the timestamps for a given post type.
132 *
133 * @param string $post_type The post type.
134 *
135 * @return object An object with last_modified and published_at timestamps.
136 */
137 protected function get_object_timestamps( $post_type ) {
138 global $wpdb;
139 $post_statuses = $this->post_helper->get_public_post_statuses();
140
141 $replacements = [];
142 $replacements[] = 'post_modified_gmt';
143 $replacements[] = 'post_date_gmt';
144 $replacements[] = $wpdb->posts;
145 $replacements[] = 'post_status';
146 $replacements = \array_merge( $replacements, $post_statuses );
147 $replacements[] = 'post_password';
148 $replacements[] = 'post_type';
149 $replacements[] = $post_type;
150
151 //phpcs:disable WordPress.DB.PreparedSQLPlaceholders -- %i placeholder is still not recognized.
152 //phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- We need to use a direct query here.
153 //phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: No relevant caches.
154 return $wpdb->get_row(
155 $wpdb->prepare(
156 '
157 SELECT MAX(p.%i) AS last_modified, MIN(p.%i) AS published_at
158 FROM %i AS p
159 WHERE p.%i IN (' . \implode( ', ', \array_fill( 0, \count( $post_statuses ), '%s' ) ) . ")
160 AND p.%i = ''
161 AND p.%i = %s
162 ",
163 $replacements,
164 ),
165 );
166 //phpcs:enable
167 }
168 }
169