%PDF- %PDF-
Direktori : /var/www/pn/beta/64801_wp-content/plugins/autodescription/inc/classes/ |
Current File : /var/www/pn/beta/64801_wp-content/plugins/autodescription/inc/classes/doing-it-right.class.php |
<?php /** * @package The_SEO_Framework\Classes */ namespace The_SEO_Framework; defined( 'ABSPATH' ) or die; /** * The SEO Framework plugin * Copyright (C) 2015 - 2018 Sybre Waaijer, CyberWire (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\Doing_It_Right * * Adds data in a column to edit.php and edit-tags.php * Shows you if you're doing the SEO right. * * @since 2.8.0 */ class Doing_It_Right extends Generate_Ldjson { /** * Constructor, load parent constructor. * Initalizes columns and load post states. */ protected function __construct() { parent::__construct(); } /** * Add post state on edit.php to the page or post that has been altered. * * @uses $this->add_post_state * * @since 2.1.0 */ public function post_state() { //* Only load on singular pages. if ( $this->is_singular() ) { /** * Applies filters `the_seo_framework_allow_states` : boolean Whether to allow post states output. * @since 2.1.0 */ $allow_states = (bool) \apply_filters( 'the_seo_framework_allow_states', true ); if ( $allow_states ) \add_filter( 'display_post_states', array( $this, 'add_post_state' ), 10, 2 ); } } /** * Adds post states in post/page edit.php query * * @since 2.1.0 * @since 2.9.4 Now listens to `alter_search_query` and `alter_archive_query` options. * * @param array $states The current post states array * @param object $post The Post Object. */ public function add_post_state( $states = array(), $post ) { $post_id = isset( $post->ID ) ? $post->ID : false; if ( $post_id ) { $search_exclude = $this->get_option( 'alter_search_query' ) && $this->get_custom_field( 'exclude_local_search', $post_id ); $archive_exclude = $this->get_option( 'alter_archive_query' ) && $this->get_custom_field( 'exclude_from_archive', $post_id ); if ( $search_exclude ) $states[] = \esc_html__( 'No Search', 'autodescription' ); if ( $archive_exclude ) $states[] = \esc_html__( 'No Archive', 'autodescription' ); } return $states; } /** * Initializes SEO columns for adding a tag or category. * * @since 2.9.1 * @securitycheck 3.0.0 OK. * @access private */ public function _init_columns_wp_ajax_add_tag() { /** * Securely check the referrer, instead of leaving holes everywhere. */ if ( $this->doing_ajax() && \check_ajax_referer( 'add-tag', '_wpnonce_add-tag', false ) ) { $taxonomy = ! empty( $_POST['taxonomy'] ) ? \sanitize_key( $_POST['taxonomy'] ) : 'post_tag'; $tax = \get_taxonomy( $taxonomy ); if ( \current_user_can( $tax->cap->edit_terms ) ) $this->init_columns( '', true ); } } /** * Initializes SEO columns for adding a tag or category. * * @since 2.9.1 * @securitycheck 3.0.0 OK. * @access private */ public function _init_columns_wp_ajax_inline_save() { /** * Securely check the referrer, instead of leaving holes everywhere. */ if ( $this->doing_ajax() && \check_ajax_referer( 'inlineeditnonce', '_inline_edit', false ) ) { $post_type = isset( $_POST['post_type'] ) ? \sanitize_key( $_POST['post_type'] ) : false; if ( $post_type && isset( $_POST['post_ID'] ) ) { $post_id = (int) $_POST['post_ID']; $access = false; $pto = \get_post_type_object( $post_type ); if ( isset( $pto->capability_type ) ) $access = \current_user_can( 'edit_' . $pto->capability_type, $post_id ); if ( $access ) $this->init_columns( '', true ); } } } /** * Initializes SEO columns for adding a tag or category. * * @since 2.9.1 * @securitycheck 3.0.0 OK. * @access private */ public function _init_columns_wp_ajax_inline_save_tax() { /** * Securely check the referrer, instead of leaving holes everywhere. */ if ( $this->doing_ajax() && \check_ajax_referer( 'taxinlineeditnonce', '_inline_edit', false ) ) { $taxonomy = \sanitize_key( $_POST['taxonomy'] ); $tax = \get_taxonomy( $taxonomy ); if ( $tax && isset( $_POST['tax_ID'] ) ) { $tax_id = (int) $_POST['tax_ID']; if ( \current_user_can( 'edit_term', $tax_id ) ) $this->init_columns( '', true ); } } } /** * Initializes SEO bar columns. * * @since 2.1.9 * @since 2.9.1 Now supports inline edit AJAX. * @securitycheck 3.0.0 OK. NOTE: Sanity check is done in _init_columns_wp_ajax_inline_save_tax() * & _init_columns_wp_ajax_inline_save() * * @param \WP_Screen|string $screen \WP_Screen * @param bool $doing_ajax Whether we're doing an AJAX response. * @return void If filter is set to false. */ public function init_columns( $screen = '', $doing_ajax = false ) { /** * Applies filters 'the_seo_framework_show_seo_column' : bool * * @since ??? * * @param bool $show_seo_column */ $show_seo_column = (bool) \apply_filters( 'the_seo_framework_show_seo_column', true ); if ( false === $show_seo_column ) return; if ( $doing_ajax ) { $post_type = isset( $_POST['post_type'] ) ? \sanitize_key( $_POST['post_type'] ) : ''; $post_type = $post_type ?: ( isset( $_POST['tax_type'] ) ? \sanitize_key( $_POST['tax_type'] ) : '' ); } else { $post_type = isset( $screen->post_type ) ? $screen->post_type : ''; } if ( $this->post_type_supports_custom_seo( $post_type ) ) : if ( $doing_ajax ) { //* Nonce is done in $this->init_columns_ajax() $id = isset( $_POST['screen'] ) ? \sanitize_key( $_POST['screen'] ) : false; $taxonomy = isset( $_POST['taxonomy'] ) ? \sanitize_key( $_POST['taxonomy'] ) : false; if ( $id ) { //* Everything but inline-save-tax action. \add_filter( 'manage_' . $id . '_columns', array( $this, 'add_column' ), 10, 1 ); /** * Always load pages and posts. * Many CPT plugins rely on these. */ \add_action( 'manage_posts_custom_column', array( $this, 'seo_bar_ajax' ), 1, 3 ); \add_action( 'manage_pages_custom_column', array( $this, 'seo_bar_ajax' ), 1, 3 ); } elseif ( $taxonomy ) { //* Action: inline-save-tax does not POST screen. \add_filter( 'manage_edit-' . $taxonomy . '_columns', array( $this, 'add_column' ), 1, 1 ); } if ( $taxonomy ) \add_filter( 'manage_' . $taxonomy . '_custom_column', array( $this, 'get_taxonomy_seo_bar_ajax' ), 1, 3 ); } else { $id = isset( $screen->id ) ? $screen->id : ''; if ( '' !== $id && $this->is_wp_lists_edit() ) { \add_filter( 'manage_' . $id . '_columns', array( $this, 'add_column' ), 10, 1 ); $taxonomy = isset( $screen->taxonomy ) ? $screen->taxonomy : ''; if ( $taxonomy ) \add_filter( 'manage_' . $taxonomy . '_custom_column', array( $this, 'get_taxonomy_seo_bar' ), 1, 3 ); /** * Always load pages and posts. * Many CPT plugins rely on these. */ \add_action( 'manage_posts_custom_column', array( $this, 'seo_bar' ), 1, 3 ); \add_action( 'manage_pages_custom_column', array( $this, 'seo_bar' ), 1, 3 ); } } endif; } /** * Adds SEO column on edit(-tags).php * * Also determines where the column should be placed. Preferred before comments, then data, then tags. * If neither found, it will add the column to the end. * * @since 2.1.9 * * @param array $columns The existing columns * @return array $columns the column data */ public function add_column( $columns ) { $seocolumn = array( 'tsf-seo-bar-wrap' => 'SEO' ); $column_keys = array_keys( $columns ); //* Column keys to look for, in order of appearance. $order_keys = array( 'comments', 'posts', 'date', 'tags', ); /** * Applies filters 'the_seo_framework_seo_column_keys_order' : array * * @since 2.8.0 * * @param array $order_keys */ $order_keys = (array) \apply_filters( 'the_seo_framework_seo_column_keys_order', $order_keys ); foreach ( $order_keys as $key ) { //* Put value in $offset, if not false, break loop. if ( false !== ( $offset = array_search( $key, $column_keys, true ) ) ) break; } //* I tried but found nothing if ( false === $offset ) { //* Add SEO bar at the end of columns. $columns = array_merge( $columns, $seocolumn ); } else { //* Add seo bar between columns. //* Cache columns. $columns_before = $columns; $columns = array_merge( array_splice( $columns, 0, $offset ), $seocolumn, array_splice( $columns_before, $offset ) ); } return $columns; } /** * Echos the SEO Bar. * * @since 2.6.0 * @staticvar string $type * * @param string $column the current column : If it's a taxonomy, this is empty * @param int $post_id the post id : If it's a taxonomy, this is the column name * @param string $tax_id this is empty : If it's a taxonomy, this is the taxonomy id */ public function seo_bar( $column, $post_id, $tax_id = '' ) { echo $this->get_seo_bar( $column, $post_id, $tax_id ); } /** * Returns the SEO Bar for taxonomies. * * @since 3.0.4 * @staticvar string $type * * @param string $string The current column string. * @param string $column_name Name of the column. * @param string $term_id Term ID. */ public function get_taxonomy_seo_bar( $string, $column_name, $term_id ) { return $string . $this->get_seo_bar( '', $column_name, $term_id ); } /** * Returns the SEO Bar. * * @since 3.0.4 * @staticvar string $type * * @param string $column the current column : If it's a taxonomy, this is empty * @param int $post_id the post id : If it's a taxonomy, this is the column name * @param string $tax_id this is empty : If it's a taxonomy, this is the taxonomy id */ public function get_seo_bar( $column, $post_id, $tax_id = '' ) { static $type = null; if ( ! isset( $type ) ) { $type = \get_post_type( $post_id ); if ( false === $type || '' !== $tax_id ) { $screen = (object) \get_current_screen(); if ( isset( $screen->taxonomy ) ) $type = $screen->taxonomy; } } /** * Params are shifted. * @link https://core.trac.wordpress.org/ticket/33521 */ if ( '' !== $tax_id ) { $column = $post_id; $post_id = $tax_id; } if ( 'tsf-seo-bar-wrap' === $column ) return $this->post_status( $post_id, $type ); return ''; } /** * Echos the SEO column in edit screens on AJAX. * * @since 2.1.9 * * @param string $column the current column : If it's a taxonomy, this is empty * @param int $post_id the post id : If it's a taxonomy, this is the column name * @param string $tax_id this is empty : If it's a taxonomy, this is the taxonomy id */ public function seo_bar_ajax( $column, $post_id, $tax_id = '' ) { echo $this->get_seo_bar_ajax( $column, $post_id, $tax_id ); } /** * Returns the SEO Bar for taxonomies on AJAX. * * @since 3.0.4 * @staticvar string $type * * @param string $string The current column string. * @param string $column_name Name of the column. * @param string $term_id Term ID. */ public function get_taxonomy_seo_bar_ajax( $string, $column_name, $term_id ) { return $string . $this->get_seo_bar_ajax( '', $column_name, $term_id ); } /** * Returns the SEO column in edit screens on AJAX. * * @since 3.0.4 * * @param string $column the current column : If it's a taxonomy, this is empty * @param int $post_id the post id : If it's a taxonomy, this is the column name * @param string $tax_id this is empty : If it's a taxonomy, this is the taxonomy id */ public function get_seo_bar_ajax( $column, $post_id, $tax_id = '' ) { $is_term = false; /** * Params are shifted. * @link https://core.trac.wordpress.org/ticket/33521 */ if ( '' !== $tax_id ) { $is_term = true; $column = $post_id; $post_id = $tax_id; } if ( 'tsf-seo-bar-wrap' === $column ) { $context = \esc_html__( 'Refresh to see the SEO Bar status.', 'autodescription' ); $ajax_id = $column . $post_id; return $this->post_status_special( $context, '?', 'unknown', $is_term, $ajax_id ); } return ''; } /** * Wrap a single-line block for the SEO bar, showing special statuses. * * @since 2.6.0 * * @param string $context The hover/screenreader context. * @param string $symbol The single-character symbol. * @param string $class The SEO block color code. : 'bad', 'okay', 'good', 'unknown'. * @param int|null $ajax_id The unique Ajax ID to generate a small on-hover script for this ID. May be Arbitrary. * @param bool $echo Whether to echo the output. * @return string|void The special block with wrap. Void if $echo is true. */ protected function post_status_special( $context, $symbol = '?', $color = 'unknown', $is_term = '', $ajax_id = null, $echo = false ) { $classes = $this->get_the_seo_bar_classes(); $args = array(); $args['class'] = $classes[ $color ]; $args['width'] = $classes['100%']; $args['notice'] = $context; $args['indicator'] = $symbol; $block = $this->wrap_the_seo_bar_block( $args ); if ( empty( $is_term ) ) $is_term = $this->is_archive(); $bar = $this->get_the_seo_bar_wrap( $block, $is_term, $ajax_id ); if ( $echo ) { //* Already escaped. echo $bar; } else { return $bar; } } /** * Renders post status. Caches the output. * * @since 2.1.9 * @staticvar string $post_i18n The post type slug. * @staticvar bool $is_term If we're dealing with TT pages. * @since 2.8.0 Third parameter `$echo` has been put into effect. * * @param int $post_id The Post ID or taxonomy ID. * @param string $type Is fetched on edit.php, inpost, taxonomies, etc. * @param bool $echo Whether to echo the value. Does not eliminate return. * @return string|void $content The post SEO status. Void if $echo is true. */ public function post_status( $post_id = '', $type = 'inpost', $echo = false ) { $content = ''; //* Fetch Post ID if it hasn't been provided. if ( empty( $post_id ) ) $post_id = $this->get_the_real_ID(); if ( $post_id ) { //* Fetch Post Type. if ( 'inpost' === $type || empty( $type ) ) $type = \get_post_type( $post_id ); //* No need to re-evalute these. static $post_i18n = null; static $is_term = null; $term = false; /** * Static caching. * @since 2.3.8 */ if ( ! isset( $post_i18n ) && ! isset( $is_term ) ) { //* Setup i18n values for posts and pages. if ( 'post' === $type ) { $post_i18n = \__( 'Post', 'autodescription' ); $is_term = false; $term = false; } elseif ( 'page' === $type ) { $post_i18n = \__( 'Page', 'autodescription' ); $is_term = false; $term = false; } else { /** * Because of static caching, $is_term was never assigned. * @since 2.4.1 */ $is_term = true; } } if ( $is_term ) { //* We're on a term or taxonomy. Try fetching names. Default back to "Page". $term = $this->fetch_the_term( $post_id ); $post_i18n = $this->get_the_term_name( $term ); /** * Check if current post type is a page or taxonomy. * Only check if is_term is not yet changed to false. To save processing power. * * @since 2.3.1 */ if ( $this->is_post_type_page( $type ) ) $is_term = false; } $post_low = $this->maybe_lowercase_noun( $post_i18n ); $args = array( 'is_term' => $is_term, 'term' => $term, 'post_id' => $post_id, 'post_i18n' => $post_i18n, 'post_low' => $post_low, 'type' => $type, ); if ( $is_term ) { $bar = $this->the_seo_bar_term( $args ); } else { $bar = $this->the_seo_bar_page( $args ); } } else { $context = \esc_attr__( 'Failed to fetch post ID.', 'autodescription' ); $bar = $this->post_status_special( $context, '!', 'bad' ); } if ( $echo ) { //* Already escaped. echo $bar; } else { return $bar; } } /** * Returns a part of the SEO Bar based on parameters. * * @since 2.6.0 * @since 3.0.0 Now uses spans instead of a's * * @param array $args : { * string $indicator Required. The block text. * string $notice Required. The tooltip message. * string $width Required. The width class. * string $class Required. The item class. * } * @return string The SEO Bar block part. */ protected function wrap_the_seo_bar_block( $args ) { return vsprintf( '<span class="tsf-seo-bar-section-wrap %s">%s</span>', array( $args['width'], vsprintf( '<span class="tsf-seo-bar-item tsf-tooltip-item %1$s" aria-label="%2$s" data-desc="%2$s">%3$s</span>', array( $args['class'], $args['notice'], $args['indicator'], ) ), ) ); } /** * Wrap the SEO bar. * * If Ajax ID is set, a small jQuery script will also be output to reset the * DOM element for the status bar hover. * * @since 2.6.0 * @staticvar string $class * * @param string $content The SEO Bar content. * @param bool $is_term Whether the bar is for a term. * @param int|null $ajax_id The unique Ajax ID to generate a small on-hover script for. * @return string The SEO Bar wrapped. */ protected function get_the_seo_bar_wrap( $content, $is_term, $ajax_id = null ) { static $class = null; if ( is_null( $class ) ) { $classes = $this->get_the_seo_bar_classes(); $width = $is_term ? ' ' . $classes['100%'] : ''; $pill = $this->pill_the_seo_bar() ? ' ' . $classes['pill'] : ''; $class = \esc_attr( 'tsf-seo-bar clearfix' . $width . $pill ); } if ( isset( $ajax_id ) ) { //= Ajax handler. //* Resets tooltips. $script = '<script>tsf._triggerTooltipReset();</script>'; return sprintf( '<span class="%s" id="%s"><span class="tsf-seo-bar-inner-wrap tsf-tooltip-wrap">%s</span></span>', $class, \esc_attr( $ajax_id ), $content ) . $script; } return sprintf( '<span class="%s"><span class="tsf-seo-bar-inner-wrap tsf-tooltip-wrap">%s</span></span>', $class, $content ); } /** * Output the SEO bar for Terms and Taxonomies. * * @since 2.6.0 * * @param array $args { * 'is_term' => bool $is_term, * 'term' => object $term, * 'post_i18n' => string $post_i18n, * 'post_low' => string $post_low, * 'type' => string $type, * } * @return string $content The SEO bar. */ protected function the_seo_bar_term( $args ) { $i18n = $args['post_i18n']; $is_term = true; $data = $this->get_term_meta( $args['term']->term_id ); $noindex = isset( $data['noindex'] ) && $data['noindex']; $redirect = false; // We don't apply redirect on taxonomies (yet) //* Blocked SEO, return simple bar. if ( $redirect || $noindex ) return $this->the_seo_bar_blocked( array( 'is_term' => $is_term, 'redirect' => $redirect, 'noindex' => $noindex, 'post_i18n' => $i18n ) ); $title_notice = $this->the_seo_bar_title_notice( $args ); $description_notice = $this->the_seo_bar_description_notice( $args ); $index_notice = $this->the_seo_bar_index_notice( $args ); $follow_notice = $this->the_seo_bar_follow_notice( $args ); $archive_notice = $this->the_seo_bar_archive_notice( $args ); $content = $title_notice . $description_notice . $index_notice . $follow_notice . $archive_notice; return $this->get_the_seo_bar_wrap( $content, $is_term ); } /** * Output the SEO bar for Terms and Taxonomies. * * @since 2.6.0 * * @param array $args { * 'is_term' => $is_term, * 'term' => $term, * 'post_id' => $post_id, * 'post_i18n' => $post_i18n, * 'post_low' => $post_low, * 'type' => $type, * } * @return string $content The SEO bar. */ protected function the_seo_bar_page( $args ) { $post_id = $args['post_id']; $post = $args['post_i18n']; $is_term = false; $is_front_page = $this->is_static_frontpage( $post_id ); $redirect = (bool) $this->get_custom_field( 'redirect', $post_id ); $noindex = (bool) $this->get_custom_field( '_genesis_noindex', $post_id ); if ( $is_front_page ) $noindex = $this->is_option_checked( 'homepage_noindex' ) ?: $noindex; if ( $redirect || $noindex ) return $this->the_seo_bar_blocked( array( 'is_term' => $is_term, 'redirect' => $redirect, 'noindex' => $noindex, 'post_i18n' => $post ) ); $title_notice = $this->the_seo_bar_title_notice( $args ); $description_notice = $this->the_seo_bar_description_notice( $args ); $index_notice = $this->the_seo_bar_index_notice( $args ); $follow_notice = $this->the_seo_bar_follow_notice( $args ); $archive_notice = $this->the_seo_bar_archive_notice( $args ); $redirect_notice = $this->the_seo_bar_redirect_notice( $args ); $content = $title_notice . $description_notice . $index_notice . $follow_notice . $archive_notice . $redirect_notice; return $this->get_the_seo_bar_wrap( $content, $is_term ); } /** * Fetch the post or term data for The SEO Bar, structured and cached. * * @since 2.6.0 * @staticvar array $data * * @param array $args The term/post args. * @return array $data { * 'title' => $title, * 'title_is_from_custom_field' => $title_is_from_custom_field, * 'description' => $description, * 'description_is_from_custom_field' => $description_is_from_custom_field, * 'nofollow' => $nofollow, * 'noarchive' => $noarchive * } */ protected function the_seo_bar_data( $args ) { $post_id = $args['post_id']; static $data = array(); if ( isset( $data[ $post_id ] ) ) return $data[ $post_id ]; if ( $args['is_term'] ) { return $data[ $post_id ] = $this->the_seo_bar_term_data( $args ); } else { return $data[ $post_id ] = $this->the_seo_bar_post_data( $args ); } } /** * Fetch the term data for The SEO Bar. * * @since 2.6.0 * @since 2.9.0 Now also returns noindex value. * @since 3.0.6 Now considers custom field filters for the description. * @staticvar array $data * * @param array $args The term args. * @return array $data { * $title, * $title_is_from_custom_field, * $description, * $description_is_from_custom_field, * $noindex, * $nofollow, * $noarchive * } */ protected function the_seo_bar_term_data( $args ) { $term = $args['term']; $term_id = $args['post_id']; $taxonomy = $args['type']; $data = $this->get_term_meta( $term_id ); $title_custom_field = isset( $data['doctitle'] ) ? $data['doctitle'] : ''; $description_custom_field = $this->get_description_from_custom_field( $term_id ); $noindex = isset( $data['noindex'] ) ? $data['noindex'] : ''; $nofollow = isset( $data['nofollow'] ) ? $data['nofollow'] : ''; $noarchive = isset( $data['noarchive'] ) ? $data['noarchive'] : ''; $title_is_from_custom_field = (bool) $title_custom_field; if ( $title_is_from_custom_field ) { $title = $this->title( '', '', '', array( 'term_id' => $term_id, 'taxonomy' => $taxonomy, 'get_custom_field' => true ) ); } else { $title = $this->title( '', '', '', array( 'term_id' => $term_id, 'taxonomy' => $taxonomy, 'get_custom_field' => false ) ); } $description_is_from_custom_field = (bool) $description_custom_field; //= Call sanitized version. if ( $description_is_from_custom_field ) { $description = $this->get_description_from_custom_field( $term_id ); } else { $description = $this->get_generated_description( $term_id ); } $noindex = (bool) $noindex; $nofollow = (bool) $nofollow; $noarchive = (bool) $noarchive; return compact( 'title', 'title_is_from_custom_field', 'description', 'description_is_from_custom_field', 'noindex', 'nofollow', 'noarchive' ); } /** * Fetch the post data for The SEO Bar. * * @since 2.6.0 * @since 2.9.0 Now also returns noindex value. * @since 3.0.6 Now considers custom field filters for the description. * @staticvar array $data * * @param array $args The post args. * @return array $data { * $title, * $title_is_from_custom_field, * $description, * $description_is_from_custom_field, * $noindex, * $nofollow, * $noarchive * } */ protected function the_seo_bar_post_data( $args ) { $post_id = $args['post_id']; $page_on_front = $this->is_static_frontpage( $post_id ); $title_custom_field = $this->get_custom_field( '_genesis_title', $post_id ); $description_custom_field = $this->get_description_from_custom_field( $post_id ); $noindex = $this->get_custom_field( '_genesis_noindex', $post_id ); $nofollow = $this->get_custom_field( '_genesis_nofollow', $post_id ); $noarchive = $this->get_custom_field( '_genesis_noarchive', $post_id ); if ( $page_on_front ) { $title_custom_field = $this->get_option( 'homepage_title' ) ?: $title_custom_field; // $description_custom_field = $description_custom_field; // We already got this. $noindex = $this->get_option( 'homepage_noindex' ) ?: $nofollow; $nofollow = $this->get_option( 'homepage_nofollow' ) ?: $nofollow; $noarchive = $this->get_option( 'homepage_noarchive' ) ?: $noarchive; } $title_is_from_custom_field = (bool) $title_custom_field; if ( $title_is_from_custom_field ) { $title = $this->title( '', '', '', array( 'term_id' => $post_id, 'page_on_front' => $page_on_front, 'get_custom_field' => true ) ); } else { $title = $this->title( '', '', '', array( 'term_id' => $post_id, 'page_on_front' => $page_on_front, 'get_custom_field' => false ) ); } $description_is_from_custom_field = (bool) $description_custom_field; //= Call sanitized version. if ( $description_is_from_custom_field ) { $description = $this->get_description_from_custom_field( $post_id ); } else { $description = $this->get_generated_description( $post_id ); } $noindex = (bool) $noindex; $nofollow = (bool) $nofollow; $noarchive = (bool) $noarchive; return compact( 'title', 'title_is_from_custom_field', 'description', 'description_is_from_custom_field', 'noindex', 'nofollow', 'noarchive' ); } /** * Render the SEO bar title block and notice. * * @since 2.6.0 * * @param array $args * @return string The SEO Bar Title Block */ protected function the_seo_bar_title_notice( $args ) { //* Fetch data $data = $this->the_seo_bar_data( $args ); $title = $data['title']; $title_is_from_custom_field = $data['title_is_from_custom_field']; //* Fetch CSS classes. $classes = $this->get_the_seo_bar_classes(); $ad25 = $classes['25%']; //* Fetch i18n and put in vars $i18n = $this->get_the_seo_bar_i18n(); $title_short = $i18n['title_short']; $generated = $i18n['generated_short']; $and_i18n = $i18n['and']; $but_i18n = $i18n['but']; //* Initialize notice. $notice = $i18n['title']; $class = $classes['good']; //* Generated notice. $generated_notice = '<br>' . $i18n['generated']; $gen_t = $title_is_from_custom_field ? '' : $generated; $gen_t_notice = $title_is_from_custom_field ? '' : $generated_notice; //* Title length. Convert … to a single character as well. $tit_len = mb_strlen( html_entity_decode( $title ) ); //* Length notice. $title_length_warning = $this->get_the_seo_bar_title_length_warning( $tit_len, $class ); $notice .= $title_length_warning ? ' ' . $title_length_warning['notice'] : ''; $class = $title_length_warning['class']; $title_duplicated = false; //* Check if title is duplicated from blogname. if ( $this->add_title_additions() ) { //* We are using blognames in titles. $blogname = $this->get_blogname(); $first = stripos( $title, $blogname ); $last = strripos( $title, $blogname ); if ( $first !== $last ) $title_duplicated = true; } if ( $title_duplicated ) { //* If the title is good, we should use And. Otherwise 'But'. $but_and = $title_length_warning['but'] ? $but_i18n : $and_i18n; /* translators: %s = But or And */ $notice .= '<br>' . sprintf( \esc_attr__( '%s the Title contains the Blogname multiple times.', 'autodescription' ), $but_and ); $class = $classes['bad']; } //* Put everything together. $notice = $notice . $gen_t_notice; $title_short = $title_short . $gen_t; $tit_wrap_args = array( 'indicator' => $title_short, 'notice' => $notice, 'width' => $ad25, 'class' => $class, ); $title_notice = $this->wrap_the_seo_bar_block( $tit_wrap_args ); return $title_notice; } /** * Render the SEO bar description block and notice. * * @since 2.6.0 * * @param array $args * @return string The SEO Bar Description Block */ protected function the_seo_bar_description_notice( $args ) { //* Fetch data $data = $this->the_seo_bar_data( $args ); $description = $data['description']; $description_is_from_custom_field = $data['description_is_from_custom_field']; //* Fetch i18n and put in vars $i18n = $this->get_the_seo_bar_i18n(); $description_short = $i18n['description_short']; $generated_short = $i18n['generated_short']; //* Description length. Convert … to a single character as well. $desc_len = mb_strlen( html_entity_decode( $description ) ); //* Fetch CSS classes. $classes = $this->get_the_seo_bar_classes(); $ad25 = $classes['25%']; //* Initialize notice. $notice = $i18n['description']; $class = $classes['good']; //* Length notice. $desc_length_warning = $this->get_the_seo_bar_description_length_warning( $desc_len, $class ); $notice .= $desc_length_warning['notice'] ? $desc_length_warning['notice'] . '<br>' : ''; $class = $desc_length_warning['class']; //* Duplicated Words notice. $desc_too_many = $this->get_the_seo_bar_description_words_warning( $description, $class ); $notice .= $desc_too_many['notice'] ? $desc_too_many['notice'] . '<br>' : ''; $class = $desc_too_many['class']; //* Generation notice. $generated_notice = $i18n['generated'] . ' '; $gen_d = $description_is_from_custom_field ? '' : $generated_short; $gen_d_notice = $description_is_from_custom_field ? '' : $generated_notice; //* Put everything together. $notice = $notice . $gen_d_notice; $description_short = $description_short . $gen_d; $desc_wrap_args = array( 'indicator' => $description_short, 'notice' => $notice, 'width' => $ad25, 'class' => $class, ); $description_notice = $this->wrap_the_seo_bar_block( $desc_wrap_args ); return $description_notice; } /** * Description Length notices. * * @since 2.6.0 * @since 3.0.4 : 1. Threshold "too long" has been increased from 155 to 300. * 2. Threshold "far too long" has been increased to 330 from 175. * * @param int $desc_len The Title length * @param string $class The current color class. * @return array { * notice => The notice, * class => The class, * } */ protected function get_the_seo_bar_description_length_warning( $desc_len, $class ) { $classes = $this->get_the_seo_bar_classes(); $bad = $classes['bad']; $okay = $classes['okay']; $good = $classes['good']; $i18n = $this->get_the_seo_bar_i18n(); if ( $desc_len < 100 ) { $notice = $i18n['length_far_too_short']; $class = $bad; } elseif ( $desc_len < 137 ) { $notice = $i18n['length_too_short']; // Don't make it okay if it's already bad. $class = $bad === $class ? $class : $okay; } elseif ( $desc_len > 300 && $desc_len < 330 ) { $notice = $i18n['length_too_long']; // Don't make it okay if it's already bad. $class = $bad === $class ? $class : $okay; } elseif ( $desc_len >= 330 ) { $notice = $i18n['length_far_too_long']; $class = $bad; } else { $notice = $i18n['length_good']; // Don't make it good if it's already bad or okay. $class = $good !== $class ? $class : $good; } return array( 'notice' => $notice, 'class' => $class, ); } /** * Calculates the word count and returns a warning with the words used. * Only when count is over 3. * * @since 2.6.0 * * @param string $description The Description with maybe words too many. * @param string $class The current color class. * @return string The warning notice. */ protected function get_the_seo_bar_description_words_warning( $description, $class ) { $notice = ''; $words_too_many = $this->get_word_count( $description ); if ( ! empty( $words_too_many ) ) { $classes = $this->get_the_seo_bar_classes(); $bad = $classes['bad']; $okay = $classes['okay']; $words_count = count( $words_too_many ); //* Don't make it okay if it's already bad. $class = $bad !== $class && $words_count <= 1 ? $okay : $bad; $i = 1; $count = count( $words_too_many ); foreach ( $words_too_many as $desc_array ) { foreach ( $desc_array as $desc_value => $desc_count ) { $notice .= ' '; /** * Don't ucfirst abbreviations. * @since 2.4.1 */ $desc_value = ctype_upper( $desc_value ) ? $desc_value : ucfirst( $desc_value ); /* translators: 1: Word, 2: Occurrences */ $notice .= sprintf( \esc_attr__( '%1$s is used %2$d times.', 'autodescription' ), '<span>' . $desc_value . '</span>', $desc_count ); //* Don't add break at last occurrence. $notice .= $i === $count ? '' : '<br>'; $i++; } } } return array( 'notice' => $notice, 'class' => $class, ); } /** * Render the SEO bar index block and notice. * * @since 2.6.0 * * @param array $args * @return string The SEO Bar Index Block */ protected function the_seo_bar_index_notice( $args ) { $term = $args['term']; $is_term = $args['is_term']; $post_i18n = $args['post_i18n']; $data = $this->the_seo_bar_data( $args ); $classes = $this->get_the_seo_bar_classes(); $unknown = $classes['unknown']; $bad = $classes['bad']; $okay = $classes['okay']; $good = $classes['good']; $ad_125 = $classes['12.5%']; $i18n = $this->get_the_seo_bar_i18n(); $index_short = $i18n['index_short']; $but_i18n = $i18n['but']; $and_i18n = $i18n['and']; $ind_notice = $i18n['index']; /* Translators: %s = Post / Page / Category, etc. */ $ind_notice .= ' ' . sprintf( \esc_attr__( '%s is being indexed.', 'autodescription' ), $post_i18n ); $ind_class = $good; /** * Get noindex site option * * @since 2.2.2 */ if ( $this->is_option_checked( 'site_noindex' ) ) { $ind_notice .= '<br>' . \esc_attr__( "But you've discouraged indexing for the whole site.", 'autodescription' ); $ind_class = $unknown; $ind_but = true; } //* Adds notice for global archive indexing options. if ( $is_term ) { /** * @staticvar bool $checked * @staticvar string $label */ static $checked = null; if ( ! isset( $checked ) ) { //* Fetch whether it's checked. $checked = $this->the_seo_bar_archive_robots_options( 'noindex' ); } if ( $checked ) { $but_and = isset( $ind_but ) ? $and_i18n : $but_i18n; $label = $this->get_the_term_name( $term, false ); /* translators: 1: But or And, 2: Current taxonomy term plural label */ $ind_notice .= '<br>' . sprintf( \esc_attr__( '%1$s indexing for %2$s have been discouraged.', 'autodescription' ), $but_and, $label ); $ind_class = $unknown; $ind_but = true; } } /** * Adds post protection notice * @since 2.8.0 */ if ( ! $is_term && $this->is_protected( $args['post_id'] ) ) { $but_and = isset( $ind_but ) ? $and_i18n : $but_i18n; /* translators: 1 = But or And, 1 = Post/Page */ $ind_notice .= '<br>' . sprintf( \esc_attr__( '%1$s the %2$s is protected from public visibility. This means indexing is discouraged.', 'autodescription' ), $but_and, $post_i18n ); $ind_class = $unknown; $ind_but = true; } //* Adds notice for WordPress blog public indexing. if ( false === $this->is_blog_public() ) { $but_and = isset( $ind_but ) ? $and_i18n : $but_i18n; /* translators: %s = But or And */ $ind_notice .= '<br>' . sprintf( \esc_attr__( "%s the blog isn't set to public. This means WordPress discourages indexing.", 'autodescription' ), $but_and ); $ind_class = $bad; $ind_but = true; } /** * Check if archive is empty, and therefore has set noindex for those. * * @since 2.2.8 */ if ( $is_term && isset( $term->count ) && 0 === $term->count ) { $but_and = isset( $ind_but ) ? $and_i18n : $but_i18n; /* translators: %s = But or And */ $ind_notice .= '<br>' . sprintf( \esc_attr__( '%s there are no posts in this term; therefore, indexing has been discouraged.', 'autodescription' ), $but_and ); //* Don't make it unknown if it's not good. $ind_class = $ind_class !== $good ? $ind_class : $unknown; } $ind_wrap_args = array( 'indicator' => $index_short, 'notice' => $ind_notice, 'width' => $ad_125, 'class' => $ind_class, ); $index_notice = $this->wrap_the_seo_bar_block( $ind_wrap_args ); return $index_notice; } /** * Checks whether global index/archive/follow options are checked for archives. * * @since 2.6.0 * @staticvar bool $cache * * @param string $type : 'noindex', 'nofollow', 'noarchive' * @return bool */ protected function the_seo_bar_archive_robots_options( $type ) { $taxonomy = false; if ( $this->is_category() ) $taxonomy = 'category'; if ( $this->is_tag() ) $taxonomy = 'tag'; if ( $taxonomy ) { static $cache = array(); if ( isset( $cache[ $type ] ) ) return $cache[ $type ]; if ( $this->is_option_checked( $taxonomy . '_' . $type ) ) return $cache[ $type ] = true; return $cache[ $type ] = false; } return false; } /** * Render the SEO bar follow block and notice. * * @since 2.6.0 * * @param array $args * @return string The SEO Bar Follow Block */ protected function the_seo_bar_follow_notice( $args ) { $followed = true; $term = $args['term']; $is_term = $args['is_term']; $post_i18n = $args['post_i18n']; $data = $this->the_seo_bar_data( $args ); $nofollow = $data['nofollow']; $classes = $this->get_the_seo_bar_classes(); $unknown = $classes['unknown']; $bad = $classes['bad']; $okay = $classes['okay']; $good = $classes['good']; $ad_125 = $classes['12.5%']; $i18n = $this->get_the_seo_bar_i18n(); $follow_i18n = $i18n['follow']; $but_i18n = $i18n['but']; $and_i18n = $i18n['and']; $follow_short = $i18n['follow_short']; if ( $nofollow ) { $fol_notice = $follow_i18n . ' ' . sprintf( \esc_attr__( "%s links aren't being followed.", 'autodescription' ), $post_i18n ); $fol_class = $unknown; $fol_but = true; $followed = false; } else { $fol_notice = $follow_i18n . ' ' . sprintf( \esc_attr__( '%s links are being followed.', 'autodescription' ), $post_i18n ); $fol_class = $good; } /** * Get nofolow site option * * @since 2.2.2 */ if ( $this->is_option_checked( 'site_nofollow' ) ) { $but_and = isset( $fol_but ) ? $and_i18n : $but_i18n; /* translators: %s = But or And */ $fol_notice .= '<br>' . sprintf( \esc_attr__( "%s you've discouraged the following of links for the whole site.", 'autodescription' ), $but_and ); $fol_class = $unknown; $fol_but = true; $followed = false; } //* Adds notice for global archive indexing options. if ( $is_term ) { /** * @staticvar bool $checked * @staticvar string $label */ static $checked = null; if ( ! isset( $checked ) ) { //* Fetch whether it's checked. $checked = $this->the_seo_bar_archive_robots_options( 'nofollow' ); } if ( $checked ) { $but_and = isset( $fol_but ) ? $and_i18n : $but_i18n; $label = $this->get_the_term_name( $term, false ); /* translators: 1: But or And, 2: Current taxonomy term plural label */ $fol_notice .= '<br>' . sprintf( \esc_attr__( '%1$s following for %2$s have been discouraged.', 'autodescription' ), $but_and, $label ); $fol_class = $unknown; $followed = false; } } if ( false === $this->is_blog_public() ) { //* Make it "and" if following has not been discouraged otherwise. $but_and = $followed || ! isset( $fol_but ) ? $and_i18n : $but_i18n; /* translators: %s = But or And */ $fol_notice .= '<br>' . sprintf( \esc_attr__( "%s the blog isn't set to public. This means WordPress allows the links to be followed regardless.", 'autodescription' ), $but_and ); $fol_class = $followed ? $fol_class : $okay; $fol_but = true; $followed = false; } $fol_wrap_args = array( 'indicator' => $follow_short, 'notice' => $fol_notice, 'width' => $ad_125, 'class' => $fol_class, ); $follow_notice = $this->wrap_the_seo_bar_block( $fol_wrap_args ); return $follow_notice; } /** * Render the SEO bar archive block and notice. * * @since 2.6.0 * * @param array $args * @return string The SEO Bar Follow Block */ protected function the_seo_bar_archive_notice( $args ) { $archived = true; $term = $args['term']; $is_term = $args['is_term']; $post_low = $args['post_low']; $data = $this->the_seo_bar_data( $args ); $noarchive = $data['noarchive']; $classes = $this->get_the_seo_bar_classes(); $unknown = $classes['unknown']; $bad = $classes['bad']; $okay = $classes['okay']; $good = $classes['good']; $ad_125 = $classes['12.5%']; $i18n = $this->get_the_seo_bar_i18n(); $archive_i18n = $i18n['archive']; $but_i18n = $i18n['but']; $and_i18n = $i18n['and']; $archive_short = $i18n['archive_short']; if ( $noarchive ) { $arc_notice = $archive_i18n . ' ' . sprintf( \esc_attr__( "Search Engines aren't allowed to archive this %s.", 'autodescription' ), $post_low ); $arc_class = $unknown; $archived = false; } else { $arc_notice = $archive_i18n . ' ' . sprintf( \esc_attr__( 'Search Engines are allowed to archive this %s.', 'autodescription' ), $post_low ); $arc_class = $good; $arc_but = true; } /** * Get noarchive site option * * @since 2.2.2 */ if ( $this->is_option_checked( 'site_noarchive' ) ) { $but_and = isset( $arc_but ) ? $and_i18n : $but_i18n; $arc_notice .= '<br>' . sprintf( \esc_attr__( "%s you've discouraged archiving for the whole site.", 'autodescription' ), $but_and ); $arc_class = $unknown; $arc_but = true; $archived = false; } //* Adds notice for global archive indexing options. if ( $is_term ) { /** * @staticvar bool $checked * @staticvar string $label */ static $checked = null; if ( ! isset( $checked ) ) { //* Fetch whether it's checked. $checked = $this->the_seo_bar_archive_robots_options( 'noarchive' ); } if ( $checked ) { $but_and = isset( $arc_but ) ? $and_i18n : $but_i18n; $label = $this->get_the_term_name( $term, false ); /* translators: 1: But or And, 2: Current taxonomy term plural label */ $arc_notice .= '<br>' . sprintf( \esc_attr__( '%1$s archiving for %2$s have been discouraged.', 'autodescription' ), $but_and, $label ); $arc_class = $unknown; $arc_but = true; $archived = false; } } if ( false === $this->is_blog_public() ) { //* Make it "and" if archiving has not been discouraged otherwise. $but_and = $archived || ! isset( $arc_but ) ? $and_i18n : $but_i18n; /* translators: %s = But or And */ $arc_notice .= '<br>' . sprintf( \esc_attr__( "%s the blog isn't set to public. This means WordPress allows the blog to be archived regardless.", 'autodescription' ), $but_and ); $arc_but = true; $arc_class = $archived ? $arc_class : $okay; $archived = true; } $arc_wrap_args = array( 'indicator' => $archive_short, 'notice' => $arc_notice, 'width' => $ad_125, 'class' => $arc_class, ); $archive_notice = $this->wrap_the_seo_bar_block( $arc_wrap_args ); return $archive_notice; } /** * Render the SEO bar redirect block and notice. * * @since 2.6.0 * * @param array $args * @return string The SEO Bar Redirect Block */ protected function the_seo_bar_redirect_notice( $args ) { $is_term = $args['is_term']; if ( $is_term ) { //* No redirection on taxonomies (yet). $redirect_notice = ''; } else { //* Pretty much outputs that it's not being redirected. $post = $args['post_i18n']; $classes = $this->get_the_seo_bar_classes(); $ad_125 = $classes['12.5%']; $i18n = $this->get_the_seo_bar_i18n(); $redirect_i18n = $i18n['redirect']; $redirect_short = $i18n['redirect_short']; $red_notice = $redirect_i18n . ' ' . sprintf( \esc_attr__( "%s isn't being redirected.", 'autodescription' ), $post ); $red_class = $classes['good']; $red_wrap_args = array( 'indicator' => $redirect_short, 'notice' => $red_notice, 'width' => $ad_125, 'class' => $red_class, ); $redirect_notice = $this->wrap_the_seo_bar_block( $red_wrap_args ); } return $redirect_notice; } /** * Render the SEO bar when the page/term is blocked. * * @since 2.6.0 * * @param array $args { * $is_term => bool, * $redirect => bool, * $noindex => bool, * $post_i18n => string * } * @return string The SEO Bar */ protected function the_seo_bar_blocked( $args ) { $classes = $this->get_the_seo_bar_classes(); $i18n = $this->get_the_seo_bar_i18n(); $is_term = $args['is_term']; $redirect = $args['redirect']; $noindex = $args['noindex']; $post = $args['post_i18n']; if ( $redirect && $noindex ) { //* Redirect and noindex found, why bother showing SEO info? $red_notice = $i18n['redirect'] . ' ' . sprintf( \esc_attr__( '%s is being redirected. This means no SEO values have to be set.', 'autodescription' ), $post ); $red_class = $classes['unknown']; $noi_notice = $i18n['index'] . ' ' . sprintf( \esc_attr__( '%s is not being indexed. This means no SEO values have to be set.', 'autodescription' ), $post ); $noi_class = $classes['unknown']; $red_wrap_args = array( 'indicator' => $i18n['redirect_short'], 'notice' => $red_notice, 'width' => $classes['50%'], 'class' => $red_class, ); $noi_wrap_args = array( 'indicator' => $i18n['index_short'], 'notice' => $noi_notice, 'width' => $classes['50%'], 'class' => $noi_class, ); $redirect_notice = $this->wrap_the_seo_bar_block( $red_wrap_args ); $noindex_notice = $this->wrap_the_seo_bar_block( $noi_wrap_args ); $content = $redirect_notice . $noindex_notice; return $this->get_the_seo_bar_wrap( $content, $is_term ); } elseif ( $redirect && false === $noindex ) { //* Redirect found, why bother showing SEO info? $red_notice = $i18n['redirect'] . ' ' . sprintf( \esc_attr__( '%s is being redirected. This means no SEO values have to be set.', 'autodescription' ), $post ); $red_class = $classes['unknown']; $red_wrap_args = array( 'indicator' => $i18n['redirect_short'], 'notice' => $red_notice, 'width' => $classes['100%'], 'class' => $red_class, ); $redirect_notice = $this->wrap_the_seo_bar_block( $red_wrap_args ); return $this->get_the_seo_bar_wrap( $redirect_notice, $is_term ); } elseif ( $noindex && false === $redirect ) { //* Noindex found, why bother showing SEO info? $noi_notice = $i18n['index'] . ' ' . sprintf( \esc_attr__( '%s is not being indexed. This means no SEO values have to be set.', 'autodescription' ), $post ); $noi_class = $classes['unknown']; $noi_wrap_args = array( 'indicator' => $i18n['index_short'], 'notice' => $noi_notice, 'width' => $classes['100%'], 'class' => $noi_class, ); $noindex_notice = $this->wrap_the_seo_bar_block( $noi_wrap_args ); return $this->get_the_seo_bar_wrap( $noindex_notice, $is_term ); } return ''; } /** * Title Length notices. * * @since 2.6.0 * * @param int $tit_len The Title length * @param string $class The Current Title notification class. * @return array { * string $notice => The notice, * string $class => The class, * bool $but => Whether we should use but or and, * } */ protected function get_the_seo_bar_title_length_warning( $tit_len, $class ) { $classes = $this->get_the_seo_bar_classes(); $bad = $classes['bad']; $okay = $classes['okay']; $good = $classes['good']; $but = false; $i18n = $this->get_the_seo_bar_i18n(); if ( $tit_len < 25 ) { $notice = $i18n['length_far_too_short']; $class = $bad; } elseif ( $tit_len < 42 ) { $notice = $i18n['length_too_short']; $class = $okay; } elseif ( $tit_len > 55 && $tit_len < 75 ) { $notice = $i18n['length_too_long']; $class = $okay; } elseif ( $tit_len >= 75 ) { $notice = $i18n['length_far_too_long']; $class = $bad; } else { $notice = $i18n['length_good']; $class = $good; $but = true; } return array( 'notice' => $notice, 'class' => $class, 'but' => $but, ); } /** * Returns an array of the classes used for CSS within The SEO Bar. * * @since 2.6.0 * * @return array The class names. */ public function get_the_seo_bar_classes() { return array( 'bad' => 'tsf-seo-bar-bad', 'okay' => 'tsf-seo-bar-okay', 'good' => 'tsf-seo-bar-good', 'unknown' => 'tsf-seo-bar-unknown', 'pill' => 'pill', '100%' => 'tsf-100', '60%' => 'tsf-60', '50%' => 'tsf-50', '40%' => 'tsf-40', '33%' => 'tsf-33', '25%' => 'tsf-25', '25%' => 'tsf-25', '20%' => 'tsf-20', '16%' => 'tsf-16', '12.5%' => 'tsf-12-5', '11%' => 'tsf-11', '10%' => 'tsf-10', ); } /** * Returns an array of the i18n notices for The SEO Bar. * * @staticvar array $i18n * @since 2.6.0 * * @return array The i18n sentences. */ public function get_the_seo_bar_i18n() { static $i18n = null; if ( isset( $i18n ) ) return $i18n; return $i18n = array( 'title' => \esc_attr__( 'Title:', 'autodescription' ), 'description' => \esc_attr__( 'Description:', 'autodescription' ), 'index' => \esc_attr__( 'Index:', 'autodescription' ), 'follow' => \esc_attr__( 'Follow:', 'autodescription' ), 'archive' => \esc_attr__( 'Archive:', 'autodescription' ), 'redirect' => \esc_attr__( 'Redirect:', 'autodescription' ), 'generated' => \esc_attr__( 'Generated: Automatically generated.', 'autodescription' ), 'generated_short' => \esc_html_x( 'G', 'Generated', 'autodescription' ), 'title_short' => \esc_html_x( 'T', 'Title', 'autodescription' ), 'description_short' => \esc_html_x( 'D', 'Description', 'autodescription' ), 'index_short' => \esc_html_x( 'I', 'no-Index', 'autodescription' ), 'follow_short' => \esc_html_x( 'F', 'no-Follow', 'autodescription' ), 'archive_short' => \esc_html_x( 'A', 'no-Archive', 'autodescription' ), 'redirect_short' => \esc_html_x( 'R', 'Redirect', 'autodescription' ), 'but' => \esc_attr_x( 'But', 'But there are...', 'autodescription' ), 'and' => \esc_attr_x( 'And', 'And there are...', 'autodescription' ), 'length_far_too_short' => ' ' . \esc_attr__( 'Length is far too short.', 'autodescription' ), 'length_too_short' => ' ' . \esc_attr__( 'Length is too short.', 'autodescription' ), 'length_too_long' => ' ' . \esc_attr__( 'Length is too long.', 'autodescription' ), 'length_far_too_long' => ' ' . \esc_attr__( 'Length is far too long.', 'autodescription' ), 'length_good' => ' ' . \esc_attr__( 'Length is good.', 'autodescription' ), ); } /** * Whether to square or pill the seo bar. * * Applies filters 'the_seo_framework_seo_bar_pill' : boolean * * @staticvar bool $cache * @since 2.6.0 * * @return bool */ protected function pill_the_seo_bar() { static $cache = null; if ( isset( $cache ) ) return $cache; return $cache = (bool) \apply_filters( 'the_seo_framework_seo_bar_pill', false ); } }