/
var
/
www
/
barefootlaw.org
/
wp-content
/
plugins
/
autodescription
/
inc
/
classes
/
Upload File
HOME
<?php /** * @package The_SEO_Framework\Classes\Facade\Generate_Title * @subpackage The_SEO_Framework\Getters\Title */ namespace The_SEO_Framework; \defined( 'THE_SEO_FRAMEWORK_PRESENT' ) or die; /** * The SEO Framework plugin * Copyright (C) 2015 - 2023 Sybre Waaijer, CyberWire B.V. (https://cyberwire.nl/) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ /** * Class The_SEO_Framework\Generate_Title * * Generates title SEO data based on content. * * NOTE: Don't supply $args in any of the methods for non-term taxomies, like author archives. * ID collision isn't accounted for in these scenarios. * * @since 2.8.0 */ class Generate_Title extends Generate_Description { /** * Returns the meta title from custom fields. Falls back to autogenerated title. * * @since 3.1.0 * @since 3.2.2 No longer double-escapes the custom field title. * @since 4.1.0 Added the third $social parameter. * @since 4.2.0 Now supports the `$args['pta']` index. * @uses $this->get_custom_field_title() * @uses $this->get_generated_title() * * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * Leave null to autodetermine query. * @param bool $escape Whether to escape the title. * @param bool $social Whether the title is meant for social display. * @return string The real title output. */ public function get_title( $args = null, $escape = true, $social = false ) { $title = $this->get_custom_field_title( $args, false, $social ) ?: $this->get_generated_title( $args, false, $social ); return $escape ? $this->escape_title( $title ) : $title; } /** * Returns the custom user-inputted title. * * @since 3.1.0 * @since 4.0.0 Moved the filter to a separated method. * @since 4.1.0 Added the third $social parameter. * @since 4.2.0 Now supports the `$args['pta']` index. * * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * Leave null to autodetermine query. * @param bool $escape Whether to escape the title. * @param bool $social Whether the title is meant for social display. * @return string The custom field title. */ public function get_custom_field_title( $args = null, $escape = true, $social = false ) { $title = $this->get_filtered_raw_custom_field_title( $args ); if ( $title ) { if ( $this->use_title_protection( $args ) ) $this->merge_title_protection( $title, $args ); if ( $this->use_title_pagination( $args ) ) $this->merge_title_pagination( $title ); if ( $this->use_title_branding( $args, $social ) ) $this->merge_title_branding( $title, $args ); } return $escape ? $this->escape_title( $title ) : $title; } /** * Returns the autogenerated meta title. * * @since 3.1.0 * @since 3.2.4 1. Added check for title protection. * 2. Moved check for title pagination. * @since 4.0.0 Moved the filter to a separated method. * @since 4.1.0 Added the third $social parameter. * @since 4.2.0 Now supports the `$args['pta']` index. * @uses $this->s_title_raw() : This is the same method used to prepare custom title on save. * @uses $this->get_filtered_raw_generated_title() * * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * Leave null to autodetermine query. * @param bool $escape Whether to escape the title. * @param bool $social Whether the title is meant for social display. * @return string The generated title output. */ public function get_generated_title( $args = null, $escape = true, $social = false ) { $title = $this->get_filtered_raw_generated_title( $args ); if ( $this->use_title_protection( $args ) ) $this->merge_title_protection( $title, $args ); if ( $this->use_title_pagination( $args ) ) $this->merge_title_pagination( $title ); if ( $this->use_title_branding( $args, $social ) ) $this->merge_title_branding( $title, $args ); $title = $this->s_title_raw( $title ); return $escape ? $this->escape_title( $title ) : $title; } /** * Returns the raw filtered custom field meta title. * * @since 4.0.0 * @since 4.2.0 1. The first parameter can now be voided. * 2. The first parameter is now rectified, so you can leave out indexes. * 3. Now supports the `$args['pta']` index. * * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * Leave null to autodetermine query. * @return string The raw generated title output. */ public function get_filtered_raw_custom_field_title( $args = null ) { if ( null !== $args ) $this->fix_generation_args( $args ); /** * Filters the title from custom field, if any. * * @since 3.1.0 * @since 4.2.0 Now supports the `$args['pta']` index. * * @param string $title The title. * @param array|null $args The query arguments. Contains 'id', 'taxonomy', and 'pta'. * Is null when query is autodetermined. */ return (string) \apply_filters_ref_array( 'the_seo_framework_title_from_custom_field', [ $this->get_raw_custom_field_title( $args ), $args, ] ); } /** * Returns the raw filtered autogenerated meta title. * * @since 4.0.0 * @since 4.2.0 1. The first parameter can now be voided. * 2. The first parameter is now rectified, so you can leave out indexes. * 3. Now supports the `$args['pta']` index. * * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * Leave null to autodetermine query. * @return string The raw generated title output. */ public function get_filtered_raw_generated_title( $args = null ) { if ( null !== $args ) $this->fix_generation_args( $args ); /** * Filters the title from query. * * @NOTE: This filter doesn't consistently run on the SEO Settings page. * You may want to avoid this filter for the homepage and pta, by returning the default value. * @since 3.1.0 * @since 4.2.0 Now supports the `$args['pta']` index. * @param string $title The title. * @param array|null $args The query arguments. Contains 'id', 'taxonomy', and 'pta'. * Is null when query is autodetermined. */ return (string) \apply_filters_ref_array( 'the_seo_framework_title_from_generation', [ $this->get_raw_generated_title( $args ), $args, ] ); } /** * Returns the Twitter meta title. * Falls back to Open Graph title. * * @since 3.0.4 * @since 3.1.0 1. The first parameter now expects an array. * 2. Now tries to get the homepage social titles. * @since 4.2.0 Now supports the `$args['pta']` index. * * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * Leave null to autodetermine query. * @param bool $escape Whether to escape the title. * @return string Twitter Title. */ public function get_twitter_title( $args = null, $escape = true ) { $title = $this->get_twitter_title_from_custom_field( $args, false ) ?: $this->get_generated_twitter_title( $args, false ); return $escape ? $this->escape_title( $title ) : $title; } /** * Returns the Twitter meta title from custom field. * Falls back to Open Graph title. * * @since 3.1.0 * @see $this->get_twitter_title() * * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * @param bool $escape Whether to escape the title. * @return string Twitter Title. */ protected function get_twitter_title_from_custom_field( $args, $escape ) { if ( null === $args ) { $title = $this->get_custom_twitter_title_from_query(); } else { $this->fix_generation_args( $args ); $title = $this->get_custom_twitter_title_from_args( $args ); } return $escape ? $this->escape_title( $title ) : $title; } /** * Returns the Twitter meta title from custom field, based on query. * Falls back to Open Graph title. * * @since 3.1.0 * @since 3.2.2 Now tests for the static frontpage metadata prior getting fallback data. * @since 4.0.0 Added term meta item checks. * @since 4.2.0 Can now return custom post type archive titles. * @see $this->get_twitter_title() * @see $this->get_twitter_title_from_custom_field() * * @return string Twitter Title. */ protected function get_custom_twitter_title_from_query() { if ( $this->is_real_front_page() ) { if ( $this->is_static_frontpage() ) { $title = $this->get_option( 'homepage_twitter_title' ) ?: $this->get_post_meta_item( '_twitter_title' ) ?: $this->get_option( 'homepage_og_title' ) ?: $this->get_post_meta_item( '_open_graph_title' ); } else { $title = $this->get_option( 'homepage_twitter_title' ) ?: $this->get_option( 'homepage_og_title' ); } } elseif ( $this->is_singular() ) { $title = $this->get_post_meta_item( '_twitter_title' ) ?: $this->get_post_meta_item( '_open_graph_title' ); } elseif ( $this->is_term_meta_capable() ) { $title = $this->get_term_meta_item( 'tw_title' ) ?: $this->get_term_meta_item( 'og_title' ); } elseif ( \is_post_type_archive() ) { $title = $this->get_post_type_archive_meta_item( 'tw_title' ) ?: $this->get_post_type_archive_meta_item( 'og_title' ); } return $title ?? '' ?: ''; } /** * Returns the Twitter meta title from custom field, based on arguments. * Falls back to Open Graph title. * * @since 3.1.0 * @since 3.2.2 Now tests for the static frontpage metadata prior getting fallback data. * @since 4.0.0 Added term meta item checks. * @since 4.2.0 Now supports the `$args['pta']` index. * @see $this->get_twitter_title() * @see $this->get_twitter_title_from_custom_field() * * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * @return string Twitter Title. */ protected function get_custom_twitter_title_from_args( $args ) { if ( $args['taxonomy'] ) { $title = $this->get_term_meta_item( 'tw_title', $args['id'] ) ?: $this->get_term_meta_item( 'og_title', $args['id'] ); } elseif ( $args['pta'] ) { $title = $this->get_post_type_archive_meta_item( 'tw_title', $args['pta'] ) ?: $this->get_post_type_archive_meta_item( 'og_title', $args['pta'] ); } else { if ( $this->is_static_frontpage( $args['id'] ) ) { $title = $this->get_option( 'homepage_twitter_title' ) ?: $this->get_post_meta_item( '_twitter_title', $args['id'] ) ?: $this->get_option( 'homepage_og_title' ) ?: $this->get_post_meta_item( '_open_graph_title', $args['id'] ); } elseif ( $this->is_real_front_page_by_id( $args['id'] ) ) { $title = $this->get_option( 'homepage_twitter_title' ) ?: $this->get_option( 'homepage_og_title' ); } else { $title = $this->get_post_meta_item( '_twitter_title', $args['id'] ) ?: $this->get_post_meta_item( '_open_graph_title', $args['id'] ); } } return $title ?: ''; } /** * Returns the autogenerated Twitter meta title. * Falls back to meta title. * * @since 3.0.4 * @since 3.1.0 The first parameter now expects an array. * @since 4.1.0 Now appends the "social" argument when getting the title. * @since 4.2.0 Now supports the `$args['pta']` index. * @uses $this->get_title() * * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * Leave null to autodetermine query. * @param bool $escape Whether to escape the title. * @return string The generated Twitter Title. */ public function get_generated_twitter_title( $args = null, $escape = true ) { return $this->get_title( $args, $escape, true ); } /** * Returns the Open Graph meta title. * Falls back to meta title. * * @since 3.0.4 * @since 3.1.0 1. The first parameter now expects an array. * 2. Now tries to get the homepage social title. * @since 4.2.0 Now supports the `$args['pta']` index. * @uses $this->get_generated_open_graph_title() * * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * Leave null to autodetermine query. * @param bool $escape Whether to escape the title. * @return string Open Graph Title. */ public function get_open_graph_title( $args = null, $escape = true ) { $title = $this->get_open_graph_title_from_custom_field( $args, false ) ?: $this->get_generated_open_graph_title( $args, false ); return $escape ? $this->escape_title( $title ) : $title; } /** * Returns the Open Graph meta title from custom field. * Falls back to meta title. * * @since 3.1.0 * @see $this->get_open_graph_title() * * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * @param bool $escape Whether to escape the title. * @return string Open Graph Title. */ protected function get_open_graph_title_from_custom_field( $args, $escape ) { if ( null === $args ) { $title = $this->get_custom_open_graph_title_from_query(); } else { $this->fix_generation_args( $args ); $title = $this->get_custom_open_graph_title_from_args( $args ); } return $escape ? $this->escape_title( $title ) : $title; } /** * Returns the Twitter meta title from custom field, based on query. * Falls back to meta title. * * @since 3.1.0 * @since 3.2.2 Now tests for the static frontpage metadata prior getting fallback data. * @since 4.0.0 Added term meta item checks. * @since 4.2.0 Can now return custom post type archive titles. * @see $this->get_open_graph_title() * @see $this->get_open_graph_title_from_custom_field() * * @return string Open Graph Title. */ protected function get_custom_open_graph_title_from_query() { if ( $this->is_real_front_page() ) { if ( $this->is_static_frontpage() ) { $title = $this->get_option( 'homepage_og_title' ) ?: $this->get_post_meta_item( '_open_graph_title' ); } else { $title = $this->get_option( 'homepage_og_title' ); } } elseif ( $this->is_singular() ) { $title = $this->get_post_meta_item( '_open_graph_title' ); } elseif ( $this->is_term_meta_capable() ) { $title = $this->get_term_meta_item( 'og_title' ); } elseif ( \is_post_type_archive() ) { $title = $this->get_post_type_archive_meta_item( 'og_title' ); } return $title ?? '' ?: ''; } /** * Returns the Open Graph meta title from custom field, based on query. * Falls back to meta title. * * @since 3.1.0 * @since 3.2.2 Now tests for the static frontpage metadata prior getting fallback data. * @since 4.0.0 Added term meta item checks. * @since 4.2.0 Now supports the `$args['pta']` index. * @see $this->get_open_graph_title() * @see $this->get_open_graph_title_from_custom_field() * * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * @return string Open Graph Title. */ protected function get_custom_open_graph_title_from_args( $args ) { if ( $args['taxonomy'] ) { $title = $this->get_term_meta_item( 'og_title', $args['id'] ); } elseif ( $args['pta'] ) { $title = $this->get_post_type_archive_meta_item( 'og_title', $args['pta'] ); } else { if ( $this->is_static_frontpage( $args['id'] ) ) { $title = $this->get_option( 'homepage_og_title' ) ?: $this->get_post_meta_item( '_open_graph_title', $args['id'] ); } elseif ( $this->is_real_front_page_by_id( $args['id'] ) ) { $title = $this->get_option( 'homepage_og_title' ); } else { $title = $this->get_post_meta_item( '_open_graph_title', $args['id'] ); } } return $title ?: ''; } /** * Returns the autogenerated Open Graph meta title. Falls back to meta title. * Falls back to meta title. * * @since 3.0.4 * @since 3.1.0 The first parameter now expects an array. * @since 4.1.0 Now appends the "social" argument when getting the title. * @since 4.2.0 Now supports the `$args['pta']` index. * @uses $this->get_title() * * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * Leave null to autodetermine query. * @param bool $escape Whether to escape the title. * @return string The generated Open Graph Title. */ public function get_generated_open_graph_title( $args = null, $escape = true ) { return $this->get_title( $args, $escape, true ); } /** * Returns the custom user-inputted title. * * This doesn't use the taxonomy arguments, because, wonderously, WordPress * finally admits through their code that terms can be queried using only IDs. * * @since 3.1.0 * @since 4.2.0 Now supports the `$args['pta']` index. * @internal But, feel free to use it. * * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * Leave null to autodetermine query. * @return string The custom field title, if it exists. */ public function get_raw_custom_field_title( $args = null ) { if ( null === $args ) { $title = $this->get_custom_field_title_from_query(); } else { $this->fix_generation_args( $args ); $title = $this->get_custom_field_title_from_args( $args ); } return $title ?: ''; } /** * Gets a custom title, based on current query, without additions or prefixes. * * @since 3.1.0 * @since 3.2.2 Now tests for the static frontpage metadata prior getting fallback data. * @since 4.2.0 Can now return custom post type archive titles. * @internal * @see $this->get_raw_custom_field_title() * * @return string The custom title. */ protected function get_custom_field_title_from_query() { if ( $this->is_real_front_page() ) { if ( $this->is_static_frontpage() ) { $title = $this->get_option( 'homepage_title' ) ?: $this->get_post_meta_item( '_genesis_title' ); } else { $title = $this->get_option( 'homepage_title' ); } } elseif ( $this->is_singular() ) { $title = $this->get_post_meta_item( '_genesis_title' ); } elseif ( $this->is_term_meta_capable() ) { $title = $this->get_term_meta_item( 'doctitle' ); } elseif ( \is_post_type_archive() ) { /** * @since 4.0.6 * @since 4.2.0 Deprecated. * @deprecated Use options instead. * @param string $title The post type archive title. */ $title = (string) \apply_filters_deprecated( 'the_seo_framework_pta_title', [ $this->get_post_type_archive_meta_item( 'doctitle' ) ], '4.2.0 of The SEO Framework' ); } return $title ?? '' ?: ''; } /** * Gets a custom title, based on input arguments query, without additions or prefixes. * * @since 3.1.0 * @since 3.1.4 Now uses the 'id' to get custom singular title. * @since 3.2.2 Now tests for the static frontpage metadata prior getting fallback data. * @since 4.2.0 Now supports the `$args['pta']` index. * @internal * @see $this->get_raw_custom_field_title() * * @param array $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * @return string The custom title. */ protected function get_custom_field_title_from_args( $args ) { if ( $args['taxonomy'] ) { $title = $this->get_term_meta_item( 'doctitle', $args['id'] ); } elseif ( $args['pta'] ) { $title = $this->get_post_type_archive_meta_item( 'doctitle', $args['pta'] ); } else { if ( $this->is_static_frontpage( $args['id'] ) ) { $title = $this->get_option( 'homepage_title' ) ?: $this->get_post_meta_item( '_genesis_title', $args['id'] ); } elseif ( $this->is_real_front_page_by_id( $args['id'] ) ) { $title = $this->get_option( 'homepage_title' ); } else { $title = $this->get_post_meta_item( '_genesis_title', $args['id'] ); } } return $title ?: ''; } /** * Generates a title, based on expected or current query, without additions or prefixes. * * @since 3.1.0 * @since 4.2.0 1. Added memoization. * 2. Now supports the `$args['pta']` index. * @uses $this->generate_title_from_query() * @uses $this->generate_title_from_args() * * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * Leave null to autodetermine query. * @return string The generated title. */ public function get_raw_generated_title( $args = null ) { // phpcs:ignore, WordPress.CodeAnalysis.AssignmentInCondition -- I know. if ( null !== $memo = memo( null, $args ) ) return $memo; $this->remove_default_title_filters( false, $args ); if ( null === $args ) { $title = $this->generate_title_from_query(); } else { $this->fix_generation_args( $args ); $title = $this->generate_title_from_args( $args ); } $this->reset_default_title_filters(); return memo( $title ?: $this->get_static_untitled_title(), $args ); } /** * Removes default title filters, for consistent output and sanitization. * Memoizes the filters removed, so it can add them back on reset. * * Performance test: 0.007ms per remove+reset on PHP 8.0, single core VPN. * * @since 3.1.0 * @since 4.1.0 Added a second parameter, $args, to help soften the burden of this method. * @internal Only to be used within $this->get_raw_generated_title() * * @param bool $reset Whether to reset the removed filters. * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * Leave null to autodetermine query. */ protected function remove_default_title_filters( $reset = false, $args = null ) { static $filtered = []; if ( $reset ) { foreach ( $filtered as $tag => $functions ) foreach ( $functions as $function => $priorities ) foreach ( $priorities as $priority ) \add_filter( $tag, $function, $priority ); // Reset filters. $filtered = []; } else { if ( null === $args ) { $filters = [ 'single_post_title', 'single_cat_title', 'single_tag_title' ]; } else { $this->fix_generation_args( $args ); if ( 'category' === $args['taxonomy'] ) { $filters = [ 'single_cat_title' ]; } elseif ( 'post_tag' === $args['taxonomy'] ) { $filters = [ 'single_tag_title' ]; } else { $filters = [ 'single_post_title' ]; } } /** * Texturization happens when outputting and saving the title; however, * we want the raw title, so we won't find unexplainable issues later. */ $functions = [ 'wptexturize' ]; if ( ! $this->get_option( 'title_strip_tags' ) ) $functions[] = 'strip_tags'; foreach ( $filters as $tag ) { foreach ( $functions as $function ) { // Only grab 10 of these. Yes, one might transform still on the 11th. $it = 10; $i = 0; // phpcs:ignore, WordPress.CodeAnalysis.AssignmentInCondition while ( $priority = \has_filter( $tag, $function ) ) { $filtered[ $tag ][ $function ][] = $priority; \remove_filter( $tag, $function, $priority ); // Some noob might've destroyed \WP_Hook. Safeguard. if ( ++$i > $it ) break 1; } } } } } /** * Resets default title filters, for consistent output and sanitation. * * @since 3.1.0 * @internal Only to be used within $this->get_raw_generated_title() * @uses $this->remove_default_title_filters() */ protected function reset_default_title_filters() { $this->remove_default_title_filters( true ); } /** * Generates a title, based on current query, without additions or prefixes. * * @since 3.1.0 * @since 4.2.0 Flipped order of query tests. * @since 4.2.7 Added failover filter for failed queries. * @internal * @see $this->get_raw_generated_title() * * @return string The generated title. */ protected function generate_title_from_query() { if ( \is_404() ) { $title = $this->get_static_404_title(); } elseif ( $this->is_search() ) { $title = $this->get_generated_search_query_title(); } elseif ( $this->is_real_front_page() ) { $title = $this->get_static_front_page_title(); } elseif ( $this->is_singular() ) { $title = $this->get_generated_single_post_title(); } elseif ( $this->is_archive() ) { $title = $this->get_generated_archive_title(); } return $title ?? ''; } /** * Generates a title, based on expected query, without additions or prefixes. * * @since 3.1.0 * @since 4.2.0 Now supports the `$args['pta']` index. * @internal * @see $this->get_raw_generated_title() * * @param array $args The query arguments. Required. Accepts 'id', 'taxonomy', and 'pta'. * @return string The generated title. Empty if query can't be replicated. */ protected function generate_title_from_args( $args ) { if ( $args['taxonomy'] ) { $title = $this->get_generated_archive_title( \get_term( $args['id'], $args['taxonomy'] ) ); } elseif ( $args['pta'] ) { $title = $this->get_generated_archive_title( \get_post_type_object( $args['pta'] ) ); } else { if ( $this->is_real_front_page_by_id( $args['id'] ) ) { $title = $this->get_static_front_page_title(); } else { $title = $this->get_generated_single_post_title( $args['id'] ); } } return $title; } /** * Generates front page title. * * This is an alias of get_blogname(). The difference is that this is used for * the front-page title output solely, whereas the other one has a mixed usage. * * @since 3.1.0 * @since 4.2.0 1. Now listens to the new `site_title` option. * 2. Now applies filters. * * @return string The generated front page title. */ public function get_static_front_page_title() { return $this->get_blogname(); } /** * Returns the archive title. Also works in admin. * * @NOTE Taken from WordPress core. Altered to work for metadata and in admin. * @see WP Core get_the_archive_title() * * @since 3.1.0 * @since 4.0.2 Now asserts the correct tag taxonomy condition. * @since 4.0.5 1: Now no longer uses `get_the_author()` to fetch the author's display name, * but uses the provided term object instead. * 2: The first parameter now accepts `\WP_User` objects. * @since 4.1.2 Now supports WP 5.5 archive titles. * * @param \WP_Term|\WP_User|\WP_Post_Type|\WP_Error|null $object The Term object or error. * Leave null to autodetermine query. * @return string The generated archive title, not escaped. */ public function get_generated_archive_title( $object = null ) { if ( $object && \is_wp_error( $object ) ) return ''; [ $title ] = $this->get_raw_generated_archive_title_items( $object ); return $title; } /** * Returns the archive title items. Also works in admin. * * @NOTE Taken from WordPress core. Altered to work for metadata. * @see WP Core get_the_archive_title() * * @since 4.2.0 * * @param \WP_Term|\WP_User|\WP_Post_Type|null $object The Term object. * Leave null to autodetermine query. * @return String[$title,$prefix,$title_without_prefix] The generated archive title items, not escaped. */ public function get_raw_generated_archive_title_items( $object = null ) { $filterobject = $object ?? \get_queried_object(); /** * @since 2.6.0 * * @param string $title The short circuit title. * @param \WP_Term|\WP_User|\WP_Post_Type $object The archive object. */ $title = (string) \apply_filters_deprecated( 'the_seo_framework_the_archive_title', [ '', $filterobject, ], '4.2.0 of The SEO Framework', 'the_seo_framework_generated_archive_title_prefix and the_seo_framework_generated_archive_title' ); if ( $title ) return [ $title, '', $title ]; [ $title, $prefix ] = $object ? $this->get_generate_archive_title_from_term( $object ) : $this->get_generate_archive_title_from_query(); $title_without_prefix = $title; if ( $this->use_generated_archive_prefix( $object ) ) { /** * Filters the archive title prefix. * This is a sibling of WordPress's `get_the_archive_title_prefix`, * but then without the HTML, and runs optionally, based on site-settings, * and then with the second paramter: `$object`. * * @since 4.2.0 * * @param string $prefix Archive title prefix. * @param \WP_Term|\WP_User|\WP_Post_Type $object The archive object. */ $prefix = \apply_filters_ref_array( 'the_seo_framework_generated_archive_title_prefix', [ $prefix, $filterobject, ] ); if ( $prefix ) { $title = sprintf( /* translators: 1: Title prefix. 2: Title. */ \_x( '%1$s %2$s', 'archive title', 'default' ), $prefix, $title ); } } /** * Filters the archive title. * This is a sibling of WordPress's `get_the_archive_title`, * but then without the HTML. * * @since 3.0.4 * @since 4.2.0 Added the `$prefix` and `$origintitle_without_prefixal_title` parameters. * * @param string $title Archive title to be displayed. * @param \WP_Term|\WP_User|\WP_Post_Type $object The archive object. * @param string $title_without_prefix Archive title without prefix. * @param string $prefix Archive title prefix. */ $title = \apply_filters_ref_array( 'the_seo_framework_generated_archive_title', [ $title, $filterobject, $title_without_prefix, $prefix, ] ); return [ $title, $prefix, $title_without_prefix ]; } /** * Returns the generated archive title by evaluating the input Term only. * * @since 4.2.0 * @see $this->get_generate_archive_title_from_term() which evaluates from arguments. * * @return string[$title,$prefix] The title and prefix. */ protected function get_generate_archive_title_from_query() { $title = \__( 'Archives', 'default' ); $prefix = ''; if ( $this->is_category() ) { $title = $this->get_generated_single_term_title( \get_queried_object() ); $prefix = \_x( 'Category:', 'category archive title prefix', 'default' ); } elseif ( $this->is_tag() ) { $title = $this->get_generated_single_term_title( \get_queried_object() ); $prefix = \_x( 'Tag:', 'tag archive title prefix', 'default' ); } elseif ( $this->is_author() ) { $title = \get_queried_object()->display_name ?? ''; $prefix = \_x( 'Author:', 'author archive title prefix', 'default' ); } elseif ( \is_date() ) { if ( \is_year() ) { $title = \get_the_date( \_x( 'Y', 'yearly archives date format', 'default' ) ); $prefix = \_x( 'Year:', 'date archive title prefix', 'default' ); } elseif ( \is_month() ) { $title = \get_the_date( \_x( 'F Y', 'monthly archives date format', 'default' ) ); $prefix = \_x( 'Month:', 'date archive title prefix', 'default' ); } elseif ( \is_day() ) { $title = \get_the_date( \_x( 'F j, Y', 'daily archives date format', 'default' ) ); $prefix = \_x( 'Day:', 'date archive title prefix', 'default' ); } } elseif ( \is_tax( 'post_format' ) ) { if ( \is_tax( 'post_format', 'post-format-aside' ) ) { $title = \_x( 'Asides', 'post format archive title', 'default' ); } elseif ( \is_tax( 'post_format', 'post-format-gallery' ) ) { $title = \_x( 'Galleries', 'post format archive title', 'default' ); } elseif ( \is_tax( 'post_format', 'post-format-image' ) ) { $title = \_x( 'Images', 'post format archive title', 'default' ); } elseif ( \is_tax( 'post_format', 'post-format-video' ) ) { $title = \_x( 'Videos', 'post format archive title', 'default' ); } elseif ( \is_tax( 'post_format', 'post-format-quote' ) ) { $title = \_x( 'Quotes', 'post format archive title', 'default' ); } elseif ( \is_tax( 'post_format', 'post-format-link' ) ) { $title = \_x( 'Links', 'post format archive title', 'default' ); } elseif ( \is_tax( 'post_format', 'post-format-status' ) ) { $title = \_x( 'Statuses', 'post format archive title', 'default' ); } elseif ( \is_tax( 'post_format', 'post-format-audio' ) ) { $title = \_x( 'Audio', 'post format archive title', 'default' ); } elseif ( \is_tax( 'post_format', 'post-format-chat' ) ) { $title = \_x( 'Chats', 'post format archive title', 'default' ); } } elseif ( \is_post_type_archive() ) { $title = $this->get_generated_post_type_archive_title(); $prefix = \_x( 'Archives:', 'post type archive title prefix', 'default' ); } elseif ( $this->is_tax() ) { $term = \get_queried_object(); if ( $term ) { $title = $this->get_generated_single_term_title( $term ); $prefix = sprintf( /* translators: %s: Taxonomy singular name. */ \_x( '%s:', 'taxonomy term archive title prefix', 'default' ), $this->get_tax_type_label( $term->taxonomy ?? '' ) ); } } return [ $title, $prefix ]; } /** * Returns the generated archive title by evaluating the input Term only. * * @since 4.2.0 * @see $this->get_generate_archive_title_from_query() which evalutates the query only. * * @param \WP_Term|\WP_User $term The Term object. * @return string[$title,$prefix] The title and prefix. */ protected function get_generate_archive_title_from_term( $term ) { $title = \__( 'Archives', 'default' ); $prefix = ''; if ( ! empty( $term->taxonomy ) ) { $title = $this->get_generated_single_term_title( $term ); switch ( $term->taxonomy ) : case 'category': $prefix = \_x( 'Category:', 'category archive title prefix', 'default' ); break; case 'post_tag': $prefix = \_x( 'Tag:', 'tag archive title prefix', 'default' ); break; default: $prefix = sprintf( /* translators: %s: Taxonomy singular name. */ \_x( '%s:', 'taxonomy term archive title prefix', 'default' ), $this->get_tax_type_label( $term->taxonomy ) ); break; endswitch; } elseif ( $term instanceof \WP_User && isset( $term->display_name ) ) { $title = $term->display_name; $prefix = \_x( 'Author:', 'author archive title prefix', 'default' ); } elseif ( $term instanceof \WP_Post_Type && isset( $term->name ) ) { $title = $this->get_generated_post_type_archive_title( $term->name ); $prefix = \_x( 'Archives:', 'post type archive title prefix', 'default' ); } return [ $title, $prefix ]; } /** * Returns Post Title from ID. * * @NOTE Taken from WordPress core. Altered to work in the Admin area. * @see WP Core single_post_title() * * @since 3.1.0 * @since 4.2.8 Now tests for post type support of 'title' before parsing the title. * * @param int|\WP_Post $id The Post ID or post object. * @return string The generated post title. */ public function get_generated_single_post_title( $id = 0 ) { // Home queries can be tricky. Use get_the_real_ID to be certain. $post = \get_post( $id ?: $this->get_the_real_ID() ); if ( isset( $post->post_title ) && \post_type_supports( $post->post_type, 'title' ) ) { /** * Filters the page title for a single post. * * @since WP Core 0.71 * * @param string $post_title The single post page title. * @param \WP_Post $post The current queried object as returned by get_queried_object(). */ $title = \apply_filters( 'single_post_title', $post->post_title, $post ); } return $title ?? '' ?: ''; } /** * Fetches single term title. * * It can autodetermine the term; so, perform your checks prior calling. * * Taken from WordPress core. Altered to work in the Admin area. * * @see WP Core single_term_title() * * @since 3.1.0 * @since 4.0.0 No longer redundantly tests the query, now only uses the term input or queried object. * @since 4.0.2 Now asserts the correct tag taxonomy condition. * @since 4.2.7 Now invokes proper filters when 'category' or 'tag' taxonomies are used. * * @param null|\WP_Term $term The term name, required in the admin area. * @return string The generated single term title. */ public function get_generated_single_term_title( $term = null ) { if ( \is_null( $term ) ) $term = \get_queried_object(); if ( ! isset( $term->name ) ) return ''; switch ( $term->taxonomy ) : case 'category': /** * Filter the category archive page title. * * @since WP Core 2.0.10 * * @param string $term_name Category name for archive being displayed. */ $term_name = \apply_filters( 'single_cat_title', $term->name ); break; case 'post_tag': /** * Filter the tag archive page title. * * @since WP Core 2.3.0 * * @param string $term_name Tag name for archive being displayed. */ $term_name = \apply_filters( 'single_tag_title', $term->name ); break; default: /** * Filter the custom taxonomy archive page title. * * @since WP Core 3.1.0 * * @param string $term_name Term name for archive being displayed. */ $term_name = \apply_filters( 'single_term_title', $term->name ); break; endswitch; return $term_name; } /** * Fetches single term title. * * @NOTE Taken from WordPress core. Altered to work in the Admin area. * @see WP Core post_type_archive_title() * * @since 3.1.0 * @since 4.2.0 Now actually works in the admin area, provided you forward $post_type. * * @param string $post_type The post type. * @return string The generated post type archive title. */ public function get_generated_post_type_archive_title( $post_type = '' ) { if ( ! $post_type && ! \is_post_type_archive() ) return ''; $post_type = $post_type ?: $this->get_current_post_type(); if ( \is_array( $post_type ) ) $post_type = reset( $post_type ); if ( ! \in_array( $post_type, $this->get_public_post_type_archives(), true ) ) return ''; /** * Filters the post type archive title. * * @since WP Core 3.1.0 * * @param string $post_type_name Post type 'name' label. * @param string $post_type Post type. */ $title = \apply_filters_ref_array( 'post_type_archive_title', [ $this->get_post_type_label( $post_type, false ), $post_type, ] ); return $title; } /** * Returns untitled title. * * @since 3.1.0 * * @return string The untitled title. */ public function get_static_untitled_title() { // FIXME: WordPress no longer outputs 'Untitled' for the title. It still actively holds this translation, but other context (Widget). return \__( 'Untitled', 'default' ); } /** * Returns search title. * * @since 3.1.0 * * @return string The generated search title, partially escaped. */ public function get_generated_search_query_title() { /* translators: %s: search phrase */ return sprintf( \__( 'Search Results for “%s”', 'default' ), \get_search_query( true ) ); } /** * Returns 404 title. * * @since 2.6.0 * @since 3.1.0 No longer accepts parameters, nor has conditions. * * @return string The generated 404 title. */ public function get_static_404_title() { /** * @since 2.5.2 * @param string $title The 404 title. */ return (string) \apply_filters( 'the_seo_framework_404_title', '404' ); } /** * Merges title branding, when allowed. * * @since 3.1.0 * @since 3.1.2 Added strict taxonomical check. * @since 3.1.3 Fixed conditional logic. * @since 4.2.0 Now supports the `$args['pta']` index. * @uses $this->get_title_branding_from_query() * @uses $this->get_title_branding_from_args() * * @param string $title The title. Passed by reference. * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * Leave null to autodetermine query. */ public function merge_title_branding( &$title, $args = null ) { if ( null === $args ) { $data = $this->get_title_branding_from_query(); } else { $this->fix_generation_args( $args ); $data = $this->get_title_branding_from_args( $args ); } $title = trim( $title ); $addition = trim( $data['addition'] ); if ( $addition && $title ) { $sep = $this->get_title_separator(); if ( 'left' === $data['seplocation'] ) { $title = "$addition $sep $title"; } else { $title = "$title $sep $addition"; } } } /** * Returns the addition and seplocation from query. * * @since 3.2.2 * @see $this->merge_title_branding(); * * @return array { 'addition', 'seplocation' } */ protected function get_title_branding_from_query() { if ( $this->is_real_front_page() ) { $addition = $this->get_home_title_additions(); $seplocation = $this->get_home_title_seplocation(); } else { $addition = $this->get_blogname(); $seplocation = $this->get_title_seplocation(); } return compact( 'addition', 'seplocation' ); } /** * Returns the addition and seplocation from arguments. * * @since 3.2.2 * @since 4.2.0 Now supports the `$args['pta']` index. * @see $this->merge_title_branding(); * * @param array $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * @return array { 'addition', 'seplocation' } */ protected function get_title_branding_from_args( $args ) { if ( ! $args['taxonomy'] && ! $args['pta'] && $this->is_real_front_page_by_id( $args['id'] ) ) { $addition = $this->get_home_title_additions(); $seplocation = $this->get_home_title_seplocation(); } else { $addition = $this->get_blogname(); $seplocation = $this->get_title_seplocation(); } return compact( 'addition', 'seplocation' ); } /** * Merges pagination with the title, if paginated. * * @since 3.1.0 * @since 3.1.2 Now uses the registered default translation. * * @param string $title The title. Passed by reference. */ public function merge_title_pagination( &$title ) { $page = $this->page(); $paged = $this->paged(); if ( $paged >= 2 || $page >= 2 ) { $sep = $this->get_title_separator(); /* translators: %s: Page number. */ $paging = sprintf( \__( 'Page %s', 'default' ), max( $paged, $page ) ); if ( \is_rtl() ) { $title = "$paging $sep $title"; } else { $title = "$title $sep $paging"; } } } /** * Merges title protection prefixes. * * @since 3.1.0 * @since 3.1.2 Added strict taxonomical checks for title protection. * @since 3.1.3 Fixed conditional logic. * @since 4.2.0 Now supports the `$args['pta']` index. * @since 4.2.4 Resolved regression where $run-test was reversed (renamed to $merge). * @see $this->merge_title_prefixes() * * @param string $title The title. Passed by reference. * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * Leave null to autodetermine query. * @return void */ public function merge_title_protection( &$title, $args = null ) { if ( null === $args ) { $id = $this->get_the_real_ID(); $merge = $this->is_singular(); } else { $this->fix_generation_args( $args ); $id = $args['id']; $merge = ! $args['taxonomy'] && ! $args['pta']; } if ( ! $merge ) return; $post = $id ? \get_post( $id ) : null; if ( ! empty( $post->post_password ) ) { /* translators: %s: Protected post title. */ $prepend = \__( 'Protected: %s', 'default' ); /** * Filters the text prepended to the post title of private posts. * * The filter is only applied on the front end. * * @since WP Core 2.8.0 * * @param string $prepend Text displayed before the post title. * Default 'Private: %s'. * @param WP_Post $post Current post object. */ $protected_title_format = (string) \apply_filters( 'protected_title_format', $prepend, $post ); $title = sprintf( $protected_title_format, $title ); } elseif ( 'private' === ( $post->post_status ?? null ) ) { /* translators: %s: Private post title. */ $prepend = \__( 'Private: %s', 'default' ); /** * Filters the text prepended to the post title of private posts. * * The filter is only applied on the front end. * * @since WP Core 2.8.0 * * @param string $prepend Text displayed before the post title. * Default 'Private: %s'. * @param WP_Post $post Current post object. */ $private_title_format = (string) \apply_filters( 'private_title_format', $prepend, $post ); $title = sprintf( $private_title_format, $title ); } } /** * Gets Title Separator. * Memoizes the return value. * * @since 2.6.0 * * @return string The Separator, unescaped. */ public function get_title_separator() { static $sep; /** * @since 2.3.9 * @param string $eparator The title separator */ return isset( $sep ) ? $sep : $sep = (string) \apply_filters( 'the_seo_framework_title_separator', $this->get_separator( 'title' ) ); } /** * Returns title separator location. * * @since 2.6.0 * @since 3.1.0 1. Removed the first $seplocation parameter. * 2. The first parameter is now $home * 3. Removed caching. * 4. Removed filters. * @since 4.0.0 The homepage option's return value is now reversed from expected. * * @param bool $home The home separator location. * @return string The separator location. */ public function get_title_seplocation( $home = false ) { return $home ? $this->get_option( 'home_title_location' ) : $this->get_option( 'title_location' ); } /** * Gets Title Seplocation for the homepage. * * @since 2.6.0 * @since 3.1.0 Removed first parameter. * @since 4.0.0 Left is now right, and right is now left. * * @return string The Seplocation for the homepage. */ public function get_home_title_seplocation() { return $this->get_title_seplocation( true ); } /** * Determines whether to add or remove title protection prefixes. * * @since 3.2.4 * @since 4.2.0 Now supports the `$args['pta']` index. * NOTE: This does not guarantee that protection is to be added. Only that it will be considered. Bad method name. * @see $this->merge_title_protection() * * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * Leave null to autodetermine query. * @return bool True when prefixes are allowed. */ public function use_title_protection( $args = null ) { if ( null === $args ) { $use = $this->is_singular(); } else { $this->fix_generation_args( $args ); $use = $args && ! $args['taxonomy'] && ! $args['pta']; } return $use; } /** * Determines whether to add or remove title pagination additions. * * @since 3.2.4 * NOTE: This does not guarantee that pagination is to be added. Only that it will be considered. Bad method name. * @see $this->merge_title_pagination() * * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * Leave null to autodetermine query. * @return bool True when additions are allowed. */ public function use_title_pagination( $args = null ) { // Only add pagination if the query is autodetermined, and on a real page. if ( null === $args ) { if ( \is_404() || \is_admin() ) { $use = false; } else { $use = true; } } else { $use = false; } return $use; } /** * Determines whether to add or remove title branding additions. * * @since 3.1.0 * @since 3.1.2 1. Added filter. * 2. Added strict taxonomical check. * @since 3.2.2 Now differentiates from query and parameter input. * @since 4.1.0 Added the second $social parameter. * @since 4.2.0 Now supports the `$args['pta']` index. * @see $this->merge_title_branding() * @uses $this->use_title_branding_from_query() * @uses $this->use_title_branding_from_args() * * @param array|null $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * Leave null to autodetermine query. * @param bool|string $social Whether the title is meant for social display. * Also accepts string 'og' and 'twitter' for future proofing. * @return bool True when additions are allowed. */ public function use_title_branding( $args = null, $social = false ) { // If social, test its option first. $use = $social ? ! $this->get_option( 'social_title_rem_additions' ) : true; // Reevaluate from general title settings, overriding social. if ( $use ) { if ( null === $args ) { $use = $this->use_title_branding_from_query(); } else { $this->fix_generation_args( $args ); $use = $this->use_title_branding_from_args( $args ); } } /** * @since 3.1.2 * @since 4.1.0 Added the third $social parameter. * @param string $use Whether to use branding. * @param array|null $args The query arguments. Contains 'id', 'taxonomy', and 'pta'. * Is null when query is autodetermined. * @param bool $social Whether the title is meant for social display. */ return \apply_filters_ref_array( 'the_seo_framework_use_title_branding', [ $use, $args, (bool) $social, ] ); } /** * Determines whether to add or remove title branding additions in the query. * * @since 3.2.2 * @since 4.0.0 Added use_taxonomical_title_branding() check. * @since 4.0.2 Removed contemned \is_post_type_archive() check for taxonomical branding. * @since 4.2.0 Can now test for custom post type archive branding. * @see $this->use_title_branding() * * @return bool */ protected function use_title_branding_from_query() { if ( $this->is_real_front_page() ) { $use = $this->use_home_page_title_tagline(); } elseif ( $this->is_singular() ) { $use = $this->use_singular_title_branding(); } elseif ( $this->is_term_meta_capable() ) { $use = $this->use_taxonomical_title_branding(); } elseif ( \is_post_type_archive() ) { $use = $this->use_post_type_archive_title_branding(); } else { $use = ! $this->get_option( 'title_rem_additions' ); } return $use; } /** * Determines whether to add or remove title branding additions from provided arguments. * * @since 3.2.2 * @since 4.0.0 Added use_taxonomical_title_branding() check. * @since 4.2.0 1. Now supports the `$args['pta']` index. * 2. Now tests for custom post type archive branding. * @see $this->use_title_branding() * * @param array $args The query arguments. Accepts 'id', 'taxonomy', and 'pta'. * @return bool */ protected function use_title_branding_from_args( $args ) { if ( $args['taxonomy'] ) { $use = $this->use_taxonomical_title_branding( $args['id'] ); } elseif ( $args['pta'] ) { $use = $this->use_post_type_archive_title_branding( $args['pta'] ); } else { if ( $this->is_real_front_page_by_id( $args['id'] ) ) { $use = $this->use_home_page_title_tagline(); } else { $use = $this->use_singular_title_branding( $args['id'] ); } } return $use; } /** * Determines whether to use the autogenerated archive title prefix or not. * * @since 3.1.0 * @since 4.0.5 1: Added first parameter `$term`. * 2: Added filter. * * @param \WP_Term|\WP_User|\WP_Post_Type|null $term The Term object. Leave null to autodermine query. * @return bool */ public function use_generated_archive_prefix( $term = null ) { $term = $term ?? \get_queried_object(); $use = ! $this->get_option( 'title_rem_prefixes' ); /** * @since 4.0.5 * @param string $use Whether to use branding. * @param \WP_Term|\WP_User|\WP_Post_Type $term The current term. */ return \apply_filters_ref_array( 'the_seo_framework_use_archive_prefix', [ $use, $term ] ); } /** * Determines whether to add homepage tagline. * * @since 2.6.0 * @since 3.0.4 Now checks for `$this->get_home_title_additions()`. * * @return bool */ public function use_home_page_title_tagline() { return $this->get_option( 'homepage_tagline' ) && $this->get_home_title_additions(); } /** * Determines whether to add the title tagline for the post. * * @since 3.1.0 * * @param int $id The post ID. Optional. * @return bool */ public function use_singular_title_branding( $id = 0 ) { return ! $this->get_post_meta_item( '_tsf_title_no_blogname', $id ) && ! $this->get_option( 'title_rem_additions' ); } /** * Determines whether to add the title tagline for the term. * * @since 4.0.0 * * @param int $id The term ID. Optional. * @return bool */ public function use_taxonomical_title_branding( $id = 0 ) { return ! $this->get_term_meta_item( 'title_no_blog_name', $id ) && ! $this->get_option( 'title_rem_additions' ); } /** * Determines whether to add the title tagline for the pta. * * @since 4.2.0 * * @param string $pta The post type archive. Optional. * @return bool */ public function use_post_type_archive_title_branding( $pta = '' ) { return ! $this->get_post_type_archive_meta_item( 'title_no_blog_name', $pta ) && ! $this->get_option( 'title_rem_additions' ); } /** * Returns the homepage additions (tagline) from option or bloginfo, when set. * Memoizes the return value. * * @since 4.1.0 * @uses $this->get_blogdescription(), that method already trims. * * @return string The trimmed tagline. */ public function get_home_title_additions() { return memo() ?? memo( $this->s_title_raw( $this->get_option( 'homepage_title_tagline' ) ?: $this->get_blogdescription() ?: '' ) ); } }