PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 27.9
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v27.9
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 / integrations / watchers / indexable-permalink-watcher.php

indexable-permalink-watcher.php in Yoast SEO – Advanced SEO with real-time guidance and built-in AI 27.9, at src/integrations/watchers/indexable-permalink-watcher.php

280 lines 7.8 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\Integrations\Watchers;
4
5 use Yoast\WP\SEO\Conditionals\Migrations_Conditional;
6 use Yoast\WP\SEO\Config\Indexing_Reasons;
7 use Yoast\WP\SEO\Helpers\Indexable_Helper;
8 use Yoast\WP\SEO\Helpers\Options_Helper;
9 use Yoast\WP\SEO\Helpers\Post_Type_Helper;
10 use Yoast\WP\SEO\Helpers\Taxonomy_Helper;
11 use Yoast\WP\SEO\Integrations\Integration_Interface;
12
13 /**
14 * WordPress Permalink structure watcher.
15 *
16 * Handles updates to the permalink_structure for the Indexables table.
17 */
18 class Indexable_Permalink_Watcher implements Integration_Interface {
19
20 /**
21 * Represents the options helper.
22 *
23 * @var Options_Helper
24 */
25 protected $options_helper;
26
27 /**
28 * The taxonomy helper.
29 *
30 * @var Taxonomy_Helper
31 */
32 protected $taxonomy_helper;
33
34 /**
35 * The post type helper.
36 *
37 * @var Post_Type_Helper
38 */
39 private $post_type;
40
41 /**
42 * The indexable helper.
43 *
44 * @var Indexable_Helper
45 */
46 protected $indexable_helper;
47
48 /**
49 * Returns the conditionals based on which this loadable should be active.
50 *
51 * @return array
52 */
53 public static function get_conditionals() {
54 return [ Migrations_Conditional::class ];
55 }
56
57 /**
58 * Indexable_Permalink_Watcher constructor.
59 *
60 * @param Post_Type_Helper $post_type The post type helper.
61 * @param Options_Helper $options The options helper.
62 * @param Indexable_Helper $indexable The indexable helper.
63 * @param Taxonomy_Helper $taxonomy_helper The taxonomy helper.
64 */
65 public function __construct( Post_Type_Helper $post_type, Options_Helper $options, Indexable_Helper $indexable, Taxonomy_Helper $taxonomy_helper ) {
66 $this->post_type = $post_type;
67 $this->options_helper = $options;
68 $this->indexable_helper = $indexable;
69 $this->taxonomy_helper = $taxonomy_helper;
70
71 $this->schedule_cron();
72 }
73
74 /**
75 * Registers the hooks.
76 *
77 * @return void
78 */
79 public function register_hooks() {
80 \add_action( 'update_option_permalink_structure', [ $this, 'reset_permalinks' ] );
81 \add_action( 'update_option_category_base', [ $this, 'reset_permalinks_term' ], 10, 3 );
82 \add_action( 'update_option_tag_base', [ $this, 'reset_permalinks_term' ], 10, 3 );
83 \add_action( 'wpseo_permalink_structure_check', [ $this, 'force_reset_permalinks' ] );
84 \add_action( 'wpseo_deactivate', [ $this, 'unschedule_cron' ] );
85 }
86
87 /**
88 * Resets the permalinks for everything that is related to the permalink structure.
89 *
90 * @return void
91 */
92 public function reset_permalinks() {
93
94 $post_types = $this->get_post_types();
95 foreach ( $post_types as $post_type ) {
96 $this->reset_permalinks_post_type( $post_type );
97 }
98
99 $taxonomies = $this->get_taxonomies_for_post_types( $post_types );
100 foreach ( $taxonomies as $taxonomy ) {
101 $this->indexable_helper->reset_permalink_indexables( 'term', $taxonomy );
102 }
103
104 $this->indexable_helper->reset_permalink_indexables( 'user' );
105 $this->indexable_helper->reset_permalink_indexables( 'date-archive' );
106 $this->indexable_helper->reset_permalink_indexables( 'system-page' );
107
108 // Always update `permalink_structure` in the wpseo option.
109 $this->options_helper->set( 'permalink_structure', \get_option( 'permalink_structure' ) );
110 }
111
112 /**
113 * Resets the permalink for the given post type.
114 *
115 * @param string $post_type The post type to reset.
116 *
117 * @return void
118 */
119 public function reset_permalinks_post_type( $post_type ) {
120 $this->indexable_helper->reset_permalink_indexables( 'post', $post_type );
121 $this->indexable_helper->reset_permalink_indexables( 'post-type-archive', $post_type );
122 }
123
124 /**
125 * Resets the term indexables when the base has been changed.
126 *
127 * @param string $old_value Unused. The old option value.
128 * @param string $new_value Unused. The new option value.
129 * @param string $type The option name.
130 *
131 * @return void
132 */
133 public function reset_permalinks_term( $old_value, $new_value, $type ) {
134 $subtype = $type;
135
136 $reason = Indexing_Reasons::REASON_PERMALINK_SETTINGS;
137
138 // When the subtype contains _base, just strip it.
139 if ( \strstr( $subtype, '_base' ) ) {
140 $subtype = \substr( $type, 0, -5 );
141 }
142
143 if ( $subtype === 'tag' ) {
144 $subtype = 'post_tag';
145 $reason = Indexing_Reasons::REASON_TAG_BASE_PREFIX;
146 }
147
148 if ( $subtype === 'category' ) {
149 $reason = Indexing_Reasons::REASON_CATEGORY_BASE_PREFIX;
150 }
151
152 $this->indexable_helper->reset_permalink_indexables( 'term', $subtype, $reason );
153 }
154
155 /**
156 * Resets the permalink indexables automatically, if necessary.
157 *
158 * @return bool Whether the reset request ran.
159 */
160 public function force_reset_permalinks() {
161 if ( \get_option( 'tag_base' ) !== $this->options_helper->get( 'tag_base_url' ) ) {
162 $this->reset_permalinks_term( null, null, 'tag_base' );
163 $this->options_helper->set( 'tag_base_url', \get_option( 'tag_base' ) );
164 }
165 if ( \get_option( 'category_base' ) !== $this->options_helper->get( 'category_base_url' ) ) {
166 $this->reset_permalinks_term( null, null, 'category_base' );
167 $this->options_helper->set( 'category_base_url', \get_option( 'category_base' ) );
168 }
169
170 if ( $this->should_reset_permalinks() ) {
171 $this->reset_permalinks();
172
173 return true;
174 }
175
176 $this->reset_altered_custom_taxonomies();
177
178 return true;
179 }
180
181 /**
182 * Checks whether the permalinks should be reset after `permalink_structure` has changed.
183 *
184 * @return bool Whether the permalinks should be reset.
185 */
186 public function should_reset_permalinks() {
187 return \get_option( 'permalink_structure' ) !== $this->options_helper->get( 'permalink_structure' );
188 }
189
190 /**
191 * Resets custom taxonomies if their slugs have changed.
192 *
193 * @return void
194 */
195 public function reset_altered_custom_taxonomies() {
196 $taxonomies = $this->taxonomy_helper->get_custom_taxonomies();
197 $custom_taxonomy_bases = $this->options_helper->get( 'custom_taxonomy_slugs', [] );
198 $new_taxonomy_bases = [];
199
200 foreach ( $taxonomies as $taxonomy ) {
201 $taxonomy_slug = $this->taxonomy_helper->get_taxonomy_slug( $taxonomy );
202
203 $new_taxonomy_bases[ $taxonomy ] = $taxonomy_slug;
204
205 if ( ! \array_key_exists( $taxonomy, $custom_taxonomy_bases ) ) {
206 continue;
207 }
208
209 if ( $taxonomy_slug !== $custom_taxonomy_bases[ $taxonomy ] ) {
210 $this->indexable_helper->reset_permalink_indexables( 'term', $taxonomy );
211 }
212 }
213
214 $this->options_helper->set( 'custom_taxonomy_slugs', $new_taxonomy_bases );
215 }
216
217 /**
218 * Retrieves a list with the public post types.
219 *
220 * @return array The post types.
221 */
222 protected function get_post_types() {
223 /**
224 * Filter: Gives the possibility to filter out post types.
225 *
226 * @param array $post_types The post type names.
227 *
228 * @return array The post types.
229 */
230 $post_types = \apply_filters( 'wpseo_post_types_reset_permalinks', $this->post_type->get_public_post_types() );
231
232 return $post_types;
233 }
234
235 /**
236 * Retrieves the taxonomies that belongs to the public post types.
237 *
238 * @param array $post_types The post types to get taxonomies for.
239 *
240 * @return array The retrieved taxonomies.
241 */
242 protected function get_taxonomies_for_post_types( $post_types ) {
243 $taxonomies = [];
244 foreach ( $post_types as $post_type ) {
245 $taxonomies[] = \get_object_taxonomies( $post_type, 'names' );
246 }
247
248 $taxonomies = \array_merge( [], ...$taxonomies );
249 $taxonomies = \array_unique( $taxonomies );
250
251 return $taxonomies;
252 }
253
254 /**
255 * Schedules the WP-Cron job to check the permalink_structure status.
256 *
257 * @return void
258 */
259 protected function schedule_cron() {
260 if ( \wp_next_scheduled( 'wpseo_permalink_structure_check' ) ) {
261 return;
262 }
263
264 \wp_schedule_event( \time(), 'daily', 'wpseo_permalink_structure_check' );
265 }
266
267 /**
268 * Unschedules the WP-Cron job to check the permalink_structure status.
269 *
270 * @return void
271 */
272 public function unschedule_cron() {
273 if ( ! \wp_next_scheduled( 'wpseo_permalink_structure_check' ) ) {
274 return;
275 }
276
277 \wp_clear_scheduled_hook( 'wpseo_permalink_structure_check' );
278 }
279 }
280