PluginProbe
WPSSO Core – Complete Schema Markup and Meta Tags / 22.7.0
WPSSO Core – Complete Schema Markup and Meta Tags v22.7.0
22.7.0 22.6.1 22.6.0 22.5.3 22.5.2 22.5.1 22.4.0 22.3.0 22.2.1 22.2.0 22.1.3 22.1.2 22.1.1 22.1.0 22.0.0 21.13.3 21.13.2 trunk 21.13.1
← All changes | lib/admin-head.php +465 -0 22.2.022.7.0 View file →
@@ -1,0 +1,465 @@
1 +<?php
2 +/*
3 + * License: GPLv3
4 + * License URI: https://www.gnu.org/licenses/gpl.txt
5 + * Copyright 2012-2026 Jean-Sebastien Morisset (https://wpsso.com/)
6 + */
7 +
8 +if ( ! defined( 'ABSPATH' ) ) {
9 +
10 + die( 'These aren\'t the droids you\'re looking for.' );
11 +}
12 +
13 +if ( ! defined( 'WPSSO_PLUGINDIR' ) ) {
14 +
15 + die( 'Do. Or do not. There is no try.' );
16 +}
17 +
18 +if ( ! class_exists( 'WpssoAdminHead' ) ) {
19 +
20 + class WpssoAdminHead {
21 +
22 + private $p; // Wpsso class object.
23 +
24 + /*
25 + * Instantiated by WpssoAdmin->__construct().
26 + */
27 + public function __construct( &$plugin ) {
28 +
29 + $this->p =& $plugin;
30 +
31 + if ( $this->p->debug->enabled ) {
32 +
33 + $this->p->debug->mark();
34 + }
35 +
36 + $doing_ajax = SucomUtilWP::doing_ajax();
37 +
38 + if ( ! $doing_ajax ) {
39 +
40 + require_once WPSSO_PLUGINDIR . 'lib/admin-head-suggest.php';
41 +
42 + new WpssoAdminHeadSuggest( $plugin );
43 +
44 + add_action( 'admin_head', array( $this, 'wp_config_check' ), -300 );
45 + add_action( 'admin_head', array( $this, 'wp_php_versions' ), -200 ); // Requires 'manage_options' capability.
46 + add_action( 'admin_head', array( $this, 'pending_updates' ), -100 ); // Requires 'update_plugins' capability.
47 + add_action( 'admin_head', array( $this->p->util, 'log_is_functions' ), 10 );
48 + add_action( 'admin_head', array( $this->p->util->cache, 'show_admin_notices' ), -1000 );
49 + add_action( 'admin_head', array( $this, 'timed_notices' ), 200 ); // Requires 'manage_options' capability.
50 + }
51 + }
52 +
53 + public function wp_config_check() {
54 +
55 + if ( $this->p->debug->enabled ) {
56 +
57 + $this->p->debug->mark();
58 + }
59 +
60 + $user_id = get_current_user_id();
61 +
62 + if ( ! $user_id ) { // Nobody there.
63 +
64 + return; // Stop here.
65 + }
66 +
67 + global $wp_version;
68 +
69 + /*
70 + * Skip if a previous config check for this WordPress version was successful.
71 + */
72 + if ( $wp_version === get_option( WPSSO_WP_CONFIG_CHECK_NAME, $default = false ) ) {
73 +
74 + return; // Stop here.
75 + }
76 +
77 + /*
78 + * Check for a PHP variable in the WP_HOME constant value.
79 + */
80 + if ( $file_path = SucomUtilWP::get_wp_config_file_path() ) {
81 +
82 + $stripped_php = SucomUtil::get_stripped_php( $file_path );
83 +
84 + if ( preg_match( '/define\( *[\'"]WP_HOME[\'"][^\)]*\$/', $stripped_php ) ) {
85 +
86 + $notice_key = 'notice-wp-config-php-variable-home';
87 +
88 + $notice_msg = $this->p->msgs->get( $notice_key );
89 +
90 + $this->p->notice->err( $notice_msg, $user_id, $notice_key );
91 +
92 + return; // Stop here.
93 + }
94 + }
95 +
96 + /*
97 + * Check for an IP address in the home URL value.
98 + */
99 + $is_public = get_option( 'blog_public' );
100 +
101 + if ( $is_public ) {
102 +
103 + $home_url = SucomUtilWP::raw_get_home_url();
104 +
105 + if ( preg_match( '/^([a-z]+):\/\/([0-9\.]+)(:[0-9]+)?$/i', $home_url ) ) {
106 +
107 + $general_settings_url = get_admin_url( $blog_id = null, 'options-general.php' );
108 + $reading_settings_url = get_admin_url( $blog_id = null, 'options-reading.php' );
109 +
110 + $notice_msg = sprintf( __( 'The WordPress <a href="%1$s">Search Engine Visibility</a> option is set to allow search engines and social sites to access this site, but your <a href="%2$s">Site Address URL</a> value is an IP address (%3$s).', 'wpsso' ), $reading_settings_url, $general_settings_url, $home_url ) . ' ';
111 +
112 + $notice_msg .= __( 'Please update your Search Engine Visibility option to discourage search engines from indexing this site, or use a fully qualified domain name as your Site Address URL.', 'wpsso' );
113 +
114 + $notice_key = 'notice-wp-config-home-url-ip-address';
115 +
116 + $this->p->notice->warn( $notice_msg, $user_id, $notice_key );
117 +
118 + return; // Stop here.
119 + }
120 + }
121 +
122 + /*
123 + * Mark the config check for this WordPress version as successful.
124 + */
125 + update_option( WPSSO_WP_CONFIG_CHECK_NAME, $wp_version, $autoload = false );
126 + }
127 +
128 + public function wp_php_versions() {
129 +
130 + if ( current_user_can( 'manage_options' ) ) {
131 +
132 + $user_id = get_current_user_id();
133 +
134 + foreach ( array( 'wp', 'php' ) as $key ) {
135 +
136 + if ( isset( WpssoConfig::$cf[ $key ][ 'rec_version' ] ) ) {
137 +
138 + switch ( $key ) {
139 +
140 + case 'wp':
141 +
142 + global $wp_version;
143 +
144 + $app_version = $wp_version;
145 + $dismiss_time = MONTH_IN_SECONDS;
146 +
147 + break;
148 +
149 + case 'php':
150 +
151 + $app_version = phpversion();
152 + $dismiss_time = 3 * MONTH_IN_SECONDS;
153 +
154 + break;
155 +
156 + default:
157 +
158 + continue 2; // Get another $key.
159 + }
160 +
161 + $app_label = WpssoConfig::$cf[ $key ][ 'label' ];
162 + $rec_version = WpssoConfig::$cf[ $key ][ 'rec_version' ];
163 +
164 + if ( version_compare( $app_version, $rec_version, '<' ) ) {
165 +
166 + $warn_msg = $this->p->msgs->get( 'notice-recommend-version', array(
167 + 'app_label' => $app_label,
168 + 'app_version' => $app_version,
169 + 'rec_version' => WpssoConfig::$cf[ $key ][ 'rec_version' ],
170 + 'version_url' => WpssoConfig::$cf[ $key ][ 'version_url' ],
171 + ) );
172 +
173 + $notice_key = 'notice-recommend-version-' . $key . '-' . $rec_version;
174 +
175 + $this->p->notice->warn( $warn_msg, $user_id, $notice_key, $dismiss_time );
176 + }
177 + }
178 + }
179 + }
180 + }
181 +
182 + /*
183 + * Show a notice if there are pending WPSSO plugin updates and the user can update plugins.
184 + */
185 + public function pending_updates() {
186 +
187 + if ( current_user_can( 'update_plugins' ) ) {
188 +
189 + $update_count = SucomPlugin::get_update_count( $plugin_prefix = 'wpsso' );
190 +
191 + if ( $update_count > 0 ) {
192 +
193 + $p_info = $this->p->cf[ 'plugin' ][ 'wpsso' ];
194 + $p_name_transl = _x( $p_info[ 'name' ], 'plugin name', 'wpsso' );
195 + $notice_key = 'pending-updates-for-wpsso-and-addons';
196 + $dismiss_time = MONTH_IN_SECONDS;
197 +
198 + $notice_msg = sprintf( _n( 'There is <a href="%1$s">%2$d pending update for the %3$s plugin and its add-on(s)</a>.',
199 + 'There are <a href="%1$s">%2$d pending updates for the %3$s plugin and its add-on(s)</a>.', $update_count, 'wpsso' ),
200 + self_admin_url( 'update-core.php' ), $update_count, $p_name_transl ) . ' ';
201 +
202 + $notice_msg .= _n( 'Please install this update at your earliest convenience.',
203 + 'Please install these updates at your earliest convenience.', $update_count, 'wpsso' );
204 +
205 + $this->p->notice->inf( $notice_msg, null, $notice_key, $dismiss_time );
206 + }
207 + }
208 + }
209 +
210 + /*
211 + * Show a single notice at a time.
212 + */
213 + public function timed_notices() {
214 +
215 + if ( current_user_can( 'manage_options' ) ) {
216 +
217 + if ( ! $this->single_notice_review() ) {
218 +
219 + if ( ! $this->single_notice_upsell() ) {
220 +
221 + // Add more timed notices here as needed.
222 + }
223 + }
224 + }
225 + }
226 +
227 + /*
228 + * This method is called by timed_notices() if WordPress can dismiss notices and the user can manage options.
229 + *
230 + * These private notice functions should return the number of notices shown.
231 + */
232 + private function single_notice_review() {
233 +
234 + $form = $this->p->admin->get_form_object( $menu_ext = 'wpsso' ); // Return and maybe set/reset the WpssoAdmin->form value.
235 + $user_id = get_current_user_id();
236 + $ext_reg = $this->p->util->reg->get_ext_reg();
237 + $week_ago_secs = time() - ( 1 * WEEK_IN_SECONDS );
238 + $dismiss_time = true; // Allow the notice to be dismissed forever.
239 +
240 + /*
241 + * Use the transient cache to show only one notice per day.
242 + */
243 + $cache_md5_pre = 'wpsso_';
244 + $cache_exp_secs = DAY_IN_SECONDS;
245 + $cache_salt = __METHOD__ . '(user_id:' . $user_id . ')';
246 + $cache_id = $cache_md5_pre . md5( $cache_salt );
247 +
248 + $showing_ext = get_transient( $cache_id ); // Returns an empty string or the $notice_key value.
249 +
250 + foreach ( $this->p->cf[ 'plugin' ] as $ext => $ext_info ) {
251 +
252 + if ( empty( $ext_info[ 'name' ] ) ) { // Just in case.
253 +
254 + continue;
255 + }
256 +
257 + $p_info = $this->p->cf[ 'plugin' ][ 'wpsso' ];
258 + $p_name_transl = _x( $p_info[ 'name' ], 'plugin name', 'wpsso' );
259 + $ext_name_transl = _x( $ext_info[ 'name' ], 'plugin name', 'wpsso' );
260 + $ext_desc_transl = _x( $ext_info[ 'desc' ], 'plugin description', 'wpsso' );
261 +
262 + /*
263 + * Make sure the plugin is installed (ie. it has a version number).
264 + */
265 + if ( empty( $ext_info[ 'version' ] ) ) {
266 +
267 + continue; // Get the next plugin.
268 + }
269 +
270 + /*
271 + * Make sure we have wordpress.org review URL.
272 + */
273 + if ( empty( $ext_info[ 'url' ][ 'review' ] ) ) {
274 +
275 + continue; // Get the next plugin.
276 + }
277 +
278 + /*
279 + * The user has already dismissed this notice.
280 + */
281 + $notice_key = 'timed-notice-' . $ext . '-plugin-review';
282 +
283 + if ( $this->p->notice->is_dismissed( $notice_key, $user_id ) ) {
284 +
285 + /*
286 + * The single notice per day period has not expired yet.
287 + */
288 + if ( $showing_ext === $notice_key ) {
289 +
290 + return 0; // Stop here.
291 + }
292 +
293 + continue; // Get the next plugin.
294 +
295 + /*
296 + * Make sure we have an activation time.
297 + */
298 + } elseif ( empty( $ext_reg[ $ext . '_activate_time' ] ) ) {
299 +
300 + continue; // Get the next plugin.
301 +
302 + /*
303 + * Activated less than a week ago.
304 + */
305 + } elseif ( $ext_reg[ $ext . '_activate_time' ] > $week_ago_secs ) {
306 +
307 + continue; // Get the next plugin.
308 +
309 + /*
310 + * Make sure we only show this single notice for the next day.
311 + */
312 + } elseif ( empty( $showing_ext ) || $showing_ext === '1' ) {
313 +
314 + set_transient( $cache_id, $notice_key, $cache_exp_secs );
315 +
316 + /*
317 + * We're not showing this plugin right now.
318 + */
319 + } elseif ( $showing_ext !== $notice_key ) {
320 +
321 + continue; // Get the next plugin.
322 + }
323 +
324 + $activated_ago = human_time_diff( time(), $ext_reg[ $ext . '_activate_time' ] );
325 + $ext_type_transl = WpssoConfig::get_ext_type_transl( $ext );
326 + $wp_plugin_link = '<a href="' . $ext_info[ 'url' ][ 'home' ] . '">' . $ext_name_transl . '</a>';
327 + $wp_plugin_link_desc = $wp_plugin_link . ' (' . trim( $ext_desc_transl, '.' ) . ')';
328 +
329 + /*
330 + * Rate plugin action button.
331 + */
332 + $rate_plugin_label = sprintf( __( 'Rate the %1$s %2$s', 'wpsso' ), $ext_info[ 'short' ], $ext_type_transl );
333 + $rate_plugin_clicked = '<p>' . __( 'Thank you!', 'wpsso' ) . '</p>';
334 + $rate_plugin_button = '<div class="notice-single-button">' . $form->get_button( $rate_plugin_label, 'button-primary dismiss-on-click',
335 + '', $ext_info[ 'url' ][ 'review' ], true, false, array( 'dismiss-msg' => $rate_plugin_clicked ) ) . '</div>';
336 +
337 + /*
338 + * Already rated action button.
339 + */
340 + $already_rated_label = sprintf( __( 'I\'ve already rated the %2$s', 'wpsso' ), $ext_info[ 'short' ], $ext_type_transl );
341 + $already_rated_clicked = '<p>' . __( 'Thank you!', 'wpsso' ) . '</p>';
342 + $already_rated_button = '<div class="notice-single-button">' . $form->get_button( $already_rated_label, 'button-secondary dismiss-on-click',
343 + '', '', false, false, array( 'dismiss-msg' => $already_rated_clicked ) ) . '</div>';
344 +
345 + /*
346 + * The notice message.
347 + */
348 + $notice_msg = '<div style="display:table-cell;">';
349 + $notice_msg .= '<p style="margin-right:30px;">' . $this->p->admin->get_ext_img_icon( $ext ) . '</p>';
350 + $notice_msg .= '</div>';
351 + $notice_msg .= '<div style="display:table-cell;vertical-align:top;">';
352 + $notice_msg .= '<p><strong>';
353 +
354 + // translators: %1$s is the plugin name, %2$s is the plugin type (ie. "plugin" or "add-on"), and %3$s is a measure of time.
355 + $notice_msg .= sprintf( __( 'The %1$s %2$s was activated %3$s ago.', 'wpsso' ),
356 + $wp_plugin_link, $ext_type_transl, $activated_ago ) . ' ';
357 +
358 + $notice_msg .= '</strong></p><p>';
359 +
360 + // translators: %1$s is the plugin type (ie. "plugin" or "add-on").
361 + $notice_msg .= sprintf( __( 'Please encourage your %1$s %2$s developers by rating the %2$s.', 'wpsso' ),
362 + $wp_plugin_link, $ext_type_transl ) . ' ';
363 +
364 + $notice_msg .= '</p><p>';
365 +
366 + // translators: %1$s is the plugin type (ie. "plugin" or "add-on").
367 + $notice_msg .= sprintf( __( 'It only takes a moment, and it really does encourage us to keep improving the %1$s.', 'wpsso' ),
368 + $ext_type_transl ) . ' ' . convert_smilies( ':-)' ) . ' ';
369 +
370 + $notice_msg .= '</p>';
371 + $notice_msg .= '<div class="notice-actions">';
372 + $notice_msg .= $rate_plugin_button . $already_rated_button;
373 + $notice_msg .= '</div>';
374 + $notice_msg .= '</div>';
375 +
376 + $this->p->notice->nag( $notice_msg, $user_id, $notice_key, $dismiss_time );
377 +
378 + return 1; // Show only one notice at a time.
379 + }
380 +
381 + return 0;
382 + }
383 +
384 + /*
385 + * This method is called by timed_notices() if WordPress can dismiss notices and the user can manage options.
386 + *
387 + * These private notice functions should return the number of notices shown.
388 + */
389 + private function single_notice_upsell() {
390 +
391 + $pkg_info = $this->p->util->get_pkg_info(); // Uses a local cache.
392 +
393 + if ( $pkg_info[ 'wpsso' ][ 'pdir' ] ) {
394 +
395 + return 0;
396 + }
397 +
398 + $ext_reg = $this->p->util->reg->get_ext_reg();
399 + $months_ago_secs = time() - ( 2 * MONTH_IN_SECONDS );
400 +
401 + if ( empty( $ext_reg[ 'wpsso_install_time' ] ) || $ext_reg[ 'wpsso_install_time' ] > $months_ago_secs ) {
402 +
403 + return 0;
404 + }
405 +
406 + $form = $this->p->admin->get_form_object( $menu_ext = 'wpsso' ); // Return and maybe set/reset the WpssoAdmin->form value.
407 + $user_id = get_current_user_id();
408 + $p_info = $this->p->cf[ 'plugin' ][ 'wpsso' ];
409 + $p_name_transl = _x( $p_info[ 'name' ], 'plugin name', 'wpsso' );
410 + $p_purchase_url = $p_info[ 'url' ][ 'purchase' ];
411 + $wp_plugin_link = '<a href="' . $p_info[ 'url' ][ 'home' ] . '">' . $p_name_transl . '</a>';
412 + $pkg_pro_transl = _x( $this->p->cf[ 'packages' ][ 'pro' ], 'package name', 'wpsso' );
413 + $pkg_std_transl = _x( $this->p->cf[ 'packages' ][ 'std' ], 'package name', 'wpsso' );
414 + $notice_key = 'timed-notice-wpsso-pro-purchase-notice';
415 + $dismiss_time = true; // Allow the notice to be dismissed forever.
416 + $installed_ago = human_time_diff( time(), $ext_reg[ 'wpsso_install_time' ] );
417 + $ext_type_transl = WpssoConfig::get_ext_type_transl( 'wpsso' );
418 +
419 + /*
420 + * The action buttons.
421 + */
422 + $purchase_label = sprintf( __( 'View the %s edition prices', 'wpsso' ), $pkg_pro_transl );
423 + $purchase_clicked = '<p>' . sprintf( __( 'Thank you for supporting the continued development of %s.', 'wpsso' ), $p_name_transl ) . '</p>';
424 + $purchase_button = '<div class="notice-single-button">' . $form->get_button( $purchase_label, 'button-primary dismiss-on-click',
425 + '', $p_purchase_url, true, false, array( 'dismiss-msg' => $purchase_clicked ) ) . '</div>';
426 +
427 + $no_thanks_label = sprintf( __( 'I\'ll stay with the %s edition', 'wpsso' ), $pkg_std_transl );
428 + $no_thanks_clicked = '<p>' . sprintf( __( 'Please consider supporting the development of %s in the future.', 'wpsso' ), $p_name_transl ) . ' ' .
429 + __( 'Thank you.', 'wpsso' ) . '</p>';
430 + $no_thanks_button = '<div class="notice-single-button">' . $form->get_button( $no_thanks_label, 'button-secondary dismiss-on-click',
431 + '', '', false, false, array( 'dismiss-msg' => $no_thanks_clicked ) ) . '</div>';
432 +
433 + /*
434 + * The notice message.
435 + */
436 + $notice_msg = '<div style="display:table-cell;">';
437 + $notice_msg .= '<p style="margin-right:30px;">' . $this->p->admin->get_ext_img_icon( 'wpsso' ) . '</p>';
438 + $notice_msg .= '</div>';
439 + $notice_msg .= '<div style="display:table-cell;vertical-align:top;">';
440 + $notice_msg .= '<p><strong>';
441 +
442 + // translators: %1$s is the plugin name, %2$s is the plugin type (ie. "plugin" or "add-on"), and %3$s is a measure of time.
443 + $notice_msg .= sprintf( __( 'The %1$s %2$s was installed %3$s ago.', 'wpsso' ),
444 + $wp_plugin_link, $ext_type_transl, $installed_ago ) . ' ';
445 +
446 + $notice_msg .= '</strong></p><p>';
447 +
448 + $notice_msg .= sprintf( __( 'Have you thought about purchasing the %s edition?', 'wpsso' ), $pkg_pro_transl ) . ' ';
449 +
450 + $notice_msg .= sprintf( __( 'The %s edition includes loads of extra features!', 'wpsso' ), $pkg_pro_transl ) . ' ';
451 +
452 + $notice_msg .= convert_smilies( ':-)' ) . ' ';
453 +
454 + $notice_msg .= '</p>';
455 + $notice_msg .= '<div class="notice-actions">';
456 + $notice_msg .= $purchase_button . $no_thanks_button;
457 + $notice_msg .= '</div>';
458 + $notice_msg .= '</div>';
459 +
460 + $this->p->notice->nag( $notice_msg, $user_id, $notice_key, $dismiss_time );
461 +
462 + return 1;
463 + }
464 + }
465 +}