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/util-inline.php +615 -0 22.5.322.7.0 View file →
@@ -1,0 +1,615 @@
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( 'WpssoUtilInline' ) ) {
19 +
20 + class WpssoUtilInline {
21 +
22 + private $p; // Wpsso class object.
23 + private $u; // WpssoUtil class object.
24 +
25 + /*
26 + * Instantiated by WpssoUtil->__construct().
27 + */
28 + public function __construct( &$plugin, &$util ) {
29 +
30 + $this->p =& $plugin;
31 + $this->u =& $util;
32 +
33 + if ( $this->p->debug->enabled ) {
34 +
35 + $this->p->debug->mark();
36 + }
37 + }
38 +
39 + /*
40 + * Replace inline variables in the subject text.
41 + *
42 + * $atts can be an associative array with additional information ('canonical_url', 'canonical_short_url', 'add_page', etc.).
43 + *
44 + * See WpssoPage->get_title().
45 + * See WpssoPage->get_description().
46 + */
47 + public function replace_variables( $value, $mod = false, array $atts = array() ) {
48 +
49 + static $local_recursion = 0;
50 +
51 + if ( 0 === $local_recursion ) { // Do not log recursions.
52 +
53 + if ( $this->p->debug->enabled ) {
54 +
55 + $this->p->debug->mark();
56 + }
57 +
58 + } elseif ( $local_recursion > 32 ) { // Just in case.
59 +
60 + return $value;
61 +
62 + }
63 +
64 + if ( is_array( $value ) ) {
65 +
66 + /*
67 + * The $mod array argument is preferred but not required.
68 + *
69 + * $mod = true | false | post_id | $mod array
70 + */
71 + if ( ! is_array( $mod ) ) {
72 +
73 + if ( $this->p->debug->enabled ) {
74 +
75 + $this->p->debug->log( 'optional call to WpssoPage->get_mod()' );
76 + }
77 +
78 + $mod = $this->p->page->get_mod( $mod );
79 + }
80 +
81 + foreach ( $value as $key => $el ) {
82 +
83 + $local_recursion++;
84 +
85 + $value[ $key ] = $this->replace_variables( $el, $mod, $atts );
86 +
87 + $local_recursion--;
88 + }
89 +
90 + return $value;
91 +
92 + } elseif ( ! is_string( $value ) ) { // Just in case - accept only arrays and strings.
93 +
94 + return $value;
95 +
96 + } elseif ( false === strpos( $value, '%%' ) ) { // No inline variable.
97 +
98 + return $value;
99 + }
100 +
101 + /*
102 + * The $mod array argument is preferred but not required.
103 + *
104 + * $mod = true | false | post_id | $mod array
105 + */
106 + if ( ! is_array( $mod ) ) {
107 +
108 + if ( $this->p->debug->enabled ) {
109 +
110 + $this->p->debug->log( 'optional call to WpssoPage->get_mod()' );
111 + }
112 +
113 + $mod = $this->p->page->get_mod( $mod );
114 + }
115 +
116 + /*
117 + * Use a callback to get the inline variable values we need, as we need them.
118 + *
119 + * See https://www.php.net/manual/en/function.preg-replace-callback.php.
120 + */
121 + $callback = function( $matches ) use ( $mod, $atts ) {
122 +
123 + return $this->replace_callback( $matches, $mod, $atts );
124 + };
125 +
126 + static $local_depth = 0;
127 +
128 + while ( ++$local_depth <= 5 && false !== strpos( $value, '%%' ) ) {
129 +
130 + if ( $this->p->debug->enabled ) {
131 +
132 + $this->p->debug->log( 'preg_replace_callback() for value = ' . $value );
133 + }
134 +
135 + $value = preg_replace_callback( '/%%([^%]+)%%/', $callback, $value );
136 + }
137 +
138 + $local_depth = 0;
139 +
140 + return $value;
141 + }
142 +
143 + private function replace_callback( array $matches, array $mod, array $atts ) {
144 +
145 + $varname = $matches[ 1 ];
146 + $ret_val = '';
147 + $url_enc = empty( $atts[ 'rawurlencode' ] ) ? false : true;
148 +
149 + /*
150 + * Some inline variables and values may be passed in the $atts array, so check this array first.
151 + */
152 + if ( isset( $atts[ $varname ] ) ) {
153 +
154 + return $url_enc ? rawurlencode( $atts[ $varname ] ) : $atts[ $varname ];
155 + }
156 +
157 + /*
158 + * Use a local cache for values that will not change for this page load.
159 + */
160 + static $local_cache = null;
161 +
162 + if ( null === $local_cache ) {
163 +
164 + $date_format = get_option( 'date_format' );
165 + $time_format = get_option( 'time_format' );
166 + $charset = get_bloginfo( $show = 'charset', $filter = 'raw' );
167 +
168 + $local_cache = array(
169 + 'def_title_sep' => html_entity_decode( $this->p->options[ 'og_title_sep' ], ENT_QUOTES, $charset ),
170 + 'def_ellipsis' => html_entity_decode( $this->p->options[ 'og_ellipsis' ], ENT_QUOTES, $charset ),
171 + 'date_format' => $date_format,
172 + 'time_format' => $time_format,
173 + 'currentdate' => date_i18n( $date_format ),
174 + 'currenttime' => date_i18n( $time_format ),
175 + 'currentday' => date_i18n( 'j' ),
176 + 'currentmonth' => date_i18n( 'F' ),
177 + 'currentyear' => date_i18n( 'Y' ),
178 + );
179 + }
180 +
181 + if ( isset( $local_cache[ $varname ] ) ) {
182 +
183 + return $url_enc ? rawurlencode( $local_cache[ $varname ] ) : $local_cache[ $varname ];
184 + }
185 +
186 + /*
187 + * Detect and prevent recursion, just in case.
188 + */
189 + static $local_recursion = array();
190 +
191 + if ( ! empty( $local_recursion[ $varname ] ) ) { // Recursion detected.
192 +
193 + return $ret_val; // Stop here.
194 + }
195 +
196 + $local_recursion[ $varname ] = true; // Prevent recursion.
197 +
198 + if ( $this->p->debug->enabled ) {
199 +
200 + $this->p->debug->log( 'getting the %%' . $varname . '%% value' );
201 + }
202 +
203 + $add_page = isset( $atts[ 'add_page' ] ) ? $atts[ 'add_page' ] : false;
204 + $title_sep = isset( $atts[ 'title_sep' ] ) ? $atts[ 'title_sep' ] : $local_cache[ 'def_title_sep' ];
205 +
206 + if ( 0 === strpos( $varname, 'post' ) ) { // The inline variable includes 'post' in its name.
207 +
208 + if ( $mod[ 'is_post' ] ) { // Just in case.
209 +
210 + switch ( $varname ) {
211 +
212 + case 'post_date':
213 +
214 + if ( ! empty( $mod[ 'post_time' ] ) ) {
215 +
216 + $ret_val = mysql2date( $local_cache[ 'date_format' ], $mod[ 'post_time' ] );
217 + }
218 +
219 + break;
220 +
221 + case 'post_description': // Used by AIOSEOP.
222 +
223 + $ret_val = $this->p->page->get_the_description( $mod );
224 +
225 + break;
226 +
227 + case 'post_modified':
228 + case 'post_modified_date':
229 +
230 + if ( ! empty( $mod[ 'post_modified_time' ] ) ) {
231 +
232 + $ret_val = mysql2date( $local_cache[ 'date_format' ], $mod[ 'post_modified_time' ] );
233 + }
234 +
235 + break;
236 +
237 + case 'post_primary_tax_slug':
238 +
239 + $ret_val = $mod[ 'post_primary_tax_slug' ];
240 +
241 + break;
242 +
243 + case 'post_title': // Used by AIOSEOP.
244 +
245 + $ret_val = $this->p->page->get_the_title( $mod, $title_sep );
246 +
247 + break;
248 + }
249 + }
250 +
251 + } elseif ( 0 === strpos( $varname, 'term' ) ) { // The inline variable includes 'term' in its name.
252 +
253 + if ( $mod[ 'is_term' ] ) { // Just in case.
254 +
255 + switch ( $varname ) {
256 +
257 + case 'term':
258 + case 'term_name':
259 +
260 + $term_obj = $this->p->term->get_mod_wp_object( $mod );
261 +
262 + $ret_val = $term_obj->name;
263 +
264 + break;
265 +
266 + case 'term_description': // Used by AIOSEOP, Rank Math, and Yoast SEO.
267 +
268 + $ret_val = $this->p->page->get_the_description( $mod );
269 +
270 + break;
271 +
272 + case 'term_tax_single':
273 +
274 + $ret_val = $mod[ 'tax_label_single' ];
275 +
276 + break;
277 +
278 + case 'term_tax_single_lower':
279 +
280 + $ret_val = mb_strtolower( $mod[ 'tax_label_single' ] );
281 +
282 + break;
283 +
284 + case 'term_hierarchy': // Used by Yoast SEO.
285 +
286 + /*
287 + * Includes parent names in the term title if the $title_sep value is not empty.
288 + *
289 + * Use $title_sep = false to avoid adding term parent names in the term title.
290 + */
291 + $term_obj = $this->p->term->get_mod_wp_object( $mod );
292 +
293 + $ret_val = $this->p->page->get_term_title( $term_obj, null );
294 +
295 + break;
296 +
297 + case 'term_title': // Used by Yoast SEO.
298 +
299 + /*
300 + * Includes parent names in the term title if the $title_sep value is not empty.
301 + *
302 + * Use $title_sep = false to avoid adding term parent names in the term title.
303 + */
304 + $term_obj = $this->p->term->get_mod_wp_object( $mod );
305 +
306 + $ret_val = $this->p->page->get_term_title( $term_obj, false );
307 +
308 + break;
309 + }
310 + }
311 +
312 + } elseif ( 0 === strpos( $varname, 'cf_' ) ) { // The inline variable includes 'cf_' in its name.
313 +
314 + if ( $meta_key = substr( $varname, 3 ) ) { // Just in case.
315 +
316 + if ( ! empty( $mod[ 'obj' ] ) && $mod[ 'id' ] ) { // Just in case.
317 +
318 + $ret_val = $mod[ 'obj' ]->get_meta( $mod[ 'id' ], $meta_key, $single = true );
319 +
320 + if ( is_array( $ret_val ) ) { // Just in case.
321 +
322 + $ret_val = implode( $glue = ', ', $ret_val );
323 + }
324 + }
325 + }
326 +
327 + } else {
328 +
329 + switch ( $varname ) {
330 +
331 + case 'org_url': // Used by Rank Math.
332 + case 'site_url':
333 +
334 + $ret_val = SucomUtilWP::get_home_url( $this->p->options, $mod );
335 +
336 + break;
337 +
338 + case 'canonical_url':
339 +
340 + $ret_val = $this->u->get_canonical_url( $mod, $add_page );
341 +
342 + break;
343 +
344 + case 'canonical_short_url':
345 +
346 + $ret_val = $this->u->get_canonical_short_url( $mod, $add_page );
347 +
348 + break;
349 +
350 + case 'description':
351 + case 'seo_description': // Used by Rank Math.
352 +
353 + $ret_val = $this->p->page->get_the_description( $mod );
354 +
355 + break;
356 +
357 + case 'user_description': // Used by Rank Math.
358 +
359 + /*
360 + * Returns the description for a user module or post author.
361 + */
362 + $ret_val = $this->p->user->get_author_description( $mod );
363 +
364 + break;
365 +
366 + case 'sharing_url':
367 +
368 + /*
369 + * The $atts array may contain 'utm_medium', 'utm_source', 'utm_campaign', 'utm_content', and 'utm_term'.
370 + */
371 + $ret_val = $this->u->get_sharing_url( $mod, $add_page, $atts );
372 +
373 + break;
374 +
375 + case 'sharing_short_url':
376 + case 'short_url': // Used by older WPSSO RRSSB templates.
377 +
378 + /*
379 + * The $atts array may contain 'utm_medium', 'utm_source', 'utm_campaign', 'utm_content', and 'utm_term'.
380 + */
381 + $ret_val = $this->u->get_sharing_short_url( $mod, $add_page, $atts );
382 +
383 + break;
384 +
385 + case 'request_url':
386 +
387 + if ( is_admin() ) {
388 +
389 + $ret_val = $this->u->get_canonical_url( $mod, $add_page );
390 +
391 + } else {
392 +
393 + $ret_val = SucomUtil::get_url( $remove_ignored_args = true ); // Uses a local cache.
394 +
395 + $ret_val = apply_filters( 'wpsso_server_request_url', $ret_val );
396 + }
397 +
398 + break;
399 +
400 + case 'org_name': // Used by Rank Math.
401 + case 'sitename':
402 + case 'sitetitle': // Used by SEOPress.
403 +
404 + $ret_val = SucomUtilWP::get_site_name( $this->p->options, $mod );
405 +
406 + break;
407 +
408 + case 'sitealtname':
409 +
410 + $ret_val = SucomUtilWP::get_site_name_alt( $this->p->options, $mod );
411 +
412 + break;
413 +
414 + case 'sitedesc': // Used by Rank Math.
415 + case 'tagline': // Used by SEOPress.
416 +
417 + $ret_val = SucomUtilWP::get_site_description( $this->p->options, $mod );
418 +
419 + break;
420 +
421 + case 'sep':
422 + case 'separator_sa': // Used by AIOSEOP.
423 +
424 + $ret_val = $title_sep;
425 +
426 + break;
427 +
428 + case 'ellipsis':
429 +
430 + $ret_val = $local_cache[ 'def_ellipsis' ];
431 +
432 + break;
433 +
434 + case 'title':
435 + case 'seo_title': // Used by Rank Math.
436 +
437 + $ret_val = $this->p->page->get_the_title( $mod, $title_sep );
438 +
439 + break;
440 +
441 + case 'parent_title':
442 +
443 + if ( $mod[ 'is_post' ] && $mod[ 'post_parent' ] ) { // Just in case.
444 +
445 + $parent_mod = $this->p->post->get_mod( $mod[ 'post_parent' ] );
446 +
447 + $ret_val = $this->p->page->get_the_title( $parent_mod, $title_sep );
448 + }
449 +
450 + break;
451 +
452 + case 'author':
453 + case 'author_name':
454 + case 'name': // Used by Yoast SEO.
455 +
456 + /*
457 + * Returns the display name for a user module, comment author, or post author.
458 + */
459 + $ret_val = $this->p->user->get_author_name( $mod );
460 +
461 + break;
462 +
463 + case 'page':
464 +
465 + $page_num = $this->u->get_page_number( $mod, $add_page );
466 +
467 + if ( $page_num > 1 ) {
468 +
469 + $page_transl = __( 'Page %1$d of %2$d', 'wpsso' );
470 +
471 + $ret_val = $title_sep . ' ' . sprintf( $page_transl, $page_num, $mod[ 'paged_total' ] );
472 + }
473 +
474 + break;
475 +
476 + case 'pagename':
477 +
478 + if ( isset( $mod[ 'query_vars' ][ 'pagename' ] ) ) {
479 +
480 + $ret_val = $mod[ 'query_vars' ][ 'pagename' ];
481 + }
482 +
483 + break;
484 +
485 + case 'pagenumber':
486 +
487 + $ret_val = $this->u->get_page_number( $mod, $add_page );
488 +
489 + break;
490 +
491 + case 'pagetotal':
492 +
493 + $ret_val = $mod[ 'paged_total' ];
494 +
495 + break;
496 +
497 + case 'date': // Used by Yoast SEO.
498 +
499 + if ( ! empty( $mod[ 'post_time' ] ) ) {
500 +
501 + $ret_val = mysql2date( $local_cache[ 'date_format' ], $mod[ 'post_time' ] );
502 + }
503 +
504 + break;
505 +
506 + case 'modified': // Used by Yoast SEO.
507 +
508 + if ( ! empty( $mod[ 'post_modified_time' ] ) ) {
509 +
510 + $ret_val = mysql2date( $local_cache[ 'date_format' ], $mod[ 'post_modified_time' ] );
511 + }
512 +
513 + break;
514 +
515 + case 'excerpt':
516 +
517 + if ( $mod[ 'is_post' ] ) { // Just in case.
518 +
519 + $ret_val = $this->p->page->get_the_excerpt( $mod );
520 +
521 + if ( empty( $ret_val ) ) {
522 +
523 + $ret_val = wp_trim_excerpt( '', $mod[ 'id' ] );
524 + }
525 + }
526 +
527 + break;
528 +
529 + case 'excerpt_only':
530 +
531 + if ( $mod[ 'is_post' ] ) { // Just in case.
532 +
533 + $ret_val = $this->p->page->get_the_excerpt( $mod );
534 + }
535 +
536 + break;
537 +
538 + case 'comment_author':
539 +
540 + $ret_val = $mod[ 'comment_author_name' ];
541 +
542 + break;
543 +
544 + case 'comment_date':
545 +
546 + if ( ! empty( $mod[ 'comment_time' ] ) ) {
547 +
548 + $ret_val = mysql2date( $local_cache[ 'date_format' ], $mod[ 'comment_time' ] );
549 + }
550 +
551 + break;
552 +
553 + case 'query_search':
554 + case 'search_keywords': // Used by SEOPress.
555 + case 'search_query': // Used by Rank Math.
556 + case 'searchphrase': // Used by Yoast SEO.
557 +
558 + if ( isset( $mod[ 'query_vars' ][ 's' ] ) ) {
559 +
560 + $ret_val = $mod[ 'query_vars' ][ 's' ];
561 + }
562 +
563 + break;
564 +
565 + case 'query_year':
566 +
567 + if ( isset( $mod[ 'query_vars' ][ 'year' ] ) ) {
568 +
569 + $ret_val = $mod[ 'query_vars' ][ 'year' ];
570 +
571 + } elseif ( ! empty( $mod[ 'query_vars' ][ 'm' ] ) ) {
572 +
573 + $ret_val = substr( $mod[ 'query_vars' ][ 'm' ], 0, 4 );
574 + }
575 +
576 + break;
577 +
578 + case 'query_month':
579 + case 'query_monthnum':
580 +
581 + if ( isset( $mod[ 'query_vars' ][ 'monthnum' ] ) ) {
582 +
583 + $ret_val = $mod[ 'query_vars' ][ 'monthnum' ];
584 +
585 + } elseif ( ! empty( $mod[ 'query_vars' ][ 'm' ] ) ) {
586 +
587 + $ret_val = substr( $mod[ 'query_vars' ][ 'm' ], 4, 2 );
588 + }
589 +
590 + if ( 'query_month' === $varname ) { // Convert month number to month name.
591 +
592 + global $wp_locale;
593 +
594 + $ret_val = $ret_val ? $wp_locale->get_month( $ret_val ) : '';
595 + }
596 +
597 + break;
598 +
599 + case 'query_day':
600 +
601 + if ( isset( $mod[ 'query_vars' ][ 'day' ] ) ) {
602 +
603 + $ret_val = $mod[ 'query_vars' ][ 'day' ];
604 + }
605 +
606 + break;
607 + }
608 + }
609 +
610 + unset( $local_recursion[ $varname ] ); // Done preventing recursion.
611 +
612 + return $url_enc ? rawurlencode( $ret_val ) : $ret_val;
613 + }
614 + }
615 +}