1. <?php
  2. /**
  3. * @package Frontend
  4. *
  5. * Main frontend code.
  6. */
  7.  
  8. if ( !defined( 'WPSEO_VERSION' ) ) {
  9. header( 'HTTP/1.0 403 Forbidden' );
  10. die;
  11. }
  12.  
  13. /**
  14. * Main frontend class for WordPress SEO, responsible for the SEO output as well as removing default WordPress output.
  15. *
  16. * @package WPSEO_Frontend
  17. */
  18. class WPSEO_Frontend {
  19.  
  20. /**
  21. * @var array Holds the plugins options.
  22. */
  23. var $options = array();
  24.  
  25. /**
  26. * Class constructor
  27. *
  28. * Adds and removes a lot of filters.
  29. */
  30. function __construct() {
  31.  
  32. $this->options = get_wpseo_options();
  33.  
  34. add_action( 'wp_head', array( $this, 'head' ), 1 );
  35.  
  36. // The head function here calls action wpseo_head, to which we hook all our functionality
  37. add_action( 'wpseo_head', array( $this, 'debug_marker' ), 2 );
  38. add_action( 'wpseo_head', array( $this, 'robots' ), 6 );
  39. add_action( 'wpseo_head', array( $this, 'metadesc' ), 10 );
  40. add_action( 'wpseo_head', array( $this, 'metakeywords' ), 11 );
  41. add_action( 'wpseo_head', array( $this, 'canonical' ), 20 );
  42. add_action( 'wpseo_head', array( $this, 'adjacent_rel_links' ), 21 );
  43. add_action( 'wpseo_head', array( $this, 'author' ), 22 );
  44. add_action( 'wpseo_head', array( $this, 'publisher' ), 23 );
  45. add_action( 'wpseo_head', array( $this, 'webmaster_tools_authentication' ), 90 );
  46.  
  47. // Remove actions that we will handle through our wpseo_head call, and probably change the output of
  48. remove_action( 'wp_head', 'rel_canonical' );
  49. remove_action( 'wp_head', 'index_rel_link' );
  50. remove_action( 'wp_head', 'start_post_rel_link' );
  51. remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head' );
  52.  
  53. add_filter( 'wp_title', array( $this, 'title' ), 15, 3 );
  54. add_filter( 'thematic_doctitle', array( $this, 'title' ), 15 );
  55.  
  56. add_action( 'wp', array( $this, 'page_redirect' ), 99, 1 );
  57.  
  58. add_action( 'template_redirect', array( $this, 'noindex_feed' ) );
  59.  
  60. add_filter( 'loginout', array( $this, 'nofollow_link' ) );
  61. add_filter( 'register', array( $this, 'nofollow_link' ) );
  62.  
  63. if ( isset( $this->options['hide-rsdlink'] ) && $this->options['hide-rsdlink'] )
  64. remove_action( 'wp_head', 'rsd_link' );
  65.  
  66. if ( isset( $this->options['hide-wlwmanifest'] ) && $this->options['hide-wlwmanifest'] )
  67. remove_action( 'wp_head', 'wlwmanifest_link' );
  68.  
  69. if ( isset( $this->options['hide-shortlink'] ) && $this->options['hide-shortlink'] ) {
  70. remove_action( 'wp_head', 'wp_shortlink_wp_head' );
  71. remove_action( 'template_redirect', 'wp_shortlink_header' );
  72. }
  73. if ( isset( $this->options['hide-feedlinks'] ) && $this->options['hide-feedlinks'] ) {
  74. // @todo: add option to display just normal feed and hide comment feed.
  75. remove_action( 'wp_head', 'feed_links', 2 );
  76. remove_action( 'wp_head', 'feed_links_extra', 3 );
  77. }
  78.  
  79. if ( ( isset( $this->options['disable-date'] ) && $this->options['disable-date'] ) ||
  80. ( isset( $this->options['disable-author'] ) && $this->options['disable-author'] ) ||
  81. ( isset( $this->options['disable-post_formats'] ) && $this->options['disable-post_formats'] )
  82. )
  83. add_action( 'wp', array( $this, 'archive_redirect' ) );
  84.  
  85. if ( isset( $this->options['redirectattachment'] ) && $this->options['redirectattachment'] )
  86. add_action( 'template_redirect', array( $this, 'attachment_redirect' ), 1 );
  87.  
  88. if ( isset( $this->options['trailingslash'] ) && $this->options['trailingslash'] )
  89. add_filter( 'user_trailingslashit', array( $this, 'add_trailingslash' ), 10, 2 );
  90.  
  91. if ( isset( $this->options['cleanpermalinks'] ) && $this->options['cleanpermalinks'] )
  92. add_action( 'template_redirect', array( $this, 'clean_permalink' ), 1 );
  93.  
  94. if ( isset( $this->options['cleanreplytocom'] ) && $this->options['cleanreplytocom'] )
  95. add_filter( 'comment_reply_link', array( $this, 'remove_reply_to_com' ) );
  96.  
  97. add_filter( 'the_content_feed', array( $this, 'embed_rssfooter' ) );
  98. add_filter( 'the_excerpt_rss', array( $this, 'embed_rssfooter_excerpt' ) );
  99.  
  100. if ( isset( $this->options['forcerewritetitle'] ) && $this->options['forcerewritetitle'] ) {
  101. add_action( 'get_header', array( $this, 'force_rewrite_output_buffer' ) );
  102. add_action( 'wp_footer', array( $this, 'flush_cache' ) );
  103. }
  104.  
  105. if ( isset( $this->options['title_test'] ) && $this->options['title_test'] )
  106. add_filter( 'wpseo_title', array( $this, 'title_test_helper' ) );
  107.  
  108. if ( isset( $_GET['replytocom'] ) )
  109. remove_action( 'wp_head', 'wp_no_robots' );
  110.  
  111. }
  112.  
  113. /**
  114. * Determine whether the current page is the homepage and shows posts.
  115. *
  116. * @return bool
  117. */
  118. function is_home_posts_page() {
  119. return ( is_home() && 'page' != get_option( 'show_on_front' ) );
  120. }
  121.  
  122. /**
  123. * Determine whether the current page is a static homepage.
  124. *
  125. * @return bool
  126. */
  127. function is_home_static_page() {
  128. return ( is_front_page() && 'page' == get_option( 'show_on_front' ) && is_page( get_option( 'page_on_front' ) ) );
  129. }
  130.  
  131. /**
  132. * Determine whether this is the posts page, regardless of whether it's the frontpage or not.
  133. *
  134. * @return bool
  135. */
  136. function is_posts_page() {
  137. return ( is_home() && 'page' == get_option( 'show_on_front' ) );
  138. }
  139.  
  140. /**
  141. * Used for static home and posts pages as well as singular titles.
  142. *
  143. * @param object|null $object if filled, object to get the title for
  144. * @return string
  145. */
  146. function get_content_title( $object = null ) {
  147. if ( is_null( $object ) ) {
  148. global $wp_query;
  149. $object = $wp_query->get_queried_object();
  150. }
  151.  
  152. $title = wpseo_get_value( 'title', $object->ID );
  153.  
  154. if ( !empty( $title ) )
  155. return wpseo_replace_vars( $title, (array) $object );
  156.  
  157. return $this->get_title_from_options( 'title-' . $object->post_type, $object );
  158. }
  159.  
  160. /**
  161. * Used for category, tag, and tax titles.
  162. *
  163. * @return string
  164. */
  165. function get_taxonomy_title() {
  166. global $wp_query;
  167. $object = $wp_query->get_queried_object();
  168.  
  169. $title = trim( wpseo_get_term_meta( $object, $object->taxonomy, 'title' ) );
  170.  
  171. if ( !empty( $title ) )
  172. return wpseo_replace_vars( $title, (array) $object );
  173.  
  174. return $this->get_title_from_options( 'title-' . $object->taxonomy, $object );
  175. }
  176.  
  177. /**
  178. * Used for author titles.
  179. *
  180. * @return string
  181. */
  182. function get_author_title() {
  183. $author_id = get_query_var( 'author' );
  184. $title = get_the_author_meta( 'wpseo_title', $author_id );
  185.  
  186. if ( !empty( $title ) )
  187. return wpseo_replace_vars( $title, array() );
  188.  
  189. return $this->get_title_from_options( 'title-author' );
  190. }
  191.  
  192. /**
  193. * Simple function to use to pull data from $options.
  194. *
  195. * All titles pulled from options will be run through the wpseo_replace_vars function.
  196. *
  197. * @param string $index name of the page to get the title from the settings for.
  198. * @param object|array $var_source possible object to pul variables from.
  199. * @return string
  200. */
  201. function get_title_from_options( $index, $var_source = array() ) {
  202. if ( !isset( $this->options[$index] ) || empty( $this->options[$index] ) ) {
  203. if ( is_singular() )
  204. return wpseo_replace_vars( '%%title%% %%sep%% %%sitename%%', (array) $var_source );
  205. else
  206. return '';
  207. }
  208.  
  209. return wpseo_replace_vars( $this->options[$index], (array) $var_source );
  210. }
  211.  
  212. /**
  213. * Get the default title for the current page.
  214. *
  215. * This is the fallback title generator used when a title hasn't been set for the specific content, taxonomy, author
  216. * details, or in the options. It scrubs off any present prefix before or after the title (based on $seplocation) in
  217. * order to prevent duplicate seperations from appearing in the title (this happens when a prefix is supplied to the
  218. * wp_title call on singular pages).
  219. *
  220. * @param string $sep the separator used between variables
  221. * @param string $seplocation Whether the separator should be left or right.
  222. * @param string $title possible title that's already set
  223. * @return string
  224. */
  225. function get_default_title( $sep, $seplocation, $title = '' ) {
  226. if ( 'right' == $seplocation )
  227. $regex = '/\s*' . preg_quote( trim( $sep ), '/' ) . '\s*/';
  228. else
  229. $regex = '/^\s*' . preg_quote( trim( $sep ), '/' ) . '\s*/';
  230. $title = preg_replace( $regex, '', $title );
  231.  
  232. if ( empty( $title ) ) {
  233. $title = get_bloginfo( 'name' );
  234. $title = $this->add_paging_to_title( $sep, $seplocation, $title );
  235. $title = $this->add_to_title( $sep, $seplocation, $title, get_bloginfo( 'description' ) );
  236. return $title;
  237. }
  238.  
  239. $title = $this->add_paging_to_title( $sep, $seplocation, $title );
  240. $title = $this->add_to_title( $sep, $seplocation, $title, get_bloginfo( 'name' ) );
  241. return $title;
  242. }
  243.  
  244. /**
  245. * This function adds paging details to the title.
  246. *
  247. * @param string $sep separator used in the title
  248. * @param string $seplocation Whether the separator should be left or right.
  249. * @param string $title the title to append the paging info to
  250. * @return string
  251. */
  252. function add_paging_to_title( $sep, $seplocation, $title ) {
  253. global $wp_query;
  254.  
  255. if ( !empty( $wp_query->query_vars['paged'] ) && $wp_query->query_vars['paged'] > 1 )
  256. return $this->add_to_title( $sep, $seplocation, $title, $wp_query->query_vars['paged'] . '/' . $wp_query->max_num_pages );
  257.  
  258. return $title;
  259. }
  260.  
  261. /**
  262. * Add part to title, while ensuring that the $seplocation variable is respected.
  263. *
  264. * @param string $sep separator used in the title
  265. * @param string $seplocation Whether the separator should be left or right.
  266. * @param string $title the title to append the title_part to
  267. * @param string $title_part the part to append to the title
  268. * @return string
  269. */
  270. function add_to_title( $sep, $seplocation, $title, $title_part ) {
  271. if ( 'right' == $seplocation )
  272. return $title . $sep . $title_part;
  273. return $title_part . $sep . $title;
  274. }
  275.  
  276. /**
  277. * Main title function.
  278. *
  279. * @param string $title Title that might have already been set.
  280. * @param string $sepinput Separator determined in theme.
  281. * @param string $seplocation Whether the separator should be left or right.
  282. * @return string
  283. */
  284. function title( $title, $sepinput = '-', $seplocation = '' ) {
  285. global $sep;
  286.  
  287. $sep = $sepinput;
  288.  
  289. if ( is_feed() )
  290. return $title;
  291.  
  292. // This needs to be kept track of in order to generate
  293. // default titles for singular pages.
  294. $original_title = $title;
  295.  
  296. // This conditional ensures that sites that use of wp_title(''); as the plugin
  297. // used to suggest will still work properly with these changes.
  298. if ( '' == trim( $sep ) && '' == $seplocation ) {
  299. $sep = '-';
  300. $seplocation = 'right';
  301. } // In the event that $seplocation is left empty, the direction will be
  302. // determined by whether the site is in rtl mode or not. This is based
  303. // upon my findings that rtl sites tend to reverse the flow of the site titles.
  304. else if ( '' == $seplocation )
  305. $seplocation = ( is_rtl() ) ? 'left' : 'right';
  306.  
  307. $sep = ' ' . trim( $sep ) . ' ';
  308.  
  309. // This flag is used to determine if any additional
  310. // processing should be done to the title after the
  311. // main section of title generation completes.
  312. $modified_title = true;
  313.  
  314. // This variable holds the page-specific title part
  315. // that is used to generate default titles.
  316. $title_part = '';
  317.  
  318. if ( $this->is_home_static_page() ) {
  319. $title = $this->get_content_title();
  320. } else if ( $this->is_home_posts_page() ) {
  321. $title = $this->get_title_from_options( 'title-home' );
  322. } else if ( $this->is_posts_page() ) {
  323. $title = $this->get_content_title( get_post( get_option( 'page_for_posts' ) ) );
  324. } else if ( is_singular() ) {
  325. $title = $this->get_content_title();
  326.  
  327. if ( empty( $title ) )
  328. $title_part = $original_title;
  329. } else if ( is_search() ) {
  330. $title = $this->get_title_from_options( 'title-search' );
  331.  
  332. if ( empty( $title ) )
  333. $title_part = sprintf( __( 'Search for "%s"', 'wordpress-seo' ), esc_html( get_search_query() ) );
  334. } else if ( is_category() || is_tag() || is_tax() ) {
  335. $title = $this->get_taxonomy_title();
  336.  
  337. if ( empty( $title ) ) {
  338. if ( is_category() )
  339. $title_part = single_cat_title( '', false );
  340. else if ( is_tag() )
  341. $title_part = single_tag_title( '', false );
  342. else if ( function_exists( 'single_term_title' ) ) {
  343. $title_part = single_term_title( '', false );
  344. } else {
  345. global $wp_query;
  346. $term = $wp_query->get_queried_object();
  347. $title_part = $term->name;
  348. }
  349. }
  350. } else if ( is_author() ) {
  351. $title = $this->get_author_title();
  352.  
  353. if ( empty( $title ) )
  354. $title_part = get_the_author_meta( 'display_name', get_query_var( 'author' ) );
  355. } else if ( function_exists( 'is_post_type_archive' ) && is_post_type_archive() ) {
  356. $post_type = get_query_var( 'post_type' );
  357. $title = $this->get_title_from_options( 'title-ptarchive-' . $post_type );
  358.  
  359. if ( empty( $title ) ) {
  360. $post_type_obj = get_post_type_object( $post_type );
  361. if ( isset( $post_type_obj->labels->menu_name ) )
  362. $title_part = $post_type_obj->labels->menu_name;
  363. else
  364. $title_part = $post_type_obj->name;
  365. }
  366. } else if ( is_archive() ) {
  367. $title = $this->get_title_from_options( 'title-archive' );
  368.  
  369. if ( empty( $title ) ) {
  370. if ( is_month() )
  371. $title_part = sprintf( __( '%s Archives', 'wordpress-seo' ), single_month_title( ' ', false ) );
  372. else if ( is_year() )
  373. $title_part = sprintf( __( '%s Archives', 'wordpress-seo' ), get_query_var( 'year' ) );
  374. else if ( is_day() )
  375. $title_part = sprintf( __( '%s Archives', 'wordpress-seo' ), get_the_date() );
  376. else
  377. $title_part = __( 'Archives', 'wordpress-seo' );
  378. }
  379. } else if ( is_404() ) {
  380. $title = $this->get_title_from_options( 'title-404' );
  381.  
  382. if ( empty( $title ) )
  383. $title_part = __( 'Page not found', 'wordpress-seo' );
  384. } else {
  385. // In case the page type is unknown, leave the title alone.
  386. $modified_title = false;
  387.  
  388. // If you would like to generate a default title instead,
  389. // the following code could be used instead of the line above:
  390. // $title_part = $title;
  391. }
  392.  
  393. if ( ( $modified_title && empty( $title ) ) || !empty( $title_part ) )
  394. $title = $this->get_default_title( $sep, $seplocation, $title_part );
  395. if (bp_is_group() or bp_is_group_forum() or bp_is_group_forum_topic() or bp_is_user() ){
  396. $title = (bp_is_group_forum_topic() ? bp_get_the_topic_title() . ' - ' : '')
  397. . bp_get_current_group_name() . bp_get_displayed_user_fullname() .' - '. $this->get_default_title( $sep, $seplocation, $title_part );
  398. }
  399. return esc_html( strip_tags( stripslashes( apply_filters( 'wpseo_title', $title ) ) ) );
  400. }
  401.  
  402. /**
  403. * Function used when title needs to be force overridden.
  404. *
  405. * @return string
  406. */
  407. function force_wp_title() {
  408. global $wp_query;
  409. $old_wp_query = null;
  410.  
  411. if ( !$wp_query->is_main_query() ) {
  412. $old_wp_query = $wp_query;
  413. wp_reset_query();
  414. }
  415.  
  416. $title = $this->title( '' );
  417.  
  418. if ( !empty( $old_wp_query ) ) {
  419. $GLOBALS['wp_query'] = $old_wp_query;
  420. unset( $old_wp_query );
  421. }
  422.  
  423. return $title;
  424. }
  425.  
  426. /**
  427. * Outputs or returns the debug marker, which is also used for title replacement when force rewrite is active.
  428. *
  429. * @param bool $echo Whether or not to echo the debug marker.
  430. * @return string
  431. */
  432. public function debug_marker( $echo = true ) {
  433. $marker = "<!-- This site is optimized with the Yoast WordPress SEO plugin v" . WPSEO_VERSION . " - http://yoast.com/wordpress/seo/ -->";
  434. if ( $echo === false )
  435. return $marker;
  436. else
  437. echo "\n${marker}\n";
  438. }
  439.  
  440. /**
  441. * Output Webmaster Tools authentication strings
  442. */
  443. public function webmaster_tools_authentication() {
  444. if ( is_front_page() ) {
  445. if ( !empty( $this->options['googleverify'] ) ) {
  446. $google_meta = $this->options['googleverify'];
  447. if ( strpos( $google_meta, 'content' ) ) {
  448. preg_match( '/content="([^"]+)"/', $google_meta, $match );
  449. $google_meta = $match[1];
  450. }
  451. echo "<meta name=\"google-site-verification\" content=\"$google_meta\" />\n";
  452. }
  453.  
  454. if ( !empty( $this->options['msverify'] ) ) {
  455. $bing_meta = $this->options['msverify'];
  456. if ( strpos( $bing_meta, 'content' ) ) {
  457. preg_match( '/content="([^"]+)"/', $bing_meta, $match );
  458. $bing_meta = $match[1];
  459. }
  460. echo "<meta name=\"msvalidate.01\" content=\"$bing_meta\" />\n";
  461. }
  462.  
  463. if ( !empty( $this->options['alexaverify'] ) ) {
  464. echo "<meta name=\"alexaVerifyID\" content=\"" . esc_attr( $this->options['alexaverify'] ) . "\" />\n";
  465. }
  466. }
  467. }
  468.  
  469. /**
  470. * Main wrapper function attached to wp_head. This combines all the output on the frontend of the WP SEO plugin.
  471. */
  472. public function head() {
  473. global $wp_query;
  474.  
  475. $old_wp_query = null;
  476.  
  477. if ( !$wp_query->is_main_query() ) {
  478. $old_wp_query = $wp_query;
  479. wp_reset_query();
  480. }
  481.  
  482. do_action( 'wpseo_head' );
  483.  
  484. echo "<!-- / Yoast WordPress SEO plugin. -->\n\n";
  485.  
  486. if ( !empty( $old_wp_query ) ) {
  487. $GLOBALS['wp_query'] = $old_wp_query;
  488. unset( $old_wp_query );
  489. }
  490.  
  491. return;
  492. }
  493.  
  494. /**
  495. * Output the meta robots value.
  496. */
  497. public function robots() {
  498. global $wp_query;
  499.  
  500. $robots = array();
  501. $robots['index'] = 'index';
  502. $robots['follow'] = 'follow';
  503. $robots['other'] = array();
  504.  
  505. if ( is_singular() ) {
  506. global $post;
  507. if ( isset( $this->options['noindex-' . $post->post_type] ) && $this->options['noindex-' . $post->post_type] )
  508. $robots['index'] = 'noindex';
  509. if ( wpseo_get_value( 'meta-robots-noindex' ) == 1 )
  510. $robots['index'] = 'noindex';
  511. if ( wpseo_get_value( 'meta-robots-noindex' ) == 2 )
  512. $robots['index'] = 'index';
  513. if ( wpseo_get_value( 'meta-robots-nofollow' ) )
  514. $robots['follow'] = 'nofollow';
  515. if ( wpseo_get_value( 'meta-robots-adv' ) && wpseo_get_value( 'meta-robots-adv' ) != 'none' ) {
  516. foreach ( explode( ',', wpseo_get_value( 'meta-robots-adv' ) ) as $r ) {
  517. $robots['other'][] = $r;
  518. }
  519. }
  520. } else {
  521. if ( is_search() ) {
  522. $robots['index'] = 'noindex';
  523. } else if ( is_tax() || is_tag() || is_category() ) {
  524. $term = $wp_query->get_queried_object();
  525. if ( isset( $this->options['noindex-' . $term->taxonomy] ) && $this->options['noindex-' . $term->taxonomy] )
  526. $robots['index'] = 'noindex';
  527.  
  528. // Three possible values, index, noindex and default, do nothing for default
  529. $term_meta = wpseo_get_term_meta( $term, $term->taxonomy, 'noindex' );
  530. if ( 'noindex' == $term_meta || 'on' == $term_meta ) // on is for backwards compatibility
  531. $robots['index'] = 'noindex';
  532.  
  533. if ( 'index' == $term_meta )
  534. $robots['index'] = 'index';
  535. } else if (
  536. ( is_author() && isset( $this->options['noindex-author'] ) && $this->options['noindex-author'] ) ||
  537. ( is_date() && isset( $this->options['noindex-archive'] ) && $this->options['noindex-archive'] ) ||
  538. ( is_home() && get_query_var( 'paged' ) > 1 )
  539. ) {
  540. $robots['index'] = 'noindex';
  541. } else if ( function_exists( 'is_post_type_archive' ) && is_post_type_archive() ) {
  542. $post_type = get_query_var( 'post_type' );
  543. if ( isset( $this->options['noindex-ptarchive-' . $post_type] ) && $this->options['noindex-ptarchive-' . $post_type] )
  544. $robots['index'] = 'noindex';
  545. }
  546.  
  547. if ( $wp_query->query_vars['paged'] && $wp_query->query_vars['paged'] > 1 && isset( $this->options['noindex-subpages'] ) && $this->options['noindex-subpages'] ) {
  548. $robots['index'] = 'noindex';
  549. $robots['follow'] = 'follow';
  550. }
  551. }
  552.  
  553. foreach ( array( 'noodp', 'noydir' ) as $robot ) {
  554. if ( isset( $this->options[$robot] ) && $this->options[$robot] ) {
  555. $robots['other'][] = $robot;
  556. }
  557. }
  558.  
  559. $robotsstr = $robots['index'] . ',' . $robots['follow'];
  560.  
  561. $robots['other'] = array_unique( $robots['other'] );
  562. foreach ( $robots['other'] as $robot ) {
  563. $robotsstr .= ',' . $robot;
  564. }
  565.  
  566. $robotsstr = preg_replace( '/^index,follow,?/', '', $robotsstr );
  567.  
  568. $robotsstr = apply_filters( 'wpseo_robots', $robotsstr );
  569.  
  570. if ( $robotsstr != '' )
  571. echo '<meta name="robots" content="' . esc_attr( $robotsstr ) . '"/>' . "\n";
  572. }
  573.  
  574. /**
  575. * This function normally outputs the canonical but is also used in other places to retrieve the canonical URL
  576. * for the current page.
  577. *
  578. * @param bool $echo Whether or not to output the canonical element.
  579. * @param bool $unpaged Whether or not to return the canonical with or without pagination added to the URL.
  580. * @return string $canonical
  581. */
  582. public function canonical( $echo = true, $unpaged = false ) {
  583. $canonical = false;
  584.  
  585. // Set decent canonicals for homepage, singulars and taxonomy pages
  586. if ( is_singular() ) {
  587. if ( wpseo_get_value( 'canonical' ) && wpseo_get_value( 'canonical' ) != '' ) {
  588. $canonical = wpseo_get_value( 'canonical' );
  589. } else {
  590. $obj = get_queried_object();
  591. $canonical = get_permalink( $obj->ID );
  592.  
  593. // Fix paginated pages canonical, but only if the page is truly paginated.
  594. if ( get_query_var( 'page' ) > 1 ) {
  595. global $wp_rewrite;
  596. $numpages = substr_count( $obj->post_content, '<!--nextpage-->' ) + 1;
  597. if ( $numpages && get_query_var( 'page' ) < $numpages ) {
  598. if ( !$wp_rewrite->using_permalinks() ) {
  599. $canonical = add_query_arg( 'page', get_query_var( 'page' ), $canonical );
  600. } else {
  601. $canonical = user_trailingslashit( trailingslashit( $canonical ) . get_query_var( 'page' ) );
  602. }
  603. }
  604. }
  605. }
  606. } else {
  607. if ( is_search() ) {
  608. $canonical = get_search_link();
  609. } else if ( is_front_page() ) {
  610. $canonical = home_url( '/' );
  611. } else if ( $this->is_posts_page() ) {
  612. $canonical = get_permalink( get_option( 'page_for_posts' ) );
  613. } else if ( is_tax() || is_tag() || is_category() ) {
  614. $term = get_queried_object();
  615. $canonical = wpseo_get_term_meta( $term, $term->taxonomy, 'canonical' );
  616. if ( !$canonical )
  617. $canonical = get_term_link( $term, $term->taxonomy );
  618. } else if ( function_exists( 'get_post_type_archive_link' ) && is_post_type_archive() ) {
  619. $canonical = get_post_type_archive_link( get_query_var( 'post_type' ) );
  620. } else if ( is_author() ) {
  621. $canonical = get_author_posts_url( get_query_var( 'author' ), get_query_var( 'author_name' ) );
  622. } else if ( is_archive() ) {
  623. if ( is_date() ) {
  624. if ( is_day() ) {
  625. $canonical = get_day_link( get_query_var( 'year' ), get_query_var( 'monthnum' ), get_query_var( 'day' ) );
  626. } else if ( is_month() ) {
  627. $canonical = get_month_link( get_query_var( 'year' ), get_query_var( 'monthnum' ) );
  628. } else if ( is_year() ) {
  629. $canonical = get_year_link( get_query_var( 'year' ) );
  630. }
  631. }
  632. }
  633.  
  634. if ( $canonical && $unpaged )
  635. return $canonical;
  636.  
  637. if ( $canonical && get_query_var( 'paged' ) > 1 ) {
  638. global $wp_rewrite;
  639. if ( !$wp_rewrite->using_permalinks() ) {
  640. $canonical = add_query_arg( 'paged', get_query_var( 'paged' ), $canonical );
  641. } else {
  642. $canonical = user_trailingslashit( trailingslashit( $canonical ) . trailingslashit( $wp_rewrite->pagination_base ) . get_query_var( 'paged' ) );
  643. }
  644. }
  645. }
  646.  
  647. if ( $canonical && isset( $this->options['force_transport'] ) && 'default' != $this->options['force_transport'] )
  648. $canonical = preg_replace( '/https?/', $this->options['force_transport'], $canonical );
  649.  
  650. $canonical = apply_filters( 'wpseo_canonical', $canonical );
  651.  
  652. if ( $canonical && !is_wp_error( $canonical ) ) {
  653. if ( $echo !== false )
  654. echo '<link rel="canonical" href="' . esc_url( $canonical, null, 'other' ) . '" />' . "\n";
  655. else
  656. return $canonical;
  657. }
  658. }
  659.  
  660. /**
  661. * Adds 'prev' and 'next' links to archives.
  662. *
  663. * @link http://googlewebmastercentral.blogspot.com/2011/09/pagination-with-relnext-and-relprev.html
  664. * @since 1.0.3
  665. */
  666. public function adjacent_rel_links() {
  667. // Don't do this for Genesis, as the way Genesis handles homepage functionality is different and causes issues sometimes.
  668. if ( is_home() || function_exists( 'genesis' ) )
  669. return;
  670.  
  671. global $wp_query;
  672.  
  673. if ( !is_singular() ) {
  674. $url = $this->canonical( false, true );
  675.  
  676. if ( $url ) {
  677. $paged = get_query_var( 'paged' );
  678.  
  679. if ( 0 == $paged )
  680. $paged = 1;
  681.  
  682. if ( $paged > 1 )
  683. $this->adjacent_rel_link( "prev", $url, $paged - 1, true );
  684.  
  685. if ( $paged < $wp_query->max_num_pages )
  686. $this->adjacent_rel_link( "next", $url, $paged + 1, true );
  687. }
  688. } else {
  689. $numpages = 0;
  690. if ( isset( $wp_query->post->post_content ) ) {
  691. $numpages = substr_count( $wp_query->post->post_content, '<!--nextpage-->' ) + 1;
  692. }
  693. if ( $numpages > 1 ) {
  694. $page = get_query_var( 'page' );
  695. if ( !$page )
  696. $page = 1;
  697.  
  698. $url = get_permalink( $wp_query->post->ID );
  699.  
  700. // If the current page is the frontpage, pagination should use /base/
  701. if ( $this->is_home_static_page() )
  702. $usebase = true;
  703. else
  704. $usebase = false;
  705.  
  706. if ( $page > 1 )
  707. $this->adjacent_rel_link( "prev", $url, $page - 1, $usebase, 'single_paged' );
  708. if ( $page < $numpages )
  709. $this->adjacent_rel_link( "next", $url, $page + 1, $usebase, 'single_paged' );
  710. }
  711. }
  712. }
  713.  
  714. /**
  715. * Get adjacent pages link for archives
  716. *
  717. * @param string $rel Link relationship, prev or next.
  718. * @param string $url the unpaginated URL of the current archive.
  719. * @param string $page the page number to add on to $url for the $link tag.
  720. * @param boolean $incl_pagination_base whether or not to include /page/ or not.
  721. * @return string $link link element
  722. *
  723. * @since 1.0.2
  724. */
  725. private function adjacent_rel_link( $rel, $url, $page, $incl_pagination_base ) {
  726. global $wp_rewrite;
  727. if ( !$wp_rewrite->using_permalinks() ) {
  728. if ( $page > 1 )
  729. $url = add_query_arg( 'paged', $page, $url );
  730. } else {
  731. if ( $page > 1 ) {
  732. $base = '';
  733. if ( $incl_pagination_base )
  734. $base = trailingslashit( $wp_rewrite->pagination_base );
  735. $url = user_trailingslashit( trailingslashit( $url ) . $base . $page );
  736. }
  737. }
  738. $link = apply_filters( "wpseo_" . $rel . "_rel_link", "<link rel=\"$rel\" href=\"$url\" />\n" );
  739.  
  740. if ( $link )
  741. echo $link;
  742. }
  743.  
  744. /**
  745. * Output the rel=publisher code on the frontpage of the site.
  746. */
  747. public function publisher() {
  748. if ( is_front_page() ) {
  749. if ( isset( $this->options['plus-publisher'] ) && !empty( $this->options['plus-publisher'] ) )
  750. echo '<link rel="publisher" href="' . esc_attr( $this->options['plus-publisher'] ) . '"/>' . "\n";
  751. }
  752. }
  753.  
  754. /**
  755. * Outputs the rel=author
  756. */
  757. public function author() {
  758. $gplus = false;
  759.  
  760. if ( is_singular() ) {
  761. global $post;
  762. $gplus = get_the_author_meta( 'googleplus', $post->post_author );
  763. } else if ( is_home() ) {
  764. if ( isset( $this->options['plus-author'] ) )
  765. $gplus = get_the_author_meta( 'googleplus', $this->options['plus-author'] );
  766. }
  767.  
  768. $gplus = apply_filters( 'wpseo_author_link', $gplus );
  769.  
  770. if ( $gplus )
  771. echo '<link rel="author" href="' . $gplus . '"/>' . "\n";
  772.  
  773. }
  774.  
  775. /**
  776. * Outputs the meta keywords element.
  777. *
  778. * @return string
  779. */
  780. public function metakeywords() {
  781. global $wp_query;
  782.  
  783. if ( !isset( $this->options['usemetakeywords'] ) || !$this->options['usemetakeywords'] )
  784. return;
  785.  
  786. $metakey = '';
  787.  
  788. if ( is_singular() ) {
  789. global $post;
  790. $metakey = wpseo_get_value( 'metakeywords' );
  791. if ( isset( $this->options['metakey-' . $post->post_type] ) && ( !$metakey || empty( $metakey ) ) ) {
  792. $metakey = wpseo_replace_vars( $this->options['metakey-' . $post->post_type], (array) $post );
  793. }
  794. } else {
  795. if ( $this->is_home_posts_page() && isset( $this->options['metakey-home'] ) ) {
  796. $metakey = wpseo_replace_vars( $this->options['metakey-home'], array() );
  797. } else if ( $this->is_home_static_page() ) {
  798. global $post;
  799. $metakey = wpseo_get_value( 'metakey' );
  800. if ( ( $metakey == '' || !$metakey ) && isset( $this->options['metakey-' . $post->post_type] ) )
  801. $metakey = wpseo_replace_vars( $this->options['metakey-' . $post->post_type], (array) $post );
  802. } else if ( is_category() || is_tag() || is_tax() ) {
  803. $term = $wp_query->get_queried_object();
  804.  
  805. $metakey = wpseo_get_term_meta( $term, $term->taxonomy, 'metakey' );
  806. if ( !$metakey && isset( $this->options['metakey-' . $term->taxonomy] ) )
  807. $metakey = wpseo_replace_vars( $this->options['metakey-' . $term->taxonomy], (array) $term );
  808. } else if ( is_author() ) {
  809. $author_id = get_query_var( 'author' );
  810. $metakey = get_the_author_meta( 'metakey', $author_id );
  811. if ( !$metakey && isset( $this->options['metakey-author'] ) )
  812. $metakey = wpseo_replace_vars( $this->options['metakey-author'], (array) $wp_query->get_queried_object() );
  813. }
  814.  
  815. }
  816.  
  817. $metakey = apply_filters( 'wpseo_metakey', trim( $metakey ) );
  818.  
  819. if ( !empty( $metakey ) )
  820. echo '<meta name="keywords" content="' . esc_attr( strip_tags( stripslashes( $metakey ) ) ) . '"/>' . "\n";
  821.  
  822. }
  823.  
  824. /**
  825. * Outputs the meta description element or returns the description text.
  826. *
  827. * @param bool $echo Whether or not to echo the description.
  828. * @return string
  829. */
  830. public function metadesc( $echo = true ) {
  831. if ( get_query_var( 'paged' ) && get_query_var( 'paged' ) > 1 )
  832. return;
  833.  
  834. global $post, $wp_query;
  835.  
  836. $metadesc = '';
  837. if ( is_singular() ) {
  838. $metadesc = wpseo_get_value( 'metadesc' );
  839. if ( $metadesc == '' || !$metadesc ) {
  840. if ( isset( $this->options['metadesc-' . $post->post_type] ) && $this->options['metadesc-' . $post->post_type] != '' )
  841. $metadesc = wpseo_replace_vars( $this->options['metadesc-' . $post->post_type], (array) $post );
  842. }
  843. } else {
  844. if ( is_search() ) {
  845. $metadesc = '';
  846. } else if ( $this->is_home_posts_page() && isset( $this->options['metadesc-home'] ) ) {
  847. $metadesc = wpseo_replace_vars( $this->options['metadesc-home'], array() );
  848. } else if ( $this->is_posts_page() ) {
  849. $metadesc = wpseo_get_value( 'metadesc', get_option( 'page_for_posts' ) );
  850. if ( ( $metadesc == '' || !$metadesc ) && isset( $this->options['metadesc-' . $post->post_type] ) ) {
  851. $page = get_post( get_option( 'page_for_posts' ) );
  852. $metadesc = wpseo_replace_vars( $this->options['metadesc-' . $post->post_type], (array) $page );
  853. }
  854. } else if ( $this->is_home_static_page() ) {
  855. global $post;
  856. $metadesc = wpseo_get_value( 'metadesc' );
  857. if ( ( $metadesc == '' || !$metadesc ) && isset( $this->options['metadesc-' . $post->post_type] ) )
  858. $metadesc = wpseo_replace_vars( $this->options['metadesc-' . $post->post_type], (array) $post );
  859. } else if ( is_category() || is_tag() || is_tax() ) {
  860. $term = $wp_query->get_queried_object();
  861.  
  862. $metadesc = wpseo_get_term_meta( $term, $term->taxonomy, 'desc' );
  863. if ( !$metadesc && isset( $this->options['metadesc-' . $term->taxonomy] ) )
  864. $metadesc = wpseo_replace_vars( $this->options['metadesc-' . $term->taxonomy], (array) $term );
  865. } else if ( is_author() ) {
  866. $author_id = get_query_var( 'author' );
  867. $metadesc = get_the_author_meta( 'wpseo_metadesc', $author_id );
  868. if ( !$metadesc && isset( $this->options['metadesc-author'] ) )
  869. $metadesc = wpseo_replace_vars( $this->options['metadesc-author'], (array) $wp_query->get_queried_object() );
  870. } else if ( function_exists( 'is_post_type_archive' ) && is_post_type_archive() ) {
  871. $post_type = get_query_var( 'post_type' );
  872. if ( isset( $this->options['metadesc-ptarchive-' . $post_type] ) && '' != $this->options['metadesc-ptarchive-' . $post_type] ) {
  873. $metadesc = wpseo_replace_vars( $this->options['metadesc-ptarchive-' . $post_type], (array) $wp_query->get_queried_object() );
  874. }
  875. }
  876. }
  877.  
  878. $metadesc = apply_filters( 'wpseo_metadesc', trim( $metadesc ) );
  879.  
  880. if ( $echo !== false ) {
  881. if ( !empty( $metadesc ) )
  882. echo '<meta name="description" content="' . esc_attr( strip_tags( stripslashes( $metadesc ) ) ) . '"/>' . "\n";
  883. else if ( current_user_can( 'manage_options' ) && is_singular() )
  884. 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";
  885. } else {
  886. return $metadesc;
  887. }
  888.  
  889. }
  890.  
  891. /**
  892. * Based on the redirect meta value, this function determines whether it should redirect the current post / page.
  893. *
  894. * @return mixed
  895. */
  896. function page_redirect() {
  897. if ( is_singular() ) {
  898. global $post;
  899. if ( !isset( $post ) )
  900. return;
  901. $redir = wpseo_get_value( 'redirect', $post->ID );
  902. if ( !empty( $redir ) ) {
  903. wp_redirect( $redir, 301 );
  904. exit;
  905. }
  906. }
  907. }
  908.  
  909. /**
  910. * Outputs noindex values for the current page.
  911. */
  912. public function noindex_page() {
  913. echo '<meta name="robots" content="noindex" />' . "\n";
  914. }
  915.  
  916. /**
  917. * Send a Robots HTTP header preventing feeds from being indexed in the search results while allowing search engines to follow the links in the feed.
  918. *
  919. * @since 1.1.7
  920. */
  921. public function noindex_feed() {
  922. if ( is_feed() )
  923. header( "X-Robots-Tag: noindex,follow", true );
  924. }
  925.  
  926. /**
  927. * Adds rel="nofollow" to a link, only used for login / registration links.
  928. *
  929. * @param string $input The link element as a string.
  930. * @return string
  931. */
  932. public function nofollow_link( $input ) {
  933. return str_replace( '<a ', '<a rel="nofollow" ', $input );
  934. }
  935.  
  936. /**
  937. * When certain archives are disabled, this redirects those to the homepage.
  938. */
  939. function archive_redirect() {
  940. global $wp_query;
  941.  
  942. if (
  943. ( isset( $this->options['disable-date'] ) && $this->options['disable-date'] && $wp_query->is_date ) ||
  944. ( isset( $this->options['disable-author'] ) && $this->options['disable-author'] && $wp_query->is_author ) ||
  945. ( isset( $this->options['disable-post_formats'] ) && $this->options['disable-post_formats'] && $wp_query->is_tax( 'post_format' ) )
  946. ) {
  947. wp_safe_redirect( get_bloginfo( 'url' ), 301 );
  948. exit;
  949. }
  950. }
  951.  
  952. /**
  953. * If the option to redirect attachments to their parent is checked, this performs the redirect.
  954. *
  955. * An extra check is done for when the attachment has no parent.
  956. */
  957. function attachment_redirect() {
  958. global $post;
  959. if ( is_attachment() && isset( $post->post_parent ) && is_numeric( $post->post_parent ) && $post->post_parent != 0 ) {
  960. wp_safe_redirect( get_permalink( $post->post_parent ), 301 );
  961. exit;
  962. }
  963. }
  964.  
  965. /**
  966. * Trailing slashes for everything except is_single().
  967. *
  968. * Thanks to Mark Jaquith for this code.
  969. *
  970. * @param string $url
  971. * @param string $type
  972. * @return string
  973. */
  974. function add_trailingslash( $url, $type ) {
  975. if ( 'single' === $type || 'single_paged' === $type ) {
  976. return $url;
  977. } else {
  978. return trailingslashit( $url );
  979. }
  980. }
  981.  
  982. /**
  983. * Removes the ?replytocom variable from the link, replacing it with a #comment-<number> anchor.
  984. *
  985. * @param string $link The comment link as a string.
  986. * @return string
  987. */
  988. public function remove_reply_to_com( $link ) {
  989. return preg_replace( '/href=\'(.*(\?|&)replytocom=(\d+)#respond)/', 'href=\'#comment-$3', $link );
  990. }
  991.  
  992. /**
  993. * Removes unneeded query variables from the URL.
  994. */
  995. public function clean_permalink() {
  996. if ( is_robots() || get_query_var( 'sitemap' ) )
  997. return;
  998.  
  999. global $wp_query;
  1000.  
  1001. // Recreate current URL
  1002. $cururl = 'http';
  1003. if ( isset( $_SERVER["HTTPS"] ) && $_SERVER["HTTPS"] == "on" ) {
  1004. $cururl .= "s";
  1005. }
  1006. $cururl .= "://";
  1007. if ( $_SERVER["SERVER_PORT"] != "80" )
  1008. $cururl .= $_SERVER["SERVER_NAME"] . ":" . $_SERVER["SERVER_PORT"] . $_SERVER["REQUEST_URI"];
  1009. else
  1010. $cururl .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
  1011.  
  1012. $properurl = '';
  1013.  
  1014. if ( is_singular() ) {
  1015. global $post;
  1016. if ( empty( $post ) )
  1017. $post = $wp_query->get_queried_object();
  1018.  
  1019. $properurl = get_permalink( $post->ID );
  1020.  
  1021. $page = get_query_var( 'page' );
  1022. if ( $page && $page != 1 ) {
  1023. $post = get_post( $post->ID );
  1024. $page_count = substr_count( $post->post_content, '<!--nextpage-->' );
  1025. if ( $page > ( $page_count + 1 ) )
  1026. $properurl = user_trailingslashit( trailingslashit( $properurl ) . ( $page_count + 1 ) );
  1027. else
  1028. $properurl = user_trailingslashit( trailingslashit( $properurl ) . $page );
  1029. }
  1030.  
  1031. // Fix reply to comment links, whoever decided this should be a GET variable?
  1032. $result = preg_match( '/(\?replytocom=[^&]+)/', $_SERVER["REQUEST_URI"], $matches );
  1033. if ( $result )
  1034. $properurl .= str_replace( '?replytocom=', '#comment-', $matches[0] );
  1035.  
  1036. // Prevent cleaning out posts & page previews for people capable of viewing them
  1037. if ( isset( $_GET['preview'] ) && isset( $_GET['preview_nonce'] ) && current_user_can( 'edit_post' ) )
  1038. $properurl = '';
  1039. } else if ( is_front_page() ) {
  1040. if ( $this->is_home_posts_page() ) {
  1041. $properurl = get_bloginfo( 'url' ) . '/';
  1042. } elseif ( $this->is_home_static_page() ) {
  1043. global $post;
  1044. $properurl = get_permalink( $post->ID );
  1045. }
  1046. } else if ( is_category() || is_tag() || is_tax() ) {
  1047. $term = $wp_query->get_queried_object();
  1048. if ( is_feed() )
  1049. $properurl = get_term_feed_link( $term->term_id, $term->taxonomy );
  1050. else
  1051. $properurl = get_term_link( $term, $term->taxonomy );
  1052. } else if ( is_search() ) {
  1053. $s = preg_replace( '/(%20|\+)/', ' ', get_search_query() );
  1054. $properurl = get_bloginfo( 'url' ) . '/?s=' . rawurlencode( $s );
  1055. } else if ( is_404() ) {
  1056. if ( function_exists( 'is_multisite' ) && is_multisite() && !is_subdomain_install() && is_main_site() ) {
  1057. if ( $cururl == get_bloginfo( 'url' ) . '/blog/' || $cururl == get_bloginfo( 'url' ) . '/blog' ) {
  1058. if ( $this->is_home_static_page() )
  1059. $properurl = get_permalink( get_option( 'page_for_posts' ) );
  1060. else
  1061. $properurl = get_bloginfo( 'url' ) . '/';
  1062. }
  1063. }
  1064. }
  1065.  
  1066. if ( !empty( $properurl ) && $wp_query->query_vars['paged'] != 0 && $wp_query->post_count != 0 ) {
  1067. if ( is_search() ) {
  1068. $properurl = get_bloginfo( 'url' ) . '/page/' . $wp_query->query_vars['paged'] . '/?s=' . rawurlencode( get_search_query() );
  1069. } else {
  1070. $properurl = user_trailingslashit( trailingslashit( $properurl ) . 'page/' . $wp_query->query_vars['paged'] );
  1071. }
  1072. }
  1073.  
  1074. // Prevent cleaning out the WP Subscription managers interface for everyone
  1075. foreach ( array( 'wp-subscription-manager' ) as $get ) {
  1076. if ( isset( $_GET[$get] ) ) {
  1077. $properurl = '';
  1078. }
  1079. }
  1080.  
  1081. // Allow plugins to register their own variables not to clean
  1082. $whitelisted_extravars = apply_filters( 'wpseo_whitelist_permalink_vars', array() );
  1083.  
  1084. if ( isset( $this->options['cleanpermalink-googlesitesearch'] ) && $this->options['cleanpermalink-googlesitesearch'] ) {
  1085. // Prevent cleaning out Google Site searches
  1086. $whitelisted_extravars = array_merge( $whitelisted_extravars, array( 'q', 'cx', 'debug', 'cof', 'ie', 'sa' ) );
  1087. }
  1088.  
  1089. if ( isset( $this->options['cleanpermalink-googlecampaign'] ) && $this->options['cleanpermalink-googlecampaign'] ) {
  1090. // Prevent cleaning out Google Analytics campaign variables
  1091. $whitelisted_extravars = array_merge( $whitelisted_extravars, array( 'utm_campaign', 'utm_medium', 'utm_source', 'utm_content', 'utm_term' ) );
  1092. }
  1093.  
  1094. if ( isset( $this->options['cleanpermalink-extravars'] ) && strlen( $this->options['cleanpermalink-extravars'] ) > 0 ) {
  1095. $whitelisted_extravars = array_merge( $whitelisted_extravars, explode( ',', $this->options['cleanpermalink-extravars'] ) );
  1096. }
  1097.  
  1098. foreach ( $whitelisted_extravars as $get ) {
  1099. if ( isset( $_GET[trim( $get )] ) ) {
  1100. $properurl = '';
  1101. }
  1102. }
  1103.  
  1104. if ( !empty( $properurl ) && $cururl != $properurl ) {
  1105. wp_safe_redirect( $properurl, 301 );
  1106. exit;
  1107. }
  1108. }
  1109.  
  1110. /**
  1111. * Replaces the possible RSS variables with their actual values.
  1112. *
  1113. * @param string $content The RSS content that should have the variables replaced.
  1114. * @return string
  1115. */
  1116. function rss_replace_vars( $content ) {
  1117. global $post;
  1118.  
  1119. $authorlink = '<a rel="author" href="' . get_author_posts_url( $post->post_author ) . '">' . get_the_author() . '</a>';
  1120. $postlink = '<a href="' . get_permalink() . '">' . get_the_title() . "</a>";
  1121. $bloglink = '<a href="' . get_bloginfo( 'url' ) . '">' . get_bloginfo( 'name' ) . '</a>';
  1122. $blogdesclink = '<a href="' . get_bloginfo( 'url' ) . '">' . get_bloginfo( 'name' ) . ' - ' . get_bloginfo( 'description' ) . '</a>';
  1123.  
  1124. $content = stripslashes( $content );
  1125. $content = str_replace( "%%AUTHORLINK%%", $authorlink, $content );
  1126. $content = str_replace( "%%POSTLINK%%", $postlink, $content );
  1127. $content = str_replace( "%%BLOGLINK%%", $bloglink, $content );
  1128. $content = str_replace( "%%BLOGDESCLINK%%", $blogdesclink, $content );
  1129. return $content;
  1130. }
  1131.  
  1132. /**
  1133. * Adds the RSS footer (or header) to the full RSS feed item.
  1134. *
  1135. * @param string $content Feed item content.
  1136. * @return string
  1137. */
  1138. function embed_rssfooter( $content ) {
  1139. if ( is_feed() ) {
  1140.  
  1141. if ( isset( $this->options['rssbefore'] ) && !empty( $this->options['rssbefore'] ) ) {
  1142. $content = "<p>" . $this->rss_replace_vars( $this->options['rssbefore'] ) . "</p>" . $content;
  1143. }
  1144. if ( isset( $this->options['rssafter'] ) && !empty( $this->options['rssafter'] ) ) {
  1145. $content .= "<p>" . $this->rss_replace_vars( $this->options['rssafter'] ) . "</p>";
  1146. }
  1147. }
  1148. return $content;
  1149. }
  1150.  
  1151. /**
  1152. * Adds the RSS footer (or header) to the excerpt RSS feed item.
  1153. *
  1154. * @param string $content Feed item excerpt.
  1155. * @return string
  1156. */
  1157. function embed_rssfooter_excerpt( $content ) {
  1158. if ( is_feed() ) {
  1159.  
  1160. if ( isset( $this->options['rssbefore'] ) && !empty( $this->options['rssbefore'] ) ) {
  1161. $content = "<p>" . $this->rss_replace_vars( $this->options['rssbefore'] ) . "</p><p>" . $content . "</p>";
  1162. }
  1163. if ( isset( $this->options['rssafter'] ) && !empty( $this->options['rssafter'] ) ) {
  1164. $content = "<p>" . $content . "</p><p>" . $this->rss_replace_vars( $this->options['rssafter'] ) . "</p>";
  1165. }
  1166. }
  1167. return $content;
  1168. }
  1169.  
  1170. /**
  1171. * Used in the force rewrite functionality this retrieves the output, replaces the title with the proper SEO
  1172. * title and then flushes the output.
  1173. */
  1174. function flush_cache() {
  1175. global $wp_query, $wpseo_ob, $sep;
  1176.  
  1177. if ( !$wpseo_ob )
  1178. return;
  1179.  
  1180. $content = ob_get_contents();
  1181.  
  1182. $old_wp_query = $wp_query;
  1183.  
  1184. wp_reset_query();
  1185.  
  1186. $title = $this->title( '', $sep );
  1187.  
  1188. // 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.
  1189. if ( preg_match_all( '/<title>(.*)?<\/title>/i', $content, $matches ) ) {
  1190. $count = count( $matches[0] );
  1191. if ( $count > 0 ) {
  1192. $i = 0;
  1193. while ( $count > $i ) {
  1194. $content = str_replace( $matches[0][$i], '', $content );
  1195. $i++;
  1196. }
  1197. }
  1198. }
  1199. $content = str_replace( $this->debug_marker( false ), $this->debug_marker( false ) . "\n" . '<title>' . $title . '</title>', $content );
  1200.  
  1201. ob_end_clean();
  1202.  
  1203. $GLOBALS['wp_query'] = $old_wp_query;
  1204.  
  1205. echo $content;
  1206. }
  1207.  
  1208. /**
  1209. * Starts the output buffer so it can later be fixed by flush_cache()
  1210. */
  1211. function force_rewrite_output_buffer() {
  1212. global $wpseo_ob;
  1213. $wpseo_ob = true;
  1214. ob_start();
  1215. }
  1216.  
  1217. /**
  1218. * Function used in testing whether the title should be force rewritten or not.
  1219. *
  1220. * @param string $title
  1221. * @return string
  1222. */
  1223. function title_test_helper( $title ) {
  1224. if ( !defined( 'DONOTCACHEPAGE' ) )
  1225. define( 'DONOTCACHEPAGE', true );
  1226.  
  1227. if ( !defined( 'DONOTCACHCEOBJECT' ) )
  1228. define( 'DONOTCACHCEOBJECT', true );
  1229.  
  1230. if ( !defined( 'DONOTMINIFY' ) )
  1231. define( 'DONOTMINIFY', true );
  1232.  
  1233. global $wp_version;
  1234. if ( $_SERVER['HTTP_USER_AGENT'] == "WordPress/${wp_version}; " . get_bloginfo( 'url' ) . " - Yoast" )
  1235. return 'This is a Yoast Test Title';
  1236. return $title;
  1237. }
  1238.  
  1239. }
  1240.  
  1241. function initialize_wpseo_front() {
  1242. global $wpseo_front;
  1243. $wpseo_front = new WPSEO_Frontend;
  1244. }
  1245. add_action( 'init', 'initialize_wpseo_front' );