XML Sitemap & Google News feeds - Version 4.6

Version Description

New action hook xmlsf_news_tags_after, attempt to remove conflicting static sitemap files on activation

=

Download this release

Release Info

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

Code changes from version 4.5.1 to 4.6

Files changed (4) hide show
  1. includes/core.php +233 -216
  2. includes/feed-sitemap-news.php +3 -0
  3. readme.txt +8 -4
  4. xml-sitemap.php +27 -24
includes/core.php CHANGED
@@ -10,31 +10,31 @@ class XMLSitemapFeed {
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;
@@ -43,32 +43,32 @@ class XMLSitemapFeed {
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') )
@@ -93,14 +93,14 @@ class XMLSitemapFeed {
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';
@@ -115,7 +115,7 @@ class XMLSitemapFeed {
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
@@ -154,7 +154,7 @@ class XMLSitemapFeed {
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
@@ -163,25 +163,25 @@ class XMLSitemapFeed {
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
}
@@ -189,8 +189,8 @@ class XMLSitemapFeed {
189
/**
190
* QUERY FUNCTIONS
191
*/
192
-
193
- public function defaults($key = false)
194
{
195
if (empty($this->defaults))
196
$this->set_defaults();
@@ -203,50 +203,50 @@ class XMLSitemapFeed {
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 ) {
@@ -262,16 +262,16 @@ class XMLSitemapFeed {
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
@@ -283,10 +283,10 @@ class XMLSitemapFeed {
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
@@ -298,24 +298,24 @@ class XMLSitemapFeed {
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 ] ) ) {
@@ -352,28 +352,28 @@ class XMLSitemapFeed {
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) )
@@ -387,12 +387,12 @@ class XMLSitemapFeed {
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
@@ -416,27 +416,27 @@ class XMLSitemapFeed {
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(
@@ -454,9 +454,9 @@ class XMLSitemapFeed {
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
@@ -467,7 +467,7 @@ class XMLSitemapFeed {
467
endif;
468
}
469
470
- public function get_images($sitemap = '')
471
{
472
global $post;
473
if ( empty($this->images[$post->ID]) ) {
@@ -484,7 +484,7 @@ class XMLSitemapFeed {
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 )
@@ -495,7 +495,7 @@ class XMLSitemapFeed {
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 )
@@ -505,67 +505,67 @@ class XMLSitemapFeed {
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) )
@@ -579,7 +579,7 @@ class XMLSitemapFeed {
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) ) :
@@ -602,7 +602,7 @@ class XMLSitemapFeed {
602
$priority = 0.5;
603
604
endif;
605
-
606
// make sure we're not below zero
607
if ($priority < 0)
608
$priority = 0;
@@ -614,43 +614,43 @@ class XMLSitemapFeed {
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;
@@ -662,13 +662,13 @@ class XMLSitemapFeed {
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;
@@ -677,24 +677,24 @@ class XMLSitemapFeed {
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) )
@@ -702,13 +702,13 @@ class XMLSitemapFeed {
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
*/
@@ -719,8 +719,7 @@ class XMLSitemapFeed {
719
*
720
* @param string $request
721
*/
722
-
723
- public function trailingslash($request)
724
{
725
if (pathinfo($request, PATHINFO_EXTENSION)) {
726
return untrailingslashit($request);
@@ -733,8 +732,7 @@ class XMLSitemapFeed {
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();
@@ -745,7 +743,7 @@ class XMLSitemapFeed {
745
if (!empty($sitemaps['sitemap'])) {
746
// home urls
747
$xmlsf_rules[ $this->base_name . '-home\.' . $this->extension . '#x27; ] = $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'] )
@@ -762,10 +760,10 @@ class XMLSitemapFeed {
762
$xmlsf_rules[ $this->base_name . '-custom\.' . $this->extension . '#x27; ] = $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
*/
@@ -778,12 +776,12 @@ class XMLSitemapFeed {
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
@@ -794,18 +792,18 @@ class XMLSitemapFeed {
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';
@@ -814,7 +812,7 @@ class XMLSitemapFeed {
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
}
@@ -825,9 +823,9 @@ class XMLSitemapFeed {
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;
@@ -898,37 +896,37 @@ class XMLSitemapFeed {
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
}
@@ -938,19 +936,19 @@ class XMLSitemapFeed {
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' );
@@ -959,15 +957,15 @@ class XMLSitemapFeed {
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
}
@@ -976,7 +974,7 @@ class XMLSitemapFeed {
976
* PINGING
977
*/
978
979
- public function ping($uri, $timeout = 3)
980
{
981
$options = array();
982
$options['timeout'] = $timeout;
@@ -986,12 +984,12 @@ class XMLSitemapFeed {
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();
@@ -1004,7 +1002,7 @@ class XMLSitemapFeed {
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
@@ -1058,17 +1056,17 @@ class XMLSitemapFeed {
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?
@@ -1078,7 +1076,7 @@ class XMLSitemapFeed {
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 ) )
@@ -1095,13 +1093,13 @@ class XMLSitemapFeed {
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
}
@@ -1136,9 +1134,9 @@ class XMLSitemapFeed {
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');
@@ -1151,7 +1149,7 @@ class XMLSitemapFeed {
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 );
@@ -1189,7 +1187,7 @@ class XMLSitemapFeed {
1189
$time = strtotime($date);
1190
$arr[$pretty] = (int)$time < time() ? $time : '';
1191
}
1192
- // and set array
1193
$ping[$se]['pong'] = $arr;
1194
}
1195
}
@@ -1203,18 +1201,38 @@ class XMLSitemapFeed {
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);
@@ -1224,7 +1242,7 @@ class XMLSitemapFeed {
1224
1225
// TAXONOMIES
1226
$sitemaps = $this->get_sitemaps();
1227
-
1228
if (isset($sitemaps['sitemap-news'])) {
1229
// register the taxonomies
1230
$this->register_gn_taxonomies();
@@ -1238,38 +1256,38 @@ class XMLSitemapFeed {
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');
@@ -1295,9 +1313,9 @@ class XMLSitemapFeed {
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();
@@ -1311,53 +1329,52 @@ class XMLSitemapFeed {
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
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;
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') )
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';
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
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
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
}
189
/**
190
* QUERY FUNCTIONS
191
*/
192
+
193
+ public function defaults($key = false)
194
{
195
if (empty($this->defaults))
196
$this->set_defaults();
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 ) {
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
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
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 ] ) ) {
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) )
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
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(
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
467
endif;
468
}
469
470
+ public function get_images($sitemap = '')
471
{
472
global $post;
473
if ( empty($this->images[$post->ID]) ) {
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 )
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 )
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) )
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) ) :
602
$priority = 0.5;
603
604
endif;
605
+
606
// make sure we're not below zero
607
if ($priority < 0)
608
$priority = 0;
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;
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;
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) )
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
*/
719
*
720
* @param string $request
721
*/
722
+ public function trailingslash($request)
723
{
724
if (pathinfo($request, PATHINFO_EXTENSION)) {
725
return untrailingslashit($request);
732
*
733
* @param string $wp_rewrite
734
*/
735
+ public function rewrite_rules($wp_rewrite)
736
{
737
$xmlsf_rules = array();
738
$sitemaps = $this->get_sitemaps();
743
if (!empty($sitemaps['sitemap'])) {
744
// home urls
745
$xmlsf_rules[ $this->base_name . '-home\.' . $this->extension . '#x27; ] = $wp_rewrite->index . '?feed=sitemap-home';
746
+
747
// add rules for post types (can be split by month or year)
748
foreach ( $this->get_post_types() as $post_type ) {
749
if ( isset($post_type['active']) && '1' == $post_type['active'] )
760
$xmlsf_rules[ $this->base_name . '-custom\.' . $this->extension . '#x27; ] = $wp_rewrite->index . '?feed=sitemap-custom';
761
762
}
763
+
764
$wp_rewrite->rules = $xmlsf_rules + $wp_rewrite->rules;
765
}
766
+
767
/**
768
* REQUEST FILTER
769
*/
776
return $theme;
777
}
778
779
+ public function filter_request( $request )
780
{
781
if ( isset($request['feed']) && strpos($request['feed'],'sitemap') == 0 ) {
782
783
if ( $request['feed'] == 'sitemap' ) {
784
+
785
// setup actions and filters
786
add_action('do_feed_sitemap', array($this, 'load_template_index'), 10, 1);
787
792
$defaults = $this->defaults('news_tags');
793
$options = $this->get_option('news_tags');
794
$news_post_type = isset($options['post_type']) && !empty($options['post_type']) ? $options['post_type'] : $defaults['post_type'];
795
+ if (empty($news_post_type)) $news_post_type = 'post';
796
+
797
// disable caching
798
define('DONOTCACHEPAGE', true);
799
+ define('DONOTCACHEDB', true);
800
+
801
// setup template
802
add_action('do_feed_sitemap-news', array($this, 'load_template_news'), 10, 1);
803
804
// set up query filters
805
// TODO: test 'gmt' against 'blog' against 'server'
806
+
807
if ( function_exists('date_default_timezone_set') ) {
808
date_default_timezone_set ( 'UTC' );
809
$zone = 'gmt';
812
}
813
if ( get_lastdate($zone, $news_post_type) > date('Y-m-d H:i:s', strtotime('-48 hours')) ) {
814
add_filter('post_limits', array($this, 'filter_news_limits'));
815
+ add_filter('posts_where', array($this, 'filter_news_where'), 10, 1);
816
} else {
817
add_filter('post_limits', array($this, 'filter_no_news_limits'));
818
}
823
824
// categories
825
if ( isset($options['categories']) && is_array($options['categories']) )
826
+ $request['cat'] = implode(',',$options['categories']);
827
+
828
+ $request['post_status'] = 'publish';
829
$request['no_found_rows'] = true;
830
831
return $request;
896
*/
897
898
// set up the sitemap index template
899
+ public function load_template_index()
900
{
901
load_template( dirname( __FILE__ ) . '/feed-sitemap.php' );
902
}
903
904
// set up the sitemap home page(s) template
905
+ public function load_template_base()
906
{
907
load_template( dirname( __FILE__ ) . '/feed-sitemap-home.php' );
908
}
909
910
// set up the post types sitemap template
911
+ public function load_template()
912
{
913
load_template( dirname( __FILE__ ) . '/feed-sitemap-post_type.php' );
914
}
915
916
// set up the taxonomy sitemap template
917
+ public function load_template_taxonomy()
918
{
919
load_template( dirname( __FILE__ ) . '/feed-sitemap-taxonomy.php' );
920
}
921
922
// set up the news sitemap template
923
+ public function load_template_news()
924
{
925
load_template( dirname( __FILE__ ) . '/feed-sitemap-news.php' );
926
}
927
928
// set up the news sitemap template
929
+ public function load_template_custom()
930
{
931
load_template( dirname( __FILE__ ) . '/feed-sitemap-custom.php' );
932
}
936
*/
937
938
// override default feed limit
939
+ public function filter_limits( $limits )
940
{
941
return 'LIMIT 0, 50000';
942
}
943
944
// override default feed limit for taxonomy sitemaps
945
+ public function filter_limits_taxonomy( $limits )
946
{
947
return 'LIMIT 0, 1';
948
}
949
950
// only posts from the last 48 hours
951
+ public function filter_news_where( $where = '' )
952
{
953
if ( function_exists('date_default_timezone_set') ) {
954
date_default_timezone_set ( 'UTC' );
957
return $where . " AND post_date > '" . date('Y-m-d H:i:s', strtotime('-48 hours')) . "'";
958
}
959
}
960
+
961
// override default feed limit for GN
962
+ public function filter_news_limits( $limits )
963
{
964
return 'LIMIT 0, 1000';
965
}
966
967
// in case there is no news, just take the latest post
968
+ public function filter_no_news_limits( $limits )
969
{
970
return 'LIMIT 0, 1';
971
}
974
* PINGING
975
*/
976
977
+ public function ping($uri, $timeout = 3)
978
{
979
$options = array();
980
$options['timeout'] = $timeout;
984
if ( '200' == wp_remote_retrieve_response_code($response) )
985
$succes = true;
986
else
987
+ $succes = false;
988
989
return $succes;
990
}
991
992
+ public function do_pings($new_status, $old_status, $post)
993
{
994
$sitemaps = $this->get_sitemaps();
995
$to_ping = $this->get_ping();
1002
if ( !empty($news_tags['post_type']) && is_array($news_tags['post_type']) && in_array($post->post_type,$news_tags['post_type']) ) {
1003
1004
// TODO: check if we're posting to an included category!
1005
+
1006
// are we publishing?
1007
if ( $old_status != 'publish' && $new_status == 'publish' ) {
1008
// loop through ping targets
1056
* CLEARING & PURGING
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($new_status, $old_status)
1071
{
1072
// are we moving the post in or out of published status?
1076
}
1077
}
1078
1079
+ public function nginx_helper_purge_urls( $urls = array(), $redis = false )
1080
{
1081
// are permalinks set, blog public and $urls an array?
1082
if ( '' == get_option('permalink_structure') || '1' != get_option('blog_public') || ! is_array( $urls ) )
1093
foreach ( $this->get_sitemaps() as $pretty ) {
1094
1095
if ( 'sitemap.xml' == $pretty ) {
1096
+
1097
// add home sitemap
1098
$urls[] = parse_url( $this->get_index_url('home'), PHP_URL_PATH);
1099
1100
// add public post types sitemaps
1101
foreach ( $this->have_post_types() as $post_type ) {
1102
+ $archive = !empty($post_type['archive']) ? $post_type['archive'] : '';
1103
foreach ( $this->get_archives($post_type['name'],$archive) as $url )
1104
$urls[] = parse_url( $url, PHP_URL_PATH);
1105
}
1134
* INITIALISATION
1135
*/
1136
1137
+ public function upgrade($old_version)
1138
{
1139
+ // rewrite rules not available on plugins_loaded
1140
// and don't flush rules from init as Polylang chokes on that
1141
// just remove the db option and let WP regenerate them when ready...
1142
delete_option('rewrite_rules');
1149
delete_option($this->prefix.'robots');
1150
add_option($this->prefix.'robots', $robot_rules, '', 'no');
1151
}
1152
+
1153
if ( version_compare('4.4.1', $old_version, '>') ) {
1154
// register location taxonomies then delete all terms
1155
register_taxonomy( 'gn-location-3', null );
1187
$time = strtotime($date);
1188
$arr[$pretty] = (int)$time < time() ? $time : '';
1189
}
1190
+ // and set array
1191
$ping[$se]['pong'] = $arr;
1192
}
1193
}
1201
1202
if ( defined('WP_DEBUG') && WP_DEBUG )
1203
error_log('XML Sitemap Feeds upgraded from '.$old_version.' to '.XMLSF_VERSION);
1204
+
1205
}
1206
1207
+ public function plugins_loaded()
1208
{
1209
// TEXT DOMAIN
1210
if ( is_admin() ) // text domain needed on admin only
1211
load_plugin_textdomain('xml-sitemap-feed', false, dirname(dirname(plugin_basename( __FILE__ ))) . '/languages' );
1212
+
1213
}
1214
1215
+ public function activate()
1216
+ {
1217
+ // return if this is a multisite and we're not network activating
1218
+ if ( is_multisite() ) {
1219
+ if ( !is_network_admin() ) return;
1220
+ }
1221
+
1222
+ // is file.php included on plugin activation? if not, get_home_path()
1223
+ // is not available and we need to do:
1224
+ //require_once(ABSPATH . 'wp-admin/includes/file.php');
1225
+ $home_path = trailingslashit( get_home_path() );
1226
+
1227
+ // CHECK FOR STATIC SITEMAP FILES, DELETE IF EXIST
1228
+ $sitemaps = $this->get_sitemaps();
1229
+ foreach ( $sitemaps as $name => $pretty ) {
1230
+ if ( file_exists( $home_path . $pretty ) )
1231
+ unlink( $home_path . $pretty );
1232
+ }
1233
+ }
1234
+
1235
+ public function init()
1236
{
1237
// UPGRADE
1238
$version = get_option('xmlsf_version', 0);
1242
1243
// TAXONOMIES
1244
$sitemaps = $this->get_sitemaps();
1245
+
1246
if (isset($sitemaps['sitemap-news'])) {
1247
// register the taxonomies
1248
$this->register_gn_taxonomies();
1256
}
1257
}
1258
1259
+ public function admin_init()
1260
{
1261
// CATCH TRANSIENT for reset
1262
if (delete_transient('xmlsf_clear_settings'))
1263
$this->clear_settings();
1264
+
1265
// CATCH TRANSIENT for flushing rewrite rules after the sitemaps setting has changed
1266
if (delete_transient('xmlsf_flush_rewrite_rules'))
1267
$this->flush_rules();
1268
+
1269
// Include the admin class file
1270
include_once( dirname(__FILE__) . '/admin.php' );
1271
1272
}
1273
1274
+ public function flush_rules($hard = false)
1275
+ {
1276
// did you flush already?
1277
if ($this->yes_mother)
1278
return; // yes, mother!
1279
1280
global $wp_rewrite;
1281
// don't need hard flush by default
1282
+ $wp_rewrite->flush_rules($hard);
1283
1284
if ( defined('WP_DEBUG') && WP_DEBUG )
1285
error_log('XML Sitemap Feeds rewrite rules flushed');
1286
1287
$this->yes_mother = true;
1288
}
1289
+
1290
+ public function register_gn_taxonomies()
1291
{
1292
$defaults = $this->defaults('news_tags');
1293
$options = $this->get_option('news_tags');
1313
)
1314
));
1315
}
1316
+
1317
// for debugging
1318
+ public function _e_usage()
1319
{
1320
if (defined('WP_DEBUG') && WP_DEBUG == true) {
1321
echo '<!-- Queries executed '.get_num_queries();
1329
* CONSTRUCTOR
1330
*/
1331
1332
+ function __construct()
1333
{
1334
// sitemap element filters
1335
add_filter('the_title_xmlsitemap', 'strip_tags');
1336
add_filter('the_title_xmlsitemap', 'ent2ncr', 8);
1337
add_filter('the_title_xmlsitemap', 'esc_html');
1338
add_filter('bloginfo_xmlsitemap', 'ent2ncr', 8);
1339
+
1340
// TEMPLATE
1341
add_filter('template', array($this, 'template'), 0);
1342
+
1343
// REQUEST main filtering function
1344
add_filter('request', array($this, 'filter_request'), 1 );
1345
+
1346
// TEXT DOMAIN, UPGRADE PROCESS ...
1347
add_action('plugins_loaded', array($this,'plugins_loaded'), 11 );
1348
1349
// REWRITES
1350
add_action('generate_rewrite_rules', array($this, 'rewrite_rules') );
1351
add_filter('user_trailingslashit', array($this, 'trailingslash') );
1352
+
1353
// TAXONOMY
1354
add_action('init', array($this,'init'), 0 );
1355
+
1356
// REGISTER SETTINGS, SETTINGS FIELDS...
1357
add_action('admin_init', array($this,'admin_init'), 0);
1358
+
1359
// ROBOTSTXT
1360
add_action('do_robotstxt', array($this, 'robots'), 0 );
1361
add_filter('robots_txt', array($this, 'robots_txt'), 0 );
1362
+
1363
// PINGING
1364
+ add_action('transition_post_status', array($this, 'do_pings'), 10, 3);
1365
1366
// CLEAR OBJECT CACHE
1367
+ add_action('transition_post_status', array($this, 'cache_flush'), 99, 2);
1368
+
1369
// NGINX HELPER PURGE URLS
1370
add_filter('rt_nginx_helper_purge_urls', array($this, 'nginx_helper_purge_urls'), 10, 2);
1371
+
1372
// ACTIVATION
1373
+ register_activation_hook( XMLSF_PLUGIN_BASENAME, array($this, 'activate') );
1374
+
1375
// DE-ACTIVATION
1376
register_deactivation_hook( XMLSF_PLUGIN_BASENAME, array($this, 'flush_rules') );
1377
+
1378
}
1379
}
1380
includes/feed-sitemap-news.php CHANGED
@@ -157,6 +157,9 @@ if ( have_posts() ) :
157
<news:keywords><?php echo $keywords; ?></news:keywords>
158
<?php
159
}
160
?>
161
</news:news>
162
<?php
157
<news:keywords><?php echo $keywords; ?></news:keywords>
158
<?php
159
}
160
+
161
+ /* xmlsf_news_tags_after action hook */
162
+ do_action( 'xmlsf_news_tags_after' );
163
?>
164
</news:news>
165
<?php
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=ravan
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.5
7
- Stable tag: 4.5.1
8
9
XML and Google News Sitemaps to feed the hungry spiders. Multisite, WP Super Cache and Polylang compatible.
10
@@ -287,17 +287,21 @@ Thanks for sharing your translation :)
287
288
== Screenshots ==
289
290
- 1. XML Sitemap feed viewed in a normal browser. For human eyes only ;)
291
2. XML Sitemap source as read by search engines.
292
293
294
== Upgrade Notice ==
295
296
- = 4.5.1 =
297
- Fix Persistent/Stored XSS vulnerability on admin page, thanks to Sneha Rajguru @Sneharajguru
298
299
== Changelog ==
300
301
= 4.5.1 =
302
* fix Persistent/Stored XSS vulnerability on admin page, thanks to Sneha Rajguru @Sneharajguru
303
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.5
7
+ Stable tag: 4.6
8
9
XML and Google News Sitemaps to feed the hungry spiders. Multisite, WP Super Cache and Polylang compatible.
10
287
288
== Screenshots ==
289
290
+ 1. XML Sitemap feed viewed in a normal browser. For your eyes only ;)
291
2. XML Sitemap source as read by search engines.
292
293
294
== Upgrade Notice ==
295
296
+ = 4.6 =
297
+ New action hook xmlsf_news_tags_after, attempt to remove conflicting static sitemap files on activation
298
299
== Changelog ==
300
301
+ = 4.6 =
302
+ * NEW: xmlsf_news_tags_after action hook
303
+ * Attempt to remove static sitemap files left over by other sitemap plugins
304
+
305
= 4.5.1 =
306
* fix Persistent/Stored XSS vulnerability on admin page, thanks to Sneha Rajguru @Sneharajguru
307
xml-sitemap.php CHANGED
@@ -4,13 +4,13 @@ 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.5.1
8
Author: RavanH
9
Author URI: http://status301.net/
10
*/
11
12
- /* Copyright 2015 RavanH
13
- http://status301.net/
14
mailto: ravanhagen@gmail.com
15
16
This program is free software; you can redistribute it and/or modify
@@ -29,14 +29,17 @@ Author URI: http://status301.net/
29
*
30
* FILTERS
31
* xmlsf_defaults -> Filters the default array values for different option groups.
32
- * xmlsf_allowed_domain -> Filters the response when checking the url against allowed domains.
33
* Can be true or false.
34
- * the_title_xmlsitemap -> Filters the Google News publication name, title and keywords
35
and Image title and caption tags
36
-
37
* ACTIONS
38
- * none at this point, but feel free to request, suggest or submit one :)
39
- *
40
*/
41
42
if(!empty($_SERVER['SCRIPT_FILENAME']) && 'xml-sitemap.php' == basename($_SERVER['SCRIPT_FILENAME']))
@@ -47,41 +50,41 @@ if(!empty($_SERVER['SCRIPT_FILENAME']) && 'xml-sitemap.php' == basename($_SERVER
47
* CONSTANTS
48
* -------------------- */
49
50
- define('XMLSF_VERSION', '4.5.1');
51
52
define('XMLSF_PLUGIN_BASENAME', plugin_basename(__FILE__));
53
54
- /*
55
- * The following constants can be used to change plugin defaults
56
* by defining them in wp-config.php
57
*/
58
59
- /*
60
- * XMLSF_NAME
61
- *
62
* Pretty permalink name for the main sitemap (index)
63
*/
64
-
65
if ( !defined('XMLSF_NAME') )
66
67
define('XMLSF_NAME', 'sitemap.xml');
68
69
- /*
70
- * XMLSF_NEWS_NAME
71
- *
72
* Pretty permalink name for the news sitemap
73
*/
74
-
75
if ( !defined('XMLSF_NEWS_NAME') )
76
77
define('XMLSF_NEWS_NAME', 'sitemap-news.xml');
78
79
- /*
80
- * XMLSF_MULTISITE_UNINSTALL
81
- *
82
* Set this constant in wp-config.php if you want to allow looping over each site
83
* in the network to run XMLSitemapFeed_Uninstall->uninstall() defined in uninstall.php
84
- *
85
* Be careful: There is NO batch-processing so it does not scale on large networks!
86
*
87
* example:
@@ -92,7 +95,7 @@ if ( !defined('XMLSF_NEWS_NAME') )
92
/* -------------------------------------
93
* INCLUDE HACKS & CLASS
94
* ------------------------------------- */
95
-
96
$xmlsf_dir = dirname(__FILE__);
97
98
if ( file_exists ( $xmlsf_dir.'/xml-sitemap-feed' ) )
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.6
8
Author: RavanH
9
Author URI: http://status301.net/
10
*/
11
12
+ /* Copyright 2015 RavanH
13
+ http://status301.net/
14
mailto: ravanhagen@gmail.com
15
16
This program is free software; you can redistribute it and/or modify
29
*
30
* FILTERS
31
* xmlsf_defaults -> Filters the default array values for different option groups.
32
+ * xmlsf_allowed_domain -> Filters the response when checking the url against allowed domains.
33
* Can be true or false.
34
+ * the_title_xmlsitemap -> Filters the Google News publication name, title and keywords
35
and Image title and caption tags
36
+
37
* ACTIONS
38
+ * xmlsf_news_tags_after -> Fired inside the Google News Sitemap loop at the end of the news
39
+ * tags, just before each closing </news:news> is generated. Can be used to
40
+ * echo custom tags or trigger another action in the background.
41
+ *
42
+ * feel free to request, suggest or submit more :)
43
*/
44
45
if(!empty($_SERVER['SCRIPT_FILENAME']) && 'xml-sitemap.php' == basename($_SERVER['SCRIPT_FILENAME']))
50
* CONSTANTS
51
* -------------------- */
52
53
+ define('XMLSF_VERSION', '4.6');
54
55
define('XMLSF_PLUGIN_BASENAME', plugin_basename(__FILE__));
56
57
+ /*
58
+ * The following constants can be used to change plugin defaults
59
* by defining them in wp-config.php
60
*/
61
62
+ /*
63
+ * XMLSF_NAME
64
+ *
65
* Pretty permalink name for the main sitemap (index)
66
*/
67
+
68
if ( !defined('XMLSF_NAME') )
69
70
define('XMLSF_NAME', 'sitemap.xml');
71
72
+ /*
73
+ * XMLSF_NEWS_NAME
74
+ *
75
* Pretty permalink name for the news sitemap
76
*/
77
+
78
if ( !defined('XMLSF_NEWS_NAME') )
79
80
define('XMLSF_NEWS_NAME', 'sitemap-news.xml');
81
82
+ /*
83
+ * XMLSF_MULTISITE_UNINSTALL
84
+ *
85
* Set this constant in wp-config.php if you want to allow looping over each site
86
* in the network to run XMLSitemapFeed_Uninstall->uninstall() defined in uninstall.php
87
+ *
88
* Be careful: There is NO batch-processing so it does not scale on large networks!
89
*
90
* example:
95
/* -------------------------------------
96
* INCLUDE HACKS & CLASS
97
* ------------------------------------- */
98
+
99
$xmlsf_dir = dirname(__FILE__);
100
101
if ( file_exists ( $xmlsf_dir.'/xml-sitemap-feed' ) )