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