PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / trunk
Yoast SEO – Advanced SEO with real-time guidance and built-in AI vtrunk
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 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 All 129 releases
← All changes | inc/class-wpseo-replace-vars.php +92 -49 18.2 → trunk View file →
@@ -62,8 +62,10 @@
62 62 protected static $external_replacements = [];
63 63
64 64 /**
65 65 * Setup the help texts and external replacements as statics so they will be available to all instances.
66 + *
67 + * @return void
66 68 */
67 69 public static function setup_statics_once() {
68 70 if ( self::$help_texts === [] ) {
69 71 self::set_basic_help_texts();
@@ -106,9 +108,9 @@
106 108 }
107 109 elseif ( strpos( $var_to_replace, 'cf_' ) === 0 || strpos( $var_to_replace, 'ct_' ) === 0 ) {
108 110 trigger_error( esc_html__( 'A replacement variable can not start with "%%cf_" or "%%ct_" as these are reserved for the WPSEO standard variable variables for custom fields and custom taxonomies. Try making your variable name unique.', 'wordpress-seo' ), E_USER_WARNING );
109 111 }
110 - elseif ( ! method_exists( __CLASS__, 'retrieve_' . $var_to_replace ) ) {
112 + elseif ( ! method_exists( self::class, 'retrieve_' . $var_to_replace ) ) {
111 113 if ( $var_to_replace !== '' && ! isset( self::$external_replacements[ $var_to_replace ] ) ) {
112 114 self::$external_replacements[ $var_to_replace ] = $replace_function;
113 115 $replacement_variable = new WPSEO_Replacement_Variable( $var_to_replace, $var_to_replace, $help_text );
114 116 self::register_help_text( $type, $replacement_variable );
@@ -128,12 +130,12 @@
128 130
129 131 /**
130 132 * Replace `%%variable_placeholders%%` with their real value based on the current requested page/post/cpt/etc.
131 133 *
132 - * @param string $text The string to replace the variables in.
133 - * @param array $args The object some of the replacement values might come from,
134 - * could be a post, taxonomy or term.
135 - * @param array $omit Variables that should not be replaced by this function.
134 + * @param string $text The string to replace the variables in.
135 + * @param array $args The object some of the replacement values might come from,
136 + * could be a post, taxonomy or term.
137 + * @param array $omit Variables that should not be replaced by this function.
136 138 *
137 139 * @return string
138 140 */
139 141 public function replace( $text, $args, $omit = [] ) {
@@ -155,9 +157,9 @@
155 157 $this->args = (object) wp_parse_args( $args, $this->defaults );
156 158
157 159 // Clean $omit array.
158 160 if ( is_array( $omit ) && $omit !== [] ) {
159 - $omit = array_map( [ __CLASS__, 'remove_var_delimiter' ], $omit );
161 + $omit = array_map( [ self::class, 'remove_var_delimiter' ], $omit );
160 162 }
161 163
162 164 $replacements = [];
163 165 if ( preg_match_all( '`%%([^%]+(%%single)?)%%?`iu', $text, $matches ) ) {
@@ -166,12 +168,11 @@
166 168
167 169 /**
168 170 * Filter: 'wpseo_replacements' - Allow customization of the replacements before they are applied.
169 171 *
170 - * @api array $replacements The replacements.
171 - *
172 - * @param array $args The object some of the replacement values might come from,
173 - * could be a post, taxonomy or term.
172 + * @param array $replacements The replacements.
173 + * @param array $args The object some of the replacement values might come from,
174 + * could be a post, taxonomy or term.
174 175 */
175 176 $replacements = apply_filters( 'wpseo_replacements', $replacements, $this->args );
176 177
177 178 // Do the actual replacements.
@@ -179,9 +180,9 @@
179 180 $text = str_replace(
180 181 array_keys( $replacements ),
181 182 // Make sure to exclude replacement values that are arrays e.g. coming from a custom field serialized value.
182 183 array_filter( array_values( $replacements ), 'is_scalar' ),
183 - $text
184 + $text,
184 185 );
185 186 }
186 187
187 188 /**
@@ -189,14 +190,14 @@
189 190 * which didn't yield a replacement.
190 191 *
191 192 * @example <code>add_filter( 'wpseo_replacements_final', '__return_false' );</code>
192 193 *
193 - * @api bool $final
194 + * @param bool $final
194 195 */
195 196 if ( apply_filters( 'wpseo_replacements_final', true ) === true && ( isset( $matches[1] ) && is_array( $matches[1] ) ) ) {
196 197 // Remove non-replaced variables.
197 198 $remove = array_diff( $matches[1], $omit ); // Make sure the $omit variables do not get removed.
198 - $remove = array_map( [ __CLASS__, 'add_var_delimiter' ], $remove );
199 + $remove = array_map( [ self::class, 'add_var_delimiter' ], $remove );
199 200 $text = str_replace( $remove, '', $text );
200 201 }
201 202
202 203 // Undouble separators which have nothing between them, i.e. where a non-replaced variable was removed.
@@ -305,9 +306,9 @@
305 306 $method_name = 'retrieve_' . $var;
306 307 $replacement = $this->$method_name();
307 308 }
308 309 // Deal with externally defined variable names.
309 - elseif ( isset( self::$external_replacements[ $var ] ) && ! is_null( self::$external_replacements[ $var ] ) ) {
310 + elseif ( isset( self::$external_replacements[ $var ] ) && is_callable( self::$external_replacements[ $var ] ) ) {
310 311 $replacement = call_user_func( self::$external_replacements[ $var ], $var, $this->args );
311 312 }
312 313
313 314 // Replacement retrievals can return null if no replacement can be determined, root those outs.
@@ -365,24 +366,20 @@
365 366 if ( $this->args->post_date !== '' ) {
366 367 // Returns a string.
367 368 $replacement = YoastSEO()->helpers->date->format_translated( $this->args->post_date, get_option( 'date_format' ) );
368 369 }
369 - else {
370 - if ( get_query_var( 'day' ) && get_query_var( 'day' ) !== '' ) {
371 - // Returns a string.
372 - $replacement = get_the_date();
373 - }
374 - else {
375 - if ( single_month_title( ' ', false ) && single_month_title( ' ', false ) !== '' ) {
376 - // Returns a string.
377 - $replacement = single_month_title( ' ', false );
378 - }
379 - elseif ( get_query_var( 'year' ) !== '' ) {
380 - // Returns an integer, let's cast to string.
381 - $replacement = (string) get_query_var( 'year' );
382 - }
383 - }
370 + elseif ( get_query_var( 'day' ) && get_query_var( 'day' ) !== '' ) {
371 + // Returns a string.
372 + $replacement = get_the_date();
384 373 }
374 + elseif ( single_month_title( ' ', false ) ) {
375 + // Returns a string.
376 + $replacement = single_month_title( ' ', false );
377 + }
378 + elseif ( get_query_var( 'year' ) !== '' ) {
379 + // Returns an integer, let's cast to string.
380 + $replacement = (string) get_query_var( 'year' );
381 + }
385 382
386 383 return $replacement;
387 384 }
388 385
@@ -393,11 +390,13 @@
393 390 * @return string|null
394 391 */
395 392 private function retrieve_excerpt() {
396 393 $replacement = null;
397 - $locale = \get_locale();
398 - $limit = ( $locale === 'ja' ) ? 80 : 156;
394 + $locale = get_locale();
399 395
396 + // Japanese doesn't have a jp_JP variant in WP.
397 + $limit = ( $locale === 'ja' ) ? 80 : 156;
398 +
400 399 // The check `post_password_required` is because excerpt must be hidden for a post with a password.
401 400 if ( ! empty( $this->args->ID ) && ! post_password_required( $this->args->ID ) ) {
402 401 if ( $this->args->post_excerpt !== '' ) {
403 402 $replacement = wp_strip_all_tags( $this->args->post_excerpt );
@@ -405,9 +404,9 @@
405 404 elseif ( $this->args->post_content !== '' ) {
406 405 $content = strip_shortcodes( $this->args->post_content );
407 406 $content = wp_strip_all_tags( $content );
408 407
409 - if ( strlen( utf8_decode( $content ) ) <= $limit ) {
408 + if ( mb_strlen( $content ) <= $limit ) {
410 409 return $content;
411 410 }
412 411
413 412 $replacement = wp_html_excerpt( $content, $limit );
@@ -413,9 +412,9 @@
413 412 $replacement = wp_html_excerpt( $content, $limit );
414 413
415 414 // Check if the description has space and trim the auto-generated string to a word boundary.
416 415 if ( strrpos( $replacement, ' ' ) ) {
417 - $replacement = substr( $replacement, 0, strrpos( $replacement, ' ' ) );
416 + $replacement = substr( $replacement, 0, strrpos( $replacement, ' ' ) );
418 417 }
419 418 }
420 419 }
421 420
@@ -765,15 +764,15 @@
765 764 if ( ! empty( $this->args->ID ) ) {
766 765 // Post meta can be arrays and in this case we need to exclude them.
767 766 $name = get_post_meta( $this->args->ID, $field, true );
768 767 if ( $name !== '' && ! is_array( $name ) ) {
769 - $replacement = $name;
768 + $replacement = sanitize_text_field( $name );
770 769 }
771 770 }
772 771 elseif ( ! empty( $this->args->term_id ) ) {
773 772 $name = get_term_meta( $this->args->term_id, $field, true );
774 773 if ( $name !== '' ) {
775 - $replacement = $name;
774 + $replacement = sanitize_text_field( $name );
776 775 }
777 776 }
778 777 }
779 778
@@ -782,11 +781,11 @@
782 781
783 782 /**
784 783 * Retrieve a post/page/cpt's custom taxonomies for use as replacement string.
785 784 *
786 - * @param string $var_to_replace The complete variable to replace which includes the name of
787 - * the custom taxonomy which value(s) is to be retrieved.
788 - * @param bool $single Whether to retrieve only the first or all values for the taxonomy.
785 + * @param string $var_to_replace The complete variable to replace which includes the name of
786 + * the custom taxonomy which value(s) is to be retrieved.
787 + * @param bool $single Whether to retrieve only the first or all values for the taxonomy.
789 788 *
790 789 * @return string|null
791 790 */
792 791 private function retrieve_ct_custom_tax_name( $var_to_replace, $single = false ) {
@@ -1145,9 +1144,9 @@
1145 1144 if ( empty( $this->args->ID ) ) {
1146 1145 return null;
1147 1146 }
1148 1147
1149 - return \get_the_date( 'Y', $this->args->ID );
1148 + return get_the_date( 'Y', $this->args->ID );
1150 1149 }
1151 1150
1152 1151 /**
1153 1152 * Retrieve the post/page/cpt's published month for use as replacement string.
@@ -1158,9 +1157,9 @@
1158 1157 if ( empty( $this->args->ID ) ) {
1159 1158 return null;
1160 1159 }
1161 1160
1162 - return \get_the_date( 'F', $this->args->ID );
1161 + return get_the_date( 'F', $this->args->ID );
1163 1162 }
1164 1163
1165 1164 /**
1166 1165 * Retrieve the post/page/cpt's published day for use as replacement string.
@@ -1171,9 +1170,9 @@
1171 1170 if ( empty( $this->args->ID ) ) {
1172 1171 return null;
1173 1172 }
1174 1173
1175 - return \get_the_date( 'd', $this->args->ID );
1174 + return get_the_date( 'd', $this->args->ID );
1176 1175 }
1177 1176
1178 1177 /**
1179 1178 * Retrieve the post/page/cpt author's first name for use as replacement string.
@@ -1218,9 +1217,9 @@
1218 1217 if ( empty( $this->args->ID ) ) {
1219 1218 return null;
1220 1219 }
1221 1220
1222 - return \get_permalink( $this->args->ID );
1221 + return get_permalink( $this->args->ID );
1223 1222 }
1224 1223
1225 1224 /**
1226 1225 * Retrieve the post/page/cpt content for use as replacement string.
@@ -1260,9 +1259,9 @@
1260 1259 }
1261 1260 $post_terms = get_the_terms( $post_id, $taxonomy_slug );
1262 1261 if ( is_array( $post_terms ) && count( $post_terms ) > 0 ) {
1263 1262 // AiOSEO takes the name of whatever the first hierarchical taxonomy is.
1264 - $term = $post_terms[0];
1263 + $term = reset( $post_terms );
1265 1264 if ( $term ) {
1266 1265 return $term->name;
1267 1266 }
1268 1267 }
@@ -1277,8 +1276,10 @@
1277 1276 * Set the help text for a user/plugin/theme defined extra variable.
1278 1277 *
1279 1278 * @param string $type Type of variable: 'basic' or 'advanced'.
1280 1279 * @param WPSEO_Replacement_Variable $replacement_variable The replacement variable to register.
1280 + *
1281 + * @return void
1281 1282 */
1282 1283 private static function register_help_text( $type, WPSEO_Replacement_Variable $replacement_variable ) {
1283 1284 $identifier = $replacement_variable->get_variable();
1284 1285
@@ -1293,8 +1294,46 @@
1293 1294 * Generates a list of replacement variables based on the help texts.
1294 1295 *
1295 1296 * @return array List of replace vars.
1296 1297 */
1298 + public function get_replacement_variables_with_labels() {
1299 + self::setup_statics_once();
1300 +
1301 + $custom_variables = [];
1302 + foreach ( array_merge( WPSEO_Custom_Fields::get_custom_fields(), WPSEO_Custom_Taxonomies::get_custom_taxonomies() ) as $custom_variable ) {
1303 + $custom_variables[ $custom_variable ] = new WPSEO_Replacement_Variable( $custom_variable, $this->get_label( $custom_variable ), '' );
1304 + }
1305 +
1306 + $replacement_variables = array_filter(
1307 + array_merge( self::$help_texts['basic'], self::$help_texts['advanced'] ),
1308 + [ $this, 'is_not_prefixed' ],
1309 + ARRAY_FILTER_USE_KEY,
1310 + );
1311 +
1312 + $hidden = $this->get_hidden_replace_vars();
1313 +
1314 + return array_values(
1315 + array_map(
1316 + static function ( WPSEO_Replacement_Variable $replacement_variable ) use ( $hidden ) {
1317 + $name = $replacement_variable->get_variable();
1318 +
1319 + return [
1320 + 'name' => $name,
1321 + 'value' => '',
1322 + 'label' => $replacement_variable->get_label(),
1323 + 'hidden' => in_array( $name, $hidden, true ),
1324 + ];
1325 + },
1326 + array_merge( $replacement_variables, $custom_variables ),
1327 + ),
1328 + );
1329 + }
1330 +
1331 + /**
1332 + * Generates a list of replacement variables based on the help texts.
1333 + *
1334 + * @return array List of replace vars.
1335 + */
1297 1336 public function get_replacement_variables_list() {
1298 1337 self::setup_statics_once();
1299 1338
1300 1339 $replacement_variables = array_merge(
@@ -1299,9 +1338,9 @@
1299 1338
1300 1339 $replacement_variables = array_merge(
1301 1340 $this->get_replacement_variables(),
1302 1341 WPSEO_Custom_Fields::get_custom_fields(),
1303 - WPSEO_Custom_Taxonomies::get_custom_taxonomies()
1342 + WPSEO_Custom_Taxonomies::get_custom_taxonomies(),
1304 1343 );
1305 1344
1306 1345 return array_map( [ $this, 'format_replacement_variable' ], $replacement_variables );
1307 1346 }
@@ -1414,8 +1453,10 @@
1414 1453 }
1415 1454
1416 1455 /**
1417 1456 * Set/translate the help texts for the WPSEO standard basic variables.
1457 + *
1458 + * @return void
1418 1459 */
1419 1460 private static function set_basic_help_texts() {
1420 1461 /* translators: %s: wp_title() function. */
1421 1462 $separator_description = __( 'The separator defined in your theme\'s %s tag.', 'wordpress-seo' );
@@ -1421,9 +1462,9 @@
1421 1462 $separator_description = __( 'The separator defined in your theme\'s %s tag.', 'wordpress-seo' );
1422 1463 $separator_description = sprintf(
1423 1464 $separator_description,
1424 1465 // '<code>wp_title()</code>'
1425 - 'wp_title()'
1466 + 'wp_title()',
1426 1467 );
1427 1468
1428 1469 $replacement_variables = [
1429 1470 new WPSEO_Replacement_Variable( 'date', __( 'Date', 'wordpress-seo' ), __( 'Replaced with the date of the post/page', 'wordpress-seo' ) ),
@@ -1464,8 +1505,10 @@
1464 1505 }
1465 1506
1466 1507 /**
1467 1508 * Set/translate the help texts for the WPSEO standard advanced variables.
1509 + *
1510 + * @return void
1468 1511 */
1469 1512 private static function set_advanced_help_texts() {
1470 1513 $replacement_variables = [
1471 1514 new WPSEO_Replacement_Variable( 'pt_single', __( 'Post type (singular)', 'wordpress-seo' ), __( 'Replaced with the content type single label', 'wordpress-seo' ) ),
@@ -1473,9 +1516,9 @@
1473 1516 new WPSEO_Replacement_Variable( 'modified', __( 'Modified', 'wordpress-seo' ), __( 'Replaced with the post/page modified time', 'wordpress-seo' ) ),
1474 1517 new WPSEO_Replacement_Variable( 'id', __( 'ID', 'wordpress-seo' ), __( 'Replaced with the post/page ID', 'wordpress-seo' ) ),
1475 1518 new WPSEO_Replacement_Variable( 'name', __( 'Name', 'wordpress-seo' ), __( 'Replaced with the post/page author\'s \'nicename\'', 'wordpress-seo' ) ),
1476 1519 new WPSEO_Replacement_Variable( 'user_description', __( 'User description', 'wordpress-seo' ), __( 'Replaced with the post/page author\'s \'Biographical Info\'', 'wordpress-seo' ) ),
1477 - new WPSEO_Replacement_Variable( 'page', __( 'Page number', 'wordpress-seo' ), __( 'Replaced with the current page number with context (i.e. page 2 of 4)', 'wordpress-seo' ) ),
1520 + new WPSEO_Replacement_Variable( 'page', __( 'Page', 'wordpress-seo' ), __( 'Replaced with the current page number with context (i.e. page 2 of 4)', 'wordpress-seo' ) ),
1478 1521 new WPSEO_Replacement_Variable( 'pagetotal', __( 'Pagetotal', 'wordpress-seo' ), __( 'Replaced with the current page total', 'wordpress-seo' ) ),
1479 1522 new WPSEO_Replacement_Variable( 'pagenumber', __( 'Pagenumber', 'wordpress-seo' ), __( 'Replaced with the current page number', 'wordpress-seo' ) ),
1480 1523 new WPSEO_Replacement_Variable( 'caption', __( 'Caption', 'wordpress-seo' ), __( 'Attachment caption', 'wordpress-seo' ) ),
1481 1524 new WPSEO_Replacement_Variable( 'focuskw', __( 'Focus keyword', 'wordpress-seo' ), __( 'Replaced with the posts focus keyphrase', 'wordpress-seo' ) ),
@@ -1550,10 +1593,10 @@
1550 1593 /**
1551 1594 * Allows filtering of the terms list used to replace %%category%%, %%tag%%
1552 1595 * and %%ct_<custom-tax-name>%% variables.
1553 1596 *
1554 - * @api string $output Comma-delimited string containing the terms.
1555 - * @api string $taxonomy The taxonomy of the terms.
1597 + * @param string $output Comma-delimited string containing the terms.
1598 + * @param string $taxonomy The taxonomy of the terms.
1556 1599 */
1557 1600 return apply_filters( 'wpseo_terms', $output, $taxonomy );
1558 1601 }
1559 1602
@@ -1577,9 +1620,9 @@
1577 1620 ];
1578 1621
1579 1622 return rtrim(
1580 1623 get_term_parents_list( $this->args->term_id, $this->args->taxonomy, $args ),
1581 - $separator
1624 + $separator,
1582 1625 );
1583 1626 }
1584 1627
1585 1628 /**