settings = $settings; } /** * Tokens available in templates, for help text. * * @return array token => description */ public static function tokens() { return array( '%title%' => __( 'Post or page title', 'orbitstem-seo' ), '%excerpt%' => __( 'Excerpt, or the start of the content', 'orbitstem-seo' ), '%sitename%' => __( 'Site title', 'orbitstem-seo' ), '%tagline%' => __( 'Site tagline', 'orbitstem-seo' ), '%sep%' => __( 'Separator', 'orbitstem-seo' ), '%term%' => __( 'Term name', 'orbitstem-seo' ), '%term_description%' => __( 'Term description', 'orbitstem-seo' ), '%type%' => __( 'Post type name (plural)', 'orbitstem-seo' ), '%author%' => __( 'Author display name', 'orbitstem-seo' ), '%author_description%' => __( 'Author biographical info', 'orbitstem-seo' ), '%date%' => __( 'Archive date', 'orbitstem-seo' ), '%search%' => __( 'Search phrase', 'orbitstem-seo' ), '%page%' => __( '"Page 2" on paginated views, empty on page 1', 'orbitstem-seo' ), '%not_found%' => __( '"Page not found"', 'orbitstem-seo' ), ); } /** * Renders a template. * * @param string $template Template text. * @param array $vars Values keyed by token name without percent signs. * @return string Plain text (not escaped). */ public function render( $template, array $vars ) { $sep = $this->settings->separator(); $vars = array_merge( array( 'sitename' => self::plain( get_bloginfo( 'name' ) ), 'tagline' => self::plain( get_bloginfo( 'description' ) ), ), $vars ); $out = preg_replace_callback( '/%([a-z_]+)%/', function ( $m ) use ( $vars ) { if ( 'sep' === $m[1] ) { return "\x1F"; // Placeholder so a literal separator character in a value is never collapsed. } return isset( $vars[ $m[1] ] ) ? (string) $vars[ $m[1] ] : ''; }, (string) $template ); // Collapse runs of separators and drop separators at either end. $out = preg_replace( '/\x1F(?:\s*\x1F)+/', "\x1F", $out ); $out = preg_replace( '/^[\s\x1F]+|[\s\x1F]+$/', '', $out ); $out = str_replace( "\x1F", $sep, $out ); $out = preg_replace( '/\s+/', ' ', $out ); return trim( $out ); } /** * Strips tags, then decodes entities, so values are plain text before * escaping. Stripping first keeps an encoded "<5" as text instead of * treating it as a tag. Block boundaries and page breaks become spaces so * words from separate paragraphs are not glued together. * * @param string $text Text. * @return string */ public static function plain( $text ) { $text = preg_replace( '#(|||)#i', '$1 ', (string) $text ); $text = Settings::strip_tags( $text ); $text = html_entity_decode( $text, ENT_QUOTES | ENT_HTML5, 'UTF-8' ); return trim( (string) preg_replace( '/\s+/', ' ', $text ) ); } /** * Shortens text to a length at a word boundary, adding an ellipsis. * * @param string $text Plain text. * @param int $length Maximum characters. * @return string */ public static function truncate( $text, $length = 155 ) { $text = self::plain( $text ); if ( mb_strlen( $text ) <= $length ) { return $text; } $cut = mb_substr( $text, 0, $length ); $words = preg_replace( '/\s+\S*$/u', '', $cut ); // Drop the partial last word. if ( mb_strlen( $words ) > $length * 0.6 ) { $cut = $words; } return rtrim( $cut, " \t\n\r\0\x0B,.;:-" ) . "\u{2026}"; } }