PluginProbe
Redirection / 5.6.0
Redirection v5.6.0
5.10.0 5.9.0 5.8.1 5.8.0 3.7.2 3.7.3 4.0 4.0.1 4.1 4.1.1 4.2 4.2.1 4.2.2 4.2.3 4.3 4.3.1 4.3.2 4.3.3 4.4 4.4.1 4.4.2 4.5 4.5.1 4.6.2 4.7.1 All 130 releases
redirection / models / monitor.php

monitor.php in Redirection 5.6.0, at models/monitor.php

216 lines 5.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class Red_Monitor {
4 /**
5 * @var int
6 */
7 private $monitor_group_id = 0;
8
9 /**
10 * @var array<int, string>
11 */
12 private $updated_posts = array();
13
14 /**
15 * @var list<string>
16 */
17 private $monitor_types = array();
18
19 /**
20 * @var string
21 */
22 private $associated = '';
23
24 /**
25 * @param array<string, mixed> $options
26 */
27 public function __construct( array $options ) {
28 $this->monitor_types = apply_filters( 'redirection_monitor_types', isset( $options['monitor_types'] ) ? $options['monitor_types'] : array() );
29
30 if ( count( $this->monitor_types ) > 0 && $options['monitor_post'] > 0 ) {
31 $this->monitor_group_id = intval( $options['monitor_post'], 10 );
32 $this->associated = isset( $options['associated_redirect'] ) ? $options['associated_redirect'] : '';
33
34 // Only monitor if permalinks enabled
35 if ( get_option( 'permalink_structure' ) !== false ) {
36 add_action( 'pre_post_update', array( $this, 'pre_post_update' ), 10, 2 );
37 add_action( 'post_updated', array( $this, 'post_updated' ), 11, 3 );
38 add_action( 'redirection_remove_existing', array( $this, 'remove_existing_redirect' ) );
39 add_filter( 'redirection_permalink_changed', array( $this, 'has_permalink_changed' ), 10, 3 );
40
41 if ( in_array( 'trash', $this->monitor_types, true ) ) {
42 add_action( 'wp_trash_post', array( $this, 'post_trashed' ) );
43 }
44 }
45 }
46 }
47
48 /**
49 * @param string $url
50 * @return void
51 */
52 public function remove_existing_redirect( string $url ): void {
53 Red_Item::disable_where_matches( $url );
54 }
55
56 /**
57 * @param WP_Post $post
58 * @param WP_Post $post_before
59 * @return bool
60 */
61 public function can_monitor_post( WP_Post $post, WP_Post $post_before ): bool {
62 // Check this is for the expected post
63 // @phpstan-ignore isset.property
64 if ( ! isset( $post->ID ) || ! isset( $this->updated_posts[ $post->ID ] ) ) {
65 return false;
66 }
67
68 // Don't do anything if we're not published
69 if ( $post->post_status !== 'publish' || $post_before->post_status !== 'publish' ) {
70 return false;
71 }
72
73 $type = get_post_type( $post->ID );
74 if ( ! in_array( $type, $this->monitor_types, true ) ) {
75 return false;
76 }
77
78 return true;
79 }
80
81 /**
82 * Called when a post has been updated - check if the slug has changed
83 *
84 * @param int $post_id
85 * @param WP_Post $post
86 * @param WP_Post $post_before
87 * @return void
88 */
89 public function post_updated( int $post_id, WP_Post $post, WP_Post $post_before ): void {
90 if ( isset( $this->updated_posts[ $post_id ] ) && $this->can_monitor_post( $post, $post_before ) ) {
91 $this->check_for_modified_slug( $post_id, $this->updated_posts[ $post_id ] );
92 }
93 }
94
95 /**
96 * Remember the previous post permalink
97 *
98 * @param int $post_id
99 * @param array<string, mixed> $data
100 * @return void
101 */
102 public function pre_post_update( int $post_id, array $data ): void {
103 $permalink = get_permalink( $post_id );
104 if ( $permalink !== false ) {
105 $this->updated_posts[ $post_id ] = $permalink;
106 }
107 }
108
109 /**
110 * @param int $post_id
111 * @return void
112 */
113 public function post_trashed( int $post_id ): void {
114 $permalink = get_permalink( $post_id );
115 if ( $permalink === false ) {
116 return;
117 }
118
119 $data = array(
120 'url' => wp_parse_url( $permalink, PHP_URL_PATH ),
121 'action_data' => array( 'url' => '/' ),
122 'match_type' => 'url',
123 'action_type' => 'url',
124 'action_code' => 301,
125 'group_id' => $this->monitor_group_id,
126 'status' => 'disabled',
127 );
128
129 // Create a new redirect for this post, but only if not draft
130 if ( $data['url'] !== null && $data['url'] !== false && $data['url'] !== '/' ) {
131 Red_Item::create( $data );
132 }
133 }
134
135 /**
136 * Changed if permalinks are different and the before wasn't the site url (we don't want to redirect the site URL)
137 *
138 * @param bool $result
139 * @param string|false $before
140 * @param string|false $after
141 * @return bool
142 */
143 public function has_permalink_changed( $result, $before, $after ) {
144 // Check it's not redirecting from the root
145 if ( $this->get_site_path() === $before || $before === '/' ) {
146 return false;
147 }
148
149 // Are the URLs the same?
150 if ( $before === $after ) {
151 return false;
152 }
153
154 return true;
155 }
156
157 /**
158 * @return string
159 */
160 private function get_site_path(): string {
161 $path = wp_parse_url( get_site_url(), PHP_URL_PATH );
162
163 if ( is_string( $path ) ) {
164 return rtrim( $path, '/' ) . '/';
165 }
166
167 return '/';
168 }
169
170 /**
171 * @param int $post_id
172 * @param string $before
173 * @return bool
174 */
175 public function check_for_modified_slug( int $post_id, string $before ): bool {
176 $permalink = get_permalink( $post_id );
177 if ( $permalink === false ) {
178 return false;
179 }
180
181 $after = wp_parse_url( $permalink, PHP_URL_PATH );
182 $before = wp_parse_url( esc_url( $before ), PHP_URL_PATH );
183
184 if ( is_string( $before ) && is_string( $after ) && apply_filters( 'redirection_permalink_changed', false, $before, $after ) ) {
185 do_action( 'redirection_remove_existing', $after, $post_id );
186
187 $data = array(
188 'url' => $before,
189 'action_data' => array( 'url' => $after ),
190 'match_type' => 'url',
191 'action_type' => 'url',
192 'action_code' => 301,
193 'group_id' => $this->monitor_group_id,
194 );
195
196 // Create a new redirect for this post
197 $new_item = Red_Item::create( $data );
198
199 if ( ! is_wp_error( $new_item ) ) {
200 do_action( 'redirection_monitor_created', $new_item, $before, $post_id );
201
202 if ( ! empty( $this->associated ) ) {
203 // Create an associated redirect for this post
204 $data['url'] = trailingslashit( $data['url'] ) . ltrim( $this->associated, '/' );
205 $data['action_data'] = array( 'url' => trailingslashit( $data['action_data']['url'] ) . ltrim( $this->associated, '/' ) );
206 Red_Item::create( $data );
207 }
208 }
209
210 return true;
211 }
212
213 return false;
214 }
215 }
216