SlugMonitor.php
5.23 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
<?php
namespace AIOSEO\Plugin\Common\Admin;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Monitors changes to post slugs.
*
* @since 4.2.3
*/
class SlugMonitor {
/**
* Holds posts that have been updated.
*
* @since 4.2.3
*
* @var array
*/
private $updatedPosts = [];
/**
* Class constructor.
*
* @since 4.2.3
*/
public function __construct() {
// We can't monitor changes without permalinks enabled.
if ( ! get_option( 'permalink_structure' ) ) {
return;
}
add_action( 'pre_post_update', [ $this, 'prePostUpdate' ] );
// WP 5.6+.
if ( function_exists( 'wp_after_insert_post' ) ) {
add_action( 'wp_after_insert_post', [ $this, 'afterInsertPost' ], 11, 4 );
} else {
add_action( 'post_updated', [ $this, 'postUpdated' ], 11, 3 );
}
}
/**
* Remember the previous post permalink.
*
* @since 4.2.3
*
* @param integer $postId The post ID.
* @return void
*/
public function prePostUpdate( $postId ) {
$this->updatedPosts[ $postId ] = get_permalink( $postId );
}
/**
* Called when a post has been completely inserted ( with categories and meta ).
*
* @since 4.2.3
*
* @param integer $postId The post ID.
* @param \WP_Post $post The post object.
* @param bool $update Whether this is an existing post being updated.
* @param null|\WP_Post $postBefore The post object before changes were made.
* @return void
*/
public function afterInsertPost( $postId, $post, $update, $postBefore ) {
if ( ! $update ) {
return;
}
$this->postUpdated( $postId, $post, $postBefore );
}
/**
* Called when a post has been updated - check if the slug has changed.
*
* @since 4.2.3
*
* @param integer $postId The post ID.
* @param \WP_Post $post The post object.
* @param \WP_Post $postBefore The post object before changes were made.
* @return void
*/
public function postUpdated( $postId, $post, $postBefore ) {
if ( ! isset( $this->updatedPosts[ $postId ] ) ) {
return;
}
$before = aioseo()->helpers->getPermalinkPath( $this->updatedPosts[ $postId ] );
$after = aioseo()->helpers->getPermalinkPath( get_permalink( $postId ) );
if ( ! aioseo()->helpers->hasPermalinkChanged( $before, $after ) ) {
return;
}
// Can we monitor this slug?
if ( ! $this->canMonitorPost( $post, $postBefore ) ) {
return;
}
// Ask aioseo-redirects if automatic redirects is monitoring it.
if ( $this->automaticRedirect( $post->post_type, $before, $after ) ) {
return;
}
// Filter to allow users to disable the slug monitor messages.
if ( apply_filters( 'aioseo_redirects_disable_slug_monitor', false ) ) {
return;
}
$redirectUrl = $this->manualRedirectUrl( [
'url' => $before,
'target' => $after,
'type' => 301
] );
$message = __( 'The permalink for this post just changed! This could result in 404 errors for your site visitors.', 'all-in-one-seo-pack' );
// Default notice redirecting to the Redirects screen.
$action = [
'url' => $redirectUrl,
'label' => __( 'Add Redirect to improve SEO', 'all-in-one-seo-pack' ),
'target' => '_blank',
'class' => 'aioseo-redirects-slug-changed'
];
// If redirects is active we'll show add-redirect in a modal.
if ( aioseo()->addons->getLoadedAddon( 'redirects' ) ) {
// We need to remove the target here so the action keeps the url used by the add-redirect modal.
unset( $action['target'] );
}
aioseo()->wpNotices->addNotice( $message, 'warning', [ 'actions' => [ $action ] ], [ 'posts' ] );
}
/**
* Checks if this is a post we can monitor.
*
* @since 4.2.3
*
* @param \WP_Post $post The post object.
* @param \WP_Post $postBefore The post object before changes were made.
* @return boolean True if we can monitor this post.
*/
private function canMonitorPost( $post, $postBefore ) {
// Check that this is for the expected post.
if ( ! isset( $post->ID ) || ! isset( $this->updatedPosts[ $post->ID ] ) ) {
return false;
}
// Don't do anything if we're not published.
if ( 'publish' !== $post->post_status || 'publish' !== $postBefore->post_status ) {
return false;
}
// Don't do anything is the post type is not public.
if ( ! is_post_type_viewable( $post->post_type ) ) {
return false;
}
return true;
}
/**
* Tries to add a automatic redirect.
*
* @since 4.2.3
*
* @param string $postType The post type.
* @param string $before The url before.
* @param string $after The url after.
* @return bool True if an automatic redirect was added.
*/
private function automaticRedirect( $postType, $before, $after ) {
if ( ! aioseo()->addons->getLoadedAddon( 'redirects' ) ) {
return false;
}
return aioseoRedirects()->monitor->automaticRedirect( $postType, $before, $after );
}
/**
* Generates a URL for adding manual redirects.
*
* @since 4.2.3
*
* @param array $urls An array of [url, target, type, slash, case, regex].
* @return string The redirect link.
*/
public function manualRedirectUrl( $urls ) {
if ( ! aioseo()->addons->getLoadedAddon( 'redirects' ) ) {
return admin_url( 'admin.php?page=aioseo-redirects' );
}
return aioseoRedirects()->helpers->manualRedirectUrl( $urls );
}
}