WPSEO_Frontend

Main frontend class for Yoast SEO, responsible for the SEO output as well as removing default WordPress output.

Defined (1)

The class is defined in the following location(s).

/frontend/class-frontend.php  
  1. class WPSEO_Frontend { 
  2.  
  3. /** 
  4. * @var object Instance of this class. 
  5. */ 
  6. public static $instance; 
  7.  
  8. /** 
  9. * @var array Holds the plugins options. 
  10. */ 
  11. public $options = array(); 
  12.  
  13. /** 
  14. * @var boolean Boolean indicating wether output buffering has been started. 
  15. */ 
  16. private $ob_started = false; 
  17.  
  18. /** 
  19. * Holds the canonical URL for the current page. 
  20. * @var string 
  21. */ 
  22. private $canonical = null; 
  23.  
  24. /** 
  25. * Holds the canonical URL for the current page that cannot be overriden by a manual canonical input. 
  26. * @var string 
  27. */ 
  28. private $canonical_no_override = null; 
  29.  
  30. /** 
  31. * Holds the canonical URL for the current page without pagination. 
  32. * @var string 
  33. */ 
  34. private $canonical_unpaged = null; 
  35.  
  36. /** 
  37. * Holds the pages meta description. 
  38. * @var string 
  39. */ 
  40. private $metadesc = null; 
  41.  
  42. /** 
  43. * Holds the generated title for the page. 
  44. * @var string 
  45. */ 
  46. private $title = null; 
  47.  
  48. /** 
  49. * Holds the names of the required options. 
  50. * @var array 
  51. */ 
  52. private $required_options = array( 'wpseo', 'wpseo_rss', 'wpseo_social', 'wpseo_permalinks', 'wpseo_titles' ); 
  53.  
  54. /** 
  55. * @var array 
  56. */ 
  57. private $hooks; 
  58.  
  59. /** 
  60. * Class constructor 
  61. * Adds and removes a lot of filters. 
  62. */ 
  63. protected function __construct() { 
  64.  
  65. $this->options = WPSEO_Options::get_options( $this->required_options ); 
  66.  
  67. add_action( 'wp_head', array( $this, 'front_page_specific_init' ), 0 ); 
  68. add_action( 'wp_head', array( $this, 'head' ), 1 ); 
  69.  
  70. // The head function here calls action wpseo_head, to which we hook all our functionality. 
  71. add_action( 'wpseo_head', array( $this, 'debug_mark' ), 2 ); 
  72. add_action( 'wpseo_head', array( $this, 'metadesc' ), 6 ); 
  73. add_action( 'wpseo_head', array( $this, 'robots' ), 10 ); 
  74. add_action( 'wpseo_head', array( $this, 'metakeywords' ), 11 ); 
  75. add_action( 'wpseo_head', array( $this, 'canonical' ), 20 ); 
  76. add_action( 'wpseo_head', array( $this, 'adjacent_rel_links' ), 21 ); 
  77. add_action( 'wpseo_head', array( $this, 'publisher' ), 22 ); 
  78.  
  79. // Remove actions that we will handle through our wpseo_head call, and probably change the output of. 
  80. remove_action( 'wp_head', 'rel_canonical' ); 
  81. remove_action( 'wp_head', 'index_rel_link' ); 
  82. remove_action( 'wp_head', 'start_post_rel_link' ); 
  83. remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head' ); 
  84. remove_action( 'wp_head', 'noindex', 1 ); 
  85.  
  86. // When using WP 4.4, just use the new hook. 
  87. add_filter( 'pre_get_document_title', array( $this, 'title' ), 15 ); 
  88. add_filter( 'wp_title', array( $this, 'title' ), 15, 3 ); 
  89.  
  90. add_filter( 'thematic_doctitle', array( $this, 'title' ), 15 ); 
  91.  
  92. add_action( 'wp', array( $this, 'page_redirect' ), 99 ); 
  93.  
  94. add_action( 'template_redirect', array( $this, 'noindex_feed' ) ); 
  95.  
  96. add_filter( 'loginout', array( $this, 'nofollow_link' ) ); 
  97. add_filter( 'register', array( $this, 'nofollow_link' ) ); 
  98.  
  99. // Fix the WooThemes woo_title() output. 
  100. add_filter( 'woo_title', array( $this, 'fix_woo_title' ), 99 ); 
  101.  
  102. if ( $this->options['disable-date'] === true || 
  103. $this->options['disable-author'] === true || 
  104. $this->options['disable-post_format'] === true 
  105. ) { 
  106. add_action( 'wp', array( $this, 'archive_redirect' ) ); 
  107. if ( $this->options['redirectattachment'] === true ) { 
  108. add_action( 'template_redirect', array( $this, 'attachment_redirect' ), 1 ); 
  109.  
  110. /** 
  111. * The setting to get here has been deprecated, but don't remove the code as that would break 
  112. * the functionality for those that still have it! 
  113. */ 
  114. if ( $this->options['trailingslash'] === true ) { 
  115. add_filter( 'user_trailingslashit', array( $this, 'add_trailingslash' ), 10, 2 ); 
  116. if ( $this->options['cleanpermalinks'] === true ) { 
  117. add_action( 'template_redirect', array( $this, 'clean_permalink' ), 1 ); 
  118. if ( $this->options['cleanreplytocom'] === true ) { 
  119. add_filter( 'comment_reply_link', array( $this, 'remove_reply_to_com' ) ); 
  120. add_action( 'template_redirect', array( $this, 'replytocom_redirect' ), 1 ); 
  121. add_filter( 'the_content_feed', array( $this, 'embed_rssfooter' ) ); 
  122. add_filter( 'the_excerpt_rss', array( $this, 'embed_rssfooter_excerpt' ) ); 
  123.  
  124. // For WordPress functions below 4.4. 
  125. if ( ! current_theme_supports( 'title-tag' ) && $this->options['forcerewritetitle'] === true ) { 
  126. add_action( 'template_redirect', array( $this, 'force_rewrite_output_buffer' ), 99999 ); 
  127. add_action( 'wp_footer', array( $this, 'flush_cache' ), - 1 ); 
  128.  
  129. if ( $this->options['title_test'] > 0 ) { 
  130. add_filter( 'wpseo_title', array( $this, 'title_test_helper' ) ); 
  131.  
  132. $primary_category = new WPSEO_Frontend_Primary_Category(); 
  133. $primary_category->register_hooks(); 
  134.  
  135. $this->hooks = array( $primary_category ); 
  136.  
  137. /** 
  138. * Initialize the functions that only need to run on the frontpage 
  139. */ 
  140. public function front_page_specific_init() { 
  141. if ( ! is_front_page() ) { 
  142. return; 
  143.  
  144. new WPSEO_JSON_LD; 
  145. add_action( 'wpseo_head', array( $this, 'webmaster_tools_authentication' ), 90 ); 
  146.  
  147. /** 
  148. * Resets the entire class so canonicals, titles etc can be regenerated. 
  149. */ 
  150. public function reset() { 
  151. foreach ( get_class_vars( __CLASS__ ) as $name => $default ) { 
  152. if ( $name == 'instance' ) { 
  153. self::$instance = null; 
  154. else { 
  155. $this->$name = $default; 
  156. $this->options = WPSEO_Options::get_options( $this->required_options ); 
  157.  
  158. /** 
  159. * Get the singleton instance of this class 
  160. * @return WPSEO_Frontend 
  161. */ 
  162. public static function get_instance() { 
  163. if ( ! ( self::$instance instanceof self ) ) { 
  164. self::$instance = new self(); 
  165.  
  166. return self::$instance; 
  167.  
  168. /** 
  169. * Override Woo's title with our own. 
  170. * @param string $title Title string. 
  171. * @return string 
  172. */ 
  173. public function fix_woo_title( $title ) { 
  174. return $this->title( $title ); 
  175.  
  176. /** 
  177. * Determine whether this is the homepage and shows posts. 
  178. * @return bool 
  179. */ 
  180. public function is_home_posts_page() { 
  181. return ( is_home() && 'posts' == get_option( 'show_on_front' ) ); 
  182.  
  183. /** 
  184. * Determine whether the this is the static frontpage. 
  185. * @return bool 
  186. */ 
  187. public function is_home_static_page() { 
  188. return ( is_front_page() && 'page' == get_option( 'show_on_front' ) && is_page( get_option( 'page_on_front' ) ) ); 
  189.  
  190. /** 
  191. * Determine whether this is the posts page, when it's not the frontpage. 
  192. * @return bool 
  193. */ 
  194. public function is_posts_page() { 
  195. return ( is_home() && 'page' == get_option( 'show_on_front' ) ); 
  196.  
  197. /** 
  198. * Used for static home and posts pages as well as singular titles. 
  199. * @param object|null $object If filled, object to get the title for. 
  200. * @return string 
  201. */ 
  202. public function get_content_title( $object = null ) { 
  203. if ( is_null( $object ) ) { 
  204. $object = $GLOBALS['wp_query']->get_queried_object(); 
  205.  
  206. if ( is_object( $object ) ) { 
  207. $title = WPSEO_Meta::get_value( 'title', $object->ID ); 
  208.  
  209. if ( $title !== '' ) { 
  210. return wpseo_replace_vars( $title, $object ); 
  211.  
  212. $post_type = ( isset( $object->post_type ) ? $object->post_type : $object->query_var ); 
  213.  
  214. return $this->get_title_from_options( 'title-' . $post_type, $object ); 
  215.  
  216. return $this->get_title_from_options( 'title-404-wpseo' ); 
  217.  
  218. /** 
  219. * Used for category, tag, and tax titles. 
  220. * @return string 
  221. */ 
  222. public function get_taxonomy_title() { 
  223. $object = $GLOBALS['wp_query']->get_queried_object(); 
  224.  
  225. $title = WPSEO_Taxonomy_Meta::get_term_meta( $object, $object->taxonomy, 'title' ); 
  226.  
  227. if ( is_string( $title ) && $title !== '' ) { 
  228. return wpseo_replace_vars( $title, $object ); 
  229. else { 
  230. return $this->get_title_from_options( 'title-tax-' . $object->taxonomy, $object ); 
  231.  
  232. /** 
  233. * Used for author titles. 
  234. * @return string 
  235. */ 
  236. public function get_author_title() { 
  237. $author_id = get_query_var( 'author' ); 
  238. $title = trim( get_the_author_meta( 'wpseo_title', $author_id ) ); 
  239.  
  240. if ( $title !== '' ) { 
  241. return wpseo_replace_vars( $title, array() ); 
  242.  
  243. return $this->get_title_from_options( 'title-author-wpseo' ); 
  244.  
  245. /** 
  246. * Simple function to use to pull data from $options. 
  247. * All titles pulled from options will be run through the wpseo_replace_vars function. 
  248. * @param string $index name of the page to get the title from the settings for. 
  249. * @param object|array $var_source possible object to pull variables from. 
  250. * @return string 
  251. */ 
  252. public function get_title_from_options( $index, $var_source = array() ) { 
  253. if ( ! isset( $this->options[ $index ] ) || $this->options[ $index ] === '' ) { 
  254. if ( is_singular() ) { 
  255. return wpseo_replace_vars( '%%title%% %%sep%% %%sitename%%', $var_source ); 
  256. else { 
  257. return ''; 
  258. else { 
  259. return wpseo_replace_vars( $this->options[ $index ], $var_source ); 
  260.  
  261. /** 
  262. * Get the default title for the current page. 
  263. * This is the fallback title generator used when a title hasn't been set for the specific content, taxonomy, author 
  264. * details, or in the options. It scrubs off any present prefix before or after the title (based on $seplocation) in 
  265. * order to prevent duplicate seperations from appearing in the title (this happens when a prefix is supplied to the 
  266. * wp_title call on singular pages). 
  267. * @param string $sep The separator used between variables. 
  268. * @param string $seplocation Whether the separator should be left or right. 
  269. * @param string $title Possible title that's already set. 
  270. * @return string 
  271. */ 
  272. public function get_default_title( $sep, $seplocation, $title = '' ) { 
  273. if ( 'right' == $seplocation ) { 
  274. $regex = '`\s*' . preg_quote( trim( $sep ), '`' ) . '\s*`u'; 
  275. else { 
  276. $regex = '`^\s*' . preg_quote( trim( $sep ), '`' ) . '\s*`u'; 
  277. $title = preg_replace( $regex, '', $title ); 
  278.  
  279. if ( ! is_string( $title ) || ( is_string( $title ) && $title === '' ) ) { 
  280. $title = get_bloginfo( 'name' ); 
  281. $title = $this->add_paging_to_title( $sep, $seplocation, $title ); 
  282. $title = $this->add_to_title( $sep, $seplocation, $title, strip_tags( get_bloginfo( 'description' ) ) ); 
  283.  
  284. return $title; 
  285.  
  286. $title = $this->add_paging_to_title( $sep, $seplocation, $title ); 
  287. $title = $this->add_to_title( $sep, $seplocation, $title, strip_tags( get_bloginfo( 'name' ) ) ); 
  288.  
  289. return $title; 
  290.  
  291. /** 
  292. * This function adds paging details to the title. 
  293. * @param string $sep Separator used in the title. 
  294. * @param string $seplocation Whether the separator should be left or right. 
  295. * @param string $title The title to append the paging info to. 
  296. * @return string 
  297. */ 
  298. public function add_paging_to_title( $sep, $seplocation, $title ) { 
  299. global $wp_query; 
  300.  
  301. if ( ! empty( $wp_query->query_vars['paged'] ) && $wp_query->query_vars['paged'] > 1 ) { 
  302. return $this->add_to_title( $sep, $seplocation, $title, $wp_query->query_vars['paged'] . '/' . $wp_query->max_num_pages ); 
  303.  
  304. return $title; 
  305.  
  306. /** 
  307. * Add part to title, while ensuring that the $seplocation variable is respected. 
  308. * @param string $sep Separator used in the title. 
  309. * @param string $seplocation Whether the separator should be left or right. 
  310. * @param string $title The title to append the title_part to. 
  311. * @param string $title_part The part to append to the title. 
  312. * @return string 
  313. */ 
  314. public function add_to_title( $sep, $seplocation, $title, $title_part ) { 
  315. if ( 'right' === $seplocation ) { 
  316. return $title . $sep . $title_part; 
  317.  
  318. return $title_part . $sep . $title; 
  319.  
  320. /** 
  321. * Main title function. 
  322. * @param string $title Title that might have already been set. 
  323. * @param string $separator Separator determined in theme (unused). 
  324. * @param string $separator_location Whether the separator should be left or right. 
  325. * @return string 
  326. */ 
  327. public function title( $title, $separator = '', $separator_location = '' ) { 
  328. if ( is_null( $this->title ) ) { 
  329. $this->title = $this->generate_title( $title, $separator_location ); 
  330.  
  331. return $this->title; 
  332.  
  333. /** 
  334. * Main title generation function. 
  335. * @param string $title Title that might have already been set. 
  336. * @param string $separator_location Whether the separator should be left or right. 
  337. * @return string 
  338. */ 
  339. private function generate_title( $title, $separator_location ) { 
  340.  
  341. if ( is_feed() ) { 
  342. return $title; 
  343.  
  344. $separator = wpseo_replace_vars( '%%sep%%', array() ); 
  345. $separator = ' ' . trim( $separator ) . ' '; 
  346.  
  347. if ( '' === trim( $separator_location ) ) { 
  348. $separator_location = ( is_rtl() ) ? 'left' : 'right'; 
  349.  
  350. // This needs to be kept track of in order to generate 
  351. // default titles for singular pages. 
  352. $original_title = $title; 
  353.  
  354. // This flag is used to determine if any additional 
  355. // processing should be done to the title after the 
  356. // main section of title generation completes. 
  357. $modified_title = true; 
  358.  
  359. // This variable holds the page-specific title part 
  360. // that is used to generate default titles. 
  361. $title_part = ''; 
  362.  
  363. if ( $this->is_home_static_page() ) { 
  364. $title = $this->get_content_title(); 
  365. elseif ( $this->is_home_posts_page() ) { 
  366. $title = $this->get_title_from_options( 'title-home-wpseo' ); 
  367. elseif ( $this->is_posts_page() ) { 
  368. $title = $this->get_content_title( get_post( get_option( 'page_for_posts' ) ) ); 
  369. elseif ( is_singular() ) { 
  370. $title = $this->get_content_title(); 
  371.  
  372. if ( ! is_string( $title ) || '' === $title ) { 
  373. $title_part = $original_title; 
  374. elseif ( is_search() ) { 
  375. $title = $this->get_title_from_options( 'title-search-wpseo' ); 
  376.  
  377. if ( ! is_string( $title ) || '' === $title ) { 
  378. $title_part = sprintf( __( 'Search for "%s"', 'wordpress-seo' ), esc_html( get_search_query() ) ); 
  379. elseif ( is_category() || is_tag() || is_tax() ) { 
  380. $title = $this->get_taxonomy_title(); 
  381.  
  382. if ( ! is_string( $title ) || '' === $title ) { 
  383. if ( is_category() ) { 
  384. $title_part = single_cat_title( '', false ); 
  385. elseif ( is_tag() ) { 
  386. $title_part = single_tag_title( '', false ); 
  387. else { 
  388. $title_part = single_term_title( '', false ); 
  389. if ( $title_part === '' ) { 
  390. $term = $GLOBALS['wp_query']->get_queried_object(); 
  391. $title_part = $term->name; 
  392. elseif ( is_author() ) { 
  393. $title = $this->get_author_title(); 
  394.  
  395. if ( ! is_string( $title ) || '' === $title ) { 
  396. $title_part = get_the_author_meta( 'display_name', get_query_var( 'author' ) ); 
  397. elseif ( is_post_type_archive() ) { 
  398. $post_type = get_query_var( 'post_type' ); 
  399.  
  400. if ( is_array( $post_type ) ) { 
  401. $post_type = reset( $post_type ); 
  402.  
  403. $title = $this->get_title_from_options( 'title-ptarchive-' . $post_type ); 
  404.  
  405. if ( ! is_string( $title ) || '' === $title ) { 
  406. $post_type_obj = get_post_type_object( $post_type ); 
  407. if ( isset( $post_type_obj->labels->menu_name ) ) { 
  408. $title_part = $post_type_obj->labels->menu_name; 
  409. elseif ( isset( $post_type_obj->name ) ) { 
  410. $title_part = $post_type_obj->name; 
  411. else { 
  412. $title_part = ''; // To be determined what this should be. 
  413. elseif ( is_archive() ) { 
  414. $title = $this->get_title_from_options( 'title-archive-wpseo' ); 
  415.  
  416. // @todo [JRF => Yoast] Should these not use the archive default if no title found ? 
  417. // WPSEO_Options::get_default( 'wpseo_titles', 'title-archive-wpseo' ) 
  418. // Replacement would be needed! 
  419. if ( empty( $title ) ) { 
  420. if ( is_month() ) { 
  421. $title_part = sprintf( __( '%s Archives', 'wordpress-seo' ), single_month_title( ' ', false ) ); 
  422. elseif ( is_year() ) { 
  423. $title_part = sprintf( __( '%s Archives', 'wordpress-seo' ), get_query_var( 'year' ) ); 
  424. elseif ( is_day() ) { 
  425. $title_part = sprintf( __( '%s Archives', 'wordpress-seo' ), get_the_date() ); 
  426. else { 
  427. $title_part = __( 'Archives', 'wordpress-seo' ); 
  428. elseif ( is_404() ) { 
  429.  
  430. $title = $this->get_title_from_options( 'title-404-wpseo' ); 
  431.  
  432. // @todo [JRF => Yoast] Should these not use the 404 default if no title found ? 
  433. // WPSEO_Options::get_default( 'wpseo_titles', 'title-404-wpseo' ) 
  434. // Replacement would be needed! 
  435. if ( empty( $title ) ) { 
  436. $title_part = __( 'Page not found', 'wordpress-seo' ); 
  437. else { 
  438. // In case the page type is unknown, leave the title alone. 
  439. $modified_title = false; 
  440.  
  441. // If you would like to generate a default title instead,  
  442. // the following code could be used 
  443. // $title_part = $title; 
  444. // instead of the line above. 
  445.  
  446. if ( ( $modified_title && empty( $title ) ) || ! empty( $title_part ) ) { 
  447. $title = $this->get_default_title( $separator, $separator_location, $title_part ); 
  448.  
  449. if ( defined( 'ICL_LANGUAGE_CODE' ) && false !== strpos( $title, ICL_LANGUAGE_CODE ) ) { 
  450. $title = str_replace( ' @' . ICL_LANGUAGE_CODE, '', $title ); 
  451.  
  452. /** 
  453. * Filter: 'wpseo_title' - Allow changing the Yoast SEO <title> output 
  454. * @api string $title The page title being put out. 
  455. */ 
  456.  
  457. return esc_html( strip_tags( stripslashes( apply_filters( 'wpseo_title', $title ) ) ) ); 
  458.  
  459. /** 
  460. * Function used when title needs to be force overridden. 
  461. * @return string 
  462. */ 
  463. function force_wp_title() { 
  464. global $wp_query; 
  465. $old_wp_query = null; 
  466.  
  467. if ( ! $wp_query->is_main_query() ) { 
  468. $old_wp_query = $wp_query; 
  469. wp_reset_query(); 
  470.  
  471. $title = $this->title( '' ); 
  472.  
  473. if ( ! empty( $old_wp_query ) ) { 
  474. $GLOBALS['wp_query'] = $old_wp_query; 
  475. unset( $old_wp_query ); 
  476.  
  477. return $title; 
  478.  
  479. /** 
  480. * Outputs or returns the debug marker, which is also used for title replacement when force rewrite is active. 
  481. * @param bool $echo Whether or not to echo the debug marker. 
  482. * @return string 
  483. */ 
  484. public function debug_mark( $echo = true ) { 
  485. $marker = sprintf( 
  486. '<!-- This site is optimized with the ' . $this->head_product_name() . '%1$s - https://yoast.com/wordpress/plugins/seo/ -->',  
  487. /** 
  488. * Filter: 'wpseo_hide_version' - can be used to hide the Yoast SEO version in the debug marker (only available in Yoast SEO Premium) 
  489. * @api bool 
  490. */ 
  491. ( ( apply_filters( 'wpseo_hide_version', false ) && $this->is_premium() ) ? '' : ' v' . WPSEO_VERSION ) 
  492. ); 
  493.  
  494. if ( $echo === false ) { 
  495. return $marker; 
  496. else { 
  497. echo "\n${marker}\n"; 
  498.  
  499. /** 
  500. * Output Webmaster Tools authentication strings 
  501. */ 
  502. public function webmaster_tools_authentication() { 
  503. // Bing. 
  504. if ( $this->options['msverify'] !== '' ) { 
  505. echo '<meta name="msvalidate.01" content="' . esc_attr( $this->options['msverify'] ) . "\" />\n"; 
  506.  
  507. // Google. 
  508. if ( $this->options['googleverify'] !== '' ) { 
  509. echo '<meta name="google-site-verification" content="' . esc_attr( $this->options['googleverify'] ) . "\" />\n"; 
  510.  
  511. // Pinterest. 
  512. if ( $this->options['pinterestverify'] !== '' ) { 
  513. echo '<meta name="p:domain_verify" content="' . esc_attr( $this->options['pinterestverify'] ) . "\" />\n"; 
  514.  
  515. // Yandex. 
  516. if ( $this->options['yandexverify'] !== '' ) { 
  517. echo '<meta name="yandex-verification" content="' . esc_attr( $this->options['yandexverify'] ) . "\" />\n"; 
  518.  
  519. /** 
  520. * Main wrapper function attached to wp_head. This combines all the output on the frontend of the Yoast SEO plugin. 
  521. */ 
  522. public function head() { 
  523. global $wp_query; 
  524.  
  525. $old_wp_query = null; 
  526.  
  527. if ( ! $wp_query->is_main_query() ) { 
  528. $old_wp_query = $wp_query; 
  529. wp_reset_query(); 
  530.  
  531. /** 
  532. * Action: 'wpseo_head' - Allow other plugins to output inside the Yoast SEO section of the head section. 
  533. */ 
  534. do_action( 'wpseo_head' ); 
  535.  
  536. echo '<!-- / ', $this->head_product_name(), ". -->\n\n"; 
  537.  
  538. if ( ! empty( $old_wp_query ) ) { 
  539. $GLOBALS['wp_query'] = $old_wp_query; 
  540. unset( $old_wp_query ); 
  541.  
  542. return; 
  543.  
  544.  
  545. /** 
  546. * Output the meta robots value. 
  547. * @return string 
  548. */ 
  549. public function robots() { 
  550. global $wp_query, $post; 
  551.  
  552. $robots = array(); 
  553. $robots['index'] = 'index'; 
  554. $robots['follow'] = 'follow'; 
  555. $robots['other'] = array(); 
  556.  
  557. if ( is_singular() && is_object( $post ) ) { 
  558.  
  559. $option_name = 'noindex-' . $post->post_type; 
  560. $noindex = isset( $this->options[ $option_name ] ) && $this->options[ $option_name ] === true; 
  561. $private = 'private' === $post->post_status; 
  562.  
  563. if ( $noindex || $private ) { 
  564. $robots['index'] = 'noindex'; 
  565.  
  566. $robots = $this->robots_for_single_post( $robots ); 
  567.  
  568. else { 
  569. if ( is_search() || is_404() ) { 
  570. $robots['index'] = 'noindex'; 
  571. elseif ( is_tax() || is_tag() || is_category() ) { 
  572. $term = $wp_query->get_queried_object(); 
  573. if ( is_object( $term ) && ( isset( $this->options[ 'noindex-tax-' . $term->taxonomy ] ) && $this->options[ 'noindex-tax-' . $term->taxonomy ] === true ) ) { 
  574. $robots['index'] = 'noindex'; 
  575.  
  576. // Three possible values, index, noindex and default, do nothing for default. 
  577. $term_meta = WPSEO_Taxonomy_Meta::get_term_meta( $term, $term->taxonomy, 'noindex' ); 
  578. if ( is_string( $term_meta ) && 'default' !== $term_meta ) { 
  579. $robots['index'] = $term_meta; 
  580.  
  581. if ( $this->is_multiple_terms_query() ) { 
  582. $robots['index'] = 'noindex'; 
  583. elseif ( 
  584. ( is_author() && $this->options['noindex-author-wpseo'] === true ) || 
  585. ( is_date() && $this->options['noindex-archive-wpseo'] === true ) 
  586. ) { 
  587. $robots['index'] = 'noindex'; 
  588. elseif ( is_home() ) { 
  589. if ( get_query_var( 'paged' ) > 1 && $this->options['noindex-subpages-wpseo'] === true ) { 
  590. $robots['index'] = 'noindex'; 
  591.  
  592. $page_for_posts = get_option( 'page_for_posts' ); 
  593. if ( $page_for_posts ) { 
  594. $robots = $this->robots_for_single_post( $robots, $page_for_posts ); 
  595. unset( $page_for_posts ); 
  596.  
  597. elseif ( is_post_type_archive() ) { 
  598. $post_type = get_query_var( 'post_type' ); 
  599.  
  600. if ( is_array( $post_type ) ) { 
  601. $post_type = reset( $post_type ); 
  602.  
  603. if ( isset( $this->options[ 'noindex-ptarchive-' . $post_type ] ) && $this->options[ 'noindex-ptarchive-' . $post_type ] === true ) { 
  604. $robots['index'] = 'noindex'; 
  605.  
  606. $is_paged = isset( $wp_query->query_vars['paged'] ) && ( $wp_query->query_vars['paged'] && $wp_query->query_vars['paged'] > 1 ); 
  607. $noindex_subpages = $this->options['noindex-subpages-wpseo'] === true; 
  608. if ( $is_paged && $noindex_subpages ) { 
  609. $robots['index'] = 'noindex'; 
  610.  
  611. if ( $this->options['noodp'] === true ) { 
  612. $robots['other'][] = 'noodp'; 
  613. unset( $robot ); 
  614.  
  615. // Force override to respect the WP settings. 
  616. if ( '0' == get_option( 'blog_public' ) || isset( $_GET['replytocom'] ) ) { 
  617. $robots['index'] = 'noindex'; 
  618.  
  619.  
  620. $robotsstr = $robots['index'] . ', ' . $robots['follow']; 
  621.  
  622. if ( $robots['other'] !== array() ) { 
  623. $robots['other'] = array_unique( $robots['other'] ); // TODO Most likely no longer needed, needs testing. 
  624. $robotsstr .= ', ' . implode( ', ', $robots['other'] ); 
  625.  
  626. $robotsstr = preg_replace( '`^index, follow, ?`', '', $robotsstr ); 
  627.  
  628. /** 
  629. * Filter: 'wpseo_robots' - Allows filtering of the meta robots output of Yoast SEO 
  630. * @api string $robotsstr The meta robots directives to be echoed. 
  631. */ 
  632. $robotsstr = apply_filters( 'wpseo_robots', $robotsstr ); 
  633.  
  634. if ( is_string( $robotsstr ) && $robotsstr !== '' ) { 
  635. echo '<meta name="robots" content="', esc_attr( $robotsstr ), '"/>', "\n"; 
  636.  
  637. return $robotsstr; 
  638.  
  639. /** 
  640. * Determine $robots values for a single post 
  641. * @param array $robots Robots data array. 
  642. * @param int $post_id The post ID for which to determine the $robots values, defaults to current post. 
  643. * @return array 
  644. */ 
  645. public function robots_for_single_post( $robots, $post_id = 0 ) { 
  646. $noindex = WPSEO_Meta::get_value( 'meta-robots-noindex', $post_id ); 
  647. if ( $noindex === '1' ) { 
  648. $robots['index'] = 'noindex'; 
  649. elseif ( $noindex === '2' ) { 
  650. $robots['index'] = 'index'; 
  651.  
  652. if ( WPSEO_Meta::get_value( 'meta-robots-nofollow', $post_id ) === '1' ) { 
  653. $robots['follow'] = 'nofollow'; 
  654.  
  655. $meta_robots_adv = WPSEO_Meta::get_value( 'meta-robots-adv', $post_id ); 
  656.  
  657. if ( $meta_robots_adv !== '' && ( $meta_robots_adv !== '-' && $meta_robots_adv !== 'none' ) ) { 
  658. $meta_robots_adv = explode( ', ', $meta_robots_adv ); 
  659. foreach ( $meta_robots_adv as $robot ) { 
  660. $robots['other'][] = $robot; 
  661. unset( $robot ); 
  662. elseif ( $meta_robots_adv === '' || $meta_robots_adv === '-' ) { 
  663. if ( $this->options['noodp'] === true ) { 
  664. $robots['other'][] = 'noodp'; 
  665. unset( $meta_robots_adv ); 
  666.  
  667. return $robots; 
  668.  
  669. /** 
  670. * This function normally outputs the canonical but is also used in other places to retrieve 
  671. * the canonical URL for the current page. 
  672. * @param bool $echo Whether or not to output the canonical element. 
  673. * @param bool $un_paged Whether or not to return the canonical with or without pagination added to the URL. 
  674. * @param bool $no_override Whether or not to return a manually overridden canonical. 
  675. * @return string $canonical 
  676. */ 
  677. public function canonical( $echo = true, $un_paged = false, $no_override = false ) { 
  678. if ( is_null( $this->canonical ) ) { 
  679. $this->generate_canonical(); 
  680.  
  681. $canonical = $this->canonical; 
  682.  
  683. if ( $un_paged ) { 
  684. $canonical = $this->canonical_unpaged; 
  685. elseif ( $no_override ) { 
  686. $canonical = $this->canonical_no_override; 
  687.  
  688. if ( $echo === false ) { 
  689. return $canonical; 
  690.  
  691. if ( is_string( $canonical ) && '' !== $canonical ) { 
  692. echo '<link rel="canonical" href="' . esc_url( $canonical, null, 'other' ) . '" />' . "\n"; 
  693.  
  694. /** 
  695. * This function normally outputs the canonical but is also used in other places to retrieve 
  696. * the canonical URL for the current page. 
  697. * @return void 
  698. */ 
  699. private function generate_canonical() { 
  700. $canonical = false; 
  701. $canonical_override = false; 
  702.  
  703. // Set decent canonicals for homepage, singulars and taxonomy pages. 
  704. if ( is_singular() ) { 
  705. $obj = get_queried_object(); 
  706. $canonical = get_permalink( $obj->ID ); 
  707.  
  708. $this->canonical_unpaged = $canonical; 
  709.  
  710. $canonical_override = WPSEO_Meta::get_value( 'canonical' ); 
  711.  
  712. // Fix paginated pages canonical, but only if the page is truly paginated. 
  713. if ( get_query_var( 'page' ) > 1 ) { 
  714. $num_pages = ( substr_count( $obj->post_content, '<!--nextpage-->' ) + 1 ); 
  715. if ( $num_pages && get_query_var( 'page' ) <= $num_pages ) { 
  716. if ( ! $GLOBALS['wp_rewrite']->using_permalinks() ) { 
  717. $canonical = add_query_arg( 'page', get_query_var( 'page' ), $canonical ); 
  718. else { 
  719. $canonical = user_trailingslashit( trailingslashit( $canonical ) . get_query_var( 'page' ) ); 
  720. else { 
  721. if ( is_search() ) { 
  722. $search_query = get_search_query(); 
  723.  
  724. // Regex catches case when /search/page/N without search term is itself mistaken for search term. R. 
  725. if ( ! empty( $search_query ) && ! preg_match( '|^page/\d+$|', $search_query ) ) { 
  726. $canonical = get_search_link(); 
  727. elseif ( is_front_page() ) { 
  728. $canonical = WPSEO_Utils::home_url(); 
  729. elseif ( $this->is_posts_page() ) { 
  730.  
  731. $posts_page_id = get_option( 'page_for_posts' ); 
  732. $canonical = WPSEO_Meta::get_value( 'canonical', $posts_page_id ); 
  733.  
  734. if ( empty( $canonical ) ) { 
  735. $canonical = get_permalink( $posts_page_id ); 
  736. elseif ( is_tax() || is_tag() || is_category() ) { 
  737.  
  738. $term = get_queried_object(); 
  739.  
  740. if ( ! empty( $term ) && ! $this->is_multiple_terms_query() ) { 
  741.  
  742. $canonical_override = WPSEO_Taxonomy_Meta::get_term_meta( $term, $term->taxonomy, 'canonical' ); 
  743. $term_link = get_term_link( $term, $term->taxonomy ); 
  744.  
  745. if ( ! is_wp_error( $term_link ) ) { 
  746. $canonical = $term_link; 
  747. elseif ( is_post_type_archive() ) { 
  748. $post_type = get_query_var( 'post_type' ); 
  749. if ( is_array( $post_type ) ) { 
  750. $post_type = reset( $post_type ); 
  751. $canonical = get_post_type_archive_link( $post_type ); 
  752. elseif ( is_author() ) { 
  753. $canonical = get_author_posts_url( get_query_var( 'author' ), get_query_var( 'author_name' ) ); 
  754. elseif ( is_archive() ) { 
  755. if ( is_date() ) { 
  756. if ( is_day() ) { 
  757. $canonical = get_day_link( get_query_var( 'year' ), get_query_var( 'monthnum' ), get_query_var( 'day' ) ); 
  758. elseif ( is_month() ) { 
  759. $canonical = get_month_link( get_query_var( 'year' ), get_query_var( 'monthnum' ) ); 
  760. elseif ( is_year() ) { 
  761. $canonical = get_year_link( get_query_var( 'year' ) ); 
  762.  
  763. $this->canonical_unpaged = $canonical; 
  764.  
  765. if ( $canonical && get_query_var( 'paged' ) > 1 ) { 
  766. global $wp_rewrite; 
  767. if ( ! $wp_rewrite->using_permalinks() ) { 
  768. if ( is_front_page() ) { 
  769. $canonical = trailingslashit( $canonical ); 
  770. $canonical = add_query_arg( 'paged', get_query_var( 'paged' ), $canonical ); 
  771. else { 
  772. if ( is_front_page() ) { 
  773. $canonical = WPSEO_Sitemaps_Router::get_base_url( '' ); 
  774. $canonical = user_trailingslashit( trailingslashit( $canonical ) . trailingslashit( $wp_rewrite->pagination_base ) . get_query_var( 'paged' ) ); 
  775.  
  776. $this->canonical_no_override = $canonical; 
  777.  
  778. if ( is_string( $canonical ) && $canonical !== '' ) { 
  779. // Force canonical links to be absolute, relative is NOT an option. 
  780. if ( WPSEO_Utils::is_url_relative( $canonical ) === true ) { 
  781. $canonical = $this->base_url( $canonical ); 
  782.  
  783. if ( is_string( $canonical_override ) && $canonical_override !== '' ) { 
  784. $canonical = $canonical_override; 
  785.  
  786. /** 
  787. * Filter: 'wpseo_canonical' - Allow filtering of the canonical URL put out by Yoast SEO 
  788. * @api string $canonical The canonical URL 
  789. */ 
  790. $this->canonical = apply_filters( 'wpseo_canonical', $canonical ); 
  791.  
  792. /** 
  793. * Parse the home URL setting to find the base URL for relative URLs. 
  794. * @param string $path Optional path string. 
  795. * @return string 
  796. */ 
  797. private function base_url( $path = null ) { 
  798. $url = get_option( 'home' ); 
  799.  
  800. $parts = wp_parse_url( $url ); 
  801.  
  802. $base_url = trailingslashit( $parts['scheme'] . '://' . $parts['host'] ); 
  803.  
  804. if ( ! is_null( $path ) ) { 
  805. $base_url .= ltrim( $path, '/' ); 
  806.  
  807. return $base_url; 
  808.  
  809. /** 
  810. * Adds 'prev' and 'next' links to archives. 
  811. * @link http://googlewebmastercentral.blogspot.com/2011/09/pagination-with-relnext-and-relprev.html 
  812. * @since 1.0.3 
  813. */ 
  814. public function adjacent_rel_links() { 
  815. // Don't do this for Genesis, as the way Genesis handles homepage functionality is different and causes issues sometimes. 
  816. /** 
  817. * Filter 'wpseo_genesis_force_adjacent_rel_home' - Allows devs to allow echoing rel="next" / rel="prev" by Yoast SEO on Genesis installs 
  818. * @api bool $unsigned Whether or not to rel=next / rel=prev 
  819. */ 
  820. if ( is_home() && function_exists( 'genesis' ) && apply_filters( 'wpseo_genesis_force_adjacent_rel_home', false ) === false ) { 
  821. return; 
  822.  
  823. global $wp_query; 
  824.  
  825. if ( ! is_singular() ) { 
  826. $url = $this->canonical( false, true, true ); 
  827.  
  828. if ( is_string( $url ) && $url !== '' ) { 
  829. $paged = get_query_var( 'paged' ); 
  830.  
  831. if ( 0 == $paged ) { 
  832. $paged = 1; 
  833.  
  834. if ( $paged == 2 ) { 
  835. $this->adjacent_rel_link( 'prev', $url, ( $paged - 1 ), true ); 
  836.  
  837. // Make sure to use index.php when needed, done after paged == 2 check so the prev links to homepage will not have index.php erroneously. 
  838. if ( is_front_page() ) { 
  839. $url = WPSEO_Sitemaps_Router::get_base_url( '' ); 
  840.  
  841. if ( $paged > 2 ) { 
  842. $this->adjacent_rel_link( 'prev', $url, ( $paged - 1 ), true ); 
  843.  
  844. if ( $paged < $wp_query->max_num_pages ) { 
  845. $this->adjacent_rel_link( 'next', $url, ( $paged + 1 ), true ); 
  846. else { 
  847. $numpages = 0; 
  848. if ( isset( $wp_query->post->post_content ) ) { 
  849. $numpages = ( substr_count( $wp_query->post->post_content, '<!--nextpage-->' ) + 1 ); 
  850. if ( $numpages > 1 ) { 
  851. $page = get_query_var( 'page' ); 
  852. if ( ! $page ) { 
  853. $page = 1; 
  854.  
  855. $url = get_permalink( $wp_query->post->ID ); 
  856.  
  857. // If the current page is the frontpage, pagination should use /base/. 
  858. if ( $this->is_home_static_page() ) { 
  859. $usebase = true; 
  860. else { 
  861. $usebase = false; 
  862.  
  863. if ( $page > 1 ) { 
  864. $this->adjacent_rel_link( 'prev', $url, ( $page - 1 ), $usebase, 'single_paged' ); 
  865. if ( $page < $numpages ) { 
  866. $this->adjacent_rel_link( 'next', $url, ( $page + 1 ), $usebase, 'single_paged' ); 
  867.  
  868. /** 
  869. * Get adjacent pages link for archives 
  870. * @since 1.0.2 
  871. * @param string $rel Link relationship, prev or next. 
  872. * @param string $url the un-paginated URL of the current archive. 
  873. * @param string $page the page number to add on to $url for the $link tag. 
  874. * @param boolean $incl_pagination_base whether or not to include /page/ or not. 
  875. * @return void 
  876. */ 
  877. private function adjacent_rel_link( $rel, $url, $page, $incl_pagination_base ) { 
  878. global $wp_rewrite; 
  879. if ( ! $wp_rewrite->using_permalinks() ) { 
  880. if ( $page > 1 ) { 
  881. $url = add_query_arg( 'paged', $page, $url ); 
  882. else { 
  883. if ( $page > 1 ) { 
  884. $base = ''; 
  885. if ( $incl_pagination_base ) { 
  886. $base = trailingslashit( $wp_rewrite->pagination_base ); 
  887. $url = user_trailingslashit( trailingslashit( $url ) . $base . $page ); 
  888. /** 
  889. * Filter: 'wpseo_' . $rel . '_rel_link' - Allow changing link rel output by Yoast SEO 
  890. * @api string $unsigned The full `<link` element. 
  891. */ 
  892. $link = apply_filters( 'wpseo_' . $rel . '_rel_link', '<link rel="' . esc_attr( $rel ) . '" href="' . esc_url( $url ) . "\" />\n" ); 
  893.  
  894. if ( is_string( $link ) && $link !== '' ) { 
  895. echo $link; 
  896.  
  897. /** 
  898. * Output the rel=publisher code on every page of the site. 
  899. * @return boolean Boolean indicating whether the publisher link was printed 
  900. */ 
  901. public function publisher() { 
  902.  
  903. if ( $this->options['plus-publisher'] !== '' ) { 
  904. echo '<link rel="publisher" href="', esc_url( $this->options['plus-publisher'] ), '"/>', "\n"; 
  905.  
  906. return true; 
  907.  
  908. return false; 
  909.  
  910. /** 
  911. * Outputs the meta keywords element. 
  912. * @return void 
  913. */ 
  914. public function metakeywords() { 
  915. global $wp_query, $post; 
  916.  
  917. if ( $this->options['usemetakeywords'] === false ) { 
  918. return; 
  919.  
  920. $keywords = ''; 
  921.  
  922. if ( is_singular() ) { 
  923. $keywords = WPSEO_Meta::get_value( 'metakeywords' ); 
  924. if ( $keywords === '' && ( is_object( $post ) && ( ( isset( $this->options[ 'metakey-' . $post->post_type ] ) && $this->options[ 'metakey-' . $post->post_type ] !== '' ) ) ) ) { 
  925. $keywords = wpseo_replace_vars( $this->options[ 'metakey-' . $post->post_type ], $post ); 
  926. else { 
  927. if ( $this->is_home_posts_page() && $this->options['metakey-home-wpseo'] !== '' ) { 
  928. $keywords = wpseo_replace_vars( $this->options['metakey-home-wpseo'], array() ); 
  929. elseif ( $this->is_home_static_page() ) { 
  930. $keywords = WPSEO_Meta::get_value( 'metakeywords' ); 
  931. if ( $keywords === '' && ( is_object( $post ) && ( isset( $this->options[ 'metakey-' . $post->post_type ] ) && $this->options[ 'metakey-' . $post->post_type ] !== '' ) ) ) { 
  932. $keywords = wpseo_replace_vars( $this->options[ 'metakey-' . $post->post_type ], $post ); 
  933. elseif ( $this->is_posts_page() ) { 
  934. $keywords = $this->get_keywords( get_post( get_option( 'page_for_posts' ) ) ); 
  935. elseif ( is_category() || is_tag() || is_tax() ) { 
  936. $term = $wp_query->get_queried_object(); 
  937.  
  938. if ( is_object( $term ) ) { 
  939. $keywords = WPSEO_Taxonomy_Meta::get_term_meta( $term, $term->taxonomy, 'metakey' ); 
  940. if ( ( ! is_string( $keywords ) || $keywords === '' ) && ( isset( $this->options[ 'metakey-tax-' . $term->taxonomy ] ) && $this->options[ 'metakey-tax-' . $term->taxonomy ] !== '' ) ) { 
  941. $keywords = wpseo_replace_vars( $this->options[ 'metakey-tax-' . $term->taxonomy ], $term ); 
  942. elseif ( is_author() ) { 
  943. $author_id = get_query_var( 'author' ); 
  944. $keywords = get_the_author_meta( 'metakey', $author_id ); 
  945. if ( ! $keywords && $this->options['metakey-author-wpseo'] !== '' ) { 
  946. $keywords = wpseo_replace_vars( $this->options['metakey-author-wpseo'], $wp_query->get_queried_object() ); 
  947. elseif ( is_post_type_archive() ) { 
  948. $post_type = get_query_var( 'post_type' ); 
  949. if ( is_array( $post_type ) ) { 
  950. $post_type = reset( $post_type ); 
  951. if ( isset( $this->options[ 'metakey-ptarchive-' . $post_type ] ) && $this->options[ 'metakey-ptarchive-' . $post_type ] !== '' ) { 
  952. $keywords = wpseo_replace_vars( $this->options[ 'metakey-ptarchive-' . $post_type ], $wp_query->get_queried_object() ); 
  953.  
  954. $keywords = apply_filters( 'wpseo_metakey', trim( $keywords ) ); // TODO Make deprecated. 
  955.  
  956. /** 
  957. * Filter: 'wpseo_metakeywords' - Allow changing the Yoast SEO meta keywords 
  958. * @api string $keywords The meta keywords to be echoed. 
  959. */ 
  960. $keywords = apply_filters( 'wpseo_metakeywords', trim( $keywords ) ); // More appropriately named. 
  961.  
  962. if ( is_string( $keywords ) && $keywords !== '' ) { 
  963. echo '<meta name="keywords" content="', esc_attr( strip_tags( stripslashes( $keywords ) ) ), '"/>', "\n"; 
  964.  
  965. /** 
  966. * Outputs the meta description element or returns the description text. 
  967. * @param bool $echo Echo or return output flag. 
  968. * @return string 
  969. */ 
  970. public function metadesc( $echo = true ) { 
  971. if ( is_null( $this->metadesc ) ) { 
  972. $this->generate_metadesc(); 
  973.  
  974. if ( $echo !== false ) { 
  975. if ( is_string( $this->metadesc ) && $this->metadesc !== '' ) { 
  976. echo '<meta name="description" content="', esc_attr( strip_tags( stripslashes( $this->metadesc ) ) ), '"/>', "\n"; 
  977. $this->add_robot_content_noodp( $this->metadesc ); 
  978. elseif ( current_user_can( 'manage_options' ) && is_singular() ) { 
  979. echo '<!-- ', __( 'Admin only notice: this page doesn\'t show a meta description because it doesn\'t have one, either write it for this page specifically or go into the SEO -> Titles menu and set up a template.', 'wordpress-seo' ), ' -->', "\n"; 
  980. else { 
  981. return $this->metadesc; 
  982.  
  983. /** 
  984. * Generates the meta description text. 
  985. */ 
  986. private function generate_metadesc() { 
  987. global $post, $wp_query; 
  988.  
  989. $metadesc = ''; 
  990. $metadesc_override = false; 
  991. $post_type = ''; 
  992. $template = ''; 
  993.  
  994. if ( is_object( $post ) && ( isset( $post->post_type ) && $post->post_type !== '' ) ) { 
  995. $post_type = $post->post_type; 
  996.  
  997. if ( is_singular() ) { 
  998. if ( ( $metadesc === '' && $post_type !== '' ) && isset( $this->options[ 'metadesc-' . $post_type ] ) ) { 
  999. $template = $this->options[ 'metadesc-' . $post_type ]; 
  1000. $term = $post; 
  1001. $metadesc_override = WPSEO_Meta::get_value( 'metadesc' ); 
  1002. else { 
  1003. if ( is_search() ) { 
  1004. $metadesc = ''; 
  1005. elseif ( $this->is_home_posts_page() ) { 
  1006. $template = $this->options['metadesc-home-wpseo']; 
  1007. $term = array(); 
  1008.  
  1009. if ( empty( $template ) ) { 
  1010. $template = get_bloginfo( 'description' ); 
  1011. elseif ( $this->is_posts_page() ) { 
  1012. $metadesc = WPSEO_Meta::get_value( 'metadesc', get_option( 'page_for_posts' ) ); 
  1013. if ( ( $metadesc === '' && $post_type !== '' ) && isset( $this->options[ 'metadesc-' . $post_type ] ) ) { 
  1014. $page = get_post( get_option( 'page_for_posts' ) ); 
  1015. $template = $this->options[ 'metadesc-' . $post_type ]; 
  1016. $term = $page; 
  1017. elseif ( $this->is_home_static_page() ) { 
  1018. $metadesc = WPSEO_Meta::get_value( 'metadesc' ); 
  1019. if ( ( $metadesc === '' && $post_type !== '' ) && isset( $this->options[ 'metadesc-' . $post_type ] ) ) { 
  1020. $template = $this->options[ 'metadesc-' . $post_type ]; 
  1021. elseif ( is_category() || is_tag() || is_tax() ) { 
  1022. $term = $wp_query->get_queried_object(); 
  1023. $metadesc_override = WPSEO_Taxonomy_Meta::get_term_meta( $term, $term->taxonomy, 'desc' ); 
  1024. if ( is_object( $term ) && isset( $term->taxonomy, $this->options[ 'metadesc-tax-' . $term->taxonomy ] ) ) { 
  1025. $template = $this->options[ 'metadesc-tax-' . $term->taxonomy ]; 
  1026. elseif ( is_author() ) { 
  1027. $author_id = get_query_var( 'author' ); 
  1028. $metadesc = get_the_author_meta( 'wpseo_metadesc', $author_id ); 
  1029. if ( ( ! is_string( $metadesc ) || $metadesc === '' ) && '' !== $this->options['metadesc-author-wpseo'] ) { 
  1030. $template = $this->options['metadesc-author-wpseo']; 
  1031. elseif ( is_post_type_archive() ) { 
  1032. $post_type = get_query_var( 'post_type' ); 
  1033. if ( is_array( $post_type ) ) { 
  1034. $post_type = reset( $post_type ); 
  1035. if ( isset( $this->options[ 'metadesc-ptarchive-' . $post_type ] ) ) { 
  1036. $template = $this->options[ 'metadesc-ptarchive-' . $post_type ]; 
  1037. elseif ( is_archive() ) { 
  1038. $template = $this->options['metadesc-archive-wpseo']; 
  1039.  
  1040. // If we're on a paginated page, and the template doesn't change for paginated pages, bail. 
  1041. if ( ( ! is_string( $metadesc ) || $metadesc === '' ) && get_query_var( 'paged' ) && get_query_var( 'paged' ) > 1 && $template !== '' ) { 
  1042. if ( strpos( $template, '%%page' ) === false ) { 
  1043. $metadesc = ''; 
  1044.  
  1045. $post_data = $post; 
  1046.  
  1047. if ( is_string( $metadesc_override ) && '' !== $metadesc_override ) { 
  1048. $metadesc = $metadesc_override; 
  1049. if ( isset( $term ) ) { 
  1050. $post_data = $term; 
  1051. else if ( ( ! is_string( $metadesc ) || '' === $metadesc ) && '' !== $template ) { 
  1052. if ( ! isset( $term ) ) { 
  1053. $term = $wp_query->get_queried_object(); 
  1054.  
  1055. $metadesc = $template; 
  1056. $post_data = $term; 
  1057.  
  1058. $metadesc = wpseo_replace_vars( $metadesc, $post_data ); 
  1059.  
  1060. /** 
  1061. * Filter: 'wpseo_metadesc' - Allow changing the Yoast SEO meta description sentence. 
  1062. * @api string $metadesc The description sentence. 
  1063. */ 
  1064. $this->metadesc = apply_filters( 'wpseo_metadesc', trim( $metadesc ) ); 
  1065.  
  1066. /** 
  1067. * Based on the redirect meta value, this function determines whether it should redirect the current post / page. 
  1068. * @return boolean 
  1069. */ 
  1070. function page_redirect() { 
  1071. if ( is_singular() ) { 
  1072. global $post; 
  1073. if ( ! isset( $post ) || ! is_object( $post ) ) { 
  1074. return false; 
  1075.  
  1076. $redir = WPSEO_Meta::get_value( 'redirect', $post->ID ); 
  1077. if ( $redir !== '' ) { 
  1078. wp_redirect( $redir, 301 ); 
  1079. exit; 
  1080.  
  1081. return false; 
  1082.  
  1083. /** 
  1084. * Outputs noindex values for the current page. 
  1085. */ 
  1086. public function noindex_page() { 
  1087. echo '<meta name="robots" content="noindex" />', "\n"; 
  1088.  
  1089. /** 
  1090. * Send a Robots HTTP header preventing URL from being indexed in the search results while allowing search engines 
  1091. * to follow the links in the object at the URL. 
  1092. * @since 1.1.7 
  1093. * @return boolean Boolean indicating whether the noindex header was sent 
  1094. */ 
  1095. public function noindex_feed() { 
  1096.  
  1097. if ( ( is_feed() || is_robots() ) && headers_sent() === false ) { 
  1098. header( 'X-Robots-Tag: noindex, follow', true ); 
  1099.  
  1100. return true; 
  1101.  
  1102. return false; 
  1103.  
  1104. /** 
  1105. * Adds rel="nofollow" to a link, only used for login / registration links. 
  1106. * @param string $input The link element as a string. 
  1107. * @return string 
  1108. */ 
  1109. public function nofollow_link( $input ) { 
  1110. return str_replace( '<a ', '<a rel="nofollow" ', $input ); 
  1111.  
  1112. /** 
  1113. * When certain archives are disabled, this redirects those to the homepage. 
  1114. * @return boolean False when no redirect was triggered 
  1115. */ 
  1116. function archive_redirect() { 
  1117. global $wp_query; 
  1118.  
  1119. if ( 
  1120. ( $this->options['disable-date'] === true && $wp_query->is_date ) || 
  1121. ( $this->options['disable-author'] === true && $wp_query->is_author ) || 
  1122. ( $this->options['disable-post_format'] === true && $wp_query->is_tax( 'post_format' ) ) 
  1123. ) { 
  1124. wp_safe_redirect( get_bloginfo( 'url' ), 301 ); 
  1125. exit; 
  1126.  
  1127. return false; 
  1128.  
  1129. /** 
  1130. * If the option to redirect attachments to their parent is checked, this performs the redirect. 
  1131. * An extra check is done for when the attachment has no parent. 
  1132. * @return boolean False when no redirect was triggered 
  1133. */ 
  1134. function attachment_redirect() { 
  1135. global $post; 
  1136. if ( is_attachment() && ( ( is_object( $post ) && isset( $post->post_parent ) ) && ( is_numeric( $post->post_parent ) && $post->post_parent != 0 ) ) ) { 
  1137. wp_safe_redirect( get_permalink( $post->post_parent ), 301 ); 
  1138. exit; 
  1139.  
  1140. return false; 
  1141.  
  1142. /** 
  1143. * Trailing slashes for everything except is_single(). 
  1144. * Thanks to Mark Jaquith for this code. 
  1145. * @param string $url URL string. 
  1146. * @param string $type Context (such as single). 
  1147. * @return string 
  1148. */ 
  1149. function add_trailingslash( $url, $type ) { 
  1150. if ( 'single' === $type || 'single_paged' === $type ) { 
  1151. return $url; 
  1152. else { 
  1153. return trailingslashit( $url ); 
  1154.  
  1155. /** 
  1156. * Removes the ?replytocom variable from the link, replacing it with a #comment-<number> anchor. 
  1157. * @todo Should this function also allow for relative urls ? 
  1158. * @param string $link The comment link as a string. 
  1159. * @return string 
  1160. */ 
  1161. public function remove_reply_to_com( $link ) { 
  1162. return preg_replace( '`href=(["\'])(?:.*(?:\?|&|&)replytocom=(\d+)#respond)`', 'href=$1#comment-$2', $link ); 
  1163.  
  1164. /** 
  1165. * Redirect out the ?replytocom variables when cleanreplytocom is enabled 
  1166. * @since 1.4.13 
  1167. * @return boolean 
  1168. */ 
  1169. function replytocom_redirect() { 
  1170.  
  1171. if ( isset( $_GET['replytocom'] ) && is_singular() ) { 
  1172. $url = get_permalink( $GLOBALS['post']->ID ); 
  1173. $hash = sanitize_text_field( $_GET['replytocom'] ); 
  1174. $query_string = remove_query_arg( 'replytocom', sanitize_text_field( $_SERVER['QUERY_STRING'] ) ); 
  1175. if ( ! empty( $query_string ) ) { 
  1176. $url .= '?' . $query_string; 
  1177. $url .= '#comment-' . $hash; 
  1178. wp_safe_redirect( $url, 301 ); 
  1179. exit; 
  1180.  
  1181. return false; 
  1182.  
  1183. /** 
  1184. * Removes unneeded query variables from the URL. 
  1185. * @return boolean 
  1186. */ 
  1187. public function clean_permalink() { 
  1188. if ( is_robots() || get_query_var( 'sitemap' ) || empty( $_GET ) ) { 
  1189. return false; 
  1190.  
  1191. global $wp_query; 
  1192.  
  1193. // Recreate current URL. 
  1194. $cururl = 'http'; 
  1195. if ( isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] == 'on' ) { 
  1196. $cururl .= 's'; 
  1197. $cururl .= '://'; 
  1198.  
  1199. if ( $_SERVER['SERVER_PORT'] != '80' && $_SERVER['SERVER_PORT'] != '443' ) { 
  1200. $cururl .= $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT'] . $_SERVER['REQUEST_URI']; 
  1201. else { 
  1202. $cururl .= $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']; 
  1203. $properurl = ''; 
  1204.  
  1205. if ( is_singular() ) { 
  1206. global $post; 
  1207. if ( empty( $post ) ) { 
  1208. $post = $wp_query->get_queried_object(); 
  1209.  
  1210. $properurl = get_permalink( $post->ID ); 
  1211.  
  1212. $page = get_query_var( 'page' ); 
  1213. if ( $page && $page != 1 ) { 
  1214. $post = get_post( $post->ID ); 
  1215. $page_count = substr_count( $post->post_content, '<!--nextpage-->' ); 
  1216. if ( $page > ( $page_count + 1 ) ) { 
  1217. $properurl = user_trailingslashit( trailingslashit( $properurl ) . ( $page_count + 1 ) ); 
  1218. else { 
  1219. $properurl = user_trailingslashit( trailingslashit( $properurl ) . $page ); 
  1220.  
  1221. // Fix reply to comment links, whoever decided this should be a GET variable? 
  1222. if ( preg_match( '`(\?replytocom=[^&]+)`', sanitize_text_field( $_SERVER['REQUEST_URI'] ), $matches ) ) { 
  1223. $properurl .= str_replace( '?replytocom=', '#comment-', $matches[0] ); 
  1224. unset( $matches ); 
  1225.  
  1226. // Prevent cleaning out posts & page previews for people capable of viewing them. 
  1227. if ( isset( $_GET['preview'], $_GET['preview_nonce'] ) && current_user_can( 'edit_post' ) ) { 
  1228. $properurl = ''; 
  1229. elseif ( is_front_page() ) { 
  1230. if ( $this->is_home_posts_page() ) { 
  1231. $properurl = get_bloginfo( 'url' ) . '/'; 
  1232. elseif ( $this->is_home_static_page() ) { 
  1233. $properurl = get_permalink( $GLOBALS['post']->ID ); 
  1234. elseif ( is_category() || is_tag() || is_tax() ) { 
  1235. $term = $wp_query->get_queried_object(); 
  1236. if ( is_feed() ) { 
  1237. $properurl = get_term_feed_link( $term->term_id, $term->taxonomy ); 
  1238. else { 
  1239. $properurl = get_term_link( $term, $term->taxonomy ); 
  1240. elseif ( is_search() ) { 
  1241. $s = urlencode( preg_replace( '`(%20|\+)`', ' ', get_search_query() ) ); 
  1242. $properurl = get_bloginfo( 'url' ) . '/?s=' . $s; 
  1243. elseif ( is_404() ) { 
  1244. if ( is_multisite() && ! is_subdomain_install() && is_main_site() ) { 
  1245. if ( $cururl == get_bloginfo( 'url' ) . '/blog/' || $cururl == get_bloginfo( 'url' ) . '/blog' ) { 
  1246. if ( $this->is_home_static_page() ) { 
  1247. $properurl = get_permalink( get_option( 'page_for_posts' ) ); 
  1248. else { 
  1249. $properurl = get_bloginfo( 'url' ) . '/'; 
  1250.  
  1251. if ( ! empty( $properurl ) && $wp_query->query_vars['paged'] != 0 && $wp_query->post_count != 0 ) { 
  1252. if ( is_search() && ! empty( $s ) ) { 
  1253. $properurl = get_bloginfo( 'url' ) . '/page/' . $wp_query->query_vars['paged'] . '/?s=' . $s; 
  1254. else { 
  1255. $properurl = user_trailingslashit( trailingslashit( $properurl ) . 'page/' . $wp_query->query_vars['paged'] ); 
  1256.  
  1257. // Prevent cleaning out the WP Subscription managers interface for everyone. 
  1258. if ( isset( $_GET['wp-subscription-manager'] ) ) { 
  1259. $properurl = ''; 
  1260.  
  1261. /** 
  1262. * Filter: 'wpseo_whitelist_permalink_vars' - Allow plugins to register their own variables not to clean 
  1263. * @api array $unsigned Array of permalink variables _not_ to clean. Empty by default. 
  1264. */ 
  1265. $whitelisted_extravars = apply_filters( 'wpseo_whitelist_permalink_vars', array() ); 
  1266.  
  1267. if ( $this->options['cleanpermalink-googlesitesearch'] === true ) { 
  1268. // Prevent cleaning out Google Site searches. 
  1269. $whitelisted_extravars = array_merge( $whitelisted_extravars, array( 
  1270. 'q',  
  1271. 'cx',  
  1272. 'debug',  
  1273. 'cof',  
  1274. 'ie',  
  1275. 'sa',  
  1276. ) ); 
  1277.  
  1278. if ( $this->options['cleanpermalink-googlecampaign'] === true ) { 
  1279. // Prevent cleaning out Google Analytics campaign variables. 
  1280. $whitelisted_extravars = array_merge( $whitelisted_extravars, array( 
  1281. 'utm_campaign',  
  1282. 'utm_medium',  
  1283. 'utm_source',  
  1284. 'utm_content',  
  1285. 'utm_term',  
  1286. 'utm_id',  
  1287. 'gclid',  
  1288. ) ); 
  1289.  
  1290. if ( $this->options['cleanpermalink-extravars'] !== '' ) { 
  1291. $extravars = explode( ', ', $this->options['cleanpermalink-extravars'] ); 
  1292. $extravars = array_map( 'trim', $extravars ); 
  1293. $whitelisted_extravars = array_merge( $whitelisted_extravars, $extravars ); 
  1294. unset( $extravars ); 
  1295.  
  1296. foreach ( $whitelisted_extravars as $get ) { 
  1297. if ( isset( $_GET[ trim( $get ) ] ) ) { 
  1298. $properurl = ''; 
  1299. unset( $get ); 
  1300.  
  1301. if ( ! empty( $properurl ) && $cururl != $properurl ) { 
  1302. wp_safe_redirect( $properurl, 301 ); 
  1303. exit; 
  1304.  
  1305. /** 
  1306. * Replaces the possible RSS variables with their actual values. 
  1307. * @param string $content The RSS content that should have the variables replaced. 
  1308. * @return string 
  1309. */ 
  1310. function rss_replace_vars( $content ) { 
  1311. global $post; 
  1312.  
  1313. /** 
  1314. * Allow the developer to determine whether or not to follow the links in the bits Yoast SEO adds to the RSS feed, defaults to true. 
  1315. * @api bool $unsigned Whether or not to follow the links in RSS feed, defaults to true. 
  1316. * @since 1.4.20 
  1317. */ 
  1318. $no_follow = apply_filters( 'nofollow_rss_links', true ); 
  1319. $no_follow_attr = ''; 
  1320. if ( $no_follow === true ) { 
  1321. $no_follow_attr = 'rel="nofollow" '; 
  1322.  
  1323. $author_link = ''; 
  1324. if ( is_object( $post ) ) { 
  1325. $author_link = '<a ' . $no_follow_attr . 'href="' . esc_url( get_author_posts_url( $post->post_author ) ) . '">' . get_the_author() . '</a>'; 
  1326.  
  1327. $post_link = '<a ' . $no_follow_attr . 'href="' . esc_url( get_permalink() ) . '">' . get_the_title() . '</a>'; 
  1328. $blog_link = '<a ' . $no_follow_attr . 'href="' . esc_url( get_bloginfo( 'url' ) ) . '">' . get_bloginfo( 'name' ) . '</a>'; 
  1329. $blog_desc_link = '<a ' . $no_follow_attr . 'href="' . esc_url( get_bloginfo( 'url' ) ) . '">' . get_bloginfo( 'name' ) . ' - ' . strip_tags( get_bloginfo( 'description' ) ) . '</a>'; 
  1330.  
  1331. $content = stripslashes( trim( $content ) ); 
  1332. $content = str_replace( '%%AUTHORLINK%%', $author_link, $content ); 
  1333. $content = str_replace( '%%POSTLINK%%', $post_link, $content ); 
  1334. $content = str_replace( '%%BLOGLINK%%', $blog_link, $content ); 
  1335. $content = str_replace( '%%BLOGDESCLINK%%', $blog_desc_link, $content ); 
  1336.  
  1337. return $content; 
  1338.  
  1339. /** 
  1340. * Adds the RSS footer (or header) to the full RSS feed item. 
  1341. * @param string $content Feed item content. 
  1342. * @return string 
  1343. */ 
  1344. function embed_rssfooter( $content ) { 
  1345. return $this->embed_rss( $content, 'full' ); 
  1346.  
  1347. /** 
  1348. * Adds the RSS footer (or header) to the excerpt RSS feed item. 
  1349. * @param string $content Feed item excerpt. 
  1350. * @return string 
  1351. */ 
  1352. function embed_rssfooter_excerpt( $content ) { 
  1353. return $this->embed_rss( $content, 'excerpt' ); 
  1354.  
  1355. /** 
  1356. * Adds the RSS footer and/or header to an RSS feed item. 
  1357. * @since 1.4.14 
  1358. * @param string $content Feed item content. 
  1359. * @param string $context Feed item context, either 'excerpt' or 'full'. 
  1360. * @return string 
  1361. */ 
  1362. function embed_rss( $content, $context = 'full' ) { 
  1363.  
  1364. /** 
  1365. * Filter: 'wpseo_include_rss_footer' - Allow the RSS footer to be dynamically shown/hidden. 
  1366. * @api boolean $show_embed Indicates if the RSS footer should be shown or not 
  1367. * @param string $context The context of the RSS content - 'full' or 'excerpt'. 
  1368. */ 
  1369. if ( ! apply_filters( 'wpseo_include_rss_footer', true, $context ) ) { 
  1370. return $content; 
  1371.  
  1372. if ( is_feed() ) { 
  1373. $before = ''; 
  1374. $after = ''; 
  1375.  
  1376. if ( $this->options['rssbefore'] !== '' ) { 
  1377. $before = wpautop( $this->rss_replace_vars( $this->options['rssbefore'] ) ); 
  1378. if ( $this->options['rssafter'] !== '' ) { 
  1379. $after = wpautop( $this->rss_replace_vars( $this->options['rssafter'] ) ); 
  1380. if ( $before !== '' || $after !== '' ) { 
  1381. if ( ( isset( $context ) && $context === 'excerpt' ) && trim( $content ) !== '' ) { 
  1382. $content = wpautop( $content ); 
  1383. $content = $before . $content . $after; 
  1384.  
  1385. return $content; 
  1386.  
  1387.  
  1388. /** 
  1389. * Used in the force rewrite functionality this retrieves the output, replaces the title with the proper SEO 
  1390. * title and then flushes the output. 
  1391. */ 
  1392. function flush_cache() { 
  1393.  
  1394. global $wp_query; 
  1395.  
  1396. if ( $this->ob_started !== true ) { 
  1397. return false; 
  1398.  
  1399. $content = ob_get_clean(); 
  1400.  
  1401. $old_wp_query = $wp_query; 
  1402.  
  1403. wp_reset_query(); 
  1404.  
  1405. $title = $this->title( '' ); 
  1406.  
  1407. // Find all titles, strip them out and add the new one in within the debug marker, so it's easily identified whether a site uses force rewrite. 
  1408. $content = preg_replace( '/<title.*?\/title>/i', '', $content ); 
  1409. $content = str_replace( $this->debug_mark( false ), $this->debug_mark( false ) . "\n" . '<title>' . $title . '</title>', $content ); 
  1410.  
  1411. $GLOBALS['wp_query'] = $old_wp_query; 
  1412.  
  1413. echo $content; 
  1414.  
  1415. return true; 
  1416.  
  1417. /** 
  1418. * Starts the output buffer so it can later be fixed by flush_cache() 
  1419. */ 
  1420. function force_rewrite_output_buffer() { 
  1421. $this->ob_started = true; 
  1422. ob_start(); 
  1423.  
  1424. /** 
  1425. * Function used in testing whether the title should be force rewritten or not. 
  1426. * @param string $title Title string. 
  1427. * @return string 
  1428. */ 
  1429. function title_test_helper( $title ) { 
  1430. $wpseo_titles = get_option( 'wpseo_titles' ); 
  1431.  
  1432. $wpseo_titles['title_test'] ++; 
  1433. update_option( 'wpseo_titles', $wpseo_titles ); 
  1434.  
  1435. // Prevent this setting from being on forever when something breaks, as it breaks caching. 
  1436. if ( $wpseo_titles['title_test'] > 5 ) { 
  1437. $wpseo_titles['title_test'] = 0; 
  1438. update_option( 'wpseo_titles', $wpseo_titles ); 
  1439.  
  1440. remove_filter( 'wpseo_title', array( $this, 'title_test_helper' ) ); 
  1441.  
  1442. return $title; 
  1443.  
  1444. if ( ! defined( 'DONOTCACHEPAGE' ) ) { 
  1445. define( 'DONOTCACHEPAGE', true ); 
  1446. if ( ! defined( 'DONOTCACHCEOBJECT' ) ) { 
  1447. define( 'DONOTCACHCEOBJECT', true ); 
  1448. if ( ! defined( 'DONOTMINIFY' ) ) { 
  1449. define( 'DONOTMINIFY', true ); 
  1450.  
  1451. if ( $_SERVER['HTTP_USER_AGENT'] === "WordPress/{$GLOBALS['wp_version']}; " . get_bloginfo( 'url' ) . ' - Yoast' ) { 
  1452. return 'This is a Yoast Test Title'; 
  1453.  
  1454. return $title; 
  1455.  
  1456. /** 
  1457. * Get the product name in the head section 
  1458. * @return string 
  1459. */ 
  1460. private function head_product_name() { 
  1461. if ( $this->is_premium() ) { 
  1462. return 'Yoast SEO Premium plugin'; 
  1463. else { 
  1464. return 'Yoast SEO plugin'; 
  1465.  
  1466. /** 
  1467. * Check if this plugin is the premium version of WPSEO 
  1468. * @return bool 
  1469. */ 
  1470. private function is_premium() { 
  1471. return file_exists( WPSEO_PATH . 'premium/' ); 
  1472.  
  1473. /** 
  1474. * Checks whether the user has written a meta-description. If written, makes sure meta robots content is noodp. 
  1475. * @param String $description The content of the meta description. 
  1476. */ 
  1477. private function add_robot_content_noodp( $description ) { 
  1478. if ( ! ( empty( $description ) ) && $this->options['noodp'] === false ) { 
  1479. $this->options['noodp'] = true; 
  1480.  
  1481. /** 
  1482. * Getting the keywords 
  1483. * @param WP_Post $post The post object with the values. 
  1484. * @return string 
  1485. */ 
  1486. private function get_keywords( $post ) { 
  1487. $keywords = WPSEO_Meta::get_value( 'metakeywords', $post->ID ); 
  1488. $option_meta_key = 'metakey-' . $post->post_type; 
  1489.  
  1490. if ( $keywords === '' && ( is_object( $post ) && ( isset( $this->options[ $option_meta_key ] ) && $this->options[ $option_meta_key ] !== '' ) ) ) { 
  1491. $keywords = wpseo_replace_vars( $this->options[ $option_meta_key ], $post ); 
  1492.  
  1493. return $keywords; 
  1494.  
  1495. /** 
  1496. * Check if term archive query is for multiple terms (/term-1, term2/ or /term-1+term-2/). 
  1497. * @return bool 
  1498. */ 
  1499. protected function is_multiple_terms_query() { 
  1500.  
  1501. global $wp_query; 
  1502.  
  1503. if ( ! is_tax() && ! is_tag() && ! is_category() ) { 
  1504. return false; 
  1505.  
  1506. $term = get_queried_object(); 
  1507. $queried_terms = $wp_query->tax_query->queried_terms; 
  1508.  
  1509. if ( empty( $queried_terms[ $term->taxonomy ]['terms'] ) ) { 
  1510. return false; 
  1511.  
  1512. return count( $queried_terms[ $term->taxonomy ]['terms'] ) > 1; 
  1513.  
  1514. /** Deprecated functions */ 
  1515. // @codeCoverageIgnoreStart 
  1516. /** 
  1517. * Outputs or returns the debug marker, which is also used for title replacement when force rewrite is active. 
  1518. * @deprecated 4.4 
  1519. * @param bool $echo Whether or not to echo the debug marker. 
  1520. * @return string 
  1521. */ 
  1522. public function debug_marker( $echo = false ) { 
  1523. return $this->debug_mark( $echo ); 
  1524.  
  1525. // @codeCoverageIgnoreEnd