XML Sitemap & Google News feeds - Version 4.5

Version Description

Set access or exclude individual posts from Google News sitemap. Improved cache handling and Nginx Helper compatibility.

=

Download this release

Release Info

Developer RavanH
Plugin Icon 128x128 XML Sitemap & Google News feeds
Version 4.5
Comparing to
See all releases

Code changes from version 4.4.1 to 4.5

includes/admin.php CHANGED
@@ -19,12 +19,12 @@ class XMLSF_Admin extends XMLSitemapFeed {
19
  $prefix = parent::prefix();
20
 
21
  echo '<fieldset id="xmlsf_sitemaps"><legend class="screen-reader-text">'.__('XML Sitemaps','xml-sitemap-feed').'</legend>
22
- <label><input type="checkbox" name="'.$prefix.'sitemaps[sitemap]" id="xmlsf_sitemaps_index" value="'.XMLSF_NAME.'" '.checked(isset($options['sitemap']), true, false).' '.disabled($disabled, true, false).' /> '.__('XML Sitemap Index','xml-sitemap-feed').'</label>';//xmlsf
23
  if (isset($options['sitemap']))
24
  echo '<span class="description"> &nbsp;&ndash;&nbsp; <a href="#xmlsf" id="xmlsf_link">'.translate('Settings').'</a> &nbsp;&ndash;&nbsp; <a href="'.trailingslashit(get_bloginfo('url')). ( ('' == get_option('permalink_structure')) ? '?feed=sitemap' : $options['sitemap'] ) .'" target="_blank">'.translate('View').'</a></span>';
25
 
26
  echo '<br>
27
- <label><input type="checkbox" name="'.$prefix.'sitemaps[sitemap-news]" id="xmlsf_sitemaps_news" value="'.XMLSF_NEWS_NAME.'" '.checked(isset($options['sitemap-news']), true, false).' '.disabled($disabled, true, false).' /> '.__('Google News Sitemap','xml-sitemap-feed').'</label>';
28
  if (isset($options['sitemap-news']))
29
  echo '<span class="description"> &nbsp;&ndash;&nbsp; <a href="#xmlnf" id="xmlnf_link">'.translate('Settings').'</a> &nbsp;&ndash;&nbsp; <a href="'.trailingslashit(get_bloginfo('url')). ( ('' == get_option('permalink_structure')) ? '?feed=sitemap-news' : $options['sitemap-news'] ) .'" target="_blank">'.translate('View').'</a></span>';
30
 
@@ -472,8 +472,8 @@ jQuery( document ).ready( function() {
472
  $name = !empty($options['name']) ? $options['name'] : '';
473
  echo '
474
  <fieldset><legend class="screen-reader-text">'.__('Publication name','xml-sitemap-feed').'</legend>
475
- <input type="text" name="'.parent::prefix().'news_tags[name]" id="xmlsf_news_name" value="'.$name.'" class="regular-text"> <span class="description">'.sprintf(__('By default, the general %s setting will be used.','xml-sitemap-feed'),'<a href="options-general.php">'.translate('Site Title').'</a>').'</span> ' .
476
- __('The publication name should match the name submitted on the Google News Publisher Center. If you wish to change it, please read <a href="https://support.google.com/news/publisher/answer/40402" target="_blank">Updated publication name</a>.') . '
477
  </fieldset>';
478
  }
479
 
@@ -586,14 +586,14 @@ jQuery( document ).ready( function() {
586
  '>'.__('Attached images','xml-sitemap-feed').'</option>
587
  ';
588
  echo '</select></label>
589
- <p class="description">'.__('Note: Google News prefers at most one image per article in the News Sitemap. If multiple valid images are specified, the crawler will have to pick one arbitrarily. Images in News Sitemaps should be in jpeg or png format.','xml-sitemap-feed').' <a href="https://support.google.com/news/publisher/answer/185541" target="_blank">'.__('More information&hellip;','xml-sitemap-feed').'</a></p>
590
  </fieldset>';
591
  }
592
 
593
  public function news_labels_field() {
594
  echo '
595
  <fieldset id="xmlsf_news_labels"><legend class="screen-reader-text">'.__('Source labels','xml-sitemap-feed').'</legend>' .
596
- __('You can use the &lt;access&gt; and &lt;genres&gt; tags to provide Google more information about the content of your articles.','xml-sitemap-feed') . ' <a href="https://support.google.com/news/publisher/answer/93992" target="_blank">'.__('More information&hellip;','xml-sitemap-feed').'</a>
597
  <br><br>';
598
 
599
  $options = parent::get_option('news_tags');
@@ -604,21 +604,21 @@ jQuery( document ).ready( function() {
604
  $access_default = !empty($access['default']) ? $access['default'] : '';
605
  $access_password = !empty($access['password']) ? $access['password'] : '';
606
  echo '
607
- <fieldset id="xmlsf_news_access"><legend class="screen-reader-text">'.__('Access (&lt;access&gt; tag)','xml-sitemap-feed').'</legend>
608
- '.sprintf(__('The &lt;access&gt; tag specifies whether an article is available to all readers (%1$s), or only to those with a free (%2$s) or paid membership (%3$s) to your site.','xml-sitemap-feed'),translate('Public'),__('Registration','xml-sitemap-feed'),__('Subscription','xml-sitemap-feed')).'
609
-
610
  <ul>';
611
 
612
  echo '
613
  <li><label>'.__('Tag normal posts as','xml-sitemap-feed').' <select name="'.$prefix.'news_tags[access][default]" id="xmlsf_news_tags_access_default">
614
  <option value="">'.translate('Public').'</option>
615
- <option value="Registration" '.selected( "Registration" == $access_default, true, false).'>'.__('Registration','xml-sitemap-feed').'</option>
616
- <option value="Subscription" '.selected( "Subscription" == $access_default, true, false).'>'.__('Subscription','xml-sitemap-feed').'</option>
617
  </select></label></li>';
618
  echo '
619
  <li><label>'.__('Tag Password Protected posts as','xml-sitemap-feed').' <select name="'.$prefix.'news_tags[access][password]" id="xmlsf_news_tags_access_password">
620
- <option value="Registration" '.selected( "Registration" == $access_password, true, false).'>'.__('Registration','xml-sitemap-feed').'</option>
621
- <option value="Subscription" '.selected( "Subscription" == $access_password, true, false).'>'.__('Subscription','xml-sitemap-feed').'</option>
622
  </select></label></li>';
623
  echo '
624
  </ul>
@@ -629,11 +629,9 @@ jQuery( document ).ready( function() {
629
  $genres = !empty($options['genres']) ? $options['genres'] : array();
630
  $genres_default = !empty($genres['default']) ? (array)$genres['default'] : array();
631
 
632
- $count = count($gn_genres);
633
-
634
  echo '
635
- <fieldset id="xmlsf_news_genres"><legend class="screen-reader-text">'.__('Genres (&lt;genres&gt; tag)','xml-sitemap-feed').'</legend>
636
- '.__('The &lt;genres&gt; tag specifies one or more properties for an article, namely, whether it is a press release, a blog post, an opinion, an op-ed piece, user-generated content, or satire.','xml-sitemap-feed').' '.__('You can assign more genres when writing a post.','xml-sitemap-feed');
637
  echo '<input type="hidden" name="'.$prefix.'news_tags[genres][active]" value="';
638
  echo !empty($genres['active']) ? $genres['active'] : '';
639
  echo '" />';
@@ -644,8 +642,8 @@ jQuery( document ).ready( function() {
644
  */
645
  echo '
646
  <ul>
647
- <li><label>'.__('Default genre:','xml-sitemap-feed').'<br><select multiple name="'.$prefix.'news_tags[genres][default][]" id="xmlsf_news_tags_genres_default" size="'.$count.'">';
648
- foreach ( $gn_genres as $slug => $name)
649
  echo '
650
  <option value="'.$name.'" '.selected( in_array($name,$genres_default), true, false ).'>'.$name.'</option>';
651
  echo '
@@ -655,17 +653,17 @@ jQuery( document ).ready( function() {
655
  <p class="description">'.__('Use the Ctrl/Cmd key plus click to select more than one or to deselect.','xml-sitemap-feed').' '.sprintf(__('Read more about source labels on %s','xml-sitemap-feed'),'<a href="https://support.google.com/news/publisher/answer/4582731" target="_blank">'.__('What does each source label mean?','xml-sitemap-feed').'</a>').'</p>
656
  </fieldset>';
657
 
658
- }
659
 
660
  public function news_keywords_field() {
661
  $options = parent::get_option('news_tags');
662
- $prefix = parent::prefix();
663
 
664
  $keywords = !empty($options['keywords']) ? $options['keywords'] : array();
665
  $keywords_from = !empty($keywords['from']) ? $keywords['from'] : '';
666
  echo '
667
- <fieldset id="xmlsf_news_keywords"><legend class="screen-reader-text">'.__('Topics (&lt;keywords&gt; tag)','xml-sitemap-feed').'</legend>
668
- '.__('The &lt;keywords&gt; tag is used to help classify the articles you submit to Google News by <strong>topic</strong>.','xml-sitemap-feed').'
669
  <ul>
670
  <li><label>'.sprintf(__('Use %s for topics.','xml-sitemap-feed'),' <select name="'.$prefix.'news_tags[keywords][from]" id="xmlsf_news_tags_keywords_from">
671
  <option value="">'.translate('None').'</option>
@@ -815,9 +813,15 @@ jQuery( document ).ready( function() {
815
  $line = trim($line);
816
  $parsed_url = parse_url(trim(filter_var($line,FILTER_SANITIZE_URL)));
817
  // Before PHP version 5.4.7, parse_url will return the domain as path when scheme is omitted so we do:
818
- $domain_arr = explode('/', $parsed_url['path']);
819
- $domain = trim(!empty($parsed_url['host']) ? $parsed_url['host'] : array_shift(array_filter($domain_arr)));
820
-
 
 
 
 
 
 
821
  // filter out empties and default domain
822
  if(!empty($domain) && $domain !== $default && strpos($domain,".".$default) === false)
823
  $sanitized[] = $domain;
@@ -844,10 +848,11 @@ jQuery( document ).ready( function() {
844
  */
845
 
846
  /* Adds a box to the side column */
847
- public function add_meta_box()
848
  {
849
- // Only include metaboxes on post types that are included
850
  foreach (parent::get_post_types() as $post_type) {
 
851
  if (isset($post_type["active"]))
852
  add_meta_box(
853
  'xmlsf_section',
@@ -857,6 +862,18 @@ jQuery( document ).ready( function() {
857
  'side'
858
  );
859
  }
 
 
 
 
 
 
 
 
 
 
 
 
860
  }
861
 
862
  public function meta_box($post)
@@ -866,14 +883,14 @@ jQuery( document ).ready( function() {
866
 
867
  // The actual fields for data entry
868
  // Use get_post_meta to retrieve an existing value from the database and use the value for the form
869
- $value = get_post_meta( $post->ID, '_xmlsf_exclude', true );
870
  $priority = get_post_meta( $post->ID, '_xmlsf_priority', true );
871
  $disabled = '';
872
 
873
  // disable options and (visibly) set excluded to true for private posts
874
  if ( 'private' == $post->post_status ) {
875
  $disabled = ' disabled="disabled"';
876
- $value = true;
877
  }
878
 
879
  // disable options and (visibly) set priority to 1 for front page
@@ -882,16 +899,46 @@ jQuery( document ).ready( function() {
882
  $priority = '1'; // force excluded to true for private posts
883
  }
884
 
885
- echo '<p><label><input type="checkbox" name="xmlsf_exclude" id="xmlsf_exclude" value="1"'.checked(!empty($value), true, false).$disabled.' > ';
886
  _e('Exclude from XML Sitemap','xml-sitemap-feed');
887
  echo '</label></p>';
888
 
889
  echo '<p><label>';
890
  _e('Priority','xml-sitemap-feed');
891
  echo ' <input type="number" step="0.1" min="0" max="1" name="xmlsf_priority" id="xmlsf_priority" value="'.$priority.'" class="small-text"'.$disabled.'></label> <span class="description">';
892
- printf(__('Leave empty for automatic Priority as configured on %1$s > %2$s.','xml-sitemap-feed'),translate('Settings'),translate('Reading'));
893
  echo '</span></p>';
894
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
895
 
896
  /* When the post is saved, save our meta data */
897
  function save_metadata( $post_id )
@@ -916,6 +963,19 @@ jQuery( document ).ready( function() {
916
  delete_post_meta($post_id, '_xmlsf_exclude');
917
  }
918
 
 
 
 
 
 
 
 
 
 
 
 
 
 
919
  }
920
 
921
  /**
@@ -961,7 +1021,7 @@ jQuery( document ).ready( function() {
961
  add_settings_field($prefix.'custom_sitemaps', __('Include custom XML Sitemaps','xml-sitemap-feed'), array($this,'custom_sitemaps_settings_field'), 'reading', 'xml_sitemap_section');
962
 
963
  // POST META BOX
964
- add_action( 'add_meta_boxes', array($this,'add_meta_box') );
965
  add_action( 'save_post', array($this,'save_metadata') );
966
  }
967
 
@@ -975,9 +1035,8 @@ jQuery( document ).ready( function() {
975
  add_settings_field($prefix.'news_post_type', __('Include post types','xml-sitemap-feed'), array($this,'news_post_type_field'), 'reading', 'news_sitemap_section');
976
  add_settings_field($prefix.'news_categories', translate('Categories'), array($this,'news_categories_field'), 'reading', 'news_sitemap_section');
977
  add_settings_field($prefix.'news_image', translate('Images'), array($this,'news_image_field'), 'reading', 'news_sitemap_section');
978
- add_settings_field($prefix.'news_access', __('Source labels','xml-sitemap-feed'), array($this,'news_labels_field'), 'reading', 'news_sitemap_section');
979
- //add_settings_field($prefix.'news_genres', __('Genres (&lt;genres&gt; tag)','xml-sitemap-feed'), array($this,'news_genres_field'), 'reading', 'news_sitemap_section');
980
- add_settings_field($prefix.'news_keywords', __('Topics','xml-sitemap-feed'), array($this,'news_keywords_field'), 'reading', 'news_sitemap_section');
981
 
982
  }
983
 
19
  $prefix = parent::prefix();
20
 
21
  echo '<fieldset id="xmlsf_sitemaps"><legend class="screen-reader-text">'.__('XML Sitemaps','xml-sitemap-feed').'</legend>
22
+ <label><input type="checkbox" name="'.$prefix.'sitemaps[sitemap]" id="xmlsf_sitemaps_index" value="'.htmlspecialchars(XMLSF_NAME).'" '.checked(isset($options['sitemap']), true, false).' '.disabled($disabled, true, false).' /> '.__('XML Sitemap Index','xml-sitemap-feed').'</label>';//xmlsf
23
  if (isset($options['sitemap']))
24
  echo '<span class="description"> &nbsp;&ndash;&nbsp; <a href="#xmlsf" id="xmlsf_link">'.translate('Settings').'</a> &nbsp;&ndash;&nbsp; <a href="'.trailingslashit(get_bloginfo('url')). ( ('' == get_option('permalink_structure')) ? '?feed=sitemap' : $options['sitemap'] ) .'" target="_blank">'.translate('View').'</a></span>';
25
 
26
  echo '<br>
27
+ <label><input type="checkbox" name="'.$prefix.'sitemaps[sitemap-news]" id="xmlsf_sitemaps_news" value="'.htmlspecialchars(XMLSF_NEWS_NAME).'" '.checked(isset($options['sitemap-news']), true, false).' '.disabled($disabled, true, false).' /> '.__('Google News Sitemap','xml-sitemap-feed').'</label>';
28
  if (isset($options['sitemap-news']))
29
  echo '<span class="description"> &nbsp;&ndash;&nbsp; <a href="#xmlnf" id="xmlnf_link">'.translate('Settings').'</a> &nbsp;&ndash;&nbsp; <a href="'.trailingslashit(get_bloginfo('url')). ( ('' == get_option('permalink_structure')) ? '?feed=sitemap-news' : $options['sitemap-news'] ) .'" target="_blank">'.translate('View').'</a></span>';
30
 
472
  $name = !empty($options['name']) ? $options['name'] : '';
473
  echo '
474
  <fieldset><legend class="screen-reader-text">'.__('Publication name','xml-sitemap-feed').'</legend>
475
+ <input type="text" name="'.parent::prefix().'news_tags[name]" id="xmlsf_news_name" value="'.$name.'" class="regular-text"> <span class="description">'.sprintf(__('By default, the general %s setting will be used.','xml-sitemap-feed'),'<a href="options-general.php">'.translate('Site Title').'</a>').'</span><p class="description">' .
476
+ __('The publication name should match the name submitted on the Google News Publisher Center. If you wish to change it, please read <a href="https://support.google.com/news/publisher/answer/40402" target="_blank">Updated publication name</a>.') . '</p>
477
  </fieldset>';
478
  }
479
 
586
  '>'.__('Attached images','xml-sitemap-feed').'</option>
587
  ';
588
  echo '</select></label>
589
+ <p class="description">'.__('Note: Google News prefers at most one image per article in the News Sitemap. If multiple valid images are specified, the crawler will have to pick one arbitrarily. Images in News Sitemaps should be in jpeg or png format.','xml-sitemap-feed').' <a href="https://support.google.com/news/publisher/answer/13369" target="_blank">'.__('More information&hellip;','xml-sitemap-feed').'</a></p>
590
  </fieldset>';
591
  }
592
 
593
  public function news_labels_field() {
594
  echo '
595
  <fieldset id="xmlsf_news_labels"><legend class="screen-reader-text">'.__('Source labels','xml-sitemap-feed').'</legend>' .
596
+ sprintf(__('You can use the %1$s and %2$s tags to provide Google more information about the content of your articles.','xml-sitemap-feed'),'&lt;access&gt;','&lt;genres&gt;') . ' <a href="https://support.google.com/news/publisher/answer/93992" target="_blank">'.__('More information&hellip;','xml-sitemap-feed').'</a>
597
  <br><br>';
598
 
599
  $options = parent::get_option('news_tags');
604
  $access_default = !empty($access['default']) ? $access['default'] : '';
605
  $access_password = !empty($access['password']) ? $access['password'] : '';
606
  echo '
607
+ <fieldset id="xmlsf_news_labels_access"><legend class="screen-reader-text">&lt;access&gt;</legend>
608
+ '.sprintf(__('The %4$s tag specifies whether an article is available to all readers (%1$s), or only to those with a free (%2$s) or paid membership (%3$s) to your site.','xml-sitemap-feed'),translate('Public'),__('Registration','xml-sitemap-feed'),__('Subscription','xml-sitemap-feed'),'<strong>&lt;access&gt;</strong>').'
609
+ '.__('You can assign a different access level when writing a post.','xml-sitemap-feed') . '
610
  <ul>';
611
 
612
  echo '
613
  <li><label>'.__('Tag normal posts as','xml-sitemap-feed').' <select name="'.$prefix.'news_tags[access][default]" id="xmlsf_news_tags_access_default">
614
  <option value="">'.translate('Public').'</option>
615
+ <option value="Registration" '.selected( "Registration" == $access_default, true, false).'>'.__('Free registration','xml-sitemap-feed').'</option>
616
+ <option value="Subscription" '.selected( "Subscription" == $access_default, true, false).'>'.__('Paid subscription','xml-sitemap-feed').'</option>
617
  </select></label></li>';
618
  echo '
619
  <li><label>'.__('Tag Password Protected posts as','xml-sitemap-feed').' <select name="'.$prefix.'news_tags[access][password]" id="xmlsf_news_tags_access_password">
620
+ <option value="Registration" '.selected( "Registration" == $access_password, true, false).'>'.__('Free registration','xml-sitemap-feed').'</option>
621
+ <option value="Subscription" '.selected( "Subscription" == $access_password, true, false).'>'.__('Paid subscription','xml-sitemap-feed').'</option>
622
  </select></label></li>';
623
  echo '
624
  </ul>
629
  $genres = !empty($options['genres']) ? $options['genres'] : array();
630
  $genres_default = !empty($genres['default']) ? (array)$genres['default'] : array();
631
 
 
 
632
  echo '
633
+ <fieldset id="xmlsf_news_labels_genres"><legend class="screen-reader-text">&lt;genres&gt;</legend>
634
+ '.sprintf(__('The %s tag specifies one or more properties for an article, namely, whether it is a press release, a blog post, an opinion, an op-ed piece, user-generated content, or satire.','xml-sitemap-feed'),'<strong>&lt;genres&gt;</strong>').' '.__('You can assign different genres when writing a post.','xml-sitemap-feed');
635
  echo '<input type="hidden" name="'.$prefix.'news_tags[genres][active]" value="';
636
  echo !empty($genres['active']) ? $genres['active'] : '';
637
  echo '" />';
642
  */
643
  echo '
644
  <ul>
645
+ <li><label>'.__('Default genre:','xml-sitemap-feed').'<br><select multiple name="'.$prefix.'news_tags[genres][default][]" id="xmlsf_news_tags_genres_default" size="'.count($gn_genres).'">';
646
+ foreach ( $gn_genres as $name)
647
  echo '
648
  <option value="'.$name.'" '.selected( in_array($name,$genres_default), true, false ).'>'.$name.'</option>';
649
  echo '
653
  <p class="description">'.__('Use the Ctrl/Cmd key plus click to select more than one or to deselect.','xml-sitemap-feed').' '.sprintf(__('Read more about source labels on %s','xml-sitemap-feed'),'<a href="https://support.google.com/news/publisher/answer/4582731" target="_blank">'.__('What does each source label mean?','xml-sitemap-feed').'</a>').'</p>
654
  </fieldset>';
655
 
656
+ /* }
657
 
658
  public function news_keywords_field() {
659
  $options = parent::get_option('news_tags');
660
+ $prefix = parent::prefix();*/
661
 
662
  $keywords = !empty($options['keywords']) ? $options['keywords'] : array();
663
  $keywords_from = !empty($keywords['from']) ? $keywords['from'] : '';
664
  echo '
665
+ <fieldset id="xmlsf_news_keywords"><legend class="screen-reader-text">&lt;keywords&gt;</legend>
666
+ '.sprintf(__('The %s tag is used to help classify the articles you submit to Google News by <strong>topic</strong>.','xml-sitemap-feed'),'<strong>&lt;keywords&gt;</strong>').'
667
  <ul>
668
  <li><label>'.sprintf(__('Use %s for topics.','xml-sitemap-feed'),' <select name="'.$prefix.'news_tags[keywords][from]" id="xmlsf_news_tags_keywords_from">
669
  <option value="">'.translate('None').'</option>
813
  $line = trim($line);
814
  $parsed_url = parse_url(trim(filter_var($line,FILTER_SANITIZE_URL)));
815
  // Before PHP version 5.4.7, parse_url will return the domain as path when scheme is omitted so we do:
816
+ if ( !empty($parsed_url['host']) ) {
817
+ $domain = trim( $parsed_url['host'] );
818
+ } else {
819
+ $domain_arr = explode('/', $parsed_url['path']);
820
+ $domain_arr = array_filter($domain_arr);
821
+ $domain = array_shift( $domain_arr );
822
+ $domain = trim( $domain );
823
+ }
824
+
825
  // filter out empties and default domain
826
  if(!empty($domain) && $domain !== $default && strpos($domain,".".$default) === false)
827
  $sanitized[] = $domain;
848
  */
849
 
850
  /* Adds a box to the side column */
851
+ public function add_meta_boxes()
852
  {
853
+ // XML Sitemap
854
  foreach (parent::get_post_types() as $post_type) {
855
+ // Only include metaboxes on post types that are included
856
  if (isset($post_type["active"]))
857
  add_meta_box(
858
  'xmlsf_section',
862
  'side'
863
  );
864
  }
865
+ // Google News Sitemap
866
+ // Only include metaboxes on post types that are included
867
+ $news_tags = parent::get_option('news_tags');
868
+ foreach ( (array)$news_tags['post_type'] as $post_type ) {
869
+ add_meta_box(
870
+ 'xmlsf_news_section',
871
+ __( 'Google News Sitemap', 'xml-sitemap-feed' ),
872
+ array($this,'meta_box_news'),
873
+ $post_type,
874
+ 'side'
875
+ );
876
+ }
877
  }
878
 
879
  public function meta_box($post)
883
 
884
  // The actual fields for data entry
885
  // Use get_post_meta to retrieve an existing value from the database and use the value for the form
886
+ $exclude = get_post_meta( $post->ID, '_xmlsf_exclude', true );
887
  $priority = get_post_meta( $post->ID, '_xmlsf_priority', true );
888
  $disabled = '';
889
 
890
  // disable options and (visibly) set excluded to true for private posts
891
  if ( 'private' == $post->post_status ) {
892
  $disabled = ' disabled="disabled"';
893
+ $exclude = true;
894
  }
895
 
896
  // disable options and (visibly) set priority to 1 for front page
899
  $priority = '1'; // force excluded to true for private posts
900
  }
901
 
902
+ echo '<p><label><input type="checkbox" name="xmlsf_exclude" id="xmlsf_exclude" value="1"'.checked(!empty($exclude), true, false).$disabled.' > ';
903
  _e('Exclude from XML Sitemap','xml-sitemap-feed');
904
  echo '</label></p>';
905
 
906
  echo '<p><label>';
907
  _e('Priority','xml-sitemap-feed');
908
  echo ' <input type="number" step="0.1" min="0" max="1" name="xmlsf_priority" id="xmlsf_priority" value="'.$priority.'" class="small-text"'.$disabled.'></label> <span class="description">';
909
+ printf(__('Leave empty for automatic Priority as configured on %1$s > %2$s.','xml-sitemap-feed'),translate('Settings'),'<a href="' . admin_url('options-reading.php') . '#xmlsf">' . translate('Reading') . '</a>');
910
  echo '</span></p>';
911
  }
912
+
913
+ public function meta_box_news($post)
914
+ {
915
+ // Use nonce for verification
916
+ wp_nonce_field( plugin_basename( __FILE__ ), 'xmlsf_sitemap_nonce' );
917
+
918
+ // The actual fields for data entry
919
+ // Use get_post_meta to retrieve an existing value from the database and use the value for the form
920
+ $exclude = get_post_meta( $post->ID, '_xmlsf_news_exclude', true );
921
+ $access = get_post_meta( $post->ID, '_xmlsf_news_access', true );
922
+ $disabled = '';
923
+
924
+ // disable options and (visibly) set excluded to true for private posts
925
+ if ( 'private' == $post->post_status ) {
926
+ $disabled = ' disabled="disabled"';
927
+ $exclude = true;
928
+ }
929
+
930
+ echo '<p><label>'.__('Access','xml-sitemap-feed').'
931
+ <select name="xmlsf_news_access" id="xmlsf_news_access">
932
+ <option value="">'.translate('Default').'</option>
933
+ <option value="Public" '.selected( "Public" == $access, true, false).'>'.translate('Public').'</option>
934
+ <option value="Registration" '.selected( "Registration" == $access, true, false).'>'.__('Registration','xml-sitemap-feed').'</option>
935
+ <option value="Subscription" '.selected( "Subscription" == $access, true, false).'>'.__('Subscription','xml-sitemap-feed').'</option>
936
+ </select></label></p>';
937
+
938
+ echo '<p><label><input type="checkbox" name="xmlsf_news_exclude" id="xmlsf_news_exclude" value="1"'.checked(!empty($exclude), true, false).$disabled.' > ';
939
+ _e('Exclude from Google News Sitemap','xml-sitemap-feed');
940
+ echo '</label></p>';
941
+ }
942
 
943
  /* When the post is saved, save our meta data */
944
  function save_metadata( $post_id )
963
  delete_post_meta($post_id, '_xmlsf_exclude');
964
  }
965
 
966
+ // _xmlsf_news_exclude
967
+ if ( isset($_POST['xmlsf_news_exclude']) && $_POST['xmlsf_news_exclude'] != '' ) {
968
+ update_post_meta($post_id, '_xmlsf_news_exclude', $_POST['xmlsf_news_exclude']);
969
+ } else {
970
+ delete_post_meta($post_id, '_xmlsf_news_exclude');
971
+ }
972
+
973
+ // _xmlsf_news_access
974
+ if ( isset($_POST['xmlsf_news_access']) && $_POST['xmlsf_news_access'] != '' ) {
975
+ update_post_meta($post_id, '_xmlsf_news_access', $_POST['xmlsf_news_access']);
976
+ } else {
977
+ delete_post_meta($post_id, '_xmlsf_news_access');
978
+ }
979
  }
980
 
981
  /**
1021
  add_settings_field($prefix.'custom_sitemaps', __('Include custom XML Sitemaps','xml-sitemap-feed'), array($this,'custom_sitemaps_settings_field'), 'reading', 'xml_sitemap_section');
1022
 
1023
  // POST META BOX
1024
+ add_action( 'add_meta_boxes', array($this,'add_meta_boxes') );
1025
  add_action( 'save_post', array($this,'save_metadata') );
1026
  }
1027
 
1035
  add_settings_field($prefix.'news_post_type', __('Include post types','xml-sitemap-feed'), array($this,'news_post_type_field'), 'reading', 'news_sitemap_section');
1036
  add_settings_field($prefix.'news_categories', translate('Categories'), array($this,'news_categories_field'), 'reading', 'news_sitemap_section');
1037
  add_settings_field($prefix.'news_image', translate('Images'), array($this,'news_image_field'), 'reading', 'news_sitemap_section');
1038
+ add_settings_field($prefix.'news_labels', __('Source labels','xml-sitemap-feed'), array($this,'news_labels_field'), 'reading', 'news_sitemap_section');
1039
+ // add_settings_field($prefix.'news_keywords', __('Topics','xml-sitemap-feed'), array($this,'news_keywords_field'), 'reading', 'news_sitemap_section');
 
1040
 
1041
  }
1042
 
includes/core.php CHANGED
@@ -1,1305 +1,1364 @@
1
- <?php
2
- /* ------------------------------
3
- * XMLSitemapFeed CLASS
4
- * ------------------------------ */
5
-
6
- if ( !class_exists('XMLSitemapFeed') ) :
7
-
8
- class XMLSitemapFeed {
9
-
10
- /**
11
- * Plugin variables
12
- */
13
-
14
- // Pretty permalinks base name
15
- public $base_name = 'sitemap';
16
-
17
- // Pretty permalinks extension
18
- public $extension = 'xml';
19
-
20
- // Database options prefix
21
- private $prefix = 'xmlsf_';
22
-
23
- // Flushed flag
24
- private $yes_mother = false;
25
-
26
- private $defaults = array();
27
- private $disabled_post_types = array('attachment'); /* attachment post type is disabled... images are included via tags in the post and page sitemaps */
28
- private $disabled_taxonomies = array('post_format'); /* post format taxonomy is brute force disabled for now; might come back... */
29
- private $gn_genres = array(
30
- 'gn-pressrelease' => 'PressRelease',
31
- 'gn-satire' => 'Satire',
32
- 'gn-blog' => 'Blog',
33
- 'gn-oped' => 'OpEd',
34
- 'gn-opinion' => 'Opinion',
35
- 'gn-usergenerated' => 'UserGenerated'
36
- );
37
-
38
- // Global values used for priority and changefreq calculation
39
- private $domain;
40
- private $firstdate;
41
- private $lastmodified; // unused at the moment
42
- private $postmodified = array();
43
- private $termmodified = array();
44
- private $blogpage;
45
- private $images = array();
46
-
47
- // make some private parts public ;)
48
-
49
- public function prefix()
50
- {
51
- return $this->prefix;
52
- }
53
-
54
- public function gn_genres()
55
- {
56
- return $this->gn_genres;
57
- }
58
-
59
- public function domain()
60
- {
61
- // allowed domain
62
- if (empty($this->domain)) {
63
- $url_parsed = parse_url(home_url()); // second parameter PHP_URL_HOST for only PHP5 + ...
64
- $this->domain = str_replace("www.","",$url_parsed['host']);
65
- }
66
-
67
- return $this->domain;
68
- }
69
-
70
- // default options
71
- private function set_defaults()
72
- {
73
- // sitemaps
74
- if ( '1' == get_option('blog_public') )
75
- $this->defaults['sitemaps'] = array(
76
- 'sitemap' => XMLSF_NAME
77
- );
78
- else
79
- $this->defaults['sitemaps'] = array();
80
-
81
- // post_types
82
- $this->defaults['post_types'] = array();
83
- foreach ( get_post_types(array('public'=>true),'names') as $name ) { // want 'publicly_queryable' but that excludes pages for some weird reason
84
- // skip unallowed post types
85
- if (in_array($name,$this->disabled_post_types))
86
- continue;
87
-
88
- $this->defaults['post_types'][$name] = array(
89
- 'name' => $name,
90
- 'active' => '',
91
- 'archive' => '',
92
- 'priority' => '0.5',
93
- 'dynamic_priority' => '',
94
- 'tags' => array('image' => 'attached'/*,'video' => ''*/)
95
- );
96
- }
97
-
98
- $active_arr = array('post','page');
99
-
100
- foreach ( $active_arr as $name )
101
- if ( isset($this->defaults['post_types'][$name]) )
102
- $this->defaults['post_types'][$name]['active'] = '1';
103
-
104
- if ( isset($this->defaults['post_types']['post']) ) {
105
- if (wp_count_posts('post')->publish > 500)
106
- $this->defaults['post_types']['post']['archive'] = 'yearly';
107
- $this->defaults['post_types']['post']['priority'] = '0.7';
108
- $this->defaults['post_types']['post']['dynamic_priority'] = '1';
109
- }
110
-
111
- if ( isset($this->defaults['post_types']['page']) ) {
112
- unset($this->defaults['post_types']['page']['archive']);
113
- $this->defaults['post_types']['page']['priority'] = '0.3';
114
- }
115
-
116
- // taxonomies
117
- $this->defaults['taxonomies'] = array(); // by default do not include any taxonomies
118
-
119
- // news sitemap settings
120
- $this->defaults['news_sitemap'] = array();
121
-
122
- // search engines to ping
123
- $this->defaults['ping'] = array(
124
- 'google' => array (
125
- 'active' => '1',
126
- 'uri' => 'http://www.google.com/webmasters/tools/ping?sitemap=',
127
- 'type' => 'GET',
128
- 'news' => '1'
129
- ),
130
- 'bing' => array (
131
- 'active' => '1',
132
- 'uri' => 'http://www.bing.com/ping?sitemap=',
133
- 'type' => 'GET',
134
- 'news' => '1'
135
- ),
136
- 'yandex' => array (
137
- 'active' => '',
138
- 'uri' => 'http://ping.blogs.yandex.ru/RPC2',
139
- 'type' => 'RPC',
140
- ),
141
- 'baidu' => array (
142
- 'active' => '',
143
- 'uri' => 'http://ping.baidu.com/ping/RPC2',
144
- 'type' => 'RPC',
145
- ),
146
- 'others' => array (
147
- 'active' => '1',
148
- 'uri' => 'http://rpc.pingomatic.com/',
149
- 'type' => 'RPC',
150
- ),
151
- );
152
-
153
- // robots
154
- $this->defaults['robots'] = "";
155
- // Old rules "Disallow: */xmlrpc.php\nDisallow: */wp-*.php\nDisallow: */trackback/\nDisallow: *?wptheme=\nDisallow: *?comments=\nDisallow: *?replytocom\nDisallow: */comment-page-\nDisallow: *?s=\nDisallow: */wp-content/\nAllow: */wp-content/uploads/\n";
156
- // Better is to set <meta name="robots" content="noindex, follow"> or send X-Robots-Tag header. TODO !!
157
-
158
- // additional urls
159
- $this->defaults['urls'] = array();
160
-
161
- // additional custom_sitemaps
162
- $this->defaults['custom_sitemaps'] = array();
163
-
164
- // additional allowed domains
165
- $this->defaults['domains'] = array();
166
-
167
- // news sitemap tags settings
168
- $this->defaults['news_tags'] = array(
169
- 'name' => '',
170
- 'post_type' => array('post'),
171
- 'categories' => '',
172
- 'image' => 'featured',
173
- 'access' => array(
174
- 'default' => '',
175
- //'private' => 'Registration', // private posts do not show up in feeds when not logged in. no point in setting access level then...
176
- 'password' => 'Subscription'
177
- ),
178
- 'genres' => array(
179
- 'active' => '1',
180
- 'default' => array()
181
- ),
182
- 'keywords' => array(
183
- 'from' => 'category',
184
- 'default' => ''
185
- )
186
- );
187
- }
188
-
189
- /**
190
- * QUERY FUNCTIONS
191
- */
192
-
193
- public function defaults($key = false)
194
- {
195
- if (empty($this->defaults))
196
- $this->set_defaults();
197
-
198
- if ($key) {
199
- $return = ( isset($this->defaults[$key]) ) ? $this->defaults[$key] : '';
200
- } else {
201
- $return = $this->defaults;
202
- }
203
-
204
- return apply_filters( 'xmlsf_defaults', $return, $key );
205
- }
206
-
207
- public function get_option($option)
208
- {
209
- return get_option($this->prefix.$option, $this->defaults($option));
210
- }
211
-
212
- public function get_sitemaps()
213
- {
214
- $return = $this->get_option('sitemaps');
215
-
216
- // make sure it's an array we are returning
217
- return (!empty($return)) ? (array)$return : array();
218
- }
219
-
220
- public function get_ping()
221
- {
222
- $return = $this->get_option('ping');
223
-
224
- // make sure it's an array we are returning
225
- return (!empty($return)) ? (array)$return : array();
226
- }
227
-
228
- public function disabled_post_types()
229
- {
230
- return $this->disabled_post_types;
231
-
232
- }
233
-
234
- public function disabled_taxonomies()
235
- {
236
- return $this->disabled_taxonomies;
237
-
238
- }
239
-
240
- public function get_post_types()
241
- {
242
- $return = $this->get_option('post_types');
243
-
244
- // make sure it's an array we are returning
245
- return (!empty($return)) ? (array)$return : array();
246
- }
247
-
248
- public function have_post_types()
249
- {
250
- $return = array();
251
-
252
- foreach ( $this->get_post_types() as $type => $values ) {
253
- if(!empty($values['active'])) {
254
- $count = wp_count_posts( $values['name'] );
255
- if ($count->publish > 0) {
256
- $values['count'] = $count->publish;
257
- $return[$type] = $values;
258
- }
259
- }
260
- }
261
-
262
- // make sure it's an array we are returning
263
- return (!empty($return)) ? (array)$return : array();
264
- }
265
-
266
- public function get_taxonomies()
267
- {
268
- $return = $this->get_option('taxonomies');
269
-
270
- // make sure it's an array we are returning
271
- return (!empty($return)) ? (array)$return : array();
272
- }
273
-
274
- public function get_custom_sitemaps()
275
- {
276
- $return = $this->get_option('custom_sitemaps');
277
-
278
- // make sure it's an array we are returning
279
- if(!empty($return)) {
280
- if(is_array($return))
281
- return $return;
282
- else
283
- return explode("\n",$return);
284
- } else {
285
- return array();
286
- }
287
- }
288
-
289
- public function get_urls()
290
- {
291
- $return = $this->get_option('urls');
292
-
293
- // make sure it's an array we are returning
294
- if(!empty($return)) {
295
- if(is_array($return))
296
- return $return;
297
- else
298
- return explode("\n",$return);
299
- } else {
300
- return array();
301
- }
302
- }
303
-
304
- public function get_domains()
305
- {
306
- $domains = $this->get_option('domains');
307
- if (!empty($domains) && is_array($domains))
308
- return array_merge( array( $this->domain() ), $domains );
309
- else
310
- return array( $this->domain() );
311
- }
312
-
313
- public function get_archives($post_type = 'post', $type = '')
314
- {
315
- global $wpdb;
316
- $return = array();
317
- if ( 'monthly' == $type ) {
318
- $query = "SELECT YEAR(post_date) AS `year`, LPAD(MONTH(post_date),2,'0') AS `month`, count(ID) as posts FROM $wpdb->posts WHERE post_type = '$post_type' AND post_status = 'publish' GROUP BY YEAR(post_date), MONTH(post_date) ORDER BY post_date DESC";
319
- $key = md5($query);
320
- $cache = wp_cache_get( 'xmlsf_get_archives' , 'general');
321
- if ( !isset( $cache[ $key ] ) ) {
322
- $arcresults = $wpdb->get_results($query);
323
- $cache[ $key ] = $arcresults;
324
- wp_cache_set( 'xmlsf_get_archives', $cache, 'general' );
325
- } else {
326
- $arcresults = $cache[ $key ];
327
- }
328
- if ( $arcresults ) {
329
- foreach ( (array) $arcresults as $arcresult ) {
330
- $return[$arcresult->year.$arcresult->month] = esc_html( $this->get_index_url( 'posttype', $post_type, $arcresult->year . $arcresult->month ) );
331
- }
332
- }
333
- } elseif ('yearly' == $type) {
334
- $query = "SELECT YEAR(post_date) AS `year`, count(ID) as posts FROM $wpdb->posts WHERE post_type = '$post_type' AND post_status = 'publish' GROUP BY YEAR(post_date) ORDER BY post_date DESC";
335
- $key = md5($query);
336
- $cache = wp_cache_get( 'xmlsf_get_archives' , 'general');
337
- if ( !isset( $cache[ $key ] ) ) {
338
- $arcresults = $wpdb->get_results($query);
339
- $cache[ $key ] = $arcresults;
340
- wp_cache_set( 'xmlsf_get_archives', $cache, 'general' );
341
- } else {
342
- $arcresults = $cache[ $key ];
343
- }
344
- if ($arcresults) {
345
- foreach ( (array) $arcresults as $arcresult) {
346
- $return[$arcresult->year] = esc_html($this->get_index_url( 'posttype', $post_type, $arcresult->year ) );
347
- }
348
- }
349
- } else {
350
- $return[0] = esc_html($this->get_index_url('posttype', $post_type) ); // $sitemap = 'home', $type = false, $param = false
351
- }
352
- return $return;
353
- }
354
-
355
- public function get_robots()
356
- {
357
- return ( $robots = $this->get_option('robots') ) ? $robots : '';
358
- }
359
-
360
- public function do_tags( $type = 'post' )
361
- {
362
- $return = $this->get_post_types();
363
-
364
- // make sure it's an array we are returning
365
- return (
366
- is_string($type) &&
367
- isset($return[$type]) &&
368
- !empty($return[$type]['tags'])
369
- ) ? (array)$return[$type]['tags'] : array();
370
- }
371
-
372
- public function is_home($id)
373
- {
374
- if ( empty($this->blogpage) ) {
375
- $blogpage = get_option('page_for_posts');
376
-
377
- if ( !empty($blogpage) ) {
378
- global $polylang;
379
- if ( isset($polylang) )
380
- $this->blogpage = $polylang->get_translations('post', $blogpage);
381
- else
382
- $this->blogpage = array($blogpage);
383
- } else {
384
- $this->blogpage = array('-1');
385
- }
386
- }
387
-
388
- return in_array($id,$this->blogpage);
389
- }
390
-
391
- /**
392
- * TEMPLATE FUNCTIONS
393
- */
394
-
395
- public function modified($sitemap = 'post_type', $term = '')
396
- {
397
- if ('post_type' == $sitemap) :
398
-
399
- global $post;
400
-
401
- // if blog page look for last post date
402
- if ( $post->post_type == 'page' && $this->is_home($post->ID) )
403
- return get_lastmodified('GMT','post');
404
-
405
- if ( empty($this->postmodified[$post->ID]) ) {
406
- $postmodified = get_post_modified_time( 'Y-m-d H:i:s', true, $post->ID );
407
- $options = $this->get_post_types();
408
-
409
- if( !empty($options[$post->post_type]['update_lastmod_on_comments']) )
410
- $lastcomment = get_comments( array(
411
- 'status' => 'approve',
412
- 'number' => 1,
413
- 'post_id' => $post->ID,
414
- ) );
415
-
416
- if ( isset($lastcomment[0]->comment_date_gmt) )
417
- if ( mysql2date( 'U', $lastcomment[0]->comment_date_gmt, false ) > mysql2date( 'U', $postmodified, false ) )
418
- $postmodified = $lastcomment[0]->comment_date_gmt;
419
-
420
- // make sure lastmod is not older than publication date (happens on scheduled posts)
421
- if ( isset($post->post_date_gmt) && strtotime($post->post_date_gmt) > strtotime($postmodified) )
422
- $postmodified = $post->post_date_gmt;
423
-
424
- $this->postmodified[$post->ID] = $postmodified;
425
- }
426
-
427
- return $this->postmodified[$post->ID];
428
-
429
- elseif ( !empty($term) ) :
430
-
431
- if ( is_object($term) ) {
432
- if ( !isset($this->termmodified[$term->term_id]) ) {
433
- // get the latest post in this taxonomy item, to use its post_date as lastmod
434
- $posts = get_posts ( array(
435
- 'post_type' => 'any',
436
- 'numberposts' => 1,
437
- 'no_found_rows' => true,
438
- 'update_post_meta_cache' => false,
439
- 'update_post_term_cache' => false,
440
- 'update_cache' => false,
441
- 'tax_query' => array(
442
- array(
443
- 'taxonomy' => $term->taxonomy,
444
- 'field' => 'slug',
445
- 'terms' => $term->slug
446
- )
447
- )
448
- )
449
- );
450
- $this->termmodified[$term->term_id] = isset($posts[0]->post_date_gmt) ? $posts[0]->post_date_gmt : '';
451
- }
452
- return $this->termmodified[$term->term_id];
453
- } else {
454
- $obj = get_taxonomy($term);
455
- return get_lastdate( 'gmt', $obj->object_type );
456
- // uses get_lastdate() function defined in xml-sitemap/hacks.php !
457
- // which is a shortcut: returns last post date, not last modified date...
458
- // TODO find the long way home: take tax type, get all terms,
459
- // do tax_query with all terms for one post and get its lastmod date
460
- // ... or can 'terms' in tax_query be empty?
461
- }
462
-
463
- else :
464
-
465
- return '';
466
-
467
- endif;
468
- }
469
-
470
- public function get_images($sitemap = '')
471
- {
472
- global $post;
473
- if ( empty($this->images[$post->ID]) ) {
474
- if ('news' == $sitemap) {
475
- $options = $this->get_option('news_tags');
476
- $which = isset($options['image']) ? $options['image'] : '';
477
- } else {
478
- $options = $this->get_post_types();
479
- $which = isset($options[$post->post_type]['tags']['image']) ? $options[$post->post_type]['tags']['image'] : '';
480
- }
481
- if('attached' == $which) {
482
- $args = array( 'post_type' => 'attachment', 'post_mime_type' => 'image', 'numberposts' => -1, 'post_status' =>'inherit', 'post_parent' => $post->ID );
483
- $attachments = get_posts($args);
484
- if ($attachments) {
485
- foreach ( $attachments as $attachment ) {
486
- $url = wp_get_attachment_image_src( $attachment->ID, 'full' );
487
- $this->images[$post->ID][] = array(
488
- 'loc' => esc_url( $url[0] ),
489
- 'title' => apply_filters( 'the_title_xmlsitemap', $attachment->post_title ),
490
- 'caption' => apply_filters( 'the_title_xmlsitemap', $attachment->post_excerpt )
491
- );
492
- }
493
- }
494
- } elseif ('featured' == $which) {
495
- if (has_post_thumbnail( $post->ID ) ) {
496
- $attachment = get_post(get_post_thumbnail_id( $post->ID ));
497
- $url = wp_get_attachment_image_src( $attachment->ID, 'full' );
498
- $this->images[$post->ID][] = array(
499
- 'loc' => esc_url( $url[0] ),
500
- 'title' => apply_filters( 'the_title_xmlsitemap', $attachment->post_title ),
501
- 'caption' => apply_filters( 'the_title_xmlsitemap', $attachment->post_excerpt )
502
- );
503
- }
504
- }
505
- }
506
- return ( isset($this->images[$post->ID]) ) ? $this->images[$post->ID] : false;
507
- }
508
-
509
- public function get_lastmod($sitemap = 'post_type', $term = '')
510
- {
511
- $return = trim(mysql2date('Y-m-d\TH:i:s+00:00', $this->modified($sitemap,$term), false));
512
- return !empty($return) ? "\t<lastmod>".$return."</lastmod>\r\n\t" : '';
513
- }
514
-
515
- public function get_changefreq($sitemap = 'post_type', $term = '')
516
- {
517
- $modified = trim($this->modified($sitemap,$term));
518
-
519
- if (empty($modified))
520
- return 'weekly';
521
-
522
- $lastactivityage = ( gmdate('U') - mysql2date( 'U', $modified, false ) ); // post age
523
-
524
- if ( ($lastactivityage/86400) < 1 ) { // last activity less than 1 day old
525
- $changefreq = 'hourly';
526
- } else if ( ($lastactivityage/86400) < 7 ) { // last activity less than 1 week old
527
- $changefreq = 'daily';
528
- } else if ( ($lastactivityage/86400) < 30 ) { // last activity less than one month old
529
- $changefreq = 'weekly';
530
- } else if ( ($lastactivityage/86400) < 365 ) { // last activity less than 1 year old
531
- $changefreq = 'monthly';
532
- } else {
533
- $changefreq = 'yearly'; // over a year old...
534
- }
535
-
536
- return $changefreq;
537
- }
538
-
539
- public function get_priority($sitemap = 'post_type', $term = '')
540
- {
541
- if ( 'post_type' == $sitemap ) :
542
- global $post;
543
- $options = $this->get_post_types();
544
- $defaults = $this->defaults('post_types');
545
- $priority_meta = get_metadata('post', $post->ID, '_xmlsf_priority' , true);
546
-
547
- if ( !empty($priority_meta) || $priority_meta == '0' ) {
548
-
549
- $priority = floatval(str_replace(",",".",$priority_meta));
550
-
551
- } elseif ( !empty($options[$post->post_type]['dynamic_priority']) ) {
552
-
553
- $post_modified = mysql2date('U',$post->post_modified_gmt, false);
554
-
555
- if ( empty($this->lastmodified) )
556
- $this->lastmodified = mysql2date('U',get_lastmodified('GMT',$post->post_type),false);
557
- // last posts or page modified date in Unix seconds
558
- // uses get_lastmodified() function defined in xml-sitemap/hacks.php !
559
-
560
- if ( empty($this->firstdate) )
561
- $this->firstdate = mysql2date('U',get_firstdate('GMT',$post->post_type),false);
562
- // uses get_firstdate() function defined in xml-sitemap/hacks.php !
563
-
564
- if ( isset($options[$post->post_type]['priority']) )
565
- $priority_value = floatval(str_replace(",",".",$options[$post->post_type]['priority']));
566
- else
567
- $priority_value = floatval($defaults[$post->post_type]['priority']);
568
-
569
- // reduce by age
570
- // NOTE : home/blog page gets same treatment as sticky post
571
- if ( is_sticky($post->ID) || $this->is_home($post->ID) )
572
- $priority = $priority_value;
573
- else
574
- $priority = ( $this->lastmodified > $this->firstdate ) ? $priority_value - $priority_value * ( $this->lastmodified - $post_modified ) / ( $this->lastmodified - $this->firstdate ) : $priority_value;
575
-
576
- if ( $post->comment_count > 0 )
577
- $priority = $priority + 0.1 + ( 0.9 - $priority ) * $post->comment_count / wp_count_comments($post->post_type)->approved;
578
-
579
- } else {
580
-
581
- $priority = ( isset($options[$post->post_type]['priority']) && is_numeric($options[$post->post_type]['priority']) ) ? $options[$post->post_type]['priority'] : $defaults[$post->post_type]['priority'];
582
-
583
- }
584
-
585
- elseif ( ! empty($term) ) :
586
-
587
- $max_priority = 0.4;
588
- $min_priority = 0.0;
589
- // TODO make these values optional
590
-
591
- $tax_obj = get_taxonomy($term->taxonomy);
592
- $postcount = 0;
593
- foreach ($tax_obj->object_type as $post_type) {
594
- $_post_count = wp_count_posts($post_type);
595
- $postcount += $_post_count->publish;
596
- }
597
-
598
- $priority = ( $postcount > 0 ) ? $min_priority + ( $max_priority * $term->count / $postcount ) : $min_priority;
599
-
600
- else :
601
-
602
- $priority = 0.5;
603
-
604
- endif;
605
-
606
- // make sure we're not below zero
607
- if ($priority < 0)
608
- $priority = 0;
609
-
610
- // and a final trim for cases where we ended up above 1 (sticky posts with many comments)
611
- if ($priority > 1)
612
- $priority = 1;
613
-
614
- return number_format($priority,1);
615
- }
616
-
617
- public function get_home_urls()
618
- {
619
- $urls = array();
620
-
621
- global $polylang,$q_config;
622
-
623
- if ( isset($polylang) )
624
- foreach ($polylang->get_languages_list() as $term)
625
- $urls[] = $polylang->get_home_url($term);
626
- else
627
- $urls[] = home_url();
628
-
629
- return $urls;
630
- }
631
-
632
- public function get_excluded($post_type)
633
- {
634
- $exclude = array();
635
-
636
- if ( $post_type == 'page' && $id = get_option('page_on_front') ) {
637
- global $polylang;
638
- if ( isset($polylang) )
639
- $exclude += $polylang->get_translations('post', $id);
640
- else
641
- $exclude[] = $id;
642
- }
643
-
644
- return $exclude;
645
- }
646
-
647
- public function is_allowed_domain($url)
648
- {
649
- $domains = $this->get_domains();
650
- $return = false;
651
- $parsed_url = parse_url($url);
652
-
653
- if (isset($parsed_url['host'])) {
654
- foreach( $domains as $domain ) {
655
- if( $parsed_url['host'] == $domain || strpos($parsed_url['host'],".".$domain) !== false ) {
656
- $return = true;
657
- break;
658
- }
659
- }
660
- }
661
-
662
- return apply_filters( 'xmlsf_allowed_domain', $return );
663
- }
664
-
665
- public function get_index_url( $sitemap = 'home', $type = false, $param = false )
666
- {
667
- $root = esc_url( trailingslashit(home_url()) );
668
- $name = $this->base_name.'-'.$sitemap;
669
-
670
- if ( $type )
671
- $name .= '-'.$type;
672
-
673
- if ( '' == get_option('permalink_structure') || '1' != get_option('blog_public')) {
674
- $name = '?feed='.$name;
675
- $name .= $param ? '&m='.$param : '';
676
- } else {
677
- $name .= $param ? '.'.$param : '';
678
- $name .= '.'.$this->extension;
679
- }
680
-
681
- return $root . $name;
682
- }
683
-
684
-
685
- /**
686
- * ROBOTSTXT
687
- */
688
-
689
- // add sitemap location in robots.txt generated by WP
690
- public function robots($output)
691
- {
692
- echo "\n# XML Sitemap & Google News Feeds version ".XMLSF_VERSION." - http://status301.net/wordpress-plugins/xml-sitemap-feed/";
693
-
694
- if ( '1' != get_option('blog_public') ) {
695
- echo "\n# XML Sitemaps are disabled. Please see Site Visibility on Settings > Reading.";
696
- } else {
697
- foreach ( $this->get_sitemaps() as $pretty )
698
- echo "\nSitemap: " . trailingslashit(get_bloginfo('url')) . $pretty;
699
-
700
- if ( empty($pretty) )
701
- echo "\n# No XML Sitemaps are enabled. Please see XML Sitemaps on Settings > Reading.";
702
- }
703
- echo "\n\n";
704
- }
705
-
706
- // add robots.txt rules
707
- public function robots_txt($output)
708
- {
709
- return $output . $this->get_option('robots') . "\n\n";
710
- }
711
-
712
- /**
713
- * REWRITES
714
- */
715
-
716
- /**
717
- * Remove the trailing slash from permalinks that have an extension,
718
- * such as /sitemap.xml (thanks to Permalink Editor plugin for WordPress)
719
- *
720
- * @param string $request
721
- */
722
-
723
- public function trailingslash($request)
724
- {
725
- if (pathinfo($request, PATHINFO_EXTENSION)) {
726
- return untrailingslashit($request);
727
- }
728
- return $request; // trailingslashit($request);
729
- }
730
-
731
- /**
732
- * Add sitemap rewrite rules
733
- *
734
- * @param string $wp_rewrite
735
- */
736
-
737
- public function rewrite_rules($wp_rewrite)
738
- {
739
- $xmlsf_rules = array();
740
- $sitemaps = $this->get_sitemaps();
741
-
742
- foreach ( $sitemaps as $name => $pretty )
743
- $xmlsf_rules[ preg_quote($pretty) . '$' ] = $wp_rewrite->index . '?feed=' . $name;
744
-
745
- if (!empty($sitemaps['sitemap'])) {
746
- // home urls
747
- $xmlsf_rules[ $this->base_name . '-home\.' . $this->extension . '$' ] = $wp_rewrite->index . '?feed=sitemap-home';
748
-
749
- // add rules for post types (can be split by month or year)
750
- foreach ( $this->get_post_types() as $post_type ) {
751
- if ( isset($post_type['active']) && '1' == $post_type['active'] )
752
- $xmlsf_rules[ $this->base_name . '-posttype-' . $post_type['name'] . '\.([0-9]+)?\.?' . $this->extension . '$' ] = $wp_rewrite->index . '?feed=sitemap-posttype-' . $post_type['name'] . '&m=$matches[1]';
753
- }
754
-
755
- // add rules for taxonomies
756
- foreach ( $this->get_taxonomies() as $taxonomy ) {
757
- $xmlsf_rules[ $this->base_name . '-taxonomy-' . $taxonomy . '\.' . $this->extension . '$' ] = $wp_rewrite->index . '?feed=sitemap-taxonomy-' . $taxonomy;
758
- }
759
-
760
- $urls = $this->get_urls();
761
- if(!empty($urls))
762
- $xmlsf_rules[ $this->base_name . '-custom\.' . $this->extension . '$' ] = $wp_rewrite->index . '?feed=sitemap-custom';
763
-
764
- }
765
-
766
- $wp_rewrite->rules = $xmlsf_rules + $wp_rewrite->rules;
767
- }
768
-
769
- /**
770
- * REQUEST FILTER
771
- */
772
- public function template( $theme ) {
773
-
774
- if ( isset($request['feed']) && strpos($request['feed'],'sitemap') == 0 )
775
- // clear get_template response to prevent themes functions.php (another source of blank line problems) from loading
776
- return '';
777
- else
778
- return $theme;
779
- }
780
-
781
- public function filter_request( $request )
782
- {
783
- if ( isset($request['feed']) && strpos($request['feed'],'sitemap') == 0 ) {
784
-
785
- if ( $request['feed'] == 'sitemap' ) {
786
-
787
- // setup actions and filters
788
- add_action('do_feed_sitemap', array($this, 'load_template_index'), 10, 1);
789
-
790
- return $request;
791
- }
792
-
793
- if ( $request['feed'] == 'sitemap-news' ) {
794
- $defaults = $this->defaults('news_tags');
795
- $options = $this->get_option('news_tags');
796
- $news_post_type = isset($options['post_type']) && !empty($options['post_type']) ? $options['post_type'] : $defaults['post_type'];
797
- if (empty($news_post_type)) $news_post_type = 'post';
798
-
799
- // disable caching
800
- define('DONOTCACHEPAGE', true);
801
- define('DONOTCACHEDB', true);
802
-
803
- // setup template
804
- add_action('do_feed_sitemap-news', array($this, 'load_template_news'), 10, 1);
805
-
806
- // set up query filters
807
- // TODO: test 'gmt' against 'blog' against 'server'
808
-
809
- if ( function_exists('date_default_timezone_set') ) {
810
- date_default_timezone_set ( 'UTC' );
811
- $zone = 'gmt';
812
- } else {
813
- $zone = 'blog';
814
- }
815
- if ( get_lastdate($zone, $news_post_type) > date('Y-m-d H:i:s', strtotime('-48 hours')) ) {
816
- add_filter('post_limits', array($this, 'filter_news_limits'));
817
- add_filter('posts_where', array($this, 'filter_news_where'), 10, 1);
818
- } else {
819
- add_filter('post_limits', array($this, 'filter_no_news_limits'));
820
- }
821
-
822
- /* modify request parameters */
823
- // post type
824
- $request['post_type'] = $news_post_type;
825
-
826
- // categories
827
- if ( isset($options['categories']) && is_array($options['categories']) )
828
- $request['cat'] = implode(',',$options['categories']);
829
-
830
- $request['post_status'] = 'publish';
831
- $request['no_found_rows'] = true;
832
-
833
- return $request;
834
- }
835
-
836
- if ( $request['feed'] == 'sitemap-home' ) {
837
- // setup actions and filters
838
- add_action('do_feed_sitemap-home', array($this, 'load_template_base'), 10, 1);
839
-
840
- return $request;
841
- }
842
-
843
- if ( strpos($request['feed'],'sitemap-posttype') == 0 ) {
844
- foreach ( $this->get_post_types() as $post_type ) {
845
- if ( $request['feed'] == 'sitemap-posttype-'.$post_type['name'] ) {
846
- // setup actions and filters
847
- add_action('do_feed_sitemap-posttype-'.$post_type['name'], array($this, 'load_template'), 10, 1);
848
- add_filter( 'post_limits', array($this, 'filter_limits') );
849
-
850
- // modify request parameters
851
- $request['post_type'] = $post_type['name'];
852
- $request['post_status'] = 'publish';
853
- $request['orderby'] = 'modified';
854
- $request['lang'] = '';
855
- $request['no_found_rows'] = true;
856
- $request['update_post_meta_cache'] = false;
857
- $request['update_post_term_cache'] = false;
858
-
859
- return $request;
860
- }
861
- }
862
- }
863
-
864
- if ( strpos($request['feed'],'sitemap-taxonomy') == 0 ) {
865
- foreach ( $this->get_taxonomies() as $taxonomy ) {
866
- if ( $request['feed'] == 'sitemap-taxonomy-'.$taxonomy ) {
867
- // setup actions and filters
868
- add_action('do_feed_sitemap-taxonomy-'.$taxonomy, array($this, 'load_template_taxonomy'), 10, 1);
869
-
870
- // modify request parameters
871
- $request['taxonomy'] = $taxonomy;
872
- $request['lang'] = '';
873
- $request['no_found_rows'] = true;
874
- $request['cache_results'] = false;
875
- $request['update_post_term_cache'] = false;
876
- $request['update_post_meta_cache'] = false;
877
- $request['post_status'] = 'publish';
878
-
879
- return $request;
880
- }
881
- }
882
- }
883
-
884
- if ( strpos($request['feed'],'sitemap-custom') == 0 ) {
885
- // setup actions and filters
886
- add_action('do_feed_sitemap-custom', array($this, 'load_template_custom'), 10, 1);
887
-
888
- return $request;
889
- }
890
-
891
- }
892
-
893
- return $request;
894
- }
895
-
896
- /**
897
- * FEED TEMPLATES
898
- */
899
-
900
- // set up the sitemap index template
901
- public function load_template_index()
902
- {
903
- load_template( dirname( __FILE__ ) . '/feed-sitemap.php' );
904
- }
905
-
906
- // set up the sitemap home page(s) template
907
- public function load_template_base()
908
- {
909
- load_template( dirname( __FILE__ ) . '/feed-sitemap-home.php' );
910
- }
911
-
912
- // set up the post types sitemap template
913
- public function load_template()
914
- {
915
- load_template( dirname( __FILE__ ) . '/feed-sitemap-post_type.php' );
916
- }
917
-
918
- // set up the taxonomy sitemap template
919
- public function load_template_taxonomy()
920
- {
921
- load_template( dirname( __FILE__ ) . '/feed-sitemap-taxonomy.php' );
922
- }
923
-
924
- // set up the news sitemap template
925
- public function load_template_news()
926
- {
927
- load_template( dirname( __FILE__ ) . '/feed-sitemap-news.php' );
928
- }
929
-
930
- // set up the news sitemap template
931
- public function load_template_custom()
932
- {
933
- load_template( dirname( __FILE__ ) . '/feed-sitemap-custom.php' );
934
- }
935
-
936
- /**
937
- * LIMITS
938
- */
939
-
940
- // override default feed limit
941
- public function filter_limits( $limits )
942
- {
943
- return 'LIMIT 0, 50000';
944
- }
945
-
946
- // override default feed limit for taxonomy sitemaps
947
- public function filter_limits_taxonomy( $limits )
948
- {
949
- return 'LIMIT 0, 1';
950
- }
951
-
952
- // override default feed limit for GN
953
- public function filter_news_limits( $limits )
954
- {
955
- return 'LIMIT 0, 1000';
956
- }
957
- public function filter_no_news_limits( $limits )
958
- {
959
- return 'LIMIT 0, 1';
960
- }
961
-
962
- // Create a new filtering function that will add a where clause to the query,
963
- // used for the Google News Sitemap
964
- public function filter_news_where( $where = '' )
965
- {
966
- // only posts from the last 48 hours
967
- if ( function_exists('date_default_timezone_set') ) {
968
- date_default_timezone_set ( 'UTC' );
969
- return $where . " AND post_date_gmt > '" . date('Y-m-d H:i:s', strtotime('-48 hours')) . "'";
970
- } else {
971
- return $where . " AND post_date > '" . date('Y-m-d H:i:s', strtotime('-48 hours')) . "'";
972
- }
973
- }
974
-
975
-
976
- /**
977
- * PINGING
978
- */
979
-
980
- public function ping($uri, $timeout = 3)
981
- {
982
- $options = array();
983
- $options['timeout'] = $timeout;
984
-
985
- $response = wp_remote_request( $uri, $options );
986
-
987
- if ( '200' == wp_remote_retrieve_response_code($response) )
988
- $succes = true;
989
- else
990
- $succes = false;
991
-
992
- return $succes;
993
- }
994
-
995
- public function do_pings($new_status, $old_status, $post)
996
- {
997
- $sitemaps = $this->get_sitemaps();
998
- $to_ping = $this->get_ping();
999
- $update = false;
1000
-
1001
- // first check if news sitemap is set
1002
- if ( !empty($sitemaps['sitemap-news']) ) {
1003
- // then check if we've got a post type that is included in our news sitemap
1004
- $news_tags = $this->get_option('news_tags');
1005
- if ( !empty($news_tags['post_type']) && is_array($news_tags['post_type']) && in_array($post->post_type,$news_tags['post_type']) ) {
1006
- // are we publishing?
1007
- if ( $old_status != 'publish' && $new_status == 'publish' ) {
1008
- // loop through ping targets
1009
- foreach ($to_ping as $se => $data) {
1010
- // check active switch
1011
- if( empty($data['active']) || empty($data['news']) )
1012
- continue;
1013
- // and if we did not ping already within the last 5 minutes
1014
- if( !empty($data['pong']) && is_array($data['pong']) && !empty($data['pong'][$sitemaps['sitemap-news']]) && (int)$data['pong'][$sitemaps['sitemap-news']] + 300 > time() )
1015
- continue;
1016
- // ping !
1017
- if ( $this->ping( $data['uri'].urlencode(trailingslashit(get_bloginfo('url')) . $sitemaps['sitemap-news']) ) ) {
1018
- $to_ping[$se]['pong'][$sitemaps['sitemap-news']] = time();
1019
- $update = true;
1020
- }
1021
-
1022
- }
1023
- }
1024
- }
1025
- }
1026
-
1027
- // first check if regular sitemap is set
1028
- if ( !empty($sitemaps['sitemap']) ) {
1029
- // then check if we've got a post type that is included in our sitemap
1030
- foreach($this->get_post_types() as $post_type) {
1031
- if ( !empty($post_type) && is_array($post_type) && in_array($post->post_type,$post_type) ) {
1032
- // are we publishing?
1033
- if ( $old_status != 'publish' && $new_status == 'publish' ) {
1034
- foreach ($to_ping as $se => $data) {
1035
- // check active switch
1036
- if( empty($data['active']) || empty($data['type']) || $data['type']!='GET' )
1037
- continue;
1038
- // and if we did not ping already within the last hour
1039
- if( !empty($data['pong']) && is_array($data['pong']) && !empty($data['pong'][$sitemaps['sitemap']]) && (int)$data['pong'][$sitemaps['sitemap']] + 3600 > time() )
1040
- continue;
1041
- // ping !
1042
- if ( $this->ping( $data['uri'].urlencode(trailingslashit(get_bloginfo('url')) . $sitemaps['sitemap']) ) ) {
1043
- $to_ping[$se]['pong'][$sitemaps['sitemap']] = time();
1044
- $update = true;
1045
- }
1046
- }
1047
- }
1048
- }
1049
- }
1050
- }
1051
-
1052
- if ( $update ) update_option($this->prefix.'ping',$to_ping);
1053
- }
1054
-
1055
- /**
1056
- * CLEAR ALL SETTINGS
1057
- */
1058
-
1059
- public function clear_settings()
1060
- {
1061
- delete_option('xmlsf_version');
1062
- foreach ( $this->defaults() as $option => $settings ) {
1063
- delete_option('xmlsf_'.$option);
1064
- }
1065
-
1066
- if ( defined('WP_DEBUG') && WP_DEBUG )
1067
- error_log('XML Sitemap Feeds settings cleared');
1068
- }
1069
-
1070
- function cache_flush()
1071
- {
1072
- // make this optional?
1073
- wp_cache_flush();
1074
- }
1075
-
1076
- /**
1077
- * INITIALISATION
1078
- */
1079
-
1080
- public function upgrade($version)
1081
- {
1082
- // rewrite rules not available on plugins_loaded
1083
- // and don't flush rules from init as Polylang chokes on that
1084
- // just remove the db option and let WP regenerate them when ready...
1085
- delete_option('rewrite_rules');
1086
- // ... but make sure rules are regenerated when admin is visited.
1087
- set_transient('xmlsf_flush_rewrite_rules','');
1088
-
1089
- // remove robots.txt rule blocking stylesheets, but only one time!
1090
- if ( version_compare('4.4', $version, '>') && $robot_rules = get_option($this->prefix.'robots')) {
1091
- $robot_rules = str_replace(array("Disallow: */wp-content/","Allow: */wp-content/uploads/"),"",$robot_rules);
1092
- delete_option($this->prefix.'robots');
1093
- add_option($this->prefix.'robots', $robot_rules, '', 'no');
1094
- }
1095
-
1096
- if ( version_compare('4.4.1', $version, '>') ) {
1097
- // register location taxonomies then delete all terms
1098
-
1099
- register_taxonomy( 'gn-location-3', null );
1100
-
1101
- $terms = get_terms('gn-location-3',array('hide_empty' => false));
1102
-
1103
- foreach ( $terms as $term )
1104
- wp_delete_term( $term->term_id, 'gn-location-3' );
1105
-
1106
- register_taxonomy( 'gn-location-2', null );
1107
-
1108
- $terms = get_terms('gn-location-2',array('hide_empty' => false));
1109
-
1110
- foreach ( $terms as $term )
1111
- wp_delete_term( $term->term_id, 'gn-location-2' );
1112
-
1113
- register_taxonomy( 'gn-location-1', null );
1114
-
1115
- $terms = get_terms('gn-location-1',array('hide_empty' => false));
1116
-
1117
- foreach ( $terms as $term )
1118
- wp_delete_term( $term->term_id, 'gn-location-1' );
1119
-
1120
- }
1121
-
1122
- // upgrade pings
1123
- if ( $pong = get_option( $this->prefix.'pong' ) && is_array($pong) ) {
1124
- $ping = $this->get_ping();
1125
- foreach ( $pong as $se => $arr) {
1126
- if ( is_array( $arr ) ) {
1127
- // convert formatted time to unix time
1128
- foreach ( $arr as $pretty => $date ) {
1129
- $time = strtotime($date);
1130
- $arr[$pretty] = (int)$time < time() ? $time : '';
1131
- }
1132
- // and set array
1133
- $ping[$se]['pong'] = $arr;
1134
- }
1135
- }
1136
- delete_option( $this->prefix.'pong' );
1137
- delete_option( $this->prefix.'ping' );
1138
- add_option( $this->prefix.'ping', array_merge( $this->defaults('ping'), $ping ), '', 'no' );
1139
- }
1140
-
1141
- delete_option('xmlsf_version');
1142
- add_option($this->prefix.'version', XMLSF_VERSION, '', 'no');
1143
-
1144
- if ( defined('WP_DEBUG') && WP_DEBUG )
1145
- error_log('XML Sitemap Feeds upgraded from '.$version.' to '.XMLSF_VERSION);
1146
-
1147
- }
1148
-
1149
- public function plugins_loaded()
1150
- {
1151
- // TEXT DOMAIN
1152
- if ( is_admin() ) // text domain needed on admin only
1153
- load_plugin_textdomain('xml-sitemap-feed', false, dirname(dirname(plugin_basename( __FILE__ ))) . '/languages' );
1154
-
1155
- }
1156
-
1157
- public function init()
1158
- {
1159
- // UPGRADE
1160
- $version = get_option('xmlsf_version', 0);
1161
-
1162
- if ( version_compare(XMLSF_VERSION, $version, '>') )
1163
- $this->upgrade($version);
1164
-
1165
- // TAXONOMIES
1166
- $sitemaps = $this->get_sitemaps();
1167
-
1168
- if (isset($sitemaps['sitemap-news'])) {
1169
- // register the taxonomies
1170
- $this->register_gn_taxonomies();
1171
-
1172
- // create terms
1173
- if ( delete_transient('xmlsf_create_genres') ) {
1174
- foreach ($this->gn_genres as $slug => $name) {
1175
- wp_insert_term( $name, 'gn-genre', array(
1176
- 'slug' => $slug,
1177
- ) );
1178
- }
1179
- }
1180
- }
1181
-
1182
- }
1183
-
1184
- public function admin_init()
1185
- {
1186
- // CATCH TRANSIENT for reset
1187
- if (delete_transient('xmlsf_clear_settings'))
1188
- $this->clear_settings();
1189
-
1190
- // CATCH TRANSIENT for flushing rewrite rules after the sitemaps setting has changed
1191
- if (delete_transient('xmlsf_flush_rewrite_rules'))
1192
- $this->flush_rules();
1193
-
1194
- // Include the admin class file
1195
- include_once( dirname(__FILE__) . '/admin.php' );
1196
-
1197
- }
1198
-
1199
- public function flush_rules($hard = false)
1200
- {
1201
- // did you flush already?
1202
- if ($this->yes_mother)
1203
- return; // yes, mother!
1204
-
1205
- global $wp_rewrite;
1206
- // don't need hard flush by default
1207
- $wp_rewrite->flush_rules($hard);
1208
-
1209
- if ( defined('WP_DEBUG') && WP_DEBUG )
1210
- error_log('XML Sitemap Feeds rewrite rules flushed');
1211
-
1212
- $this->yes_mother = true;
1213
- }
1214
-
1215
- public function register_gn_taxonomies()
1216
- {
1217
- $defaults = $this->defaults('news_tags');
1218
- $options = $this->get_option('news_tags');
1219
-
1220
- $post_types = !empty($options['post_type']) ? $options['post_type'] : $defaults['post_type'];
1221
-
1222
- register_taxonomy( 'gn-genre', $post_types, array(
1223
- 'hierarchical' => true,
1224
- 'labels' => array(
1225
- 'name' => __('Google News Genres','xml-sitemap-feed'),
1226
- 'singular_name' => __('Google News Genre','xml-sitemap-feed'),
1227
- //'menu_name' => __('GN Genres','xml-sitemap-feed'),
1228
- ),
1229
- 'public' => false,
1230
- 'show_ui' => true,
1231
- 'show_tagcloud' => false,
1232
- 'query_var' => false,
1233
- 'capabilities' => array( // prevent creation / deletion
1234
- 'manage_terms' => 'nobody',
1235
- 'edit_terms' => 'nobody',
1236
- 'delete_terms' => 'nobody',
1237
- 'assign_terms' => 'edit_posts'
1238
- )
1239
- ));
1240
-
1241
- }
1242
-
1243
- // for debugging
1244
- public function _e_usage()
1245
- {
1246
- if (defined('WP_DEBUG') && WP_DEBUG == true) {
1247
- echo '<!-- Queries executed '.get_num_queries();
1248
- if(function_exists('memory_get_peak_usage'))
1249
- echo ' | Peak memory usage '.round(memory_get_peak_usage()/1024/1024,2).'M';
1250
- echo ' -->';
1251
- }
1252
- }
1253
-
1254
- /**
1255
- * CONSTRUCTOR
1256
- */
1257
-
1258
- function __construct()
1259
- {
1260
- // sitemap element filters
1261
- add_filter('the_title_xmlsitemap', 'strip_tags');
1262
- add_filter('the_title_xmlsitemap', 'ent2ncr', 8);
1263
- add_filter('the_title_xmlsitemap', 'esc_html');
1264
- add_filter('bloginfo_xmlsitemap', 'ent2ncr', 8);
1265
-
1266
- // TEMPLATE
1267
- add_filter('template', array($this, 'template'), 0); //create_function ( string $args , string $code )
1268
-
1269
- // REQUEST main filtering function
1270
- add_filter('request', array($this, 'filter_request'), 1 );
1271
-
1272
- // TEXT DOMAIN, UPGRADE PROCESS ...
1273
- add_action('plugins_loaded', array($this,'plugins_loaded'), 11 );
1274
-
1275
- // REWRITES
1276
- add_action('generate_rewrite_rules', array($this, 'rewrite_rules') );
1277
- add_filter('user_trailingslashit', array($this, 'trailingslash') );
1278
-
1279
- // TAXONOMY
1280
- add_action('init', array($this,'init'), 0 );
1281
-
1282
- // REGISTER SETTINGS, SETTINGS FIELDS...
1283
- add_action('admin_init', array($this,'admin_init'));
1284
-
1285
- // ROBOTSTXT
1286
- add_action('do_robotstxt', array($this, 'robots'), 0 );
1287
- add_filter('robots_txt', array($this, 'robots_txt'), 0 );
1288
-
1289
- // PINGING
1290
- add_action('transition_post_status', array($this, 'do_pings'), 10, 3);
1291
-
1292
- // CLEAR OBJECT CACHE
1293
- add_action('transition_post_status', array($this, 'cache_flush'), 99);
1294
-
1295
- // ACTIVATION
1296
- // activation currently same as upgrade routine based on db version check
1297
- //register_activation_hook( XMLSF_PLUGIN_BASENAME, array($this, 'activate') );
1298
-
1299
- // DE-ACTIVATION
1300
- register_deactivation_hook( XMLSF_PLUGIN_BASENAME, array($this, 'flush_rules') );
1301
-
1302
- }
1303
- }
1304
-
1305
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* ------------------------------
3
+ * XMLSitemapFeed CLASS
4
+ * ------------------------------ */
5
+
6
+ if ( !class_exists('XMLSitemapFeed') ) :
7
+
8
+ class XMLSitemapFeed {
9
+
10
+ /**
11
+ * Plugin variables
12
+ */
13
+
14
+ // Pretty permalinks base name
15
+ public $base_name = 'sitemap';
16
+
17
+ // Pretty permalinks extension
18
+ public $extension = 'xml';
19
+
20
+ // Database options prefix
21
+ private $prefix = 'xmlsf_';
22
+
23
+ // Flushed flag
24
+ private $yes_mother = false;
25
+
26
+ private $defaults = array();
27
+ private $disabled_post_types = array('attachment'); /* attachment post type is disabled... images are included via tags in the post and page sitemaps */
28
+ private $disabled_taxonomies = array('post_format'); /* post format taxonomy is brute force disabled for now; might come back... */
29
+ private $gn_genres = array(
30
+ 'PressRelease',
31
+ 'Satire',
32
+ 'Blog',
33
+ 'OpEd',
34
+ 'Opinion',
35
+ 'UserGenerated'
36
+ );
37
+
38
+ // Global values used for priority and changefreq calculation
39
+ private $domain;
40
+ private $firstdate;
41
+ private $lastmodified; // unused at the moment
42
+ private $postmodified = array();
43
+ private $termmodified = array();
44
+ private $blogpage;
45
+ private $images = array();
46
+
47
+ // make some private parts public ;)
48
+
49
+ public function prefix()
50
+ {
51
+ return $this->prefix;
52
+ }
53
+
54
+ public function gn_genres()
55
+ {
56
+ return $this->gn_genres;
57
+ }
58
+
59
+ public function domain()
60
+ {
61
+ // allowed domain
62
+ if (empty($this->domain)) {
63
+ $url_parsed = parse_url(home_url()); // second parameter PHP_URL_HOST for only PHP5 + ...
64
+ $this->domain = str_replace("www.","",$url_parsed['host']);
65
+ }
66
+
67
+ return $this->domain;
68
+ }
69
+
70
+ // default options
71
+ private function set_defaults()
72
+ {
73
+ // sitemaps
74
+ if ( '1' == get_option('blog_public') )
75
+ $this->defaults['sitemaps'] = array(
76
+ 'sitemap' => XMLSF_NAME
77
+ );
78
+ else
79
+ $this->defaults['sitemaps'] = array();
80
+
81
+ // post_types
82
+ $this->defaults['post_types'] = array();
83
+ foreach ( get_post_types(array('public'=>true),'names') as $name ) { // want 'publicly_queryable' but that excludes pages for some weird reason
84
+ // skip unallowed post types
85
+ if (in_array($name,$this->disabled_post_types))
86
+ continue;
87
+
88
+ $this->defaults['post_types'][$name] = array(
89
+ 'name' => $name,
90
+ 'active' => '',
91
+ 'archive' => '',
92
+ 'priority' => '0.5',
93
+ 'dynamic_priority' => '',
94
+ 'tags' => array('image' => 'attached'/*,'video' => ''*/)
95
+ );
96
+ }
97
+
98
+ $active_arr = array('post','page');
99
+
100
+ foreach ( $active_arr as $name )
101
+ if ( isset($this->defaults['post_types'][$name]) )
102
+ $this->defaults['post_types'][$name]['active'] = '1';
103
+
104
+ if ( isset($this->defaults['post_types']['post']) ) {
105
+ if (wp_count_posts('post')->publish > 500)
106
+ $this->defaults['post_types']['post']['archive'] = 'yearly';
107
+ $this->defaults['post_types']['post']['priority'] = '0.7';
108
+ $this->defaults['post_types']['post']['dynamic_priority'] = '1';
109
+ }
110
+
111
+ if ( isset($this->defaults['post_types']['page']) ) {
112
+ unset($this->defaults['post_types']['page']['archive']);
113
+ $this->defaults['post_types']['page']['priority'] = '0.3';
114
+ }
115
+
116
+ // taxonomies
117
+ $this->defaults['taxonomies'] = array(); // by default do not include any taxonomies
118
+
119
+ // news sitemap settings
120
+ $this->defaults['news_sitemap'] = array();
121
+
122
+ // search engines to ping
123
+ $this->defaults['ping'] = array(
124
+ 'google' => array (
125
+ 'active' => '1',
126
+ 'uri' => 'http://www.google.com/webmasters/tools/ping?sitemap=',
127
+ 'type' => 'GET',
128
+ 'news' => '1'
129
+ ),
130
+ 'bing' => array (
131
+ 'active' => '1',
132
+ 'uri' => 'http://www.bing.com/ping?sitemap=',
133
+ 'type' => 'GET',
134
+ 'news' => '1'
135
+ ),
136
+ 'yandex' => array (
137
+ 'active' => '',
138
+ 'uri' => 'http://ping.blogs.yandex.ru/RPC2',
139
+ 'type' => 'RPC',
140
+ ),
141
+ 'baidu' => array (
142
+ 'active' => '',
143
+ 'uri' => 'http://ping.baidu.com/ping/RPC2',
144
+ 'type' => 'RPC',
145
+ ),
146
+ 'others' => array (
147
+ 'active' => '1',
148
+ 'uri' => 'http://rpc.pingomatic.com/',
149
+ 'type' => 'RPC',
150
+ ),
151
+ );
152
+
153
+ // robots
154
+ $this->defaults['robots'] = "";
155
+ // Old rules "Disallow: */xmlrpc.php\nDisallow: */wp-*.php\nDisallow: */trackback/\nDisallow: *?wptheme=\nDisallow: *?comments=\nDisallow: *?replytocom\nDisallow: */comment-page-\nDisallow: *?s=\nDisallow: */wp-content/\nAllow: */wp-content/uploads/\n";
156
+ // Better is to set <meta name="robots" content="noindex, follow"> or send X-Robots-Tag header. TODO !!
157
+
158
+ // additional urls
159
+ $this->defaults['urls'] = array();
160
+
161
+ // additional custom_sitemaps
162
+ $this->defaults['custom_sitemaps'] = array();
163
+
164
+ // additional allowed domains
165
+ $this->defaults['domains'] = array();
166
+
167
+ // news sitemap tags settings
168
+ $this->defaults['news_tags'] = array(
169
+ 'name' => '',
170
+ 'post_type' => array('post'),
171
+ 'categories' => '',
172
+ 'image' => 'featured',
173
+ 'access' => array(
174
+ 'default' => '',
175
+ //'private' => 'Registration', // private posts do not show up in feeds when not logged in. no point in setting access level then...
176
+ 'password' => 'Subscription'
177
+ ),
178
+ 'genres' => array(
179
+ 'active' => '1',
180
+ 'default' => array('Blog')
181
+ ),
182
+ 'keywords' => array(
183
+ 'from' => 'category',
184
+ 'default' => ''
185
+ )
186
+ );
187
+ }
188
+
189
+ /**
190
+ * QUERY FUNCTIONS
191
+ */
192
+
193
+ public function defaults($key = false)
194
+ {
195
+ if (empty($this->defaults))
196
+ $this->set_defaults();
197
+
198
+ if ($key) {
199
+ $return = ( isset($this->defaults[$key]) ) ? $this->defaults[$key] : '';
200
+ } else {
201
+ $return = $this->defaults;
202
+ }
203
+
204
+ return apply_filters( 'xmlsf_defaults', $return, $key );
205
+ }
206
+
207
+ public function get_option($option)
208
+ {
209
+ return get_option($this->prefix.$option, $this->defaults($option));
210
+ }
211
+
212
+ public function get_sitemaps()
213
+ {
214
+ $return = $this->get_option('sitemaps');
215
+
216
+ // make sure it's an array we are returning
217
+ return (!empty($return)) ? (array)$return : array();
218
+ }
219
+
220
+ public function get_ping()
221
+ {
222
+ $return = $this->get_option('ping');
223
+
224
+ // make sure it's an array we are returning
225
+ return (!empty($return)) ? (array)$return : array();
226
+ }
227
+
228
+ public function disabled_post_types()
229
+ {
230
+ return $this->disabled_post_types;
231
+
232
+ }
233
+
234
+ public function disabled_taxonomies()
235
+ {
236
+ return $this->disabled_taxonomies;
237
+
238
+ }
239
+
240
+ public function get_post_types()
241
+ {
242
+ $return = $this->get_option('post_types');
243
+
244
+ // make sure it's an array we are returning
245
+ return (!empty($return)) ? (array)$return : array();
246
+ }
247
+
248
+ public function have_post_types()
249
+ {
250
+ $return = array();
251
+
252
+ foreach ( $this->get_post_types() as $type => $values ) {
253
+ if(!empty($values['active'])) {
254
+ $count = wp_count_posts( $values['name'] );
255
+ if ($count->publish > 0) {
256
+ $values['count'] = $count->publish;
257
+ $return[$type] = $values;
258
+ }
259
+ }
260
+ }
261
+
262
+ // make sure it's an array we are returning
263
+ return (!empty($return)) ? (array)$return : array();
264
+ }
265
+
266
+ public function get_taxonomies()
267
+ {
268
+ $return = $this->get_option('taxonomies');
269
+
270
+ // make sure it's an array we are returning
271
+ return (!empty($return)) ? (array)$return : array();
272
+ }
273
+
274
+ public function get_custom_sitemaps()
275
+ {
276
+ $return = $this->get_option('custom_sitemaps');
277
+
278
+ // make sure it's an array we are returning
279
+ if(!empty($return)) {
280
+ if(is_array($return))
281
+ return $return;
282
+ else
283
+ return explode("\n",$return);
284
+ } else {
285
+ return array();
286
+ }
287
+ }
288
+
289
+ public function get_urls()
290
+ {
291
+ $return = $this->get_option('urls');
292
+
293
+ // make sure it's an array we are returning
294
+ if(!empty($return)) {
295
+ if(is_array($return))
296
+ return $return;
297
+ else
298
+ return explode("\n",$return);
299
+ } else {
300
+ return array();
301
+ }
302
+ }
303
+
304
+ public function get_domains()
305
+ {
306
+ $domains = $this->get_option('domains');
307
+ if (!empty($domains) && is_array($domains))
308
+ return array_merge( array( $this->domain() ), $domains );
309
+ else
310
+ return array( $this->domain() );
311
+ }
312
+
313
+ public function get_archives($post_type = 'post', $type = '')
314
+ {
315
+ global $wpdb;
316
+ $return = array();
317
+ if ( 'monthly' == $type ) {
318
+ $query = "SELECT YEAR(post_date) AS `year`, LPAD(MONTH(post_date),2,'0') AS `month`, count(ID) as posts FROM $wpdb->posts WHERE post_type = '$post_type' AND post_status = 'publish' GROUP BY YEAR(post_date), MONTH(post_date) ORDER BY post_date DESC";
319
+ $key = md5($query);
320
+ $cache = wp_cache_get( 'xmlsf_get_archives' , 'general');
321
+ if ( !isset( $cache[ $key ] ) ) {
322
+ $arcresults = $wpdb->get_results($query);
323
+ $cache[ $key ] = $arcresults;
324
+ wp_cache_set( 'xmlsf_get_archives', $cache, 'general' );
325
+ } else {
326
+ $arcresults = $cache[ $key ];
327
+ }
328
+ if ( $arcresults ) {
329
+ foreach ( (array) $arcresults as $arcresult ) {
330
+ $return[$arcresult->year.$arcresult->month] = esc_html( $this->get_index_url( 'posttype', $post_type, $arcresult->year . $arcresult->month ) );
331
+ }
332
+ }
333
+ } elseif ('yearly' == $type) {
334
+ $query = "SELECT YEAR(post_date) AS `year`, count(ID) as posts FROM $wpdb->posts WHERE post_type = '$post_type' AND post_status = 'publish' GROUP BY YEAR(post_date) ORDER BY post_date DESC";
335
+ $key = md5($query);
336
+ $cache = wp_cache_get( 'xmlsf_get_archives' , 'general');
337
+ if ( !isset( $cache[ $key ] ) ) {
338
+ $arcresults = $wpdb->get_results($query);
339
+ $cache[ $key ] = $arcresults;
340
+ wp_cache_set( 'xmlsf_get_archives', $cache, 'general' );
341
+ } else {
342
+ $arcresults = $cache[ $key ];
343
+ }
344
+ if ($arcresults) {
345
+ foreach ( (array) $arcresults as $arcresult) {
346
+ $return[$arcresult->year] = esc_html($this->get_index_url( 'posttype', $post_type, $arcresult->year ) );
347
+ }
348
+ }
349
+ } else {
350
+ $return[0] = esc_html($this->get_index_url('posttype', $post_type) ); // $sitemap = 'home', $type = false, $param = false
351
+ }
352
+ return $return;
353
+ }
354
+
355
+ public function get_robots()
356
+ {
357
+ return ( $robots = $this->get_option('robots') ) ? $robots : '';
358
+ }
359
+
360
+ public function do_tags( $type = 'post' )
361
+ {
362
+ $return = $this->get_post_types();
363
+
364
+ // make sure it's an array we are returning
365
+ return (
366
+ is_string($type) &&
367
+ isset($return[$type]) &&
368
+ !empty($return[$type]['tags'])
369
+ ) ? (array)$return[$type]['tags'] : array();
370
+ }
371
+
372
+ public function is_home($id)
373
+ {
374
+ if ( empty($this->blogpage) ) {
375
+ $blogpage = get_option('page_for_posts');
376
+
377
+ if ( !empty($blogpage) ) {
378
+ global $polylang;
379
+ if ( isset($polylang) )
380
+ $this->blogpage = $polylang->get_translations('post', $blogpage);
381
+ else
382
+ $this->blogpage = array($blogpage);
383
+ } else {
384
+ $this->blogpage = array('-1');
385
+ }
386
+ }
387
+
388
+ return in_array($id,$this->blogpage);
389
+ }
390
+
391
+ /**
392
+ * TEMPLATE FUNCTIONS
393
+ */
394
+
395
+ public function modified($sitemap = 'post_type', $term = '')
396
+ {
397
+ if ('post_type' == $sitemap) :
398
+
399
+ global $post;
400
+
401
+ // if blog page look for last post date
402
+ if ( $post->post_type == 'page' && $this->is_home($post->ID) )
403
+ return get_lastmodified('GMT','post');
404
+
405
+ if ( empty($this->postmodified[$post->ID]) ) {
406
+ $postmodified = get_post_modified_time( 'Y-m-d H:i:s', true, $post->ID );
407
+ $options = $this->get_post_types();
408
+
409
+ if( !empty($options[$post->post_type]['update_lastmod_on_comments']) )
410
+ $lastcomment = get_comments( array(
411
+ 'status' => 'approve',
412
+ 'number' => 1,
413
+ 'post_id' => $post->ID,
414
+ ) );
415
+
416
+ if ( isset($lastcomment[0]->comment_date_gmt) )
417
+ if ( mysql2date( 'U', $lastcomment[0]->comment_date_gmt, false ) > mysql2date( 'U', $postmodified, false ) )
418
+ $postmodified = $lastcomment[0]->comment_date_gmt;
419
+
420
+ // make sure lastmod is not older than publication date (happens on scheduled posts)
421
+ if ( isset($post->post_date_gmt) && strtotime($post->post_date_gmt) > strtotime($postmodified) )
422
+ $postmodified = $post->post_date_gmt;
423
+
424
+ $this->postmodified[$post->ID] = $postmodified;
425
+ }
426
+
427
+ return $this->postmodified[$post->ID];
428
+
429
+ elseif ( !empty($term) ) :
430
+
431
+ if ( is_object($term) ) {
432
+ if ( !isset($this->termmodified[$term->term_id]) ) {
433
+ // get the latest post in this taxonomy item, to use its post_date as lastmod
434
+ $posts = get_posts ( array(
435
+ 'post_type' => 'any',
436
+ 'numberposts' => 1,
437
+ 'no_found_rows' => true,
438
+ 'update_post_meta_cache' => false,
439
+ 'update_post_term_cache' => false,
440
+ 'update_cache' => false,
441
+ 'tax_query' => array(
442
+ array(
443
+ 'taxonomy' => $term->taxonomy,
444
+ 'field' => 'slug',
445
+ 'terms' => $term->slug
446
+ )
447
+ )
448
+ )
449
+ );
450
+ $this->termmodified[$term->term_id] = isset($posts[0]->post_date_gmt) ? $posts[0]->post_date_gmt : '';
451
+ }
452
+ return $this->termmodified[$term->term_id];
453
+ } else {
454
+ $obj = get_taxonomy($term);
455
+ return get_lastdate( 'gmt', $obj->object_type );
456
+ // uses get_lastdate() function defined in xml-sitemap/hacks.php !
457
+ // which is a shortcut: returns last post date, not last modified date...
458
+ // TODO find the long way home: take tax type, get all terms,
459
+ // do tax_query with all terms for one post and get its lastmod date
460
+ // ... or can 'terms' in tax_query be empty?
461
+ }
462
+
463
+ else :
464
+
465
+ return '';
466
+
467
+ endif;
468
+ }
469
+
470
+ public function get_images($sitemap = '')
471
+ {
472
+ global $post;
473
+ if ( empty($this->images[$post->ID]) ) {
474
+ if ('news' == $sitemap) {
475
+ $options = $this->get_option('news_tags');
476
+ $which = isset($options['image']) ? $options['image'] : '';
477
+ } else {
478
+ $options = $this->get_post_types();
479
+ $which = isset($options[$post->post_type]['tags']['image']) ? $options[$post->post_type]['tags']['image'] : '';
480
+ }
481
+ if('attached' == $which) {
482
+ $args = array( 'post_type' => 'attachment', 'post_mime_type' => 'image', 'numberposts' => -1, 'post_status' =>'inherit', 'post_parent' => $post->ID );
483
+ $attachments = get_posts($args);
484
+ if ($attachments) {
485
+ foreach ( $attachments as $attachment ) {
486
+ $url = wp_get_attachment_image_src( $attachment->ID, 'full' );
487
+ $this->images[$post->ID][] = array(
488
+ 'loc' => esc_attr( esc_url_raw( $url[0] ) ), // use esc_attr() to entity escape & here ?? esc_url() creates &#038; which is not what we want...
489
+ 'title' => apply_filters( 'the_title_xmlsitemap', $attachment->post_title ),
490
+ 'caption' => apply_filters( 'the_title_xmlsitemap', $attachment->post_excerpt )
491
+ );
492
+ }
493
+ }
494
+ } elseif ('featured' == $which) {
495
+ if (has_post_thumbnail( $post->ID ) ) {
496
+ $attachment = get_post(get_post_thumbnail_id( $post->ID ));
497
+ $url = wp_get_attachment_image_src( $attachment->ID, 'full' );
498
+ $this->images[$post->ID][] = array(
499
+ 'loc' => esc_attr( esc_url_raw( $url[0] ) ),
500
+ 'title' => apply_filters( 'the_title_xmlsitemap', $attachment->post_title ),
501
+ 'caption' => apply_filters( 'the_title_xmlsitemap', $attachment->post_excerpt )
502
+ );
503
+ }
504
+ }
505
+ }
506
+ return ( isset($this->images[$post->ID]) ) ? $this->images[$post->ID] : false;
507
+ }
508
+
509
+ public function get_lastmod($sitemap = 'post_type', $term = '')
510
+ {
511
+ $return = trim(mysql2date('Y-m-d\TH:i:s+00:00', $this->modified($sitemap,$term), false));
512
+ return !empty($return) ? "\t<lastmod>".$return."</lastmod>\r\n\t" : '';
513
+ }
514
+
515
+ public function get_changefreq($sitemap = 'post_type', $term = '')
516
+ {
517
+ $modified = trim($this->modified($sitemap,$term));
518
+
519
+ if (empty($modified))
520
+ return 'weekly';
521
+
522
+ $lastactivityage = ( gmdate('U') - mysql2date( 'U', $modified, false ) ); // post age
523
+
524
+ if ( ($lastactivityage/86400) < 1 ) { // last activity less than 1 day old
525
+ $changefreq = 'hourly';
526
+ } else if ( ($lastactivityage/86400) < 7 ) { // last activity less than 1 week old
527
+ $changefreq = 'daily';
528
+ } else if ( ($lastactivityage/86400) < 30 ) { // last activity less than one month old
529
+ $changefreq = 'weekly';
530
+ } else if ( ($lastactivityage/86400) < 365 ) { // last activity less than 1 year old
531
+ $changefreq = 'monthly';
532
+ } else {
533
+ $changefreq = 'yearly'; // over a year old...
534
+ }
535
+
536
+ return $changefreq;
537
+ }
538
+
539
+ public function get_priority($sitemap = 'post_type', $term = '')
540
+ {
541
+ if ( 'post_type' == $sitemap ) :
542
+ global $post;
543
+ $options = $this->get_post_types();
544
+ $defaults = $this->defaults('post_types');
545
+ $priority_meta = get_metadata('post', $post->ID, '_xmlsf_priority' , true);
546
+
547
+ if ( !empty($priority_meta) || $priority_meta == '0' ) {
548
+
549
+ $priority = floatval(str_replace(",",".",$priority_meta));
550
+
551
+ } elseif ( !empty($options[$post->post_type]['dynamic_priority']) ) {
552
+
553
+ $post_modified = mysql2date('U',$post->post_modified_gmt, false);
554
+
555
+ if ( empty($this->lastmodified) )
556
+ $this->lastmodified = mysql2date('U',get_lastmodified('GMT',$post->post_type),false);
557
+ // last posts or page modified date in Unix seconds
558
+ // uses get_lastmodified() function defined in xml-sitemap/hacks.php !
559
+
560
+ if ( empty($this->firstdate) )
561
+ $this->firstdate = mysql2date('U',get_firstdate('GMT',$post->post_type),false);
562
+ // uses get_firstdate() function defined in xml-sitemap/hacks.php !
563
+
564
+ if ( isset($options[$post->post_type]['priority']) )
565
+ $priority_value = floatval(str_replace(",",".",$options[$post->post_type]['priority']));
566
+ else
567
+ $priority_value = floatval($defaults[$post->post_type]['priority']);
568
+
569
+ // reduce by age
570
+ // NOTE : home/blog page gets same treatment as sticky post
571
+ if ( is_sticky($post->ID) || $this->is_home($post->ID) )
572
+ $priority = $priority_value;
573
+ else
574
+ $priority = ( $this->lastmodified > $this->firstdate ) ? $priority_value - $priority_value * ( $this->lastmodified - $post_modified ) / ( $this->lastmodified - $this->firstdate ) : $priority_value;
575
+
576
+ if ( $post->comment_count > 0 )
577
+ $priority = $priority + 0.1 + ( 0.9 - $priority ) * $post->comment_count / wp_count_comments($post->post_type)->approved;
578
+
579
+ } else {
580
+
581
+ $priority = ( isset($options[$post->post_type]['priority']) && is_numeric($options[$post->post_type]['priority']) ) ? $options[$post->post_type]['priority'] : $defaults[$post->post_type]['priority'];
582
+
583
+ }
584
+
585
+ elseif ( ! empty($term) ) :
586
+
587
+ $max_priority = 0.4;
588
+ $min_priority = 0.0;
589
+ // TODO make these values optional
590
+
591
+ $tax_obj = get_taxonomy($term->taxonomy);
592
+ $postcount = 0;
593
+ foreach ($tax_obj->object_type as $post_type) {
594
+ $_post_count = wp_count_posts($post_type);
595
+ $postcount += $_post_count->publish;
596
+ }
597
+
598
+ $priority = ( $postcount > 0 ) ? $min_priority + ( $max_priority * $term->count / $postcount ) : $min_priority;
599
+
600
+ else :
601
+
602
+ $priority = 0.5;
603
+
604
+ endif;
605
+
606
+ // make sure we're not below zero
607
+ if ($priority < 0)
608
+ $priority = 0;
609
+
610
+ // and a final trim for cases where we ended up above 1 (sticky posts with many comments)
611
+ if ($priority > 1)
612
+ $priority = 1;
613
+
614
+ return number_format($priority,1);
615
+ }
616
+
617
+ public function get_home_urls()
618
+ {
619
+ $urls = array();
620
+
621
+ global $polylang,$q_config;
622
+
623
+ if ( isset($polylang) )
624
+ foreach ($polylang->get_languages_list() as $term)
625
+ $urls[] = $polylang->get_home_url($term);
626
+ else
627
+ $urls[] = home_url();
628
+
629
+ return $urls;
630
+ }
631
+
632
+ public function get_excluded($post_type)
633
+ {
634
+ $exclude = array();
635
+
636
+ if ( $post_type == 'page' && $id = get_option('page_on_front') ) {
637
+ global $polylang;
638
+ if ( isset($polylang) )
639
+ $exclude += $polylang->get_translations('post', $id);
640
+ else
641
+ $exclude[] = $id;
642
+ }
643
+
644
+ return $exclude;
645
+ }
646
+
647
+ public function is_allowed_domain($url)
648
+ {
649
+ $domains = $this->get_domains();
650
+ $return = false;
651
+ $parsed_url = parse_url($url);
652
+
653
+ if (isset($parsed_url['host'])) {
654
+ foreach( $domains as $domain ) {
655
+ if( $parsed_url['host'] == $domain || strpos($parsed_url['host'],".".$domain) !== false ) {
656
+ $return = true;
657
+ break;
658
+ }
659
+ }
660
+ }
661
+
662
+ return apply_filters( 'xmlsf_allowed_domain', $return );
663
+ }
664
+
665
+ public function get_index_url( $sitemap = 'home', $type = false, $param = false )
666
+ {
667
+ $root = esc_url( trailingslashit(home_url()) );
668
+ $name = $this->base_name.'-'.$sitemap;
669
+
670
+ if ( $type )
671
+ $name .= '-'.$type;
672
+
673
+ if ( '' == get_option('permalink_structure') || '1' != get_option('blog_public')) {
674
+ $name = '?feed='.$name;
675
+ $name .= $param ? '&m='.$param : '';
676
+ } else {
677
+ $name .= $param ? '.'.$param : '';
678
+ $name .= '.'.$this->extension;
679
+ }
680
+
681
+ return $root . $name;
682
+ }
683
+
684
+
685
+ /**
686
+ * ROBOTSTXT
687
+ */
688
+
689
+ // add sitemap location in robots.txt generated by WP
690
+ public function robots($output)
691
+ {
692
+ echo "\n# XML Sitemap & Google News Feeds version ".XMLSF_VERSION." - http://status301.net/wordpress-plugins/xml-sitemap-feed/";
693
+
694
+ if ( '1' != get_option('blog_public') ) {
695
+ echo "\n# XML Sitemaps are disabled. Please see Site Visibility on Settings > Reading.";
696
+ } else {
697
+ foreach ( $this->get_sitemaps() as $pretty )
698
+ echo "\nSitemap: " . trailingslashit(get_bloginfo('url')) . $pretty;
699
+
700
+ if ( empty($pretty) )
701
+ echo "\n# No XML Sitemaps are enabled. Please see XML Sitemaps on Settings > Reading.";
702
+ }
703
+ echo "\n\n";
704
+ }
705
+
706
+ // add robots.txt rules
707
+ public function robots_txt($output)
708
+ {
709
+ return $output . $this->get_option('robots') . "\n\n";
710
+ }
711
+
712
+ /**
713
+ * REWRITES
714
+ */
715
+
716
+ /**
717
+ * Remove the trailing slash from permalinks that have an extension,
718
+ * such as /sitemap.xml (thanks to Permalink Editor plugin for WordPress)
719
+ *
720
+ * @param string $request
721
+ */
722
+
723
+ public function trailingslash($request)
724
+ {
725
+ if (pathinfo($request, PATHINFO_EXTENSION)) {
726
+ return untrailingslashit($request);
727
+ }
728
+ return $request; // trailingslashit($request);
729
+ }
730
+
731
+ /**
732
+ * Add sitemap rewrite rules
733
+ *
734
+ * @param string $wp_rewrite
735
+ */
736
+
737
+ public function rewrite_rules($wp_rewrite)
738
+ {
739
+ $xmlsf_rules = array();
740
+ $sitemaps = $this->get_sitemaps();
741
+
742
+ foreach ( $sitemaps as $name => $pretty )
743
+ $xmlsf_rules[ preg_quote($pretty) . '$' ] = $wp_rewrite->index . '?feed=' . $name;
744
+
745
+ if (!empty($sitemaps['sitemap'])) {
746
+ // home urls
747
+ $xmlsf_rules[ $this->base_name . '-home\.' . $this->extension . '$' ] = $wp_rewrite->index . '?feed=sitemap-home';
748
+
749
+ // add rules for post types (can be split by month or year)
750
+ foreach ( $this->get_post_types() as $post_type ) {
751
+ if ( isset($post_type['active']) && '1' == $post_type['active'] )
752
+ $xmlsf_rules[ $this->base_name . '-posttype-' . $post_type['name'] . '\.([0-9]+)?\.?' . $this->extension . '$' ] = $wp_rewrite->index . '?feed=sitemap-posttype-' . $post_type['name'] . '&m=$matches[1]';
753
+ }
754
+
755
+ // add rules for taxonomies
756
+ foreach ( $this->get_taxonomies() as $taxonomy ) {
757
+ $xmlsf_rules[ $this->base_name . '-taxonomy-' . $taxonomy . '\.' . $this->extension . '$' ] = $wp_rewrite->index . '?feed=sitemap-taxonomy-' . $taxonomy;
758
+ }
759
+
760
+ $urls = $this->get_urls();
761
+ if(!empty($urls))
762
+ $xmlsf_rules[ $this->base_name . '-custom\.' . $this->extension . '$' ] = $wp_rewrite->index . '?feed=sitemap-custom';
763
+
764
+ }
765
+
766
+ $wp_rewrite->rules = $xmlsf_rules + $wp_rewrite->rules;
767
+ }
768
+
769
+ /**
770
+ * REQUEST FILTER
771
+ */
772
+ public function template( $theme ) {
773
+
774
+ if ( isset($request['feed']) && strpos($request['feed'],'sitemap') == 0 )
775
+ // clear get_template response to prevent themes functions.php (another source of blank line problems) from loading
776
+ return '';
777
+ else
778
+ return $theme;
779
+ }
780
+
781
+ public function filter_request( $request )
782
+ {
783
+ if ( isset($request['feed']) && strpos($request['feed'],'sitemap') == 0 ) {
784
+
785
+ if ( $request['feed'] == 'sitemap' ) {
786
+
787
+ // setup actions and filters
788
+ add_action('do_feed_sitemap', array($this, 'load_template_index'), 10, 1);
789
+
790
+ return $request;
791
+ }
792
+
793
+ if ( $request['feed'] == 'sitemap-news' ) {
794
+ $defaults = $this->defaults('news_tags');
795
+ $options = $this->get_option('news_tags');
796
+ $news_post_type = isset($options['post_type']) && !empty($options['post_type']) ? $options['post_type'] : $defaults['post_type'];
797
+ if (empty($news_post_type)) $news_post_type = 'post';
798
+
799
+ // disable caching
800
+ define('DONOTCACHEPAGE', true);
801
+ define('DONOTCACHEDB', true);
802
+
803
+ // setup template
804
+ add_action('do_feed_sitemap-news', array($this, 'load_template_news'), 10, 1);
805
+
806
+ // set up query filters
807
+ // TODO: test 'gmt' against 'blog' against 'server'
808
+
809
+ if ( function_exists('date_default_timezone_set') ) {
810
+ date_default_timezone_set ( 'UTC' );
811
+ $zone = 'gmt';
812
+ } else {
813
+ $zone = 'blog';
814
+ }
815
+ if ( get_lastdate($zone, $news_post_type) > date('Y-m-d H:i:s', strtotime('-48 hours')) ) {
816
+ add_filter('post_limits', array($this, 'filter_news_limits'));
817
+ add_filter('posts_where', array($this, 'filter_news_where'), 10, 1);
818
+ } else {
819
+ add_filter('post_limits', array($this, 'filter_no_news_limits'));
820
+ }
821
+
822
+ /* modify request parameters */
823
+ // post type
824
+ $request['post_type'] = $news_post_type;
825
+
826
+ // categories
827
+ if ( isset($options['categories']) && is_array($options['categories']) )
828
+ $request['cat'] = implode(',',$options['categories']);
829
+
830
+ $request['post_status'] = 'publish';
831
+ $request['no_found_rows'] = true;
832
+
833
+ return $request;
834
+ }
835
+
836
+ if ( $request['feed'] == 'sitemap-home' ) {
837
+ // setup actions and filters
838
+ add_action('do_feed_sitemap-home', array($this, 'load_template_base'), 10, 1);
839
+
840
+ return $request;
841
+ }
842
+
843
+ if ( strpos($request['feed'],'sitemap-posttype') == 0 ) {
844
+ foreach ( $this->get_post_types() as $post_type ) {
845
+ if ( $request['feed'] == 'sitemap-posttype-'.$post_type['name'] ) {
846
+ // setup actions and filters
847
+ add_action('do_feed_sitemap-posttype-'.$post_type['name'], array($this, 'load_template'), 10, 1);
848
+ add_filter( 'post_limits', array($this, 'filter_limits') );
849
+
850
+ // modify request parameters
851
+ $request['post_type'] = $post_type['name'];
852
+ $request['post_status'] = 'publish';
853
+ $request['orderby'] = 'modified';
854
+ $request['lang'] = '';
855
+ $request['no_found_rows'] = true;
856
+ $request['update_post_meta_cache'] = false;
857
+ $request['update_post_term_cache'] = false;
858
+
859
+ return $request;
860
+ }
861
+ }
862
+ }
863
+
864
+ if ( strpos($request['feed'],'sitemap-taxonomy') == 0 ) {
865
+ foreach ( $this->get_taxonomies() as $taxonomy ) {
866
+ if ( $request['feed'] == 'sitemap-taxonomy-'.$taxonomy ) {
867
+ // setup actions and filters
868
+ add_action('do_feed_sitemap-taxonomy-'.$taxonomy, array($this, 'load_template_taxonomy'), 10, 1);
869
+
870
+ // modify request parameters
871
+ $request['taxonomy'] = $taxonomy;
872
+ $request['lang'] = '';
873
+ $request['no_found_rows'] = true;
874
+ $request['cache_results'] = false;
875
+ $request['update_post_term_cache'] = false;
876
+ $request['update_post_meta_cache'] = false;
877
+ $request['post_status'] = 'publish';
878
+
879
+ return $request;
880
+ }
881
+ }
882
+ }
883
+
884
+ if ( strpos($request['feed'],'sitemap-custom') == 0 ) {
885
+ // setup actions and filters
886
+ add_action('do_feed_sitemap-custom', array($this, 'load_template_custom'), 10, 1);
887
+
888
+ return $request;
889
+ }
890
+
891
+ }
892
+
893
+ return $request;
894
+ }
895
+
896
+ /**
897
+ * FEED TEMPLATES
898
+ */
899
+
900
+ // set up the sitemap index template
901
+ public function load_template_index()
902
+ {
903
+ load_template( dirname( __FILE__ ) . '/feed-sitemap.php' );
904
+ }
905
+
906
+ // set up the sitemap home page(s) template
907
+ public function load_template_base()
908
+ {
909
+ load_template( dirname( __FILE__ ) . '/feed-sitemap-home.php' );
910
+ }
911
+
912
+ // set up the post types sitemap template
913
+ public function load_template()
914
+ {
915
+ load_template( dirname( __FILE__ ) . '/feed-sitemap-post_type.php' );
916
+ }
917
+
918
+ // set up the taxonomy sitemap template
919
+ public function load_template_taxonomy()
920
+ {
921
+ load_template( dirname( __FILE__ ) . '/feed-sitemap-taxonomy.php' );
922
+ }
923
+
924
+ // set up the news sitemap template
925
+ public function load_template_news()
926
+ {
927
+ load_template( dirname( __FILE__ ) . '/feed-sitemap-news.php' );
928
+ }
929
+
930
+ // set up the news sitemap template
931
+ public function load_template_custom()
932
+ {
933
+ load_template( dirname( __FILE__ ) . '/feed-sitemap-custom.php' );
934
+ }
935
+
936
+ /**
937
+ * LIMITS
938
+ */
939
+
940
+ // override default feed limit
941
+ public function filter_limits( $limits )
942
+ {
943
+ return 'LIMIT 0, 50000';
944
+ }
945
+
946
+ // override default feed limit for taxonomy sitemaps
947
+ public function filter_limits_taxonomy( $limits )
948
+ {
949
+ return 'LIMIT 0, 1';
950
+ }
951
+
952
+ // only posts from the last 48 hours
953
+ public function filter_news_where( $where = '' )
954
+ {
955
+ if ( function_exists('date_default_timezone_set') ) {
956
+ date_default_timezone_set ( 'UTC' );
957
+ return $where . " AND post_date_gmt > '" . date('Y-m-d H:i:s', strtotime('-48 hours')) . "'";
958
+ } else {
959
+ return $where . " AND post_date > '" . date('Y-m-d H:i:s', strtotime('-48 hours')) . "'";
960
+ }
961
+ }
962
+
963
+ // override default feed limit for GN
964
+ public function filter_news_limits( $limits )
965
+ {
966
+ return 'LIMIT 0, 1000';
967
+ }
968
+
969
+ // in case there is no news, just take the latest post
970
+ public function filter_no_news_limits( $limits )
971
+ {
972
+ return 'LIMIT 0, 1';
973
+ }
974
+
975
+ /**
976
+ * PINGING
977
+ */
978
+
979
+ public function ping($uri, $timeout = 3)
980
+ {
981
+ $options = array();
982
+ $options['timeout'] = $timeout;
983
+
984
+ $response = wp_remote_request( $uri, $options );
985
+
986
+ if ( '200' == wp_remote_retrieve_response_code($response) )
987
+ $succes = true;
988
+ else
989
+ $succes = false;
990
+
991
+ return $succes;
992
+ }
993
+
994
+ public function do_pings($new_status, $old_status, $post)
995
+ {
996
+ $sitemaps = $this->get_sitemaps();
997
+ $to_ping = $this->get_ping();
998
+ $update = false;
999
+
1000
+ // first check if news sitemap is set
1001
+ if ( !empty($sitemaps['sitemap-news']) ) {
1002
+ // then check if we've got a post type that is included in our news sitemap
1003
+ $news_tags = $this->get_option('news_tags');
1004
+ if ( !empty($news_tags['post_type']) && is_array($news_tags['post_type']) && in_array($post->post_type,$news_tags['post_type']) ) {
1005
+
1006
+ // TODO: check if we're posting to an included category!
1007
+
1008
+ // are we publishing?
1009
+ if ( $old_status != 'publish' && $new_status == 'publish' ) {
1010
+ // loop through ping targets
1011
+ foreach ($to_ping as $se => $data) {
1012
+ // check active switch
1013
+ if( empty($data['active']) || empty($data['news']) )
1014
+ continue;
1015
+ // and if we did not ping already within the last 5 minutes
1016
+ if( !empty($data['pong']) && is_array($data['pong']) && !empty($data['pong'][$sitemaps['sitemap-news']]) && (int)$data['pong'][$sitemaps['sitemap-news']] + 300 > time() )
1017
+ continue;
1018
+ // ping !
1019
+ if ( $this->ping( $data['uri'].urlencode(trailingslashit(get_bloginfo('url')) . $sitemaps['sitemap-news']) ) ) {
1020
+ $to_ping[$se]['pong'][$sitemaps['sitemap-news']] = time();
1021
+ $update = true;
1022
+ }
1023
+
1024
+ }
1025
+ }
1026
+ }
1027
+ }
1028
+
1029
+ // first check if regular sitemap is set
1030
+ if ( !empty($sitemaps['sitemap']) ) {
1031
+ // then check if we've got a post type that is included in our sitemap
1032
+ foreach($this->get_post_types() as $post_type) {
1033
+ if ( !empty($post_type) && is_array($post_type) && in_array($post->post_type,$post_type) ) {
1034
+ // are we publishing?
1035
+ if ( $old_status != 'publish' && $new_status == 'publish' ) {
1036
+ foreach ($to_ping as $se => $data) {
1037
+ // check active switch
1038
+ if( empty($data['active']) || empty($data['type']) || $data['type']!='GET' )
1039
+ continue;
1040
+ // and if we did not ping already within the last hour
1041
+ if( !empty($data['pong']) && is_array($data['pong']) && !empty($data['pong'][$sitemaps['sitemap']]) && (int)$data['pong'][$sitemaps['sitemap']] + 3600 > time() )
1042
+ continue;
1043
+ // ping !
1044
+ if ( $this->ping( $data['uri'].urlencode(trailingslashit(get_bloginfo('url')) . $sitemaps['sitemap']) ) ) {
1045
+ $to_ping[$se]['pong'][$sitemaps['sitemap']] = time();
1046
+ $update = true;
1047
+ }
1048
+ }
1049
+ }
1050
+ }
1051
+ }
1052
+ }
1053
+
1054
+ if ( $update ) update_option($this->prefix.'ping',$to_ping);
1055
+ }
1056
+
1057
+ /**
1058
+ * CLEARING & PURGING
1059
+ */
1060
+
1061
+ public function clear_settings()
1062
+ {
1063
+ delete_option('xmlsf_version');
1064
+ foreach ( $this->defaults() as $option => $settings ) {
1065
+ delete_option('xmlsf_'.$option);
1066
+ }
1067
+
1068
+ if ( defined('WP_DEBUG') && WP_DEBUG )
1069
+ error_log('XML Sitemap Feeds settings cleared');
1070
+ }
1071
+
1072
+ function cache_flush($new_status, $old_status)
1073
+ {
1074
+ // are we moving the post in or out of published status?
1075
+ if ( $new_status == 'publish' || $old_status == 'publish' ) {
1076
+ // Use cache_delete to remove single key instead of complete cache_flush. Thanks Jeremy Clarke!
1077
+ wp_cache_delete('xmlsf_get_archives', 'general');
1078
+ }
1079
+ }
1080
+
1081
+ public function nginx_helper_purge_urls( $urls = array(), $redis = false )
1082
+ {
1083
+ // are permalinks set, blog public and $urls an array?
1084
+ if ( '' == get_option('permalink_structure') || '1' != get_option('blog_public') || ! is_array( $urls ) )
1085
+ return $urls;
1086
+
1087
+ if ( $redis ) {
1088
+
1089
+ // wildcard allowed, this makes everything simple
1090
+ $urls[] = '/sitemap*.xml';
1091
+
1092
+ } else {
1093
+
1094
+ // no wildcard, go through the motions
1095
+ foreach ( $this->get_sitemaps() as $pretty ) {
1096
+
1097
+ if ( 'sitemap.xml' == $pretty ) {
1098
+
1099
+ // add home sitemap
1100
+ $urls[] = parse_url( $this->get_index_url('home'), PHP_URL_PATH);
1101
+
1102
+ // add public post types sitemaps
1103
+ foreach ( $this->have_post_types() as $post_type ) {
1104
+ $archive = !empty($post_type['archive']) ? $post_type['archive'] : '';
1105
+ foreach ( $this->get_archives($post_type['name'],$archive) as $url )
1106
+ $urls[] = parse_url( $url, PHP_URL_PATH);
1107
+ }
1108
+
1109
+ // add public post taxonomies sitemaps
1110
+ foreach ( $this->get_taxonomies() as $taxonomy ) {
1111
+ $urls[] = parse_url( $this->get_index_url('taxonomy',$taxonomy), PHP_URL_PATH);
1112
+ }
1113
+
1114
+ // add custom URLs sitemap
1115
+ $custom_urls = $this->get_urls();
1116
+ if ( !empty( $custom_urls ) ) {
1117
+ $urls[] = parse_url( $this->get_index_url('custom'), PHP_URL_PATH);
1118
+ }
1119
+
1120
+ // custom sitemaps
1121
+ foreach ($this->get_custom_sitemaps() as $url) {
1122
+ if ( !empty($url) && $this->is_allowed_domain($url) )
1123
+ $urls[] = parse_url( esc_url($url), PHP_URL_PATH);
1124
+ }
1125
+ }
1126
+ }
1127
+
1128
+ $urls[] = '/' . $pretty;
1129
+
1130
+ }
1131
+
1132
+ return $urls;
1133
+ }
1134
+
1135
+ /**
1136
+ * INITIALISATION
1137
+ */
1138
+
1139
+ public function upgrade($old_version)
1140
+ {
1141
+ // rewrite rules not available on plugins_loaded
1142
+ // and don't flush rules from init as Polylang chokes on that
1143
+ // just remove the db option and let WP regenerate them when ready...
1144
+ delete_option('rewrite_rules');
1145
+ // ... but make sure rules are regenerated when admin is visited.
1146
+ set_transient('xmlsf_flush_rewrite_rules','');
1147
+
1148
+ // remove robots.txt rule blocking stylesheets, but only one time!
1149
+ if ( version_compare('4.4', $old_version, '>') && $robot_rules = get_option($this->prefix.'robots')) {
1150
+ $robot_rules = str_replace(array("Disallow: */wp-content/","Allow: */wp-content/uploads/"),"",$robot_rules);
1151
+ delete_option($this->prefix.'robots');
1152
+ add_option($this->prefix.'robots', $robot_rules, '', 'no');
1153
+ }
1154
+
1155
+ if ( version_compare('4.4.1', $old_version, '>') ) {
1156
+ // register location taxonomies then delete all terms
1157
+ register_taxonomy( 'gn-location-3', null );
1158
+ $terms = get_terms('gn-location-3',array('hide_empty' => false));
1159
+ foreach ( $terms as $term )
1160
+ wp_delete_term( $term->term_id, 'gn-location-3' );
1161
+
1162
+ register_taxonomy( 'gn-location-2', null );
1163
+ $terms = get_terms('gn-location-2',array('hide_empty' => false));
1164
+ foreach ( $terms as $term )
1165
+ wp_delete_term( $term->term_id, 'gn-location-2' );
1166
+
1167
+ register_taxonomy( 'gn-location-1', null );
1168
+ $terms = get_terms('gn-location-1',array('hide_empty' => false));
1169
+ foreach ( $terms as $term )
1170
+ wp_delete_term( $term->term_id, 'gn-location-1' );
1171
+ }
1172
+
1173
+ if ( version_compare('4.5', $old_version, '>') ) {
1174
+ // purge genres taxonomy terms
1175
+ $this->register_gn_taxonomies();
1176
+ $terms = get_terms('gn-genre',array('hide_empty' => false));
1177
+ foreach ( $terms as $term )
1178
+ wp_delete_term( $term->term_id, 'gn-genre' );
1179
+ set_transient('xmlsf_create_genres','', 10); // flag recreation
1180
+ }
1181
+
1182
+ // upgrade pings
1183
+ if ( $pong = get_option( $this->prefix.'pong' ) && is_array($pong) ) {
1184
+ $ping = $this->get_ping();
1185
+ foreach ( $pong as $se => $arr) {
1186
+ if ( is_array( $arr ) ) {
1187
+ // convert formatted time to unix time
1188
+ foreach ( $arr as $pretty => $date ) {
1189
+ $time = strtotime($date);
1190
+ $arr[$pretty] = (int)$time < time() ? $time : '';
1191
+ }
1192
+ // and set array
1193
+ $ping[$se]['pong'] = $arr;
1194
+ }
1195
+ }
1196
+ delete_option( $this->prefix.'pong' );
1197
+ delete_option( $this->prefix.'ping' );
1198
+ add_option( $this->prefix.'ping', array_merge( $this->defaults('ping'), $ping ), '', 'no' );
1199
+ }
1200
+
1201
+ delete_option('xmlsf_version');
1202
+ add_option($this->prefix.'version', XMLSF_VERSION, '', 'no');
1203
+
1204
+ if ( defined('WP_DEBUG') && WP_DEBUG )
1205
+ error_log('XML Sitemap Feeds upgraded from '.$old_version.' to '.XMLSF_VERSION);
1206
+
1207
+ }
1208
+
1209
+ public function plugins_loaded()
1210
+ {
1211
+ // TEXT DOMAIN
1212
+ if ( is_admin() ) // text domain needed on admin only
1213
+ load_plugin_textdomain('xml-sitemap-feed', false, dirname(dirname(plugin_basename( __FILE__ ))) . '/languages' );
1214
+
1215
+ }
1216
+
1217
+ public function init()
1218
+ {
1219
+ // UPGRADE
1220
+ $version = get_option('xmlsf_version', 0);
1221
+
1222
+ if ( version_compare(XMLSF_VERSION, $version, '>') )
1223
+ $this->upgrade($version);
1224
+
1225
+ // TAXONOMIES
1226
+ $sitemaps = $this->get_sitemaps();
1227
+
1228
+ if (isset($sitemaps['sitemap-news'])) {
1229
+ // register the taxonomies
1230
+ $this->register_gn_taxonomies();
1231
+
1232
+ // create terms
1233
+ if ( delete_transient('xmlsf_create_genres') ) {
1234
+ foreach ($this->gn_genres as $name) {
1235
+ wp_insert_term( $name, 'gn-genre' );
1236
+ }
1237
+ }
1238
+ }
1239
+ }
1240
+
1241
+ public function admin_init()
1242
+ {
1243
+ // CATCH TRANSIENT for reset
1244
+ if (delete_transient('xmlsf_clear_settings'))
1245
+ $this->clear_settings();
1246
+
1247
+ // CATCH TRANSIENT for flushing rewrite rules after the sitemaps setting has changed
1248
+ if (delete_transient('xmlsf_flush_rewrite_rules'))
1249
+ $this->flush_rules();
1250
+
1251
+ // Include the admin class file
1252
+ include_once( dirname(__FILE__) . '/admin.php' );
1253
+
1254
+ }
1255
+
1256
+ public function flush_rules($hard = false)
1257
+ {
1258
+ // did you flush already?
1259
+ if ($this->yes_mother)
1260
+ return; // yes, mother!
1261
+
1262
+ global $wp_rewrite;
1263
+ // don't need hard flush by default
1264
+ $wp_rewrite->flush_rules($hard);
1265
+
1266
+ if ( defined('WP_DEBUG') && WP_DEBUG )
1267
+ error_log('XML Sitemap Feeds rewrite rules flushed');
1268
+
1269
+ $this->yes_mother = true;
1270
+ }
1271
+
1272
+ public function register_gn_taxonomies()
1273
+ {
1274
+ $defaults = $this->defaults('news_tags');
1275
+ $options = $this->get_option('news_tags');
1276
+
1277
+ $post_types = !empty($options['post_type']) ? $options['post_type'] : $defaults['post_type'];
1278
+
1279
+ register_taxonomy( 'gn-genre', $post_types, array(
1280
+ 'hierarchical' => true,
1281
+ 'labels' => array(
1282
+ 'name' => __('Google News Genres','xml-sitemap-feed'),
1283
+ 'singular_name' => __('Google News Genre','xml-sitemap-feed'),
1284
+ //'menu_name' => __('GN Genres','xml-sitemap-feed'),
1285
+ ),
1286
+ 'public' => false,
1287
+ 'show_ui' => true,
1288
+ 'show_tagcloud' => false,
1289
+ 'query_var' => false,
1290
+ 'capabilities' => array( // prevent creation / deletion
1291
+ 'manage_terms' => 'nobody',
1292
+ 'edit_terms' => 'nobody',
1293
+ 'delete_terms' => 'nobody',
1294
+ 'assign_terms' => 'edit_posts'
1295
+ )
1296
+ ));
1297
+ }
1298
+
1299
+ // for debugging
1300
+ public function _e_usage()
1301
+ {
1302
+ if (defined('WP_DEBUG') && WP_DEBUG == true) {
1303
+ echo '<!-- Queries executed '.get_num_queries();
1304
+ if(function_exists('memory_get_peak_usage'))
1305
+ echo ' | Peak memory usage '.round(memory_get_peak_usage()/1024/1024,2).'M';
1306
+ echo ' -->';
1307
+ }
1308
+ }
1309
+
1310
+ /**
1311
+ * CONSTRUCTOR
1312
+ */
1313
+
1314
+ function __construct()
1315
+ {
1316
+ // sitemap element filters
1317
+ add_filter('the_title_xmlsitemap', 'strip_tags');
1318
+ add_filter('the_title_xmlsitemap', 'ent2ncr', 8);
1319
+ add_filter('the_title_xmlsitemap', 'esc_html');
1320
+ add_filter('bloginfo_xmlsitemap', 'ent2ncr', 8);
1321
+
1322
+ // TEMPLATE
1323
+ add_filter('template', array($this, 'template'), 0);
1324
+
1325
+ // REQUEST main filtering function
1326
+ add_filter('request', array($this, 'filter_request'), 1 );
1327
+
1328
+ // TEXT DOMAIN, UPGRADE PROCESS ...
1329
+ add_action('plugins_loaded', array($this,'plugins_loaded'), 11 );
1330
+
1331
+ // REWRITES
1332
+ add_action('generate_rewrite_rules', array($this, 'rewrite_rules') );
1333
+ add_filter('user_trailingslashit', array($this, 'trailingslash') );
1334
+
1335
+ // TAXONOMY
1336
+ add_action('init', array($this,'init'), 0 );
1337
+
1338
+ // REGISTER SETTINGS, SETTINGS FIELDS...
1339
+ add_action('admin_init', array($this,'admin_init'), 0);
1340
+
1341
+ // ROBOTSTXT
1342
+ add_action('do_robotstxt', array($this, 'robots'), 0 );
1343
+ add_filter('robots_txt', array($this, 'robots_txt'), 0 );
1344
+
1345
+ // PINGING
1346
+ add_action('transition_post_status', array($this, 'do_pings'), 10, 3);
1347
+
1348
+ // CLEAR OBJECT CACHE
1349
+ add_action('transition_post_status', array($this, 'cache_flush'), 99, 2);
1350
+
1351
+ // NGINX HELPER PURGE URLS
1352
+ add_filter('rt_nginx_helper_purge_urls', array($this, 'nginx_helper_purge_urls'), 10, 2);
1353
+
1354
+ // ACTIVATION
1355
+ // activation currently same as upgrade routine based on db version check
1356
+ //register_activation_hook( XMLSF_PLUGIN_BASENAME, array($this, 'activate') );
1357
+
1358
+ // DE-ACTIVATION
1359
+ register_deactivation_hook( XMLSF_PLUGIN_BASENAME, array($this, 'flush_rules') );
1360
+
1361
+ }
1362
+ }
1363
+
1364
+ endif;
includes/feed-sitemap-news.php CHANGED
@@ -42,6 +42,9 @@ echo '">
42
  $language = explode('-', convert_chars(strip_tags(get_bloginfo('language'))));
43
  $language = empty($language) ? 'en' : reset($language);
44
 
 
 
 
45
  // loop away!
46
  if ( have_posts() ) :
47
  while ( have_posts() ) :
@@ -49,10 +52,11 @@ if ( have_posts() ) :
49
 
50
  // check if we are not dealing with an external URL :: Thanks to Francois Deschenes :)
51
  // or if post meta says "exclude me please"
52
- $exclude = get_post_meta( $post->ID, '_xmlsf_exclude', true );
53
  if ( !empty($exclude) || !$xmlsf->is_allowed_domain(get_permalink()) )
54
  continue;
55
 
 
56
  ?>
57
  <url>
58
  <loc><?php echo esc_url( get_permalink() ); ?></loc>
@@ -66,10 +70,12 @@ if ( have_posts() ) :
66
  else
67
  echo apply_filters( 'the_title_xmlsitemap', get_bloginfo('name') ); ?></news:name>
68
  <news:language><?php
69
- $lang = get_the_terms($post->ID,'language');
70
- if ( is_array($lang) ) {
71
- $lang = reset($lang);
72
- echo is_object($lang) ? $lang->slug : $language;
 
 
73
  } else {
74
  echo $language;
75
  } ?></news:language>
@@ -79,16 +85,19 @@ if ( have_posts() ) :
79
  <news:title><?php echo apply_filters( 'the_title_xmlsitemap', get_the_title() ); ?></news:title>
80
  <?php
81
  // access tag
82
- $access = '';
83
- if (!empty($options['access'])) {
 
 
84
  if ( post_password_required() ) {
85
  if (!empty($options['access']['password'])) $access = $options['access']['password'];
86
  } else {
87
  if (!empty($options['access']['default'])) $access = $options['access']['default'];
88
  }
89
- }
90
-
91
- if (!empty($access)) {
 
92
  ?>
93
  <news:access><?php echo $access; ?></news:access>
94
  <?php
@@ -178,8 +187,10 @@ if ( have_posts() ) :
178
  </url>
179
  <?php
180
  endwhile;
181
- else :
182
- // No posts? Then only do the homepage...
 
 
183
 
184
  $lastmodified_gmt = get_lastmodified('GMT'); // last posts or page modified date
185
  ?>
42
  $language = explode('-', convert_chars(strip_tags(get_bloginfo('language'))));
43
  $language = empty($language) ? 'en' : reset($language);
44
 
45
+ // set empty news sitemap flag
46
+ $have_posts = false;
47
+
48
  // loop away!
49
  if ( have_posts() ) :
50
  while ( have_posts() ) :
52
 
53
  // check if we are not dealing with an external URL :: Thanks to Francois Deschenes :)
54
  // or if post meta says "exclude me please"
55
+ $exclude = get_post_meta( $post->ID, '_xmlsf_news_exclude', true );
56
  if ( !empty($exclude) || !$xmlsf->is_allowed_domain(get_permalink()) )
57
  continue;
58
 
59
+ $have_posts = true;
60
  ?>
61
  <url>
62
  <loc><?php echo esc_url( get_permalink() ); ?></loc>
70
  else
71
  echo apply_filters( 'the_title_xmlsitemap', get_bloginfo('name') ); ?></news:name>
72
  <news:language><?php
73
+ if ( taxonomy_exists('language') ) {
74
+ $lang = get_the_terms($post->ID,'language');
75
+ if ( is_array($lang) ) {
76
+ $lang = reset($lang);
77
+ echo is_object($lang) ? $lang->slug : $language;
78
+ }
79
  } else {
80
  echo $language;
81
  } ?></news:language>
85
  <news:title><?php echo apply_filters( 'the_title_xmlsitemap', get_the_title() ); ?></news:title>
86
  <?php
87
  // access tag
88
+ $access = get_post_meta( $post->ID, '_xmlsf_news_access', true );
89
+
90
+ if (empty($access)) : // if not set per meta, let's get global settings
91
+ if (!empty($options['access'])) {
92
  if ( post_password_required() ) {
93
  if (!empty($options['access']['password'])) $access = $options['access']['password'];
94
  } else {
95
  if (!empty($options['access']['default'])) $access = $options['access']['default'];
96
  }
97
+ }
98
+ endif;
99
+
100
+ if (!empty($access) && $access != 'Public' ) {
101
  ?>
102
  <news:access><?php echo $access; ?></news:access>
103
  <?php
187
  </url>
188
  <?php
189
  endwhile;
190
+ endif;
191
+
192
+ if ( !$have_posts ) :
193
+ // No posts done? Then do at least the homepage to prevent error message in WMT.
194
 
195
  $lastmodified_gmt = get_lastmodified('GMT'); // last posts or page modified date
196
  ?>
includes/feed-sitemap.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * Google News Sitemap Feed Template
4
  *
5
  * @package XML Sitemap Feed plugin for WordPress
6
  */
@@ -28,13 +28,10 @@ global $xmlsf;
28
  <lastmod><?php echo mysql2date('Y-m-d\TH:i:s+00:00', get_lastdate( 'gmt' ), false); ?></lastmod>
29
  </sitemap>
30
  <?php
31
- // add rules for custom public post types
32
- foreach ( $xmlsf->have_post_types() as $post_type ) :
 
33
 
34
- if (!empty($post_type['archive']))
35
- $archive = $post_type['archive'];
36
- else
37
- $archive = '';
38
  foreach ( $xmlsf->get_archives($post_type['name'],$archive) as $m => $url ) {
39
  ?>
40
  <sitemap>
@@ -43,11 +40,10 @@ foreach ( $xmlsf->have_post_types() as $post_type ) :
43
  </sitemap>
44
  <?php
45
  }
46
- endforeach;
47
-
48
- // add rules for custom public post taxonomies
49
- foreach ( $xmlsf->get_taxonomies() as $taxonomy ) :
50
 
 
 
51
  if ( wp_count_terms( $taxonomy, array('hide_empty'=>true) ) > 0 ) {
52
  ?>
53
  <sitemap>
@@ -55,17 +51,17 @@ foreach ( $xmlsf->get_taxonomies() as $taxonomy ) :
55
  <?php echo $xmlsf->get_lastmod('taxonomy',$taxonomy); ?></sitemap>
56
  <?php
57
  }
58
- endforeach;
59
 
60
  // custom URLs sitemap
61
  $urls = $xmlsf->get_urls();
62
- if ( !empty($urls) ) :
63
  ?>
64
  <sitemap>
65
  <loc><?php echo $xmlsf->get_index_url('custom'); ?></loc>
66
  </sitemap>
67
  <?php
68
- endif;
69
 
70
  // custom sitemaps
71
  $custom_sitemaps = $xmlsf->get_custom_sitemaps();
@@ -78,5 +74,6 @@ foreach ($custom_sitemaps as $url) {
78
  </sitemap>
79
  <?php
80
  }
 
81
  ?></sitemapindex>
82
  <?php $xmlsf->_e_usage();
1
  <?php
2
  /**
3
+ * XML Sitemap Index Feed Template
4
  *
5
  * @package XML Sitemap Feed plugin for WordPress
6
  */
28
  <lastmod><?php echo mysql2date('Y-m-d\TH:i:s+00:00', get_lastdate( 'gmt' ), false); ?></lastmod>
29
  </sitemap>
30
  <?php
31
+ // add rules for public post types
32
+ foreach ( $xmlsf->have_post_types() as $post_type ) {
33
+ $archive = isset($post_type['archive']) ? $post_type['archive'] : '';
34
 
 
 
 
 
35
  foreach ( $xmlsf->get_archives($post_type['name'],$archive) as $m => $url ) {
36
  ?>
37
  <sitemap>
40
  </sitemap>
41
  <?php
42
  }
43
+ }
 
 
 
44
 
45
+ // add rules for public taxonomies
46
+ foreach ( $xmlsf->get_taxonomies() as $taxonomy ) {
47
  if ( wp_count_terms( $taxonomy, array('hide_empty'=>true) ) > 0 ) {
48
  ?>
49
  <sitemap>
51
  <?php echo $xmlsf->get_lastmod('taxonomy',$taxonomy); ?></sitemap>
52
  <?php
53
  }
54
+ }
55
 
56
  // custom URLs sitemap
57
  $urls = $xmlsf->get_urls();
58
+ if ( !empty($urls) ) {
59
  ?>
60
  <sitemap>
61
  <loc><?php echo $xmlsf->get_index_url('custom'); ?></loc>
62
  </sitemap>
63
  <?php
64
+ }
65
 
66
  // custom sitemaps
67
  $custom_sitemaps = $xmlsf->get_custom_sitemaps();
74
  </sitemap>
75
  <?php
76
  }
77
+
78
  ?></sitemapindex>
79
  <?php $xmlsf->_e_usage();
includes/xsl/sitemap-news.xsl CHANGED
@@ -16,7 +16,8 @@
16
  <body>
17
  <h1>Google News Sitemap Feed</h1>
18
  <div id="header">
19
- <p>This is a Google News Sitemap to aid <a href="http://news.google.com">Google News</a> finding news on your website. Please note that <strong><em>only posts from the last 48 hours</em></strong> will be processed by Google News. Read more about <a href="http://www.google.com/schemas/sitemap-news/0.9/">Google News Sitemaps</a>, submit your site via <a href="http://www.google.com/support/news_pub/bin/request.py?contact_type=suggest_content">Google propose news content</a> and add it in your <a href="https://www.google.com/webmasters/tools/">Google Webmaster Tools</a> account.</p>
 
20
  </div>
21
  <div id="content">
22
  <table cellpadding="5">
@@ -24,6 +25,7 @@
24
  <th>#</th>
25
  <th>Title</th>
26
  <th>Language</th>
 
27
  <th>Genre(s)</th>
28
  <th>Keyword(s)</th>
29
  <th>Image(s)</th>
@@ -38,6 +40,7 @@
38
  <a href="{$itemURL}"><xsl:value-of select="news:news/news:title"/></a>
39
  </td>
40
  <td><xsl:value-of select="news:news/news:publication/news:language"/></td>
 
41
  <td><xsl:value-of select="news:news/news:genres"/></td>
42
  <td><xsl:value-of select="news:news/news:keywords"/></td>
43
  <td><xsl:value-of select="count(image:image)"/></td>
16
  <body>
17
  <h1>Google News Sitemap Feed</h1>
18
  <div id="header">
19
+ <p>This is a <a href="https://support.google.com/news/publisher/answer/75717" target="_blank">Google News Sitemap</a> to aid <a href="http://news.google.com" target="_blank">Google News</a> finding news on your website. Please note that <strong><em>only posts from the last 48 hours</em></strong> will be processed by Google News.</p>
20
+ <p>Follow the guidelines on <a href="https://support.google.com/news/publisher/answer/40787" target="_blank">Getting into Google News</a> and when you're ready, apply for inclusion within the <a href="https://partnerdash.google.com/partnerdash/d/news#p:id=pfehome">Google News Publisher Center</a>. For general questions about Google News, please see the <a href="https://groups.google.com/a/googleproductforums.com/forum/#!categories/news/google-news-publishers" target="_blank">Publisher Help Forum</a>.</p>
21
  </div>
22
  <div id="content">
23
  <table cellpadding="5">
25
  <th>#</th>
26
  <th>Title</th>
27
  <th>Language</th>
28
+ <th>Access</th>
29
  <th>Genre(s)</th>
30
  <th>Keyword(s)</th>
31
  <th>Image(s)</th>
40
  <a href="{$itemURL}"><xsl:value-of select="news:news/news:title"/></a>
41
  </td>
42
  <td><xsl:value-of select="news:news/news:publication/news:language"/></td>
43
+ <td><xsl:value-of select="news:news/news:access"/></td>
44
  <td><xsl:value-of select="news:news/news:genres"/></td>
45
  <td><xsl:value-of select="news:news/news:keywords"/></td>
46
  <td><xsl:value-of select="count(image:image)"/></td>
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: RavanH
3
  Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=ravanhagen%40gmail%2ecom&item_name=XML%20Sitemap%20Feed&item_number=3%2e8&no_shipping=0&tax=0&bn=PP%2dDonationsBF&charset=UTF%2d8&lc=us
4
  Tags: sitemap, xml sitemap, news sitemap, sitemap.xml, robots.txt, Google, Google News, Yahoo, Bing, , Yandex, Baidu, seo, feed, polylang, image sitemap
5
  Requires at least: 3.2
6
- Tested up to: 4.3
7
- Stable tag: 4.4.1
8
 
9
  XML and Google News Sitemaps to feed the hungry spiders. Multisite, WP Super Cache and Polylang compatible.
10
 
@@ -16,7 +16,7 @@ The main advantage of this plugin over other XML Sitemap plugins is **simplicity
16
 
17
  You, or site owners on your Multisite network, will not be bothered with overly complicated settings like most other XML Sitemap plugins. The default settings will suffice in most cases and XML sitemap values like ChangeFreq and URL Priority are auto-calculated based on post age and comment activity.
18
 
19
- an XML Sitemap Index becomes instantly available on yourblog.url/sitemap.xml (or yourblog.url/?feed=sitemap) containing references to posts and pages by default, ready for indexing by search engines like Google, Bing, Yahoo, AOL and Ask. When the Google News Sitemap is activated, it will become available on yourblog.url/sitemap-news.xml (or yourblog.url/?feed=sitemap-news), ready for indexing by Google News. Both are automatically referenced in the dynamically created **robots.txt** on yourblog.url/robots.txt to tell search engines where to find your XML Sitemaps. Google and Bing can be pinged on each new publication.
20
 
21
  Please read the FAQ's for info on how to get your articles listed on Google News.
22
 
@@ -293,12 +293,18 @@ Thanks for sharing your translation :)
293
 
294
  == Upgrade Notice ==
295
 
296
- = 4.4.1 =
297
- Multiple default genres, several bugfixes, dropping Google News old geolocation tag plus XMLSF_POST_TYPE and XMLSF_NEWS_POST_TYPE.
298
-
299
 
300
  == Changelog ==
301
 
 
 
 
 
 
 
 
302
  = 4.4.1 =
303
  * BUGFIX contribution by alejandra.aranibar: multiple news post types makes get_lastdate return oldest instead of newest date
304
  * BUGFIX plugins_url filter not working, reported by Michael
3
  Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=ravanhagen%40gmail%2ecom&item_name=XML%20Sitemap%20Feed&item_number=3%2e8&no_shipping=0&tax=0&bn=PP%2dDonationsBF&charset=UTF%2d8&lc=us
4
  Tags: sitemap, xml sitemap, news sitemap, sitemap.xml, robots.txt, Google, Google News, Yahoo, Bing, , Yandex, Baidu, seo, feed, polylang, image sitemap
5
  Requires at least: 3.2
6
+ Tested up to: 4.4
7
+ Stable tag: 4.5
8
 
9
  XML and Google News Sitemaps to feed the hungry spiders. Multisite, WP Super Cache and Polylang compatible.
10
 
16
 
17
  You, or site owners on your Multisite network, will not be bothered with overly complicated settings like most other XML Sitemap plugins. The default settings will suffice in most cases and XML sitemap values like ChangeFreq and URL Priority are auto-calculated based on post age and comment activity.
18
 
19
+ An XML Sitemap Index becomes instantly available on **yourblog.url/sitemap.xml** (or yourblog.url/?feed=sitemap if you're not using a 'fancy' permalink structure) containing references to posts and pages by default, ready for indexing by search engines like Google, Bing, Yahoo, AOL and Ask. When the Google News Sitemap is activated, it will become available on **yourblog.url/sitemap-news.xml** (or yourblog.url/?feed=sitemap-news), ready for indexing by Google News. Both are automatically referenced in the dynamically created **robots.txt** on **yourblog.url/robots.txt** to tell search engines where to find your XML Sitemaps. Google and Bing can be pinged on each new publication.
20
 
21
  Please read the FAQ's for info on how to get your articles listed on Google News.
22
 
293
 
294
  == Upgrade Notice ==
295
 
296
+ = 4.5 =
297
+ Set access or exclude individual posts from Google News sitemap. Improved cache handling and Nginx Helper compatibility.
 
298
 
299
  == Changelog ==
300
 
301
+ = 4.5 =
302
+ * Set Google News access tag per post
303
+ * Exclude posts from Google News sitemap
304
+ * News Sitemap stylesheet text/links update
305
+ * FIX: delete cached key as suggested by Jeremy Clarke https://wordpress.org/support/topic/please-stop-running-wp_cache_flush-whenever-posts-are-edited
306
+ * NEW: Nginx Helper compatibility to purge cache sitemap URLs from FastCGI Cache or Redis
307
+
308
  = 4.4.1 =
309
  * BUGFIX contribution by alejandra.aranibar: multiple news post types makes get_lastdate return oldest instead of newest date
310
  * BUGFIX plugins_url filter not working, reported by Michael
xml-sitemap.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: XML Sitemap & Google News feeds
4
  Plugin URI: http://status301.net/wordpress-plugins/xml-sitemap-feed/
5
  Description: Feed the hungry spiders in compliance with the XML Sitemap and Google News protocols. Happy with the results? Please leave me a <strong><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=ravanhagen%40gmail%2ecom&item_name=XML%20Sitemap%20Feed&item_number=4%2e0&no_shipping=0&tax=0&bn=PP%2dDonationsBF&charset=UTF%2d8&lc=us">tip</a></strong> for continued development and support. Thanks :)
6
  Text Domain: xml-sitemap-feed
7
- Version: 4.4.1
8
  Author: RavanH
9
  Author URI: http://status301.net/
10
  */
@@ -47,7 +47,7 @@ if(!empty($_SERVER['SCRIPT_FILENAME']) && 'xml-sitemap.php' == basename($_SERVER
47
  * CONSTANTS
48
  * -------------------- */
49
 
50
- define('XMLSF_VERSION', '4.4.1');
51
 
52
  define('XMLSF_PLUGIN_BASENAME', plugin_basename(__FILE__));
53
 
4
  Plugin URI: http://status301.net/wordpress-plugins/xml-sitemap-feed/
5
  Description: Feed the hungry spiders in compliance with the XML Sitemap and Google News protocols. Happy with the results? Please leave me a <strong><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=ravanhagen%40gmail%2ecom&item_name=XML%20Sitemap%20Feed&item_number=4%2e0&no_shipping=0&tax=0&bn=PP%2dDonationsBF&charset=UTF%2d8&lc=us">tip</a></strong> for continued development and support. Thanks :)
6
  Text Domain: xml-sitemap-feed
7
+ Version: 4.5
8
  Author: RavanH
9
  Author URI: http://status301.net/
10
  */
47
  * CONSTANTS
48
  * -------------------- */
49
 
50
+ define('XMLSF_VERSION', '4.5');
51
 
52
  define('XMLSF_PLUGIN_BASENAME', plugin_basename(__FILE__));
53