PluginProbe ʕ •ᴥ•ʔ
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 18.0
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v18.0
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 19.1 19.10 19.11 19.12 19.13 19.14 19.2 19.3 19.4 19.5 19.5.1 19.6 19.6.1 19.7 19.7.1 19.7.2 19.8 19.9 20.0 20.1 20.10 20.11 20.12 20.13 20.2 20.2.1 20.3 20.4 20.5 20.6 20.7 20.8 20.9 21.0 21.1 21.2 21.3 21.4 21.5 21.6 21.7 21.8 21.8.1 21.9 21.9.1 22.0 22.1 22.2 22.3 22.4 22.5 22.6 22.7 22.8 22.9 23.0 23.1 23.2 23.3 23.4 23.5 23.6 23.7 23.8 23.9 24.0 24.1 24.2 24.3 24.4 24.5 24.6 24.7 24.8 24.8.1 24.9 25.0 25.1 25.2 25.3 25.3.1 25.4 25.5 25.6 25.7 25.8 25.9 26.0 26.1 26.1.1 26.2 26.3 26.4 26.5 26.6 26.7 26.8 26.9 27.0 27.1 27.1.1 27.2 27.3 27.4
wordpress-seo / admin / class-admin-init.php
wordpress-seo / admin Last commit date
ajax 5 years ago capabilities 4 years ago endpoints 5 years ago exceptions 7 years ago filters 4 years ago formatter 4 years ago google_search_console 5 years ago import 4 years ago listeners 8 years ago menu 4 years ago metabox 4 years ago notifiers 4 years ago pages 4 years ago roles 5 years ago ryte 5 years ago services 5 years ago statistics 5 years ago taxonomy 4 years ago tracking 4 years ago views 4 years ago watchers 5 years ago admin-settings-changed-listener.php 5 years ago ajax.php 4 years ago class-admin-asset-analysis-worker-location.php 5 years ago class-admin-asset-dev-server-location.php 5 years ago class-admin-asset-location.php 8 years ago class-admin-asset-manager.php 4 years ago class-admin-asset-seo-location.php 4 years ago class-admin-asset-yoast-components-l10n.php 5 years ago class-admin-editor-specific-replace-vars.php 5 years ago class-admin-gutenberg-compatibility-notification.php 5 years ago class-admin-help-panel.php 5 years ago class-admin-init.php 4 years ago class-admin-recommended-replace-vars.php 6 years ago class-admin-user-profile.php 6 years ago class-admin-utils.php 5 years ago class-admin.php 4 years ago class-asset.php 5 years ago class-bulk-description-editor-list-table.php 5 years ago class-bulk-editor-list-table.php 4 years ago class-bulk-title-editor-list-table.php 6 years ago class-collector.php 6 years ago class-config.php 4 years ago class-customizer.php 5 years ago class-database-proxy.php 5 years ago class-export.php 5 years ago class-expose-shortlinks.php 4 years ago class-gutenberg-compatibility.php 4 years ago class-helpscout.php 5 years ago class-meta-columns.php 5 years ago class-my-yoast-proxy.php 5 years ago class-option-tab.php 4 years ago class-option-tabs-formatter.php 5 years ago class-option-tabs.php 5 years ago class-paper-presenter.php 5 years ago class-plugin-availability.php 5 years ago class-plugin-conflict.php 4 years ago class-premium-popup.php 5 years ago class-premium-upsell-admin-block.php 4 years ago class-primary-term-admin.php 5 years ago class-product-upsell-notice.php 5 years ago class-remote-request.php 5 years ago class-schema-person-upgrade-notification.php 4 years ago class-suggested-plugins.php 4 years ago class-yoast-columns.php 5 years ago class-yoast-dashboard-widget.php 4 years ago class-yoast-form.php 4 years ago class-yoast-input-validation.php 5 years ago class-yoast-network-admin.php 5 years ago class-yoast-network-settings-api.php 4 years ago class-yoast-notification-center.php 4 years ago class-yoast-notification.php 5 years ago class-yoast-notifications.php 5 years ago class-yoast-plugin-conflict.php 4 years ago index.php 10 years ago interface-collection.php 7 years ago interface-installable.php 8 years ago
class-admin-init.php
499 lines
1 <?php
2 /**
3 * WPSEO plugin file.
4 *
5 * @package WPSEO\Admin
6 */
7
8 /**
9 * Performs the load on admin side.
10 */
11 class WPSEO_Admin_Init {
12
13 /**
14 * Holds the global `$pagenow` variable's value.
15 *
16 * @var string
17 */
18 private $pagenow;
19
20 /**
21 * Holds the asset manager.
22 *
23 * @var WPSEO_Admin_Asset_Manager
24 */
25 private $asset_manager;
26
27 /**
28 * Class constructor.
29 */
30 public function __construct() {
31 $GLOBALS['wpseo_admin'] = new WPSEO_Admin();
32
33 $this->pagenow = $GLOBALS['pagenow'];
34
35 $this->asset_manager = new WPSEO_Admin_Asset_Manager();
36
37 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_dismissible' ] );
38 add_action( 'admin_init', [ $this, 'unsupported_php_notice' ], 15 );
39 add_action( 'admin_init', [ $this->asset_manager, 'register_assets' ] );
40 add_action( 'admin_init', [ $this, 'show_hook_deprecation_warnings' ] );
41 add_action( 'admin_init', [ 'WPSEO_Plugin_Conflict', 'hook_check_for_plugin_conflicts' ] );
42 add_action( 'admin_notices', [ $this, 'permalink_settings_notice' ] );
43 add_action( 'post_submitbox_misc_actions', [ $this, 'add_publish_box_section' ] );
44
45 /*
46 * The `admin_notices` hook fires on single site admin pages vs.
47 * `network_admin_notices` which fires on multisite admin pages and
48 * `user_admin_notices` which fires on multisite user admin pagss.
49 */
50 add_action( 'admin_notices', [ $this, 'search_engines_discouraged_notice' ] );
51
52 $health_checks = [
53 new WPSEO_Health_Check_Page_Comments(),
54 new WPSEO_Health_Check_Ryte(),
55 new WPSEO_Health_Check_Default_Tagline(),
56 new WPSEO_Health_Check_Postname_Permalink(),
57 new WPSEO_Health_Check_Curl_Version(),
58 new WPSEO_Health_Check_Link_Table_Not_Accessible(),
59 ];
60
61 foreach ( $health_checks as $health_check ) {
62 $health_check->register_test();
63 }
64
65 $this->load_meta_boxes();
66 $this->load_taxonomy_class();
67 $this->load_admin_page_class();
68 $this->load_admin_user_class();
69 $this->load_xml_sitemaps_admin();
70 $this->load_plugin_suggestions();
71 }
72
73 /**
74 * Enqueue our styling for dismissible yoast notifications.
75 */
76 public function enqueue_dismissible() {
77 $this->asset_manager->enqueue_style( 'dismissible' );
78 }
79
80 /**
81 * Creates an unsupported PHP version notification in the notification center.
82 *
83 * @return void
84 */
85 public function unsupported_php_notice() {
86 $notification_center = Yoast_Notification_Center::get();
87 $notification_center->remove_notification_by_id( 'wpseo-dismiss-unsupported-php' );
88 }
89
90 /**
91 * Gets the latest released major WordPress version from the WordPress stable-check api.
92 *
93 * @return float|int The latest released major WordPress version. 0 when the stable-check API doesn't respond.
94 */
95 private function get_latest_major_wordpress_version() {
96 $core_updates = get_core_updates( [ 'dismissed' => true ] );
97
98 if ( $core_updates === false ) {
99 return 0;
100 }
101
102 $wp_version_latest = get_bloginfo( 'version' );
103 foreach ( $core_updates as $update ) {
104 if ( $update->response === 'upgrade' && version_compare( $update->version, $wp_version_latest, '>' ) ) {
105 $wp_version_latest = $update->version;
106 }
107 }
108
109 // Strip the patch version and convert to a float.
110 return (float) $wp_version_latest;
111 }
112
113 /**
114 * Helper to verify if the user is currently visiting one of our admin pages.
115 *
116 * @return bool
117 */
118 private function on_wpseo_admin_page() {
119 return $this->pagenow === 'admin.php' && strpos( filter_input( INPUT_GET, 'page' ), 'wpseo' ) === 0;
120 }
121
122 /**
123 * Determine whether we should load the meta box class and if so, load it.
124 */
125 private function load_meta_boxes() {
126
127 $is_editor = WPSEO_Metabox::is_post_overview( $this->pagenow ) || WPSEO_Metabox::is_post_edit( $this->pagenow );
128 $is_inline_save = filter_input( INPUT_POST, 'action' ) === 'inline-save';
129
130 /**
131 * Filter: 'wpseo_always_register_metaboxes_on_admin' - Allow developers to change whether
132 * the WPSEO metaboxes are only registered on the typical pages (lean loading) or always
133 * registered when in admin.
134 *
135 * @api bool Whether to always register the metaboxes or not. Defaults to false.
136 */
137 if ( $is_editor || $is_inline_save || apply_filters( 'wpseo_always_register_metaboxes_on_admin', false )
138 ) {
139 $GLOBALS['wpseo_metabox'] = new WPSEO_Metabox();
140 $GLOBALS['wpseo_meta_columns'] = new WPSEO_Meta_Columns();
141 }
142 }
143
144 /**
145 * Determine if we should load our taxonomy edit class and if so, load it.
146 */
147 private function load_taxonomy_class() {
148 if (
149 WPSEO_Taxonomy::is_term_edit( $this->pagenow )
150 || WPSEO_Taxonomy::is_term_overview( $this->pagenow )
151 ) {
152 new WPSEO_Taxonomy();
153 }
154 }
155
156 /**
157 * Determine if we should load our admin pages class and if so, load it.
158 *
159 * Loads admin page class for all admin pages starting with `wpseo_`.
160 */
161 private function load_admin_user_class() {
162 if ( in_array( $this->pagenow, [ 'user-edit.php', 'profile.php' ], true )
163 && current_user_can( 'edit_users' )
164 ) {
165 new WPSEO_Admin_User_Profile();
166 }
167 }
168
169 /**
170 * Determine if we should load our admin pages class and if so, load it.
171 *
172 * Loads admin page class for all admin pages starting with `wpseo_`.
173 */
174 private function load_admin_page_class() {
175
176 if ( $this->on_wpseo_admin_page() ) {
177 // For backwards compatabilty, this still needs a global, for now...
178 $GLOBALS['wpseo_admin_pages'] = new WPSEO_Admin_Pages();
179
180 $page = filter_input( INPUT_GET, 'page' );
181 // Only register the yoast i18n when the page is a Yoast SEO page.
182 if ( WPSEO_Utils::is_yoast_seo_free_page( $page ) ) {
183 $this->register_i18n_promo_class();
184 if ( $page !== 'wpseo_titles' ) {
185 $this->register_premium_upsell_admin_block();
186 }
187 }
188 }
189 }
190
191 /**
192 * Loads the plugin suggestions.
193 */
194 private function load_plugin_suggestions() {
195 $suggestions = new WPSEO_Suggested_Plugins( new WPSEO_Plugin_Availability(), Yoast_Notification_Center::get() );
196 $suggestions->register_hooks();
197 }
198
199 /**
200 * Registers the Premium Upsell Admin Block.
201 *
202 * @return void
203 */
204 private function register_premium_upsell_admin_block() {
205 if ( ! YoastSEO()->helpers->product->is_premium() ) {
206 $upsell_block = new WPSEO_Premium_Upsell_Admin_Block( 'wpseo_admin_promo_footer' );
207 $upsell_block->register_hooks();
208 }
209 }
210
211 /**
212 * Registers the promotion class for our GlotPress instance, then creates a notification with the i18n promo.
213 *
214 * @link https://github.com/Yoast/i18n-module
215 */
216 private function register_i18n_promo_class() {
217 // BC, because an older version of the i18n-module didn't have this class.
218 $i18n_module = new Yoast_I18n_WordPressOrg_v3(
219 [
220 'textdomain' => 'wordpress-seo',
221 'plugin_name' => 'Yoast SEO',
222 'hook' => 'wpseo_admin_promo_footer',
223 ],
224 false
225 );
226
227 $message = $i18n_module->get_promo_message();
228
229 if ( $message !== '' ) {
230 $message .= $i18n_module->get_dismiss_i18n_message_button();
231 }
232
233 $notification_center = Yoast_Notification_Center::get();
234
235 $notification = new Yoast_Notification(
236 $message,
237 [
238 'type' => Yoast_Notification::WARNING,
239 'id' => 'i18nModuleTranslationAssistance',
240 ]
241 );
242
243 if ( $message ) {
244 $notification_center->add_notification( $notification );
245
246 return;
247 }
248
249 $notification_center->remove_notification( $notification );
250 }
251
252 /**
253 * See if we should start our XML Sitemaps Admin class.
254 */
255 private function load_xml_sitemaps_admin() {
256 if ( WPSEO_Options::get( 'enable_xml_sitemap', false ) ) {
257 new WPSEO_Sitemaps_Admin();
258 }
259 }
260
261 /**
262 * Checks whether search engines are discouraged from indexing the site.
263 *
264 * @return bool Whether search engines are discouraged from indexing the site.
265 */
266 private function are_search_engines_discouraged() {
267 return (string) get_option( 'blog_public' ) === '0';
268 }
269
270 /**
271 * Shows deprecation warnings to the user if a plugin has registered a filter we have deprecated.
272 */
273 public function show_hook_deprecation_warnings() {
274 global $wp_filter;
275
276 if ( wp_doing_ajax() ) {
277 return;
278 }
279
280 // WordPress hooks that have been deprecated since a Yoast SEO version.
281 $deprecated_filters = [
282 'wpseo_genesis_force_adjacent_rel_home' => [
283 'version' => '9.4',
284 'alternative' => null,
285 ],
286 'wpseo_opengraph' => [
287 'version' => '14.0',
288 'alternative' => null,
289 ],
290 'wpseo_twitter' => [
291 'version' => '14.0',
292 'alternative' => null,
293 ],
294 'wpseo_twitter_taxonomy_image' => [
295 'version' => '14.0',
296 'alternative' => null,
297 ],
298 'wpseo_twitter_metatag_key' => [
299 'version' => '14.0',
300 'alternative' => null,
301 ],
302 'wp_seo_get_bc_ancestors' => [
303 'version' => '14.0',
304 'alternative' => 'wpseo_breadcrumb_links',
305 ],
306 'validate_facebook_app_id_api_response_code' => [
307 'version' => '15.5',
308 'alternative' => null,
309 ],
310 'validate_facebook_app_id_api_response_body' => [
311 'version' => '15.5',
312 'alternative' => null,
313 ],
314 ];
315
316 // Determine which filters have been registered.
317 $deprecated_notices = array_intersect(
318 array_keys( $deprecated_filters ),
319 array_keys( $wp_filter )
320 );
321
322 // Show notice for each deprecated filter or action that has been registered.
323 foreach ( $deprecated_notices as $deprecated_filter ) {
324 $deprecation_info = $deprecated_filters[ $deprecated_filter ];
325 // phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped -- Only uses the hardcoded values from above.
326 _deprecated_hook(
327 $deprecated_filter,
328 'WPSEO ' . $deprecation_info['version'],
329 $deprecation_info['alternative']
330 );
331 // phpcs:enable
332 }
333 }
334
335 /**
336 * Check if the permalink uses %postname%.
337 *
338 * @return bool
339 */
340 private function has_postname_in_permalink() {
341 return ( strpos( get_option( 'permalink_structure' ), '%postname%' ) !== false );
342 }
343
344 /**
345 * Shows a notice on the permalink settings page.
346 */
347 public function permalink_settings_notice() {
348 global $pagenow;
349
350 if ( $pagenow === 'options-permalink.php' ) {
351 printf(
352 '<div class="notice notice-warning"><p><strong>%1$s</strong><br>%2$s<br><a href="%3$s" target="_blank">%4$s</a></p></div>',
353 esc_html__( 'WARNING:', 'wordpress-seo' ),
354 sprintf(
355 /* translators: %1$s and %2$s expand to <em> items to emphasize the word in the middle. */
356 esc_html__( 'Changing your permalinks settings can seriously impact your search engine visibility. It should almost %1$s never %2$s be done on a live website.', 'wordpress-seo' ),
357 '<em>',
358 '</em>'
359 ),
360 esc_url( WPSEO_Shortlinker::get( 'https://yoa.st/why-permalinks/' ) ),
361 // The link's content.
362 esc_html__( 'Learn about why permalinks are important for SEO.', 'wordpress-seo' )
363 );
364 }
365 }
366
367 /**
368 * Determines whether and where the "search engines discouraged" admin notice should be displayed.
369 *
370 * @return bool Whether the "search engines discouraged" admin notice should be displayed.
371 */
372 private function should_display_search_engines_discouraged_notice() {
373 $discouraged_pages = [
374 'index.php',
375 'plugins.php',
376 'update-core.php',
377 ];
378
379 return (
380 $this->are_search_engines_discouraged()
381 && WPSEO_Capability_Utils::current_user_can( 'manage_options' )
382 && WPSEO_Options::get( 'ignore_search_engines_discouraged_notice', false ) === false
383 && (
384 $this->on_wpseo_admin_page()
385 || in_array( $this->pagenow, $discouraged_pages, true )
386 )
387 );
388 }
389
390 /**
391 * Displays an admin notice when WordPress is set to discourage search engines from indexing the site.
392 *
393 * @return void
394 */
395 public function search_engines_discouraged_notice() {
396 if ( ! $this->should_display_search_engines_discouraged_notice() ) {
397 return;
398 }
399
400 printf(
401 '<div id="robotsmessage" class="notice notice-error"><p><strong>%1$s</strong> %2$s <button type="button" id="robotsmessage-dismiss-button" class="button-link hide-if-no-js" data-nonce="%3$s">%4$s</button></p></div>',
402 esc_html__( 'Huge SEO Issue: You\'re blocking access to robots.', 'wordpress-seo' ),
403 sprintf(
404 /* translators: 1: Link start tag to the WordPress Reading Settings page, 2: Link closing tag. */
405 esc_html__( 'If you want search engines to show this site in their results, you must %1$sgo to your Reading Settings%2$s and uncheck the box for Search Engine Visibility.', 'wordpress-seo' ),
406 '<a href="' . esc_url( admin_url( 'options-reading.php' ) ) . '">',
407 '</a>'
408 ),
409 esc_js( wp_create_nonce( 'wpseo-ignore' ) ),
410 esc_html__( 'I don\'t want this site to show in the search results.', 'wordpress-seo' )
411 );
412 }
413
414 /**
415 * Adds a custom Yoast section within the Classic Editor publish box.
416 *
417 * @param \WP_Post $post The current post object.
418 *
419 * @return void
420 */
421 public function add_publish_box_section( $post ) {
422 if ( in_array( $this->pagenow, [ 'post.php', 'post-new.php' ], true ) ) {
423 ?>
424 <div id="yoast-seo-publishbox-section"></div>
425 <?php
426 /**
427 * Fires after the post time/date setting in the Publish meta box.
428 *
429 * @api \WP_Post The current post object.
430 */
431 do_action( 'wpseo_publishbox_misc_actions', $post );
432 }
433 }
434
435 /* ********************* DEPRECATED METHODS ********************* */
436
437 /**
438 * Notify about the default tagline if the user hasn't changed it.
439 *
440 * @deprecated 13.2
441 * @codeCoverageIgnore
442 */
443 public function tagline_notice() {
444 _deprecated_function( __METHOD__, 'WPSEO 13.2' );
445 }
446
447 /**
448 * Returns whether or not the site has the default tagline.
449 *
450 * @deprecated 13.2
451 * @codeCoverageIgnore
452 *
453 * @return bool
454 */
455 public function has_default_tagline() {
456 _deprecated_function( __METHOD__, 'WPSEO 13.2' );
457
458 $blog_description = get_bloginfo( 'description' );
459 $default_blog_description = 'Just another WordPress site';
460
461 // We are using the WordPress internal translation.
462 $translated_blog_description = __( 'Just another WordPress site', 'default' );
463
464 return $translated_blog_description === $blog_description || $default_blog_description === $blog_description;
465 }
466
467 /**
468 * Shows an alert when the permalink doesn't contain %postname%.
469 *
470 * @deprecated 13.2
471 * @codeCoverageIgnore
472 */
473 public function permalink_notice() {
474 _deprecated_function( __METHOD__, 'WPSEO 13.2' );
475 }
476
477 /**
478 * Add an alert if the blog is not publicly visible.
479 *
480 * @deprecated 14.1
481 * @codeCoverageIgnore
482 */
483 public function blog_public_notice() {
484 _deprecated_function( __METHOD__, 'WPSEO 14.1' );
485 }
486
487 /**
488 * Handles the notifiers for the dashboard page.
489 *
490 * @deprecated 14.1
491 * @codeCoverageIgnore
492 *
493 * @return void
494 */
495 public function handle_notifications() {
496 _deprecated_function( __METHOD__, 'WPSEO 14.1' );
497 }
498 }
499