*/ namespace RankMath; use RankMath\Admin\Admin_Helper; use RankMath\Traits\Hooker; use RankMath\Traits\Replacement; use MyThemeShop\Helpers\Str; use MyThemeShop\Helpers\Param; use MyThemeShop\Helpers\WordPress; defined( 'ABSPATH' ) || exit; /** * Replace_Vars class. */ class Replace_Vars { use Hooker, Replacement; /** * Register variable replacements. * * @var array */ protected static $replacements = []; /** * Additional variable replacements registered by other plugins/themes. * * @var array */ protected static $external_replacements = []; /** * Hold counter variable data. * * @var array */ protected static $counters = []; /** * Default post data. * * @var array */ protected $defaults = array( 'ID' => '', 'name' => '', 'post_author' => '', 'post_content' => '', 'post_date' => '', 'post_excerpt' => '', 'post_modified' => '', 'post_title' => '', 'taxonomy' => '', 'term_id' => '', 'term404' => '', 'filename' => '', ); /** * Replace `%variables%` with context-dependent value. * * @param string $string The string containing the %variables%. * @param array $args Context object, can be post, taxonomy or term. * @param array $exclude Excluded variables won't be replaced. * @return string */ public function replace( $string, $args = [], $exclude = [] ) { $string = strip_tags( $string ); // Bail early. if ( ! Str::contains( '%', $string ) ) { return $string; } if ( Str::ends_with( ' %sep%', $string ) ) { $string = str_replace( ' %sep%', '', $string ); } $this->args = (object) wp_parse_args( $args, $this->defaults ); // Clean $exclude. if ( is_array( $exclude ) && ! empty( $exclude ) ) { $exclude = array_map( array( __CLASS__, 'remove_var_delimiter' ), $exclude ); } $replacements = []; if ( preg_match_all( '/%(([a-z0-9_-]+)\(([^)]*)\)|[^\s]+)%/iu', $string, $matches ) ) { $replacements = $this->set_up_replacements( $matches, $exclude ); } /** * Filter: Allow customizing the replacements. * * @param array $replacements */ $replacements = $this->do_filter( 'replacements', $replacements ); // Do the replacements. if ( is_array( $replacements ) && [] !== $replacements ) { $string = str_replace( array_keys( $replacements ), array_values( $replacements ), $string ); } /** * Filter: strip variables which don't have a replacement. * * @param bool $final */ if ( true === $this->do_filter( 'replacements_remove_nonreplaced', true ) && ( isset( $matches[1] ) && is_array( $matches[1] ) ) ) { // Remove non-replaced variables. // Don't remove the $exclude variables. $remove = array_diff( $matches[1], $exclude ); $remove = array_map( array( __CLASS__, 'add_var_delimiter' ), $remove ); $string = str_replace( $remove, '', $string ); } if ( isset( $replacements['%sep%'] ) && Str::is_non_empty( $replacements['%sep%'] ) ) { $q_sep = preg_quote( $replacements['%sep%'], '`' ); $string = preg_replace( '`' . $q_sep . '(?:\s*' . $q_sep . ')*`u', $replacements['%sep%'], $string ); } return $string; } /** * Register extra %variables%. For developers. * See rank_math_register_var_replacement(). * * @codeCoverageIgnore * * @param string $var Variable name, for example %custom%. '%' signs are optional. * @param mixed $callback Replacement callback. Should return value, not output it. * @param array $args Array with additional title, description and example values for the variable. * * @return bool Whether the replacement function was succesfully registered. */ public static function register_replacement( $var, $callback, $args = [] ) { $success = false; if ( ! self::is_valid_variable( $var ) ) { return false; } $var = self::remove_var_delimiter( $var ); if ( ! method_exists( __CLASS__, 'get_' . $var ) ) { if ( ! isset( self::$external_replacements[ $var ] ) ) { $success = true; $args['callback'] = $callback; self::$external_replacements[ $var ] = $args; return $success; } trigger_error( esc_html__( 'The variable has already been registered.', 'rank-math' ), E_USER_WARNING ); return $success; } trigger_error( esc_html__( 'Standard variables cannot be overridden by registering them again. Use the "rankmath/replacements" filter for this.', 'rank-math' ), E_USER_WARNING ); return $success; } /** * Check if variable is valid before further processing. * * @param string $var Variable name. * * @return boolean Whether the variable is valid or not. */ public static function is_valid_variable( $var ) { if ( ! is_string( $var ) || empty( $var ) ) { return false; } $var = self::remove_var_delimiter( $var ); if ( false === preg_match( '`^[A-Z0-9_-]+$`i', $var ) ) { trigger_error( esc_html__( 'Variable names can only contain alphanumeric characters, underscores and dashes.', 'rank-math' ), E_USER_WARNING ); return false; } return true; } /** * Enqueue styles and scripts. */ public static function setup_json() { // Fetch data for this post. if ( Admin_Helper::is_post_edit() ) { global $post; \setup_postdata( $post ); $author = get_userdata( $post->post_author ); if ( $author ) { self::$replacements['name']['example'] = $author->display_name; } self::$replacements['id']['example'] = $post->ID; self::$replacements['userid']['example'] = $post->post_author; self::$replacements['title']['example'] = get_the_title(); self::$replacements['date']['example'] = get_the_date(); self::$replacements['modified']['example'] = get_the_modified_date(); self::$replacements['excerpt']['example'] = WordPress::strip_shortcodes( self::get_safe_excerpt( $post ) ); self::$replacements['excerpt_only']['example'] = $post->post_excerpt; // Custom Fields. $json = []; $custom_fields = get_post_custom( $post->ID ); if ( ! empty( $custom_fields ) ) { foreach ( $custom_fields as $custom_field_name => $custom_field ) { if ( substr( $custom_field_name, 0, 1 ) === '_' ) { continue; } $json[ $custom_field_name ] = $custom_field[0]; } } Helper::add_json( 'customFields', $json ); // Custom Taxonomies. self::set_custom_taxonomies( $post->ID ); } // Fetch data for this term. if ( Admin_Helper::is_term_edit() ) { global $taxnow; $tag_id = Param::request( 'tag_ID', 0, FILTER_VALIDATE_INT ); $term = get_term( $tag_id, $taxnow, OBJECT, 'edit' ); self::$replacements['term']['example'] = $term->name; self::$replacements['term_description']['example'] = term_description( $term ); } Helper::add_json( 'variables', apply_filters( 'rank_math/vars/replacements', array_merge( self::$replacements, self::$external_replacements ) ) ); } /** * Get safe excerpt. * * @param WP_Post $post Post instance. * * @return string */ public static function get_safe_excerpt( $post ) { if ( '' !== $post->post_excerpt ) { return strip_tags( $post->post_excerpt ); } elseif ( '' !== $post->post_content ) { return wp_html_excerpt( WordPress::strip_shortcodes( $post->post_content ), 155 ); } return ''; } /** * Set up replacements. */ public static function setup() { global $wp_customize; if ( isset( $wp_customize ) ) { return; } if ( empty( self::$replacements ) ) { self::set_replacements(); } if ( empty( self::$external_replacements ) ) { /** * Action: 'rank_math/vars/register_extra_replacements' - Allows adding extra variables. */ do_action( 'rank_math/vars/register_extra_replacements' ); } } /** * Get list of "swap variables" with descriptions. * Used in the basic JS swap variables function: in meta box preview, * options page title previews, and the variables dropdown. */ public static function set_replacements() { $self = new Replace_Vars(); $current_user = wp_get_current_user(); $post_id = 1; $post_title = esc_html__( 'Hello World', 'rank-math' ); $posts_array = get_posts( array( 'posts_per_page' => 1 ) ); if ( ! empty( $posts_array[0] ) ) { $post_id = $posts_array[0]->ID; $post_title = $posts_array[0]->post_title; } // Basic Variables. self::$replacements['title'] = array( 'name' => esc_html__( 'Post Title', 'rank-math' ), 'desc' => esc_html__( 'Title of the current post/page', 'rank-math' ), 'example' => $post_title, ); self::$replacements['parent_title'] = array( 'name' => esc_html__( 'Post Title of parent page', 'rank-math' ), 'desc' => esc_html__( 'Title of the parent page of the current post/page', 'rank-math' ), 'example' => esc_html__( 'Example Title', 'rank-math' ), ); self::$replacements['sep'] = array( 'name' => esc_html__( 'Separator Character', 'rank-math' ), 'desc' => esc_html__( 'Separator character, as set in the Title Settings', 'rank-math' ), 'example' => $self->get_sep(), ); self::$replacements['sitename'] = array( 'name' => esc_html__( 'Site Title', 'rank-math' ), 'desc' => esc_html__( 'Title of the site', 'rank-math' ), 'example' => get_bloginfo( 'name' ), ); self::$replacements['sitedesc'] = array( 'name' => esc_html__( 'Site Description', 'rank-math' ), 'desc' => esc_html__( 'Description of the site', 'rank-math' ), 'example' => get_bloginfo( 'description' ), ); self::$replacements['date'] = array( 'name' => esc_html__( 'Date Published', 'rank-math' ), 'desc' => wp_kses_post( __( 'Publication date of the current post/page OR specified date on date archives', 'rank-math' ) ), 'example' => current_time( get_option( 'date_format' ) ), ); self::$replacements['modified'] = array( 'name' => esc_html__( 'Date Modified', 'rank-math' ), 'desc' => esc_html__( 'Last modification date of the current post/page', 'rank-math' ), 'example' => current_time( get_option( 'date_format' ) ), ); self::$replacements['excerpt'] = array( 'name' => esc_html__( 'Post Excerpt', 'rank-math' ), 'desc' => esc_html__( 'Excerpt of the current post (or auto-generated if it does not exist)', 'rank-math' ), 'example' => esc_html__( 'Post Excerpt', 'rank-math' ), ); self::$replacements['excerpt_only'] = array( 'name' => esc_html__( 'Post Excerpt', 'rank-math' ), 'desc' => esc_html__( 'Excerpt of the current post (without auto-generation)', 'rank-math' ), 'example' => esc_html__( 'Post Excerpt', 'rank-math' ), ); self::$replacements['tag'] = array( 'name' => esc_html__( 'Post Tag', 'rank-math' ), 'desc' => wp_kses_post( __( 'First tag (alphabetically) associated to the current post OR current tag on tag archives', 'rank-math' ) ), 'example' => esc_html__( 'Example Tag', 'rank-math' ), ); self::$replacements['tags'] = array( 'name' => esc_html__( 'Post Tags', 'rank-math' ), 'desc' => esc_html__( 'Comma-separated list of tags associated to the current post', 'rank-math' ), 'example' => esc_html__( 'Example Tag 1, Example Tag 2', 'rank-math' ), ); self::$replacements['category'] = array( 'name' => esc_html__( 'Post Category', 'rank-math' ), 'desc' => wp_kses_post( __( 'First category (alphabetically) associated to the current post OR current category on category archives', 'rank-math' ) ), 'example' => esc_html__( 'Example Category', 'rank-math' ), ); self::$replacements['categories'] = array( 'name' => esc_html__( 'Post Categories', 'rank-math' ), 'desc' => esc_html__( 'Comma-separated list of categories associated to the current post', 'rank-math' ), 'example' => esc_html__( 'Example Category 1, Example Category 2', 'rank-math' ), ); self::$replacements['term'] = array( 'name' => esc_html__( 'Current Term', 'rank-math' ), 'desc' => esc_html__( 'Current term name', 'rank-math' ), 'example' => esc_html__( 'Example Term', 'rank-math' ), ); self::$replacements['term_description'] = array( 'name' => esc_html__( 'Term Description', 'rank-math' ), 'desc' => esc_html__( 'Current term description', 'rank-math' ), 'example' => esc_html__( 'Example Term Description', 'rank-math' ), ); self::$replacements['search_query'] = array( 'name' => esc_html__( 'Search Query', 'rank-math' ), 'desc' => esc_html__( 'Search query (only available on search results page)', 'rank-math' ), 'example' => esc_html__( 'example search', 'rank-math' ), ); self::$replacements['name'] = array( 'name' => esc_html__( 'Post Author', 'rank-math' ), 'desc' => esc_html__( 'Display author\'s nicename of the current post, page or author archive.', 'rank-math' ), 'example' => $current_user->display_name, ); self::$replacements['user_description'] = array( 'name' => esc_html__( 'Author Description', 'rank-math' ), 'desc' => esc_html__( 'Author\'s biographical info of the current post, page or author archive.', 'rank-math' ), 'example' => get_the_author_meta( 'desc' ), ); self::$replacements['filename'] = array( 'name' => esc_html__( 'File Name', 'rank-math' ), 'desc' => esc_html__( 'File Name of the attachment', 'rank-math' ), 'example' => 'sunrise at Maldives', ); // Advanced. self::$replacements['userid'] = array( 'name' => esc_html__( 'Author ID', 'rank-math' ), 'desc' => esc_html__( 'Author\'s user id of the current post, page or author archive.', 'rank-math' ), 'example' => $current_user->ID, ); self::$replacements['id'] = array( 'name' => esc_html__( 'Post ID', 'rank-math' ), 'desc' => esc_html__( 'ID of the current post/page', 'rank-math' ), 'example' => $post_id, ); self::$replacements['focuskw'] = array( 'name' => esc_html__( 'Focus Keyword', 'rank-math' ), 'desc' => esc_html__( 'Focus Keyword of the current post', 'rank-math' ), 'example' => esc_html__( 'Focus Keyword', 'rank-math' ), ); self::$replacements['page'] = array( 'name' => esc_html__( 'Page', 'rank-math' ), 'desc' => esc_html__( 'Page number with context (i.e. page 2 of 4). Only displayed on page 2 and above.', 'rank-math' ), 'example' => ' page 2 of 4', ); self::$replacements['pagetotal'] = array( 'name' => esc_html__( 'Max Pages', 'rank-math' ), 'desc' => esc_html__( 'Max pages number', 'rank-math' ), 'example' => '4', ); self::$replacements['pagenumber'] = array( 'name' => esc_html__( 'Page Number', 'rank-math' ), 'desc' => esc_html__( 'Current page number', 'rank-math' ), 'example' => '4', ); self::$replacements['currenttime'] = array( 'name' => esc_html__( 'Current Time', 'rank-math' ), 'desc' => esc_html__( 'Current server time', 'rank-math' ), 'example' => current_time( get_option( 'time_format' ) ), ); self::$replacements['currentdate'] = array( 'name' => esc_html__( 'Current Date', 'rank-math' ), 'desc' => esc_html__( 'Current server date', 'rank-math' ), 'example' => current_time( get_option( 'date_format' ) ), ); self::$replacements['currentday'] = array( 'name' => esc_html__( 'Current Day', 'rank-math' ), 'desc' => esc_html__( 'Current server day', 'rank-math' ), 'example' => current_time( 'dS' ), ); self::$replacements['currentmonth'] = array( 'name' => esc_html__( 'Current Month', 'rank-math' ), 'desc' => esc_html__( 'Current server month', 'rank-math' ), 'example' => current_time( 'F' ), ); self::$replacements['currentyear'] = array( 'name' => esc_html__( 'Current Year', 'rank-math' ), 'desc' => esc_html__( 'Current server year', 'rank-math' ), 'example' => current_time( 'Y' ), ); self::$replacements['pt_single'] = array( 'name' => esc_html__( 'Post Type Name Singular', 'rank-math' ), 'desc' => esc_html__( 'Name of current post type (singular)', 'rank-math' ), 'example' => esc_html__( 'Product', 'rank-math' ), ); self::$replacements['pt_plural'] = array( 'name' => esc_html__( 'Post Type Name Plural', 'rank-math' ), 'desc' => esc_html__( 'Name of current post type (plural)', 'rank-math' ), 'example' => esc_html__( 'Products', 'rank-math' ), ); self::$replacements['customfield(field-name)'] = array( 'name' => esc_html__( 'Custom Field (advanced)', 'rank-math' ), 'desc' => esc_html__( 'Custom field value.', 'rank-math' ), 'example' => esc_html__( 'Custom field value', 'rank-math' ), ); self::$replacements['date(F jS, Y)'] = array( 'name' => esc_html__( 'Date Published (advanced)', 'rank-math' ), 'desc' => esc_html__( 'Publish date with custom formatting pattern.', 'rank-math' ), 'example' => date( 'F jS, Y' ), ); self::$replacements['modified(F jS, Y)'] = array( 'name' => esc_html__( 'Date Modified (advanced)', 'rank-math' ), 'desc' => esc_html__( 'Modified date with custom formatting pattern.', 'rank-math' ), 'example' => date( 'F jS, Y' ), ); self::$replacements['currenttime(F jS, Y)'] = array( 'name' => esc_html__( 'Current Time (advanced)', 'rank-math' ), 'desc' => esc_html__( 'Current server time with custom formatting pattern.', 'rank-math' ), 'example' => current_time( 'F jS, Y' ), ); self::$replacements['categories(limit=3&separator= | &exclude=12,23)'] = array( 'name' => esc_html__( 'Categories (advanced)', 'rank-math' ), 'desc' => esc_html__( 'Output list of categories associated to the current post, with customization options.', 'rank-math' ), 'example' => esc_html__( 'Example Category 1 | Example Category 2', 'rank-math' ), ); self::$replacements['tags(limit=3&separator= | &exclude=12,23)'] = array( 'name' => esc_html__( 'Tags (advanced)', 'rank-math' ), 'desc' => esc_html__( 'Output list of tags associated to the current post, with customization options.', 'rank-math' ), 'example' => esc_html__( 'Example Tag 1 | Example Tag 2', 'rank-math' ), ); self::$replacements['count(varname)'] = array( 'name' => esc_html__( 'Counter', 'rank-math' ), 'desc' => esc_html__( 'Starts at 1 and increments by 1.', 'rank-math' ), 'example' => '2', ); } /** * Set custom taxonomies. * * @param int $post_id The current post ID. * @return void */ public static function set_custom_taxonomies( $post_id ) { $custom_taxonomies = get_post_taxonomies( $post_id ); if ( empty( $custom_taxonomies ) ) { return; } $json = []; foreach ( $custom_taxonomies as $taxonomy ) { if ( in_array( $taxonomy, [ 'category', 'post_tag' ] ) ) { continue; } $name = str_replace( '_', ' ', $taxonomy ); $name = ucwords( str_replace( '-', ' ', $name ) ); /* translators: Taxonomy name. */ $title = sprintf( __( '%s Title', 'rank-math' ), $name ); /* translators: Taxonomy name. */ $desc = sprintf( __( '%s Description', 'rank-math' ), $name ); self::$replacements[ "customterm({$taxonomy})" ] = [ 'name' => $title, 'desc' => esc_html__( 'Custom Term title.', 'rank-math' ), 'example' => $title, ]; self::$replacements[ "customterm({$taxonomy}_desc)" ] = [ 'name' => $desc, 'desc' => esc_html__( 'Custom Term description.', 'rank-math' ), 'example' => $desc, ]; $json[ $taxonomy ] = $title; $json[ "{$taxonomy}_desc" ] = $desc; } Helper::add_json( 'customTerms', $json ); } /** * Get the current post type. * * @return string Post type name. */ protected function get_queried_post_type() { $post_type = get_post_type(); if ( false !== $post_type ) { return $post_type; } $post_type = get_query_var( 'post_type' ); if ( is_array( $post_type ) ) { $post_type = reset( $post_type ); } return $post_type; } /** * Get the separator to use as a replacement. * * @return string */ protected function get_sep() { $sep = $this->do_filter( 'settings/title_separator', Helper::get_settings( 'titles.title_separator' ) ); return htmlentities( $sep, ENT_COMPAT, 'UTF-8', false ); } /** * Get the parent page title of the current page/CPT to use as a replacement. * * @return string|null */ private function get_parent_title() { $replacement = null; if ( is_singular() || is_admin() ) { if ( isset( $this->args->post_parent ) && 0 !== $this->args->post_parent ) { $replacement = get_the_title( $this->args->post_parent ); } } return $replacement; } /** * Get the site name to use as a replacement. * * @return string|null */ private function get_sitename() { static $replacement; if ( ! isset( $replacement ) ) { $sitename = wp_strip_all_tags( get_bloginfo( 'name' ), true ); if ( '' !== $sitename ) { $replacement = $sitename; } } return $replacement; } /** * Get the site tag line to use as a replacement. * * @return string|null */ private function get_sitedesc() { static $replacement; if ( ! isset( $replacement ) ) { $description = trim( strip_tags( get_bloginfo( 'description' ) ) ); if ( '' !== $description ) { $replacement = $description; } } return $replacement; } /** * Get the date of the post to use as a replacement. * * @param string $format (Optional) PHP date format. * @return string|null */ private function get_date( $format = '' ) { if ( '' !== $this->args->post_date ) { $format = $format ? $format : get_option( 'date_format' ); return mysql2date( $format, $this->args->post_date, true ); } if ( get_query_var( 'day' ) && get_query_var( 'day' ) !== '' ) { return get_the_date( $format ); } if ( single_month_title( ' ', false ) && '' !== single_month_title( ' ', false ) ) { return single_month_title( ' ', false ); } if ( '' !== get_query_var( 'year' ) ) { return get_query_var( 'year' ); } return null; } /** * Get the post modified time to use as a replacement. * * @param string $format (Optional) PHP date format. * @return string|null */ private function get_modified( $format = '' ) { $replacement = null; if ( ! empty( $this->args->post_modified ) ) { $format = $format ? $format : get_option( 'date_format' ); $replacement = mysql2date( $format, $this->args->post_modified, true ); } return $replacement; } /** * Get the post excerpt to use as a replacement. It will be auto-generated if it does not exist. * * @return string|null */ private function get_excerpt() { $replacement = null; if ( ! empty( $this->args->ID ) ) { if ( '' !== $this->args->post_excerpt ) { $replacement = strip_tags( $this->args->post_excerpt ); } elseif ( '' !== $this->args->post_content ) { $replacement = wp_html_excerpt( WordPress::strip_shortcodes( $this->args->post_content ), 155 ); } } return $replacement; } /** * Get the post excerpt to use as a replacement (without auto-generating). * * @return string|null */ private function get_excerpt_only() { $replacement = null; if ( ! empty( $this->args->ID ) && '' !== $this->args->post_excerpt ) { $replacement = strip_tags( $this->args->post_excerpt ); } return $replacement; } /** * Get the current tag to use as a replacement. * * @return string|null */ private function get_tag() { $replacement = null; if ( ! empty( $this->args->ID ) ) { $tags = $this->get_terms( $this->args->ID, 'post_tag', true ); if ( '' !== $tags ) { $replacement = $tags; } } return $replacement; } /** * Get the current tags to use as a replacement. * * @param array $args Arguments for get_terms(). * @return string|null */ private function get_tags( $args = [] ) { $replacement = null; if ( ! empty( $this->args->ID ) ) { $tags = $this->get_terms( $this->args->ID, 'post_tag', false, $args ); if ( '' !== $tags ) { $replacement = $tags; } } return $replacement; } /** * Get the post category to use as a replacement. * * @return string|null */ private function get_category() { $replacement = null; if ( ! empty( $this->args->ID ) ) { $cat = $this->get_terms( $this->args->ID, 'category', true ); if ( '' !== $cat ) { $replacement = $cat; } } if ( ( ! isset( $replacement ) || '' === $replacement ) && ( isset( $this->args->cat_name ) && ! empty( $this->args->cat_name ) ) ) { $replacement = $this->args->cat_name; } return $replacement; } /** * Get the comma-separate post categories to use as a replacement. * * @param array $args Array of arguments. * @return string|null */ private function get_categories( $args = [] ) { $replacement = null; if ( ! empty( $this->args->ID ) ) { $cat = $this->get_terms( $this->args->ID, 'category', false, $args ); if ( '' !== $cat ) { $replacement = $cat; } } return $replacement; } /** * Get the term name to use as a replacement. * * @return string|null */ private function get_term() { $replacement = null; if ( is_category() || is_tag() || is_tax() ) { global $wp_query; $replacement = $wp_query->queried_object->name; } elseif ( ! empty( $this->args->taxonomy ) && ! empty( $this->args->name ) ) { $replacement = $this->args->name; } return $replacement; } /** * Get the term description to use as a replacement. * * @return string|null */ private function get_term_description() { if ( is_category() || is_tag() || is_tax() ) { global $wp_query; return $wp_query->queried_object->description; } if ( isset( $this->args->term_id ) && ! empty( $this->args->taxonomy ) ) { $term_desc = get_term_field( 'description', $this->args->term_id, $this->args->taxonomy ); if ( '' !== $term_desc ) { return trim( strip_tags( $term_desc ) ); } } return null; } /** * Get the current search query to use as a replacement * * @return string|null */ private function get_search_query() { $replacement = null; if ( ! isset( $replacement ) ) { $search = get_search_query(); if ( '' !== $search ) { $replacement = $search; } } return $replacement; } /** * Get the post author's user ID to use as a replacement. * * @return string */ private function get_userid() { return ! empty( $this->args->post_author ) ? $this->args->post_author : get_query_var( 'author' ); } /** * Get the post author's "nice name" to use as a replacement. * * @return string|null */ private function get_name() { $replacement = null; $user_id = $this->get_userid(); $name = get_the_author_meta( 'display_name', $user_id ); if ( '' !== $name ) { $replacement = $name; } return $replacement; } /** * Get the filename of the attachment to use as a replacement. * * @return string|null */ private function get_filename() { if ( empty( $this->args->filename ) ) { return null; } $replacement = null; $name = \pathinfo( $this->args->filename ); // Remove size if embedded. $name = explode( '-', $name['filename'] ); if ( Str::contains( 'x', end( $name ) ) ) { array_pop( $name ); } // Format filename. $name = join( ' ', $name ); $name = trim( str_replace( '_', ' ', $name ) ); if ( '' !== $name ) { $replacement = $name; } return $replacement; } /** * Get the post author's user description to use as a replacement. * * @return string|null */ private function get_user_description() { $replacement = null; $user_id = $this->get_userid(); $description = get_the_author_meta( 'description', $user_id ); if ( '' !== $description ) { $replacement = $description; } return $replacement; } /** * Get the numeric post ID to use as a replacement * * @return string|null */ private function get_id() { $replacement = null; if ( ! empty( $this->args->ID ) ) { $replacement = $this->args->ID; } return $replacement; } /** * Get the focus keyword to use as a replacement. * * @return string|null */ private function get_focuskw() { $replacement = null; if ( ! empty( $this->args->ID ) ) { $focus_kw = Helper::get_post_meta( 'focus_keyword', $this->args->ID ); if ( '' !== $focus_kw ) { $replacement = $focus_kw; } } return $replacement; } /** * Get the current page number (i.e. "page 2 of 4") to use as a replacement. * * @return string */ private function get_page() { $replacement = null; $max = $this->determine_max_pages(); $page = $this->determine_page_number(); $sep = $this->get_sep(); if ( $max > 1 && $page > 1 ) { /* translators: 1: current page number, 2: total number of pages. */ $replacement = sprintf( $sep . ' ' . __( 'Page %1$d of %2$d', 'rank-math' ), $page, $max ); } return $replacement; } /** * Get only the page number (without context) to use as a replacement. * * @return string|null */ private function get_pagenumber() { $replacement = null; $page = $this->determine_page_number(); if ( isset( $page ) && $page > 0 ) { $replacement = (string) $page; } return $replacement; } /** * Get the may page number to use as a replacement. * * @return string|null */ private function get_pagetotal() { $replacement = null; $max = $this->determine_max_pages(); if ( isset( $max ) && $max > 0 ) { $replacement = (string) $max; } return $replacement; } /** * Get the current time to use as a replacement. * * @param string $format (Optional) PHP date format. * @return string */ private function get_currenttime( $format = '' ) { static $replacement; if ( ! isset( $replacement ) ) { $format = $format ? $format : get_option( 'time_format' ); $replacement = date_i18n( $format ); } return $replacement; } /** * Get the current date to use as a replacement. * * @param string $format (Optional) PHP date format. * @return string */ private function get_currentdate( $format = '' ) { static $replacement; if ( ! isset( $replacement ) ) { $format = $format ? $format : get_option( 'date_format' ); $replacement = date_i18n( $format ); } return $replacement; } /** * Get the current day to use as a replacement. * * @return string */ private function get_currentday() { static $replacement; if ( ! isset( $replacement ) ) { $replacement = date_i18n( 'j' ); } return $replacement; } /** * Get the current month to use as a replacement. * * @return string */ private function get_currentmonth() { static $replacement; if ( ! isset( $replacement ) ) { $replacement = date_i18n( 'F' ); } return $replacement; } /** * Get the current year to use as a replacement. * * @return string */ private function get_currentyear() { static $replacement; if ( ! isset( $replacement ) ) { $replacement = date_i18n( 'Y' ); } return $replacement; } /** * Get the post type "single" label to use as a replacement. * * @return string|null */ private function get_pt_single() { $replacement = null; $name = $this->determine_pt_names( 'single' ); if ( isset( $name ) && '' !== $name ) { $replacement = $name; } return $replacement; } /** * Get a specific custom field value to use as a replacement. * * @param string $name The name of the custom field to retrieve. * @return string|null */ private function get_customfield( $name ) { global $post; $replacement = null; if ( Str::is_non_empty( $name ) ) { if ( ( is_singular() || is_admin() ) && ( is_object( $post ) && isset( $post->ID ) ) ) { $name = get_post_meta( $post->ID, $name, true ); if ( '' !== $name ) { $replacement = $name; } } } return $replacement; } /** * Get a custom taxonomy term to use as a replacement. * * @param string $name The name of the taxonomy. * @return string|null */ private function get_customterm( $name ) { if ( Str::is_non_empty( $name ) ) { global $post; $taxonomy = str_replace( '_desc', '', $name ); return Str::ends_with( 'desc', $name ) ? $this->get_terms( $post->ID, $taxonomy, true, [], 'description' ) : $this->get_terms( $post->ID, $taxonomy, true, [], 'name' ); } return null; } /** * Get the counter for the given variable. * * @param string $name The name of field. * @return string|null */ private function get_count( $name ) { if ( ! isset( self::$counters[ $name ] ) ) { self::$counters[ $name ] = 0; } return ++self::$counters[ $name ]; } /** * Get the post type "plural" label to use as a replacement. * * @return string|null */ private function get_pt_plural() { $replacement = null; $name = $this->determine_pt_names( 'plural' ); if ( isset( $name ) && '' !== $name ) { $replacement = $name; } return $replacement; } /** * Get the replacements for the variables. * * @param array $matches Regex matches found in the string. * @param array $exclude Variables that should not be replaced. * * @return array Retrieved replacements. */ private function set_up_replacements( $matches, $exclude ) { $replacements = []; foreach ( $matches[1] as $k => $var ) { // Don't set up excluded replacements. if ( in_array( $var, $exclude, true ) ) { continue; } $args = []; $method = 'get_' . $var; // Complex Tags. if ( ! empty( $matches[2][ $k ] ) && ! empty( $matches[3][ $k ] ) ) { $args = $this->normalize_args( $matches[3][ $k ] ); $method = 'get_' . $matches[2][ $k ]; } if ( method_exists( $this, $method ) ) { $replacement = $this->$method( $args ); } elseif ( isset( self::$external_replacements[ $var ] ) && ! is_null( isset( self::$external_replacements[ $var ] ) ) ) { $replacement = call_user_func( self::$external_replacements[ $var ]['callback'], $var, $args ); } // If replacement value is null, remove it. if ( isset( $replacement ) ) { $var = self::add_var_delimiter( $var ); $replacements[ $var ] = $replacement; } unset( $replacement, $method ); } return $replacements; } /** * Get the title of the post to use as a replacement. * * @return string|null */ private function get_title() { $replacement = null; // Get post type name as Title. if ( is_post_type_archive() && ! Post::is_shop_page() ) { $post_type = $this->get_queried_post_type(); $replacement = get_post_type_object( $post_type )->labels->name; } elseif ( Str::is_non_empty( $this->args->post_title ) ) { $replacement = stripslashes( $this->args->post_title ); } return $replacement; } /** * Convert arguments string to arguments array. * * @param string $string The string that needs to be converted. * * @return array */ private function normalize_args( $string ) { if ( ! Str::contains( '=', $string ) ) { return $string; } return wp_parse_args( $string, [] ); } /** * Get a comma separated list of the post's terms. * * @param int $id ID of the post. * @param string $taxonomy The taxonomy to get the terms from. * @param bool $return_single Return the first term only. * @param array $args Array of arguments. * @param string $field The term field to return. * * @return string Either a single term field or a comma delimited list of terms. */ private function get_terms( $id, $taxonomy, $return_single = false, $args = [], $field = 'name' ) { $output = ''; // If we're on a taxonomy archive, use the selected term. if ( is_category() || is_tag() || is_tax() ) { $term = $GLOBALS['wp_query']->get_queried_object(); $output = $term->name; } if ( ! $output && ! empty( $id ) && ! empty( $taxonomy ) ) { $args = wp_parse_args( $args, array( 'limit' => 99, 'separator' => ', ', 'exclude' => [], ) ); if ( ! empty( $args['exclude'] ) ) { $args['exclude'] = array_map( 'trim', explode( ',', $args['exclude'] ) ); } $terms = get_the_terms( $id, $taxonomy ); if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) { $count = 0; $output = []; foreach ( $terms as $term ) { // Limit. $count++; if ( $count > $args['limit'] ) { break; } // Exclude. if ( in_array( $term->term_id, $args['exclude'], true ) ) { continue; } if ( $return_single ) { $output = $term->{$field}; break; } $output[] = $term->{$field}; } $output = is_array( $output ) ? join( $args['separator'], $output ) : $output; } } unset( $terms, $term ); /** * Filter: Allows changing the %category% and %tag% terms lists. * * @param string $output The terms list, comma separated. */ return $this->do_filter( 'vars/terms', $output ); } }