| @@ -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 ); |
| @@ -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 | |
| @@ -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 | /** |