• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Yoast / wordpress-seo / 59517635615d055f783a2be92e52a1e2637df1be

17 Feb 2025 11:08AM UTC coverage: 53.377% (-1.3%) from 54.636%
59517635615d055f783a2be92e52a1e2637df1be

Pull #22048

github

web-flow
Merge e41dbb150 into 711656c23
Pull Request #22048: Update Dashboard page description

7808 of 13867 branches covered (56.31%)

Branch coverage included in aggregate %.

4 of 5 new or added lines in 2 files covered. (80.0%)

1554 existing lines in 42 files now uncovered.

30279 of 57488 relevant lines covered (52.67%)

40022.22 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

21.51
/admin/watchers/class-slug-change-watcher.php
1
<?php
2
/**
3
 * WPSEO plugin file.
4
 *
5
 * @package WPSEO\Admin\Watchers
6
 */
7

8
/**
9
 * Class WPSEO_Slug_Change_Watcher.
10
 */
11
class WPSEO_Slug_Change_Watcher implements WPSEO_WordPress_Integration {
12

13
        /**
14
         * Registers all hooks to WordPress.
15
         *
16
         * @return void
17
         */
18
        public function register_hooks() {
×
19
                // If the current plugin is Yoast SEO Premium, stop registering.
20
                if ( YoastSEO()->helpers->product->is_premium() ) {
×
21
                        return;
×
22
                }
23

24
                add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
×
25

26
                // Detect a post trash.
27
                add_action( 'wp_trash_post', [ $this, 'detect_post_trash' ] );
×
28

29
                // Detect a post delete.
30
                add_action( 'before_delete_post', [ $this, 'detect_post_delete' ] );
×
31

32
                // Detects deletion of a term.
33
                add_action( 'delete_term_taxonomy', [ $this, 'detect_term_delete' ] );
×
34
        }
35

36
        /**
37
         * Enqueues the quick edit handler.
38
         *
39
         * @return void
40
         */
41
        public function enqueue_assets() {
×
42
                global $pagenow;
×
43

44
                if ( ! in_array( $pagenow, [ 'edit.php', 'edit-tags.php' ], true ) ) {
×
45
                        return;
×
46
                }
47

48
                $asset_manager = new WPSEO_Admin_Asset_Manager();
×
49
                $asset_manager->enqueue_script( 'quick-edit-handler' );
×
50
        }
51

52
        /**
53
         * Shows a message when a post is about to get trashed.
54
         *
55
         * @param int $post_id The current post ID.
56
         *
57
         * @return void
58
         */
59
        public function detect_post_trash( $post_id ) {
4✔
60
                if ( ! $this->is_post_viewable( $post_id ) ) {
4✔
61
                        return;
2✔
62
                }
63

64
                $post_label = $this->get_post_type_label( get_post_type( $post_id ) );
2✔
65

66
                /* translators: %1$s expands to the translated name of the post type. */
67
                $first_sentence  = sprintf( __( 'You just trashed a %1$s.', 'wordpress-seo' ), $post_label );
2✔
68
                $second_sentence = __( 'Search engines and other websites can still send traffic to your trashed content.', 'wordpress-seo' );
2✔
69
                $message         = $this->get_message( $first_sentence, $second_sentence );
2✔
70

71
                $this->add_notification( $message );
2✔
72
        }
73

74
        /**
75
         * Shows a message when a post is about to get trashed.
76
         *
77
         * @param int $post_id The current post ID.
78
         *
79
         * @return void
80
         */
81
        public function detect_post_delete( $post_id ) {
6✔
82
                if ( ! $this->is_post_viewable( $post_id ) ) {
6✔
83
                        return;
6✔
84
                }
85

86
                $post_label = $this->get_post_type_label( get_post_type( $post_id ) );
×
87

88
                /* translators: %1$s expands to the translated name of the post type. */
89
                $first_sentence  = sprintf( __( 'You just deleted a %1$s.', 'wordpress-seo' ), $post_label );
×
90
                $second_sentence = __( 'Search engines and other websites can still send traffic to your deleted content.', 'wordpress-seo' );
×
91
                $message         = $this->get_message( $first_sentence, $second_sentence );
×
92

93
                $this->add_notification( $message );
×
94
        }
95

96
        /**
97
         * Shows a message when a term is about to get deleted.
98
         *
99
         * @param int $term_taxonomy_id The term taxonomy ID that will be deleted.
100
         *
101
         * @return void
102
         */
103
        public function detect_term_delete( $term_taxonomy_id ) {
4✔
104
                if ( ! $this->is_term_viewable( $term_taxonomy_id ) ) {
4✔
105
                        return;
2✔
106
                }
107

108
                $term       = get_term_by( 'term_taxonomy_id', (int) $term_taxonomy_id );
2✔
109
                $term_label = $this->get_taxonomy_label_for_term( $term->term_id );
2✔
110

111
                /* translators: %1$s expands to the translated name of the term. */
112
                $first_sentence  = sprintf( __( 'You just deleted a %1$s.', 'wordpress-seo' ), $term_label );
2✔
113
                $second_sentence = __( 'Search engines and other websites can still send traffic to your deleted content.', 'wordpress-seo' );
2✔
114
                $message         = $this->get_message( $first_sentence, $second_sentence );
2✔
115

116
                $this->add_notification( $message );
2✔
117
        }
118

119
        /**
120
         * Checks if the post is viewable.
121
         *
122
         * @param string $post_id The post id to check.
123
         *
124
         * @return bool Whether the post is viewable or not.
125
         */
126
        protected function is_post_viewable( $post_id ) {
×
127
                $post_type = get_post_type( $post_id );
×
128
                if ( ! WPSEO_Post_Type::is_post_type_accessible( $post_type ) ) {
×
129
                        return false;
×
130
                }
131

132
                $post_status = get_post_status( $post_id );
×
133
                if ( ! $this->check_visible_post_status( $post_status ) ) {
×
134
                        return false;
×
135
                }
136

137
                return true;
×
138
        }
139

140
        /**
141
         * Checks if the term is viewable.
142
         *
143
         * @param int $term_taxonomy_id The term taxonomy ID to check.
144
         *
145
         * @return bool Whether the term is viewable or not.
146
         */
147
        protected function is_term_viewable( $term_taxonomy_id ) {
×
148
                $term = get_term_by( 'term_taxonomy_id', (int) $term_taxonomy_id );
×
149

150
                if ( ! $term || is_wp_error( $term ) ) {
×
151
                        return false;
×
152
                }
153

154
                $taxonomy = get_taxonomy( $term->taxonomy );
×
155
                if ( ! $taxonomy ) {
×
156
                        return false;
×
157
                }
158

159
                return $taxonomy->publicly_queryable || $taxonomy->public;
×
160
        }
161

162
        /**
163
         * Gets the taxonomy label to use for a term.
164
         *
165
         * @param int $term_id The term ID.
166
         *
167
         * @return string The taxonomy's singular label.
168
         */
169
        protected function get_taxonomy_label_for_term( $term_id ) {
×
170
                $term     = get_term( $term_id );
×
171
                $taxonomy = get_taxonomy( $term->taxonomy );
×
172

173
                return $taxonomy->labels->singular_name;
×
174
        }
175

176
        /**
177
         * Retrieves the singular post type label.
178
         *
179
         * @param string $post_type Post type to retrieve label from.
180
         *
181
         * @return string The singular post type name.
182
         */
183
        protected function get_post_type_label( $post_type ) {
×
184
                $post_type_object = get_post_type_object( $post_type );
×
185

186
                // If the post type of this post wasn't registered default back to post.
187
                if ( $post_type_object === null ) {
×
188
                        $post_type_object = get_post_type_object( 'post' );
×
189
                }
190

191
                return $post_type_object->labels->singular_name;
×
192
        }
193

194
        /**
195
         * Checks whether the given post status is visible or not.
196
         *
197
         * @param string $post_status The post status to check.
198
         *
199
         * @return bool Whether or not the post is visible.
200
         */
201
        protected function check_visible_post_status( $post_status ) {
×
UNCOV
202
                $visible_post_statuses = [
×
203
                        'publish',
×
UNCOV
204
                        'static',
×
UNCOV
205
                        'private',
×
UNCOV
206
                ];
×
207

208
                return in_array( $post_status, $visible_post_statuses, true );
×
209
        }
210

211
        /**
212
         * Returns the message around changed URLs.
213
         *
214
         * @param string $first_sentence  The first sentence of the notification.
215
         * @param string $second_sentence The second sentence of the notification.
216
         *
217
         * @return string The full notification.
218
         */
219
        protected function get_message( $first_sentence, $second_sentence ) {
×
220
                return '<h2>' . __( 'Make sure you don\'t miss out on traffic!', 'wordpress-seo' ) . '</h2>'
×
221
                        . '<p>'
×
222
                        . $first_sentence
×
223
                        . ' ' . $second_sentence
×
224
                        . ' ' . __( 'You should create a redirect to ensure your visitors do not get a 404 error when they click on the no longer working URL.', 'wordpress-seo' )
×
225
                        /* translators: %s expands to Yoast SEO Premium */
226
                        . ' ' . sprintf( __( 'With %s, you can easily create such redirects.', 'wordpress-seo' ), 'Yoast SEO Premium' )
×
227
                        . '</p>'
×
228
                        . '<p><a class="yoast-button-upsell" data-action="load-nfd-ctb" data-ctb-id="f6a84663-465f-4cb5-8ba5-f7a6d72224b2" href="' . WPSEO_Shortlinker::get( 'https://yoa.st/1d0' ) . '" target="_blank">'
×
229
                        /* translators: %s expands to Yoast SEO Premium */
230
                        . sprintf( __( 'Get %s', 'wordpress-seo' ), 'Yoast SEO Premium' )
×
231
                        /* translators: Hidden accessibility text. */
232
                        . '<span class="screen-reader-text">' . __( '(Opens in a new browser tab)', 'wordpress-seo' ) . '</span>'
×
233
                        . '<span aria-hidden="true" class="yoast-button-upsell__caret"></span>'
×
234
                        . '</a></p>';
×
235
        }
236

237
        /**
238
         * Adds a notification to be shown on the next page request since posts are updated in an ajax request.
239
         *
240
         * @param string $message The message to add to the notification.
241
         *
242
         * @return void
243
         */
244
        protected function add_notification( $message ) {
×
245
                $notification = new Yoast_Notification(
×
246
                        $message,
×
UNCOV
247
                        [
×
248
                                'type'           => 'notice-warning is-dismissible',
×
UNCOV
249
                                'yoast_branding' => true,
×
UNCOV
250
                        ]
×
UNCOV
251
                );
×
252

253
                $notification_center = Yoast_Notification_Center::get();
×
254
                $notification_center->add_notification( $notification );
×
255
        }
256
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc