All_in_One_SEO_Pack_Sitemap

Class All_in_One_SEO_Pack_Sitemap.

Defined (1)

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

/modules/aioseop_sitemap.php  
  1. class All_in_One_SEO_Pack_Sitemap extends All_in_One_SEO_Pack_Module { 
  2. var $cache_struct = null; 
  3. var $cache_home = null; 
  4. var $comment_string; 
  5. var $start_memory_usage = 0; 
  6. var $max_posts = 50000; 
  7. var $paginate = false; 
  8. var $prio; 
  9. var $prio_sel; 
  10. var $freq; 
  11. var $freq_sel; 
  12. var $extra_sitemaps; 
  13.  
  14. /** 
  15. * All_in_One_SEO_Pack_Sitemap constructor. 
  16. */ 
  17. function __construct() { 
  18. if ( get_class( $this ) === 'All_in_One_SEO_Pack_Sitemap' ) { // Set this up only when instantiated as this class. 
  19. $this->name = __( 'XML Sitemap', 'all-in-one-seo-pack' ); // Human-readable name of the plugin. 
  20. $this->prefix = 'aiosp_sitemap_'; // Option prefix. 
  21. $this->file = __FILE__; // The current file. 
  22. $this->extra_sitemaps = array(); 
  23. $this->extra_sitemaps = apply_filters( $this->prefix . 'extra', $this->extra_sitemaps ); 
  24. parent::__construct(); 
  25. $this->comment_string = 'Sitemap %s generated by All in One SEO Pack %s by Michael Torbert of Semper Fi Web Design on %s'; 
  26.  
  27. $this->help_text = array( 
  28. 'filename' => __( "Specifies the name of your sitemap file. This will default to 'sitemap'.", 'all-in-one-seo-pack' ),  
  29. 'google' => __( 'Notify Google when you update your sitemap settings.', 'all-in-one-seo-pack' ),  
  30. 'bing' => __( 'Notify Bing when you update your sitemap settings.', 'all-in-one-seo-pack' ),  
  31. 'daily_cron' => __( 'Notify search engines based on the selected schedule, and also update static sitemap daily if in use. (this uses WP-Cron, so make sure this is working properly on your server as well)', 'all-in-one-seo-pack' ),  
  32. 'indexes' => __( 'Organize sitemap entries into distinct files in your sitemap. Enable this only if your sitemap contains over 50, 000 URLs or the file is over 5MB in size.', 'all-in-one-seo-pack' ),  
  33. 'paginate' => __( 'Split long sitemaps into separate files.', 'all-in-one-seo-pack' ),  
  34. 'max_posts' => __( 'Allows you to specify the maximum number of posts in a sitemap (up to 50, 000).', 'all-in-one-seo-pack' ),  
  35. 'posttypes' => __( 'Select which Post Types appear in your sitemap.', 'all-in-one-seo-pack' ),  
  36. 'taxonomies' => __( 'Select which taxonomy archives appear in your sitemap', 'all-in-one-seo-pack' ),  
  37. 'archive' => __( 'Include Date Archives in your sitemap.', 'all-in-one-seo-pack' ),  
  38. 'author' => __( 'Include Author Archives in your sitemap.', 'all-in-one-seo-pack' ),  
  39. 'gzipped' => __( 'Create a compressed sitemap file in .xml.gz format.', 'all-in-one-seo-pack' ),  
  40. 'robots' => __( 'Places a link to your Sitemap.xml into your virtual Robots.txt file.', 'all-in-one-seo-pack' ),  
  41. 'rewrite' => __( 'Dynamically creates the XML sitemap instead of using a static file.', 'all-in-one-seo-pack' ),  
  42. 'debug' => __( 'Use rewrites to generate your sitemap on the fly. NOTE: This is required for WordPress Multisite.', 'all-in-one-seo-pack' ),  
  43. 'addl_url' => __( 'URL to the page.', 'all-in-one-seo-pack' ),  
  44. 'addl_prio' => __( 'The priority of the page.', 'all-in-one-seo-pack' ),  
  45. 'addl_freq' => __( 'The frequency of the page.', 'all-in-one-seo-pack' ),  
  46. 'addl_mod' => __( 'Last modified date of the page.', 'all-in-one-seo-pack' ),  
  47. 'excl_categories' => __( 'Entries from these categories will be excluded from the sitemap.', 'all-in-one-seo-pack' ),  
  48. 'excl_pages' => __( 'Use page slugs or page IDs, seperated by commas, to exclude pages from the sitemap.', 'all-in-one-seo-pack' ),  
  49. ); 
  50.  
  51. $this->help_anchors = array( 
  52. 'filename' => '#filename-prefix',  
  53. 'google' => '#notify-google-bing',  
  54. 'bing' => '#notify-google-bing',  
  55. 'daily_cron' => '#schedule-updates',  
  56. 'indexes' => '#enable-sitemap-indexes',  
  57. 'paginate' => '#enable-sitemap-indexes',  
  58. 'max_posts' => '#enable-sitemap-indexes',  
  59. 'posttypes' => '#post-types-and-taxonomies',  
  60. 'taxonomies' => '#post-types-and-taxonomies',  
  61. 'archive' => '#include-archive-pages',  
  62. 'author' => '#include-archive-pages',  
  63. 'gzipped' => '#create-compressed-sitemap',  
  64. 'robots' => '#link-from-virtual-robots',  
  65. 'rewrite' => '#dynamically-generate-sitemap',  
  66. 'addl_url' => '#additional-pages',  
  67. 'addl_prio' => '#additional-pages',  
  68. 'addl_freq' => '#additional-pages',  
  69. 'addl_mod' => '#additional-pages',  
  70. 'excl_categories' => '#excluded-items',  
  71. 'excl_pages' => '#excluded-items',  
  72. ); 
  73.  
  74. $this->default_options = array( 
  75. 'filename' => array( 
  76. 'name' => __( 'Filename Prefix', 'all-in-one-seo-pack' ),  
  77. 'default' => 'sitemap',  
  78. 'type' => 'text',  
  79. 'sanitize' => 'filename',  
  80. ),  
  81. 'google' => array( 'name' => __( 'Notify Google', 'all-in-one-seo-pack' ) ),  
  82. 'bing' => array( 'name' => __( 'Notify Bing', 'all-in-one-seo-pack' ) ),  
  83. 'daily_cron' => array( 
  84. 'name' => __( 'Schedule Updates', 'all-in-one-seo-pack' ),  
  85. 'type' => 'select',  
  86. 'initial_options' => array( 
  87. 0 => __( 'No Schedule', 'all-in-one-seo-pack' ),  
  88. 'daily' => __( 'Daily', 'all-in-one-seo-pack' ),  
  89. 'weekly' => __( 'Weekly', 'all-in-one-seo-pack' ),  
  90. 'monthly' => __( 'Monthly', 'all-in-one-seo-pack' ),  
  91. ),  
  92. 'default' => 0,  
  93. ),  
  94. 'indexes' => array( 'name' => __( 'Enable Sitemap Indexes', 'all-in-one-seo-pack' ) ),  
  95. 'paginate' => array( 
  96. 'name' => __( 'Paginate Sitemap Indexes', 'all-in-one-seo-pack' ),  
  97. 'condshow' => array( "{$this->prefix}indexes" => 'on' ),  
  98. ),  
  99. 'max_posts' => array( 
  100. 'name' => __( 'Maximum Posts Per Sitemap', 'all-in-one-seo-pack' ),  
  101. 'type' => 'text',  
  102. 'default' => 50000,  
  103. 'condshow' => array( "{$this->prefix}indexes" => 'on', "{$this->prefix}paginate" => 'on' ),  
  104. ),  
  105. 'posttypes' => array( 
  106. 'name' => __( 'Post Types', 'all-in-one-seo-pack' ),  
  107. 'type' => 'multicheckbox',  
  108. 'default' => 'all',  
  109. ),  
  110. 'taxonomies' => array( 
  111. 'name' => __( 'Taxonomies', 'all-in-one-seo-pack' ),  
  112. 'type' => 'multicheckbox',  
  113. 'default' => 'all',  
  114. ),  
  115. 'archive' => array( 'name' => __( 'Include Date Archive Pages', 'all-in-one-seo-pack' ) ),  
  116. 'author' => array( 'name' => __( 'Include Author Pages', 'all-in-one-seo-pack' ) ),  
  117. 'gzipped' => array( 
  118. 'name' => __( 'Create Compressed Sitemap', 'all-in-one-seo-pack' ),  
  119. 'default' => 'On',  
  120. ),  
  121. 'robots' => array( 
  122. 'name' => __( 'Link From Virtual Robots.txt', 'all-in-one-seo-pack' ),  
  123. 'default' => 'On',  
  124. ),  
  125. 'rewrite' => array( 
  126. 'name' => __( 'Dynamically Generate Sitemap', 'all-in-one-seo-pack' ),  
  127. 'default' => 'On',  
  128. ),  
  129. ); 
  130.  
  131. $status_options = array( 
  132. 'link' => array( 'default' => '', 'type' => 'html', 'label' => 'none', 'save' => false ),  
  133. 'debug' => array( 
  134. 'name' => __( 'Debug Log', 'all-in-one-seo-pack' ),  
  135. 'default' => '',  
  136. 'type' => 'html',  
  137. 'disabled' => 'disabled',  
  138. 'save' => false,  
  139. 'label' => 'none',  
  140. 'rows' => 5,  
  141. 'cols' => 120,  
  142. 'style' => 'min-width:950px',  
  143. ),  
  144. ); 
  145.  
  146. $this->layout = array( 
  147. 'status' => array( 
  148. 'name' => __( 'Sitemap Status', 'all-in-one-seo-pack' ),  
  149. 'help_link' => 'http://semperplugins.com/documentation/xml-sitemaps-module/',  
  150. 'options' => array_keys( $status_options ),  
  151. ),  
  152. 'default' => array( 
  153. 'name' => $this->name,  
  154. 'help_link' => 'http://semperplugins.com/documentation/xml-sitemaps-module/',  
  155. 'options' => array_keys( $this->default_options ),  
  156. ),  
  157. ); 
  158.  
  159. $prio = array(); 
  160. for ( $i = 0; $i <= 10; $i ++ ) { 
  161. $str = sprintf( '%0.1f', $i / 10.0 ); 
  162. $prio[ $str ] = $str; 
  163. $arr_no = array( 'no' => __( 'Do Not Override', 'all-in-one-seo-pack' ) ); 
  164. $arr_sel = array( 'sel' => __( 'Select Individual', 'all-in-one-seo-pack' ) ); 
  165. $this->prio_sel = array_merge( $arr_no, $arr_sel, $prio ); 
  166. $this->prio = array_merge( $arr_no, $prio ); 
  167.  
  168. $freq = array(); 
  169. foreach ( array( 'always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never' ) as $f ) { 
  170. $freq[ $f ] = $f; 
  171. $this->freq_sel = array_merge( $arr_no, $arr_sel, $freq ); 
  172. $this->freq = array_merge( $arr_no, $freq ); 
  173.  
  174. foreach ( 
  175. array( 
  176. 'prio' => __( 'priority', 'all-in-one-seo-pack' ),  
  177. 'freq' => __( 'frequency', 'all-in-one-seo-pack' ),  
  178. ) as $k => $v 
  179. ) { 
  180. $s = "{$k}_options"; 
  181. $$s = array(); 
  182. foreach ( 
  183. array( 
  184. 'homepage' => __( 'homepage', 'all-in-one-seo-pack' ),  
  185. 'post' => __( 'posts', 'all-in-one-seo-pack' ),  
  186. 'taxonomies' => __( 'taxonomies', 'all-in-one-seo-pack' ),  
  187. 'archive' => __( 'archive pages', 'all-in-one-seo-pack' ),  
  188. 'author' => __( 'author pages', 'all-in-one-seo-pack' ),  
  189. ) as $opt => $val 
  190. ) { 
  191. $arr = $$s; 
  192. if ( ( 'post' === $opt ) || ( 'taxonomies' === $opt ) ) { 
  193. $iopts = $this->{"{$k}_sel"}; 
  194. } else { 
  195. $iopts = $this->$k; 
  196.  
  197. $arr[ $k . '_' . $opt ] = array( 
  198. 'name' => $this->ucwords( $val ),  
  199. 'help_text' => sprintf( __( 'Manually set the %s of your %s.', 'all-in-one-seo-pack' ), $v, $val ),  
  200. 'type' => 'select',  
  201. 'initial_options' => $iopts,  
  202. 'default' => 'no',  
  203. ); 
  204. if ( ( 'archive' === $opt ) || ( 'author' === $opt ) ) { 
  205. $arr[ $k . '_' . $opt ]['condshow'] = array( $this->prefix . $opt => 'on' ); 
  206. $$s = $arr; 
  207.  
  208. $addl_options = array( 
  209. 'addl_instructions' => array( 
  210. 'default' => '<div>' . __( 'Enter information below for any additional links for your sitemap not already managed through WordPress.', 'all-in-one-seo-pack' ) . '</div><br />',  
  211. 'type' => 'html',  
  212. 'label' => 'none',  
  213. 'save' => false,  
  214. ),  
  215. 'addl_url' => array( 
  216. 'name' => __( 'Page URL', 'all-in-one-seo-pack' ),  
  217. 'type' => 'text',  
  218. 'label' => 'top',  
  219. 'save' => false,  
  220. ),  
  221. 'addl_prio' => array( 
  222. 'name' => __( 'Page Priority', 'all-in-one-seo-pack' ),  
  223. 'type' => 'select',  
  224. 'initial_options' => $prio,  
  225. 'label' => 'top',  
  226. 'save' => false,  
  227. ),  
  228. 'addl_freq' => array( 
  229. 'name' => __( 'Page Frequency', 'all-in-one-seo-pack' ),  
  230. 'type' => 'select',  
  231. 'initial_options' => $freq,  
  232. 'label' => 'top',  
  233. 'save' => false,  
  234. ),  
  235. 'addl_mod' => array( 
  236. 'name' => __( 'Last Modified', 'all-in-one-seo-pack' ),  
  237. 'type' => 'text',  
  238. 'label' => 'top',  
  239. 'save' => false,  
  240. ),  
  241. 'addl_pages' => array( 
  242. 'name' => __( 'Additional Pages', 'all-in-one-seo-pack' ),  
  243. 'type' => 'custom',  
  244. 'save' => true,  
  245. ),  
  246. 'Submit' => array( 
  247. 'type' => 'submit',  
  248. 'class' => 'button-primary',  
  249. 'name' => __( 'Add URL', 'all-in-one-seo-pack' ) . ' »',  
  250. 'style' => 'margin-left: 20px;',  
  251. 'label' => 'none',  
  252. 'save' => false,  
  253. 'value' => 1,  
  254. ),  
  255. ); 
  256.  
  257. $excl_options = array( 
  258. 'excl_categories' => array( 
  259. 'name' => __( 'Excluded Categories', 'all-in-one-seo-pack' ),  
  260. 'type' => 'multicheckbox',  
  261. 'initial_options' => '',  
  262. ),  
  263. 'excl_pages' => array( 'name' => __( 'Excluded Pages', 'all-in-one-seo-pack' ), 'type' => 'text' ),  
  264. ); 
  265.  
  266. $this->layout['addl_pages'] = array( 
  267. 'name' => __( 'Additional Pages', 'all-in-one-seo-pack' ),  
  268. 'help_link' => 'http://semperplugins.com/documentation/xml-sitemaps-module/#additional-pages',  
  269. 'options' => array_keys( $addl_options ),  
  270. ); 
  271.  
  272. $this->layout['excl_pages'] = array( 
  273. 'name' => __( 'Excluded Items', 'all-in-one-seo-pack' ),  
  274. 'help_link' => 'http://semperplugins.com/documentation/xml-sitemaps-module/#excluded-items',  
  275. 'options' => array_keys( $excl_options ),  
  276. ); 
  277.  
  278. $this->layout['priorities'] = array( 
  279. 'name' => __( 'Priorities', 'all-in-one-seo-pack' ),  
  280. 'help_link' => 'http://semperplugins.com/documentation/xml-sitemaps-module/#priorities-and-frequencies',  
  281. 'options' => array_keys( $prio_options ),  
  282. ); 
  283.  
  284. $this->layout['frequencies'] = array( 
  285. 'name' => __( 'Frequencies', 'all-in-one-seo-pack' ),  
  286. 'help_link' => 'http://semperplugins.com/documentation/xml-sitemaps-module/#priorities-and-frequencies',  
  287. 'options' => array_keys( $freq_options ),  
  288. ); 
  289.  
  290. $this->default_options = array_merge( $status_options, $this->default_options, $addl_options, $excl_options, $prio_options, $freq_options ); 
  291.  
  292. $this->add_help_text_links(); 
  293.  
  294. add_action( 'after_doing_aioseop_updates', array( 
  295. $this,  
  296. 'do_sitemaps',  
  297. ) ); // Update static sitemap when AIOSEOP is upgrade to new version. 
  298. add_action( 'init', array( $this, 'load_sitemap_options' ) ); 
  299. add_action( $this->prefix . 'settings_update', array( $this, 'do_sitemaps' ) ); 
  300. add_filter( $this->prefix . 'display_settings', array( $this, 'update_post_data' ) ); 
  301. add_filter( $this->prefix . 'display_options', array( $this, 'filter_display_options' ) ); 
  302. add_filter( $this->prefix . 'update_options', array( $this, 'filter_options' ) ); 
  303. add_filter( $this->prefix . 'output_option', array( $this, 'display_custom_options' ), 10, 2 ); 
  304. add_action( $this->prefix . 'daily_update_cron', array( $this, 'daily_update' ) ); 
  305. add_action( 'init', array( $this, 'make_dynamic_xsl' ) ); 
  306. add_action( 'transition_post_status', array( $this, 'update_sitemap_from_posts' ), 10, 3 ); 
  307.  
  308. /** 
  309. * Update sitemap from posts. 
  310. * @param $new_status 
  311. * @param $old_status 
  312. * @param $post 
  313. */ 
  314. function update_sitemap_from_posts( $new_status, $old_status, $post ) { 
  315.  
  316. if ( $this->option_isset( 'rewrite' ) ) { 
  317. // TODO if dynamic, delete transient (we currently don't do transients). 
  318. return; 
  319.  
  320. $posttypes = array(); 
  321. if ( ! empty( $this->options["{$this->prefix}posttypes"] ) ) { 
  322. $posttypes = $this->options["{$this->prefix}posttypes"]; 
  323.  
  324. if ( ! in_array( $post->post_type, $posttypes, true ) ) { 
  325. return; 
  326.  
  327. $statuses_for_updating = array( 'new', 'publish', 'trash' ); 
  328. if ( ! in_array( $new_status, $statuses_for_updating, true ) ) { 
  329. return; 
  330.  
  331. $this->do_sitemaps(); 
  332.  
  333. /** 
  334. * Add cron schedules. 
  335. * Add new intervals of a week and a month. 
  336. * @link http://codex.wordpress.org/Plugin_API/Filter_Reference/cron_schedules 
  337. * @param $schedules 
  338. * @return mixed 
  339. */ 
  340. function add_cron_schedules( $schedules ) { 
  341. $schedules['weekly'] = array( 
  342. 'interval' => 604800, // 1 week in seconds. 
  343. 'display' => __( 'Once Weekly', 'all-in-one-seo-pack' ),  
  344. ); 
  345. $schedules['monthly'] = array( 
  346. 'interval' => 2629740, // 1 month in seconds. 
  347. 'display' => __( 'Once Monthly', 'all-in-one-seo-pack' ),  
  348. ); 
  349.  
  350. return $schedules; 
  351.  
  352. /** 
  353. * Cron update. 
  354. */ 
  355. function cron_update() { 
  356. add_filter( 'cron_schedules', array( $this, 'add_cron_schedules' ) ); 
  357. if ( ! wp_next_scheduled( $this->prefix . 'daily_update_cron' ) ) { 
  358. wp_schedule_event( time(), $this->options[ $this->prefix . 'daily_cron' ], $this->prefix . 'daily_update_cron' ); 
  359.  
  360. /** 
  361. * Daily update. 
  362. */ 
  363. function daily_update() { 
  364. $last_run = get_option( $this->prefix . 'cron_last_run' ); 
  365. if ( empty( $last_run ) || ( time() - $last_run > 23.5 * 60 * 60 ) ) { 
  366. // Sanity check. 
  367. $this->do_sitemaps( __( 'Daily scheduled sitemap check has finished.', 'all-in-one-seo-pack' ) ); 
  368. $last_run = time(); 
  369. update_option( $this->prefix . 'cron_last_run', $last_run ); 
  370.  
  371. /** 
  372. * Initialize options, after constructor. 
  373. */ 
  374. function load_sitemap_options() { 
  375. // Load initial options / set defaults. 
  376. $this->update_options(); 
  377. if ( ! empty( $this->options["{$this->prefix}indexes"] ) && ! empty( $this->options["{$this->prefix}paginate"] ) ) { 
  378. $this->paginate = true; 
  379. if ( $this->options["{$this->prefix}max_posts"] && ( $this->options["{$this->prefix}max_posts"] > 0 ) && ( $this->options["{$this->prefix}max_posts"] < 50000 ) ) { 
  380. $this->max_posts = $this->options["{$this->prefix}max_posts"]; 
  381.  
  382. if ( is_multisite() ) { 
  383. $this->options["{$this->prefix}rewrite"] = 'On'; 
  384.  
  385. if ( $this->options["{$this->prefix}rewrite"] ) { 
  386. $this->setup_rewrites(); 
  387.  
  388. if ( $this->option_isset( 'robots' ) ) { 
  389. add_action( 'do_robots', array( $this, 'do_robots' ), 100 ); 
  390.  
  391. if ( isset( $this->options[ $this->prefix . 'daily_cron' ] ) && $this->options[ $this->prefix . 'daily_cron' ] ) { 
  392. add_action( 'wp', array( $this, 'cron_update' ) ); 
  393. } else { 
  394. if ( $time = wp_next_scheduled( $this->prefix . 'daily_update_cron' ) ) { 
  395. wp_unschedule_event( $time, $this->prefix . 'daily_update_cron' ); 
  396.  
  397. /** 
  398. * Custom settings. 
  399. * Displays boxes for add pages to sitemap option. Requires WordPress 4.1. 
  400. * @param $buf 
  401. * @param $args 
  402. * @return string 
  403. */ 
  404. function display_custom_options( $buf, $args ) { 
  405. if ( "{$this->prefix}addl_pages" === $args['name'] ) { 
  406. $buf .= "<div id='{$this->prefix}addl_pages'>"; 
  407. if ( ! empty( $args['value'] ) ) { 
  408. $buf .= "<table class='aioseop_table' cellpadding=0 cellspacing=0>\n"; 
  409. foreach ( $args['value'] as $k => $v ) { 
  410. if ( is_object( $v ) ) { 
  411. $v = (Array) $v; 
  412. $buf .= "\t<tr><td><a href='#' title='$k' class='aiosp_delete_url'></a> {$k}</td><td>{$v['prio']}</td><td>{$v['freq']}</td><td>{$v['mod']}</td></tr>\n"; 
  413. $buf .= "</table>\n"; 
  414. $args['options']['type'] = 'hidden'; 
  415. if ( ! empty( $args['value'] ) ) { 
  416. $args['value'] = wp_json_encode( $args['value'] ); 
  417. } else { 
  418. $args['options']['type'] = 'html'; 
  419. if ( empty( $args['value'] ) ) { 
  420. $args['value'] = ''; 
  421. $buf .= $this->get_option_html( $args ); 
  422. $buf .= '</div>'; 
  423.  
  424. return $buf; 
  425.  
  426. /** 
  427. * Add post type details for settings once post types have been registered. 
  428. */ 
  429. function add_post_types() { 
  430. $post_type_titles = $this->get_post_type_titles( array( 'public' => true ) ); 
  431. $taxonomy_titles = $this->get_taxonomy_titles( array( 'public' => true ) ); 
  432. if ( isset( $post_type_titles['attachment'] ) ) { 
  433. $post_type_titles['attachment'] = __( 'Media / Attachments', 'all-in-one-seo-pack' ); 
  434. $this->default_options['posttypes']['initial_options'] = array_merge( array( 'all' => __( 'All Post Types', 'all-in-one-seo-pack' ) ), $post_type_titles ); 
  435. $this->default_options['taxonomies']['initial_options'] = array_merge( array( 'all' => __( 'All Taxonomies', 'all-in-one-seo-pack' ) ), $taxonomy_titles ); 
  436. $this->default_options['posttypes']['default'] = array_keys( $this->default_options['posttypes']['initial_options'] ); 
  437. $this->default_options['taxonomies']['default'] = array_keys( $this->default_options['taxonomies']['initial_options'] ); 
  438. $this->default_options['excl_categories']['initial_options'] = $this->get_category_titles(); 
  439. $prio_help = __( 'Manually set the priority for the ', 'all-in-one-seo-pack' ); 
  440. $freq_help = __( 'Manually set the frequency for the ', 'all-in-one-seo-pack' ); 
  441. $post_name = __( ' Post Type', 'all-in-one-seo-pack' ); 
  442. $tax_name = __( ' Taxonomy', 'all-in-one-seo-pack' ); 
  443. foreach ( $post_type_titles as $k => $v ) { 
  444. $key = 'prio_post_' . $k; 
  445. $this->default_options = aioseop_array_insert_after( $this->default_options, 'prio_post', array( 
  446. $key => array( 
  447. 'name' => $v . $post_name,  
  448. 'help_text' => $prio_help . $v . $post_name,  
  449. 'type' => 'select',  
  450. 'initial_options' => $this->prio,  
  451. 'default' => 'no',  
  452. 'condshow' => array( "{$this->prefix}prio_post" => 'sel' ),  
  453. ),  
  454. ) ); 
  455. $this->layout['priorities']['options'][] = $key; 
  456. $key = 'freq_post_' . $k; 
  457. $this->default_options = aioseop_array_insert_after( $this->default_options, 'freq_post', array( 
  458. $key => array( 
  459. 'name' => $v . $post_name,  
  460. 'help_text' => $freq_help . $v . $post_name,  
  461. 'type' => 'select',  
  462. 'initial_options' => $this->freq,  
  463. 'default' => 'no',  
  464. 'condshow' => array( "{$this->prefix}freq_post" => 'sel' ),  
  465. ),  
  466. ) ); 
  467. $this->layout['frequencies']['options'][] = $key; 
  468. foreach ( $taxonomy_titles as $k => $v ) { 
  469. $key = 'prio_taxonomies_' . $k; 
  470. $this->default_options = aioseop_array_insert_after( $this->default_options, 'prio_taxonomies', array( 
  471. $key => array( 
  472. 'name' => $v . $tax_name,  
  473. 'help_text' => $prio_help . $v . $tax_name,  
  474. 'type' => 'select',  
  475. 'initial_options' => $this->prio,  
  476. 'default' => 'no',  
  477. 'condshow' => array( "{$this->prefix}prio_taxonomies" => 'sel' ),  
  478. ),  
  479. ) ); 
  480. $this->layout['priorities']['options'][] = $key; 
  481. $key = 'freq_taxonomies_' . $k; 
  482. $this->default_options = aioseop_array_insert_after( $this->default_options, 'freq_taxonomies', array( 
  483. $key => array( 
  484. 'name' => $v . $tax_name,  
  485. 'help_text' => $freq_help . $v . $tax_name,  
  486. 'type' => 'select',  
  487. 'initial_options' => $this->freq,  
  488. 'default' => 'no',  
  489. 'condshow' => array( "{$this->prefix}freq_taxonomies" => 'sel' ),  
  490. ),  
  491. ) ); 
  492. $this->layout['frequencies']['options'][] = $key; 
  493. $this->update_options(); 
  494.  
  495. /** 
  496. * Set up settings, checking for sitemap conflicts, on settings page. 
  497. */ 
  498. function add_page_hooks() { 
  499. $this->flush_rules_hook(); 
  500. $this->add_post_types(); 
  501. parent::add_page_hooks(); 
  502. add_action( $this->prefix . 'settings_header', array( $this, 'do_sitemap_scan' ), 5 ); 
  503. add_filter( "{$this->prefix}submit_options", array( $this, 'filter_submit' ) ); 
  504.  
  505. /** 
  506. * Filter submit button. 
  507. * Change settings page submit button to read "Update Sitemap". 
  508. * @param $submit 
  509. * @return mixed 
  510. */ 
  511. function filter_submit( $submit ) { 
  512. $submit['Submit']['value'] = __( 'Update Sitemap', 'all-in-one-seo-pack' ) . ' »'; 
  513.  
  514. return $submit; 
  515.  
  516. /** 
  517. * Updates post data. 
  518. * Disable writing sitemaps to the filesystem for multisite. 
  519. * @param $options 
  520. * @return mixed 
  521. */ 
  522. function update_post_data( $options ) { 
  523. if ( is_multisite() ) { 
  524. $options[ $this->prefix . 'rewrite' ]['disabled'] = 'disabled'; 
  525.  
  526. return $options; 
  527.  
  528. /** 
  529. * @param $url 
  530. * @return bool 
  531. */ 
  532. function get_rewrite_url( $url ) { 
  533. global $wp_rewrite; 
  534. $url = parse_url( esc_url( $url ), PHP_URL_PATH ); 
  535. $url = ltrim( $url, '/' ); 
  536. if ( ! empty( $wp_rewrite ) ) { 
  537. $rewrite_rules = $wp_rewrite->rewrite_rules(); 
  538. foreach ( $rewrite_rules as $k => $v ) { 
  539. if ( preg_match( "@^$k@", $url ) ) { 
  540. return $v; 
  541.  
  542. return false; 
  543.  
  544. /** 
  545. * Filter display options. 
  546. * Add in options for status display on settings page, sitemap rewriting on multisite. 
  547. * @param $options 
  548. * @return mixed 
  549. */ 
  550. function filter_display_options( $options ) { 
  551. if ( is_multisite() ) { 
  552. $options[ $this->prefix . 'rewrite' ] = 'On'; 
  553. if ( isset( $options[ $this->prefix . 'max_posts' ] ) && ( ( $options[ $this->prefix . 'max_posts' ] <= 0 ) || ( $options[ $this->prefix . 'max_posts' ] >= 50000 ) ) ) { 
  554. $options[ $this->prefix . 'max_posts' ] = 50000; 
  555. $url = trailingslashit( get_home_url() ) . $options[ $this->prefix . 'filename' ] . '.xml'; 
  556. $options[ $this->prefix . 'link' ] = sprintf( __( 'Please review your settings below and click %s to build your sitemap; then, %s.',  
  557. 'all-in-one-seo-pack' ), sprintf( '<a href="#" onclick="document.dofollow.elements[\'Submit\'][0].click();">%s</a>',  
  558. __( 'Update Sitemap', 'all-in-one-seo-pack' ) ), '<a href="' . esc_url( $url ) . '" target="_blank">' . 
  559. __( 'view your sitemap', 'all-in-one-seo-pack' ) . '</a>' ); 
  560. if ( $this->option_isset( 'rewrite' ) ) { 
  561.  
  562. $options[ $this->prefix . 'link' ] .= '<p>' . __( 'Note: you are using dynamic sitemap generation to keep your sitemap current; this will not generate a static sitemap file.', 'all-in-one-seo-pack' ) . '</p>'; 
  563. $rule = $this->get_rewrite_url( $url ); 
  564. $rules = $this->get_rewrite_rules(); 
  565. if ( in_array( $rule, $rules ) ) { 
  566. $options[ $this->prefix . 'link' ] .= '<p>' . __( 'Dynamic sitemap generation appears to be using the correct rewrite rules.', 'all-in-one-seo-pack' ) . '</p>'; 
  567. } else { 
  568. $options[ $this->prefix . 'link' ] .= '<p>' . __( 'Dynamic sitemap generation does not appear to be using the correct rewrite rules; please disable any other sitemap plugins or functionality on your site and reset your permalinks.', 'all-in-one-seo-pack' ) . '</p>'; 
  569. if ( ! get_option( 'blog_public' ) ) { 
  570. global $wp_version; 
  571. if ( version_compare( $wp_version, '3.5.0', '>=' ) || function_exists( 'set_url_scheme' ) ) { 
  572. $privacy_link = '<a href="options-reading.php">' . __( 'Reading Settings', 'all-in-one-seo-pack' ) . '</a>'; 
  573. } else { 
  574. $privacy_link = '<a href="options-privacy.php">' . __( 'Privacy Settings', 'all-in-one-seo-pack' ) . '</a>'; 
  575. $options[ $this->prefix . 'link' ] .= '<p class="aioseop_error_notice">' . sprintf( __( 'Warning: your privacy settings are configured to ask search engines to not index your site; you can change this under %s for your blog.', 'all-in-one-seo-pack' ), $privacy_link ); 
  576. if ( $this->option_isset( 'debug' ) ) { 
  577. $debug_msg = esc_html( $options["{$this->prefix}debug"] ); 
  578. $options["{$this->prefix}debug"] = '<pre>' . $debug_msg . '</pre>'; 
  579.  
  580. return $options; 
  581.  
  582. /** 
  583. * Filter options. 
  584. * Handle 'all' option for post types / taxonomies, further sanitization of filename, rewrites on for multisite, setting up addl pages option. 
  585. * @param $options 
  586. * @return mixed 
  587. */ 
  588. function filter_options( $options ) { 
  589. if ( ! isset( $this->default_options['posttypes']['initial_options'] ) ) { 
  590. $this->add_post_types(); 
  591. if ( is_array( $options["{$this->prefix}posttypes"] ) && in_array( 'all', $options["{$this->prefix}posttypes"] ) && is_array( $this->default_options['posttypes']['initial_options'] ) ) { 
  592. $options["{$this->prefix}posttypes"] = array_keys( $this->default_options['posttypes']['initial_options'] ); 
  593. if ( is_array( $options["{$this->prefix}taxonomies"] ) && in_array( 'all', $options["{$this->prefix}taxonomies"] ) && is_array( $this->default_options['taxonomies']['initial_options'] ) ) { 
  594. $options["{$this->prefix}taxonomies"] = array_keys( $this->default_options['taxonomies']['initial_options'] ); 
  595. $opt = $this->prefix . 'filename'; 
  596. if ( isset( $options[ $opt ] ) && ! empty( $options[ $opt ] ) ) { 
  597. $options[ $opt ] = str_replace( '/', '', $options[ $opt ] ); 
  598. } else { 
  599. $options[ $opt ] = 'sitemap'; 
  600. if ( is_multisite() ) { 
  601. $options[ $this->prefix . 'rewrite' ] = 'On'; 
  602. if ( ! is_array( $options[ $this->prefix . 'addl_pages' ] ) ) { 
  603. $options[ $this->prefix . 'addl_pages' ] = wp_specialchars_decode( stripslashes_deep( $options[ $this->prefix . 'addl_pages' ] ), ENT_QUOTES ); 
  604. $decoded = json_decode( $options[ $this->prefix . 'addl_pages' ] ); 
  605. if ( null === $decoded ) { 
  606. $decoded = maybe_unserialize( $options[ $this->prefix . 'addl_pages' ] ); 
  607. if ( ! is_array( $decoded ) ) { 
  608. $decoded = (Array) $decoded; 
  609. if ( null === $decoded ) { 
  610. $decoded = $options[ $this->prefix . 'addl_pages' ]; 
  611. $options[ $this->prefix . 'addl_pages' ] = $decoded; 
  612. if ( is_array( $options[ $this->prefix . 'addl_pages' ] ) ) { 
  613. foreach ( $options[ $this->prefix . 'addl_pages' ] as $k => $v ) { 
  614. if ( is_object( $v ) ) { 
  615. $options[ $this->prefix . 'addl_pages' ][ $k ] = (Array) $v; 
  616. if ( isset( $options[ $this->prefix . 'addl_pages' ][0] ) ) { 
  617. unset( $options[ $this->prefix . 'addl_pages' ][0] ); 
  618. // TODO Refactor all these... use a nonce, dump the incoming _Post into an array and use that. 
  619. if ( ! empty( $_POST[ $this->prefix . 'addl_url' ] ) ) { 
  620. foreach ( array( 'addl_url', 'addl_prio', 'addl_freq', 'addl_mod' ) as $field ) { 
  621. if ( ! empty( $_POST[ $this->prefix . $field ] ) ) { 
  622. $_POST[ $this->prefix . $field ] = esc_attr( wp_kses_post( $_POST[ $this->prefix . $field ] ) ); 
  623. } else { 
  624. $_POST[ $this->prefix . $field ] = ''; 
  625. if ( ! is_array( $options[ $this->prefix . 'addl_pages' ] ) ) { 
  626. $options[ $this->prefix . 'addl_pages' ] = array(); 
  627. $options[ $this->prefix . 'addl_pages' ][ $_POST[ $this->prefix . 'addl_url' ] ] = array( 
  628. 'prio' => $_POST[ $this->prefix . 'addl_prio' ],  
  629. 'freq' => $_POST[ $this->prefix . 'addl_freq' ],  
  630. 'mod' => $_POST[ $this->prefix . 'addl_mod' ],  
  631. ); 
  632.  
  633. return $options; 
  634.  
  635. /** 
  636. * Get sitemap urls of child blogs, if any. 
  637. * @return mixed|void 
  638. */ 
  639. function get_child_sitemap_urls() { 
  640. $siteurls = array(); 
  641. $blogs = $this->get_child_blogs(); 
  642. if ( ! empty( $blogs ) ) { 
  643. $option_name = $this->get_option_name(); 
  644. foreach ( $blogs as $blog_id ) { 
  645. if ( $this->is_aioseop_active_on_blog( $blog_id ) ) { 
  646. $options = get_blog_option( $blog_id, $this->parent_option ); 
  647. if ( ! empty( $options ) && ! empty( $options['modules'] ) && ! empty( $options['modules']['aiosp_feature_manager_options'] ) 
  648. && ! empty( $options['modules']['aiosp_feature_manager_options']['aiosp_feature_manager_enable_sitemap'] ) 
  649. && ! empty( $options['modules'][ $option_name ] ) 
  650. ) { 
  651. global $wpdb; 
  652. $sitemap_options = $options['modules'][ $option_name ]; 
  653. $siteurl = ''; 
  654. if ( defined( 'SUNRISE' ) && SUNRISE && is_object( $wpdb ) && isset( $wpdb->dmtable ) && ! empty( $wpdb->dmtable ) ) { 
  655. $domain = $wpdb->get_var( "SELECT domain FROM {$wpdb->dmtable} WHERE blog_id = '$blog_id' AND active = 1 LIMIT 1" ); 
  656. if ( $domain ) { 
  657. if ( false == isset( $_SERVER['HTTPS'] ) ) { 
  658. $_SERVER['HTTPS'] = 'Off'; 
  659. $protocol = ( 'on' == strtolower( $_SERVER['HTTPS'] ) ) ? 'https://' : 'http://'; 
  660. $siteurl = untrailingslashit( $protocol . $domain ); 
  661. if ( ! $siteurl ) { 
  662. $siteurl = get_home_url( $blog_id ); 
  663. $url = $siteurl . '/' . $sitemap_options["{$this->prefix}filename"] . '.xml'; 
  664. if ( $sitemap_options["{$this->prefix}gzipped"] ) { 
  665. $url .= '.gz'; 
  666. $siteurls[] = $url; 
  667. $siteurls = apply_filters( $this->prefix . 'sitemap_urls', $siteurls ); // Legacy. 
  668. return apply_filters( $this->prefix . 'child_urls', $siteurls ); 
  669.  
  670. /** 
  671. * Gets the home path. 
  672. * If we're in wp-admin, use the WordPress function, otherwise we user our own version here. 
  673. * This only applies to static sitemaps. 
  674. * @since 2.3.6.1 
  675. * @return mixed|string 
  676. */ 
  677. function get_home_path() { 
  678.  
  679. if ( function_exists( 'get_home_path' ) ) { 
  680. return get_home_path(); 
  681.  
  682. $home = set_url_scheme( get_option( 'home' ), 'http' ); 
  683. $siteurl = set_url_scheme( get_option( 'siteurl' ), 'http' ); 
  684. if ( ! empty( $home ) && 0 !== strcasecmp( $home, $siteurl ) ) { 
  685. $wp_path_rel_to_home = str_ireplace( $home, '', $siteurl ); /** $siteurl - $home */ 
  686. $pos = strripos( str_replace( '\\', '/', $_SERVER['SCRIPT_FILENAME'] ), trailingslashit( $wp_path_rel_to_home ) ); 
  687. $home_path = substr( $_SERVER['SCRIPT_FILENAME'], 0, $pos ); 
  688. $home_path = trailingslashit( $home_path ); 
  689. } else { 
  690. $home_path = ABSPATH; 
  691.  
  692. return str_replace( '\\', '/', $home_path ); 
  693.  
  694. /** 
  695. * Scan for sitemaps on filesystem. 
  696. * @return array 
  697. */ 
  698. function scan_match_files() { 
  699. $scan1 = $scan2 = ''; 
  700. $files = array(); 
  701.  
  702. if ( ! empty( $this->options["{$this->prefix}filename"] ) ) { 
  703. $scan1 = get_home_path() . $this->options["{$this->prefix}filename"] . '*.xml'; 
  704. if ( ! empty( $this->options["{$this->prefix}gzipped"] ) ) { 
  705. $scan2 .= get_home_path() . $this->options["{$this->prefix}filename"] . '*.xml.gz'; 
  706.  
  707. if ( empty( $scan1 ) && empty( $scan2 ) ) { 
  708. return $files; 
  709. $home_path = get_home_path(); 
  710. $filescan = $this->scandir( $home_path ); 
  711. if ( ! empty( $filescan ) ) { 
  712. foreach ( $filescan as $f ) { 
  713. if ( ! empty( $scan1 ) && fnmatch( $scan1, $home_path . $f ) ) { 
  714. $files[] = $home_path . $f; 
  715. continue; 
  716. if ( ! empty( $scan2 ) && fnmatch( $scan2, $home_path . $f ) ) { 
  717. $files[] = $home_path . $f; 
  718.  
  719. return $files; 
  720.  
  721. /** 
  722. * Scan for sitemaps. 
  723. * Handle deleting / renaming of conflicting sitemap files. 
  724. */ 
  725. function do_sitemap_scan() { 
  726. $msg = ''; 
  727. if ( ! empty( $this->options["{$this->prefix}rewrite"] ) && ( get_option( 'permalink_structure' ) === '' ) ) { 
  728. $msg = '<p>' . __( 'Warning: dynamic sitemap generation must have permalinks enabled.', 'all-in-one-seo-pack' ) . '</p>'; 
  729. if ( ! empty( $_POST['aioseop_sitemap_rename_files'] ) || ! empty( $_POST['aioseop_sitemap_delete_files'] ) ) { 
  730. $nonce = $_POST['nonce-aioseop']; 
  731. if ( ! wp_verify_nonce( $nonce, 'aioseop-nonce' ) ) { 
  732. die ( __( 'Security Check - If you receive this in error, log out and back in to WordPress', 'all-in-one-seo-pack' ) ); 
  733. if ( ! empty( $_POST['aioseop_sitemap_conflict'] ) ) { 
  734. $files = $this->scan_match_files(); 
  735. foreach ( $files as $f => $file ) { 
  736. $files[ $f ] = realpath( $file ); 
  737. foreach ( $_POST['aioseop_sitemap_conflict'] as $ren_file ) { 
  738. $ren_file = realpath( get_home_path() . $ren_file ); 
  739. if ( in_array( $ren_file, $files ) ) { 
  740. if ( ! empty( $_POST['aioseop_sitemap_delete_files'] ) ) { 
  741. if ( $this->delete_file( $ren_file ) ) { 
  742. $msg .= '<p>' . sprintf( __( 'Deleted %s.', 'all-in-one-seo-pack' ), $ren_file ) . '</p>'; 
  743. continue; 
  744. $count = 0; 
  745. do { 
  746. $ren_to = $ren_file . '._' . sprintf( '%03d', $count ) . '.old'; 
  747. $count ++; 
  748. } while ( $this->file_exists( $ren_to ) && ( $count < 1000 ) ); 
  749. if ( $count >= 1000 ) { 
  750. $msg .= '<p>' . sprintf( __( "Couldn't rename file %s!", 'all-in-one-seo-pack' ), $ren_file ) . '</p>'; 
  751. } else { 
  752. $ren = $this->rename_file( $ren_file, $ren_to ); 
  753. if ( $ren ) { 
  754. $msg .= '<p>' . sprintf( __( 'Renamed %s to %s.', 'all-in-one-seo-pack' ), $ren_file, $ren_to ) . '</p>'; 
  755. } else { 
  756. $msg .= '<p>' . sprintf( __( "Couldn't find file %s!", 'all-in-one-seo-pack' ), $ren_file ) . '</p>'; 
  757. } else { 
  758. $msg .= $this->scan_sitemaps(); 
  759.  
  760. if ( ! empty( $msg ) ) { 
  761. $this->output_error( $msg ); 
  762.  
  763. /** 
  764. * Do the scan, return the results. 
  765. * @return string 
  766. */ 
  767. function scan_sitemaps() { 
  768. $msg = ''; 
  769. $files = $this->scan_match_files(); 
  770. if ( ! empty( $files ) ) { 
  771. $msg = $this->sitemap_warning( $files ); 
  772.  
  773. return $msg; 
  774.  
  775. /** 
  776. * Get problem files. 
  777. * Get the list of potentially conflicting sitemap files. 
  778. * @param $files 
  779. * @param $msg 
  780. * @return array 
  781. */ 
  782. function get_problem_files( $files, &$msg ) { 
  783. $problem_files = array(); 
  784. $use_wpfs = true; 
  785. $wpfs = $this->get_filesystem_object(); 
  786. if ( ! is_object( $wpfs ) ) { 
  787. $use_wpfs = false; 
  788. } else { 
  789. if ( 'direct' === $wpfs->method ) { 
  790. $use_wpfs = false; 
  791.  
  792. foreach ( $files as $f ) { 
  793. if ( $this->is_file( $f ) ) { 
  794. $fn = $f; 
  795. $compressed = false; 
  796. if ( $this->substr( $f, - 3 ) === '.gz' ) { 
  797. $compressed = true; 
  798. if ( $use_wpfs ) { 
  799. if ( $compressed ) { // Inefficient but necessary. 
  800. $file = $this->load_file( $fn ); 
  801. if ( ! empty( $file ) ) { 
  802. $file = gzuncompress( $file, 4096 ); 
  803. } else { 
  804. $file = $this->load_file( $fn, false, null, - 1, 4096 ); 
  805. } else { 
  806. if ( $compressed ) { 
  807. $fn = 'compress.zlib://' . $fn; 
  808. $file = file_get_contents( $fn, false, null, - 1, 4096 ); 
  809. if ( ! empty( $file ) ) { 
  810. $matches = array(); 
  811. if ( preg_match( '/<!-- ' . sprintf( $this->comment_string, '(.*)', '(.*)', '(.*)' ) . ' -->/',  
  812. $file, $matches ) ) { 
  813. if ( ! empty( $this->options["{$this->prefix}rewrite"] ) ) { 
  814. $msg .= '<p>' . sprintf( __( "Warning: a static sitemap '%s' generated by All in One SEO Pack %s on %s already exists that may conflict with dynamic sitemap generation.", 'all-in-one-seo-pack' ),  
  815. $f, $matches[2], $matches[3] ) . "</p>\n"; 
  816. $problem_files[] = $f; 
  817. } else { 
  818. $msg .= '<p>' . sprintf( __( 'Potential conflict with unknown file %s.', 'all-in-one-seo-pack' ), $f ) . "</p>\n"; 
  819. $problem_files[] = $f; 
  820.  
  821. return $problem_files; 
  822.  
  823. /** 
  824. * Display sitemap warning. 
  825. * Display the warning and the form for conflicting sitemap files. 
  826. * @param $files 
  827. * @return string 
  828. */ 
  829. function sitemap_warning( $files ) { 
  830. $msg = ''; 
  831. $conflict = false; 
  832. $problem_files = $this->get_problem_files( $files, $msg ); 
  833. if ( ! empty( $problem_files ) ) { 
  834. $conflict = true; 
  835. if ( $conflict ) { 
  836. foreach ( $problem_files as $p ) { 
  837. $msg .= "<input type='hidden' name='aioseop_sitemap_conflict[]' value='" . esc_attr( basename( realpath( $p ) ) ) . "'>\n"; 
  838. $msg .= "<input type='hidden' name='nonce-aioseop' value='" . wp_create_nonce( 'aioseop-nonce' ) . "'>\n"; 
  839. $msg .= "<input type='submit' name='aioseop_sitemap_rename_files' value='" . __( 'Rename Conflicting Files', 'all-in-one-seo-pack' ) . "'> "; 
  840. $msg .= "<input type='submit' name='aioseop_sitemap_delete_files' value='" . __( 'Delete Conflicting Files', 'all-in-one-seo-pack' ) . "'>"; 
  841. $msg = '<form action="" method="post">' . $msg . '</form>'; 
  842.  
  843. return $msg; 
  844.  
  845. /** 
  846. * Updates debug log messages. 
  847. * @param $msg 
  848. */ 
  849. function debug_message( $msg ) { 
  850. if ( empty( $this->options["{$this->prefix}debug"] ) ) { 
  851. $this->options["{$this->prefix}debug"] = ''; 
  852. $this->options["{$this->prefix}debug"] = date( 'Y-m-d H:i:s' ) . " {$msg}\n" . $this->options["{$this->prefix}debug"]; 
  853. if ( $this->strlen( $this->options["{$this->prefix}debug"] ) > 2048 ) { 
  854. $end = $this->strrpos( $this->options["{$this->prefix}debug"], "\n" ); 
  855. if ( false === $end ) { 
  856. $end = 2048; 
  857. $this->options["{$this->prefix}debug"] = $this->substr( $this->options["{$this->prefix}debug"], 0, $end ); 
  858. $this->update_class_option( $this->options ); 
  859.  
  860. /** 
  861. * Set up hooks for rewrite rules for dynamic sitemap generation. 
  862. */ 
  863. function setup_rewrites() { 
  864. add_action( 'rewrite_rules_array', array( $this, 'rewrite_hook' ) ); 
  865. add_filter( 'query_vars', array( $this, 'query_var_hook' ) ); 
  866. add_action( 'parse_query', array( $this, 'sitemap_output_hook' ) ); 
  867. if ( ! get_transient( "{$this->prefix}rules_flushed" ) ) { 
  868. add_action( 'wp_loaded', array( $this, 'flush_rules_hook' ) ); 
  869.  
  870. /** 
  871. * Build and return our rewrite rules. 
  872. * @return array 
  873. */ 
  874. function get_rewrite_rules() { 
  875. $sitemap_rules_normal = $sitemap_rules_gzipped = array(); 
  876. $sitemap_rules_normal = array( 
  877. $this->options["{$this->prefix}filename"] . '.xml' => "index.php?{$this->prefix}path=root",  
  878. $this->options["{$this->prefix}filename"] . '_(.+)_(\d+).xml' => 'index.php?' . $this->prefix . 'path=$matches[1]&' . $this->prefix . 'page=$matches[2]',  
  879. $this->options["{$this->prefix}filename"] . '_(.+).xml' => 'index.php?' . $this->prefix . 'path=$matches[1]',  
  880. ); 
  881. if ( $this->options["{$this->prefix}gzipped"] ) { 
  882. $sitemap_rules_gzipped = array( 
  883. $this->options["{$this->prefix}filename"] . '.xml.gz' => "index.php?{$this->prefix}gzipped=1&{$this->prefix}path=root.gz",  
  884. $this->options["{$this->prefix}filename"] . '_(.+)_(\d+).xml.gz' => 'index.php?' . $this->prefix . 'path=$matches[1].gz&' . $this->prefix . 'page=$matches[2]',  
  885. $this->options["{$this->prefix}filename"] . '_(.+).xml.gz' => 'index.php?' . $this->prefix . 'path=$matches[1].gz',  
  886. ); 
  887. $sitemap_rules = $sitemap_rules_gzipped + $sitemap_rules_normal; 
  888.  
  889. return $sitemap_rules; 
  890.  
  891. /** 
  892. * Add in our rewrite rules. 
  893. * @param $rules 
  894. * @return array 
  895. */ 
  896. function rewrite_hook( $rules ) { 
  897. $sitemap_rules = $this->get_rewrite_rules(); 
  898. if ( ! empty( $sitemap_rules ) ) { 
  899. $rules = $sitemap_rules + $rules; 
  900.  
  901. return $rules; 
  902.  
  903. /** 
  904. * Flush rewrite rules when necessary. 
  905. */ 
  906. function flush_rules_hook() { 
  907. global $wp_rewrite; 
  908. $sitemap_rules = $this->get_rewrite_rules( $wp_rewrite ); 
  909. if ( ! empty( $sitemap_rules ) ) { 
  910. $rules = get_option( 'rewrite_rules' ); 
  911. $rule = key( $sitemap_rules ); 
  912. if ( ! isset( $rules[ $rule ] ) || ( $rules[ $rule ] !== $sitemap_rules[ $rule ] ) ) { 
  913. $wp_rewrite->flush_rules(); 
  914. set_transient( "{$this->prefix}rules_flushed", true, 43200 ); 
  915.  
  916. /** 
  917. * Add our query variable for sitemap generation. 
  918. * @param $vars 
  919. * @return array 
  920. */ 
  921. function query_var_hook( $vars ) { 
  922. $vars[] = "{$this->prefix}path"; 
  923. if ( $this->paginate ) { 
  924. $vars[] = "{$this->prefix}page"; 
  925.  
  926. return $vars; 
  927.  
  928. /** 
  929. * Start timing and get initial memory usage for debug info. 
  930. */ 
  931. function log_start() { 
  932. $this->start_memory_usage = memory_get_peak_usage(); 
  933. timer_start(); 
  934.  
  935.  
  936. /** 
  937. * Stop timing and log memory usage for debug info. 
  938. * @param string $sitemap_type 
  939. * @param bool $compressed 
  940. * @param bool $dynamic 
  941. */ 
  942. function log_stats( $sitemap_type = 'static', $compressed = false, $dynamic = true ) { 
  943. $time = timer_stop(); 
  944. $end_memory_usage = memory_get_peak_usage(); 
  945. $sitemap_memory_usage = $end_memory_usage - $this->start_memory_usage; 
  946. $end_memory_usage = $end_memory_usage / 1024.0 / 1024.0; 
  947. $sitemap_memory_usage = $sitemap_memory_usage / 1024.0 / 1024.0; 
  948. $sitemap_type = __( 'static', 'all-in-one-seo-pack ' ); 
  949. if ( $compressed ) { 
  950. $sitemap_type = __( 'compressed', 'all-in-one-seo-pack' ); 
  951. if ( $dynamic ) { 
  952. $sitemap_type = __( 'dynamic', 'all-in-one-seo-pack ' ); 
  953. $this->debug_message( sprintf( ' %01.2f MB memory used generating the %s sitemap in %01.3f seconds, %01.2f MB total memory used.', $sitemap_memory_usage, $sitemap_type, $time, $end_memory_usage ) ); 
  954.  
  955. /** 
  956. * Handle outputting of dynamic sitemaps, logging. 
  957. * @param $query 
  958. */ 
  959. function sitemap_output_hook( $query ) { 
  960. $page = 0; 
  961. if ( $this->options["{$this->prefix}rewrite"] && ! empty( $query->query_vars["{$this->prefix}path"] ) ) { 
  962.  
  963. // Make dynamic sitemap. 
  964.  
  965. if ( ! empty( $query->query_vars["{$this->prefix}page"] ) ) { 
  966. $page = $query->query_vars["{$this->prefix}page"] - 1; 
  967. $this->start_memory_usage = memory_get_peak_usage(); 
  968. $sitemap_type = $query->query_vars["{$this->prefix}path"]; 
  969. $gzipped = false; 
  970. if ( $this->substr( $sitemap_type, - 3 ) === '.gz' ) { 
  971. $gzipped = true; 
  972. $sitemap_type = $this->substr( $sitemap_type, 0, - 3 ); 
  973. $blog_charset = get_option( 'blog_charset' ); 
  974. if ( $this->options["{$this->prefix}gzipped"] && $gzipped ) { 
  975. header( "Content-Type: application/x-gzip; charset=$blog_charset", true ); 
  976. } else { 
  977. $gzipped = false; 
  978. header( "Content-Type: text/xml; charset=$blog_charset", true ); 
  979.  
  980. // Always follow and noindex the sitemap. 
  981. header( 'X-Robots-Tag: noindex, follow', true ); 
  982.  
  983. if ( $gzipped ) { 
  984. ob_start(); 
  985. $this->do_rewrite_sitemap( $sitemap_type, $page ); 
  986. if ( $gzipped ) { 
  987. echo gzencode( ob_get_clean() ); 
  988. $this->log_stats( $sitemap_type, $gzipped ); 
  989. exit(); 
  990.  
  991.  
  992.  
  993. /** 
  994. * Make dynamic xsl. 
  995. */ 
  996. function make_dynamic_xsl() { 
  997. // Make dynamic xsl file. 
  998. if ( preg_match( '#(/sitemap\.xsl)$#i', $_SERVER['REQUEST_URI'] ) ) { 
  999. $blog_charset = get_option( 'blog_charset' ); 
  1000. header( "Content-Type: text/xml; charset=$blog_charset", true ); 
  1001. include_once( AIOSEOP_PLUGIN_DIR . '/inc/sitemap-xsl.php' ); 
  1002. exit(); 
  1003.  
  1004. /** 
  1005. * Get sitemap data. 
  1006. * @param $sitemap_type 
  1007. * @param int $page 
  1008. * @return mixed|void 
  1009. */ 
  1010. function get_sitemap_data( $sitemap_type, $page = 0 ) { 
  1011. $sitemap_data = array(); 
  1012. if ( $this->options["{$this->prefix}indexes"] ) { 
  1013. $posttypes = $this->options["{$this->prefix}posttypes"]; 
  1014. if ( empty( $posttypes ) ) { 
  1015. $posttypes = array(); 
  1016. $taxonomies = $this->options["{$this->prefix}taxonomies"]; 
  1017. if ( empty( $taxonomies ) ) { 
  1018. $taxonomies = array(); 
  1019. if ( 'root' === $sitemap_type ) { 
  1020. $sitemap_data = array_merge( $this->get_sitemap_index_filenames() ); 
  1021. } elseif ( 'addl' === $sitemap_type ) { 
  1022. $sitemap_data = $this->get_addl_pages(); 
  1023. } elseif ( 'archive' === $sitemap_type && $this->option_isset( 'archive' ) ) { 
  1024. $sitemap_data = $this->get_archive_prio_data(); 
  1025. } elseif ( 'author' === $sitemap_type && $this->option_isset( 'author' ) ) { 
  1026. $sitemap_data = $this->get_author_prio_data(); 
  1027. } elseif ( in_array( $sitemap_type, $posttypes ) ) { 
  1028. $sitemap_data = $this->get_all_post_priority_data( $sitemap_type, 'publish', $page ); 
  1029. } elseif ( in_array( $sitemap_type, $taxonomies ) ) { 
  1030. $sitemap_data = $this->get_term_priority_data( get_terms( $sitemap_type, $this->get_tax_args( $page ) ) ); 
  1031. } else { 
  1032. if ( is_array( $this->extra_sitemaps ) && in_array( $sitemap_type, $this->extra_sitemaps ) ) { 
  1033. $sitemap_data = apply_filters( $this->prefix . 'custom_' . $sitemap_type, $sitemap_data, $page, $this_options ); 
  1034. } elseif ( 'root' === $sitemap_type ) { 
  1035. $sitemap_data = $this->get_simple_sitemap(); 
  1036.  
  1037. return apply_filters( $this->prefix . 'data', $sitemap_data, $sitemap_type, $page, $this->options ); 
  1038.  
  1039. /** 
  1040. * Rewrite sitemap. 
  1041. * Output sitemaps dynamically based on rewrite rules. 
  1042. * @param $sitemap_type 
  1043. * @param int $page 
  1044. */ 
  1045. function do_rewrite_sitemap( $sitemap_type, $page = 0 ) { 
  1046. $this->add_post_types(); 
  1047. $comment = 'dynamically'; 
  1048. echo $this->do_build_sitemap( $sitemap_type, $page, '', $comment ); 
  1049.  
  1050. /** 
  1051. * Build a url to the sitemap. 
  1052. * @return string 
  1053. */ 
  1054. function get_sitemap_url() { 
  1055. $url = get_home_url() . '/' . $this->options["{$this->prefix}filename"] . '.xml'; 
  1056. if ( $this->options["{$this->prefix}gzipped"] ) { 
  1057. $url .= '.gz'; 
  1058.  
  1059. return $url; 
  1060.  
  1061. /** 
  1062. * Notify search engines, do logging. 
  1063. */ 
  1064. function do_notify() { 
  1065. $notify_url = array( 
  1066. 'google' => 'http://www.google.com/webmasters/sitemaps/ping?sitemap=',  
  1067. 'bing' => 'http://www.bing.com/webmaster/ping.aspx?siteMap=',  
  1068. ); 
  1069.  
  1070. $url = $this->get_sitemap_url(); 
  1071. if ( ! empty( $url ) ) { 
  1072. foreach ( $notify_url as $k => $v ) { 
  1073. if ( isset( $this->options[ $this->prefix . $k ] ) && $this->options[ $this->prefix . $k ] ) { 
  1074. $response = wp_remote_get( $notify_url[ $k ] . urlencode( $url ) ); 
  1075. if ( is_array( $response ) && ! empty( $response['response'] ) && ! empty( $response['response']['code'] ) ) { 
  1076. if ( 200 == $response['response']['code'] ) { 
  1077. $this->debug_message( sprintf( __( 'Successfully notified %s about changes to your sitemap at %s.', 'all-in-one-seo-pack' ), $k, $url ) ); 
  1078. } else { 
  1079. $this->debug_message( sprintf( __( 'Failed to notify %s about changes to your sitemap at %s, error code %s.', 'all-in-one-seo-pack' ), $k, $url, $response['response']['code'] ) ); 
  1080. } else { 
  1081. $this->debug_message( sprintf( __( 'Failed to notify %s about changes to your sitemap at %s, unable to access via wp_remote_get().', 'all-in-one-seo-pack' ), $k, $url ) ); 
  1082. } else { 
  1083. $this->debug_message( sprintf( __( 'Did not notify %s about changes to your sitemap.', 'all-in-one-seo-pack' ), $k, $url ) ); 
  1084.  
  1085. /** 
  1086. * Add Sitemap parameter to virtual robots.txt file. 
  1087. */ 
  1088. function do_robots() { 
  1089. $url = $this->get_sitemap_url(); 
  1090. echo "\nSitemap: $url\n"; 
  1091.  
  1092. /** 
  1093. * Build static sitemaps. 
  1094. * Build static sitemaps on submit if rewrite rules are not in use, do logging. 
  1095. * @param string $message 
  1096. */ 
  1097. function do_sitemaps( $message = '' ) { 
  1098. if ( ! empty( $this->options["{$this->prefix}indexes"] ) && ! empty( $this->options["{$this->prefix}paginate"] ) ) { 
  1099. $this->paginate = true; 
  1100. if ( $this->options["{$this->prefix}max_posts"] && ( $this->options["{$this->prefix}max_posts"] > 0 ) && ( $this->options["{$this->prefix}max_posts"] < 50000 ) ) { 
  1101. $this->max_posts = $this->options["{$this->prefix}max_posts"]; 
  1102. } else { 
  1103. $this->max_posts = 50000; 
  1104. } else { 
  1105. $this->paginate = false; 
  1106. $this->max_posts = 50000; 
  1107. if ( ! $this->options["{$this->prefix}rewrite"] ) { 
  1108. if ( $this->options["{$this->prefix}indexes"] ) { 
  1109. $this->do_indexed_sitemaps(); 
  1110. } else { 
  1111. $this->log_start(); 
  1112. $comment = sprintf( "file '%s' statically", $this->options["{$this->prefix}filename"] ); 
  1113. $sitemap = $this->do_simple_sitemap( $comment ); 
  1114. $this->write_sitemaps( $this->options["{$this->prefix}filename"], $sitemap ); 
  1115. $this->log_stats( 'root', $this->options["{$this->prefix}gzipped"], false ); 
  1116. } else { 
  1117. delete_transient( "{$this->prefix}rules_flushed" ); 
  1118. $this->do_notify(); 
  1119. if ( ! empty( $message ) && is_string( $message ) ) { 
  1120. $this->debug_message( $message ); 
  1121. } else { 
  1122. $this->debug_message( __( 'Updated sitemap settings.', 'all-in-one-seo-pack' ) ); 
  1123.  
  1124. /** 
  1125. * Add mime type. 
  1126. * @param $mime 
  1127. * @return mixed 
  1128. */ 
  1129. function add_xml_mime_type( $mime ) { 
  1130. if ( ! empty( $mime ) ) { 
  1131. $mime['xml'] = 'text/xml'; 
  1132.  
  1133. return $mime; 
  1134.  
  1135. /** 
  1136. * Write multiple sitemaps. 
  1137. * Write sitemaps (compressed or otherwise) to the filesystem. 
  1138. * @param $filename 
  1139. * @param $contents 
  1140. */ 
  1141. function write_sitemaps( $filename, $contents ) { 
  1142. $this->write_sitemap( $filename . '.xml', $contents ); 
  1143. if ( $this->options["{$this->prefix}gzipped"] ) { 
  1144. $this->write_sitemap( $filename . '.xml.gz', $contents, true ); 
  1145.  
  1146. /** 
  1147. * Write single sitemap. 
  1148. * Write a single sitemap to the filesystem, handle compression. 
  1149. * @param $filename 
  1150. * @param $contents 
  1151. * @param bool $gzip 
  1152. * @return bool 
  1153. */ 
  1154. function write_sitemap( $filename, $contents, $gzip = false ) { 
  1155. if ( $gzip ) { 
  1156. $contents = gzencode( $contents ); 
  1157. add_filter( 'upload_mimes', array( $this, 'add_xml_mime_type' ) ); 
  1158. $filename = $this->get_home_path() . sanitize_file_name( $filename ); 
  1159. remove_filter( 'upload_mimes', array( $this, 'add_xml_mime_type' ) ); 
  1160.  
  1161. return $this->save_file( $filename, $contents ); 
  1162.  
  1163. /** 
  1164. * Gets the default values. 
  1165. * Helper function for handling default values. 
  1166. * @param $defaults 
  1167. * @param $prefix 
  1168. * @param $cache 
  1169. * @param $item 
  1170. * @param bool $nodefaults 
  1171. * @param string $type 
  1172. * @return bool 
  1173. */ 
  1174. function get_default_values( $defaults, $prefix, &$cache, $item, $nodefaults = false, $type = '' ) { 
  1175. if ( ! empty( $cache[ $item . $type ] ) ) { 
  1176. return $cache[ $item . $type ]; 
  1177. if ( ! empty( $defaults[ $item ] ) ) { 
  1178. $field = $this->prefix . $prefix . $item; 
  1179. if ( $this->option_isset( $prefix . $item ) && 'no' != $this->options[ $field ] ) { 
  1180. if ( ( 'sel' === $this->options[ $field ] ) && ! empty( $type ) && isset( $this->options[ $this->prefix . $prefix . $item . '_' . $type ] ) ) { 
  1181. if ( 'no' == $this->options[ $this->prefix . $prefix . $item . '_' . $type ] ) { 
  1182. return false; 
  1183. if ( 'sel' === $this->options[ $this->prefix . $prefix . $item . '_' . $type ] ) { 
  1184. return false; 
  1185. $cache[ $item . $type ] = $this->options[ $this->prefix . $prefix . $item . '_' . $type ]; 
  1186. } else { 
  1187. if ( 'no' == $this->options[ $field ] ) { 
  1188. return false; 
  1189. if ( 'sel' === $this->options[ $field ] ) { 
  1190. return false; 
  1191. $cache[ $item . $type ] = $this->options[ $field ]; 
  1192.  
  1193. return $cache[ $item . $type ]; 
  1194. if ( $nodefaults ) { 
  1195. return false; 
  1196.  
  1197. return $defaults[ $item ]; 
  1198.  
  1199. return false; 
  1200.  
  1201. /** 
  1202. * Get priority settings for sitemap entries. 
  1203. * @param $item 
  1204. * @param bool $nodefaults 
  1205. * @param string $type 
  1206. * @return bool 
  1207. */ 
  1208. function get_default_priority( $item, $nodefaults = false, $type = '' ) { 
  1209. $defaults = array( 
  1210. 'homepage' => '1.0',  
  1211. 'blog' => '0.9',  
  1212. 'sitemap' => '0.8',  
  1213. 'post' => '0.7',  
  1214. 'archive' => '0.5',  
  1215. 'author' => '0.3',  
  1216. 'taxonomies' => '0.3',  
  1217. ); 
  1218. static $cache = array(); 
  1219.  
  1220. return $this->get_default_values( $defaults, 'prio_', $cache, $item, $nodefaults, $type ); 
  1221.  
  1222. /** 
  1223. * Get frequency settings for sitemap entries. 
  1224. * @param $item 
  1225. * @param bool $nodefaults 
  1226. * @param string $type 
  1227. * @return bool 
  1228. */ 
  1229. function get_default_frequency( $item, $nodefaults = false, $type = '' ) { 
  1230. $defaults = array( 
  1231. 'homepage' => 'always',  
  1232. 'blog' => 'daily',  
  1233. 'sitemap' => 'hourly',  
  1234. 'post' => 'weekly',  
  1235. 'archive' => 'monthly',  
  1236. 'author' => 'weekly',  
  1237. 'taxonomies' => 'monthly',  
  1238. ); 
  1239. static $cache = array(); 
  1240.  
  1241. return $this->get_default_values( $defaults, 'freq_', $cache, $item, $nodefaults, $type ); 
  1242.  
  1243. /** 
  1244. * Build an index of sitemaps used. 
  1245. * @return array 
  1246. */ 
  1247. function get_sitemap_index_filenames() { 
  1248. $files = array(); 
  1249. $options = $this->options; 
  1250. $prefix = $options["{$this->prefix}filename"]; 
  1251. $suffix = '.xml'; 
  1252. if ( $options["{$this->prefix}gzipped"] ) { 
  1253. $suffix .= '.gz'; 
  1254. if ( empty( $options["{$this->prefix}posttypes"] ) ) { 
  1255. $options["{$this->prefix}posttypes"] = array(); 
  1256. if ( empty( $options["{$this->prefix}taxonomies"] ) ) { 
  1257. $options["{$this->prefix}taxonomies"] = array(); 
  1258. $options["{$this->prefix}posttypes"] = array_diff( $options["{$this->prefix}posttypes"], array( 'all' ) ); 
  1259. $options["{$this->prefix}taxonomies"] = array_diff( $options["{$this->prefix}taxonomies"], array( 'all' ) ); 
  1260. $url_base = trailingslashit( get_home_url() ); 
  1261. $files[] = array( 'loc' => $url_base . $prefix . '_addl' . $suffix ); 
  1262. if ( ! empty( $options["{$this->prefix}posttypes"] ) ) { 
  1263. $prio = $this->get_default_priority( 'post' ); 
  1264. $freq = $this->get_default_frequency( 'post' ); 
  1265. $post_counts = $this->get_all_post_counts( array( 
  1266. 'post_type' => $options["{$this->prefix}posttypes"],  
  1267. 'post_status' => 'publish',  
  1268. ) ); 
  1269. if ( ! is_array( $post_counts ) && is_array( $options["{$this->prefix}posttypes"] ) && count( $options["{$this->prefix}posttypes"] ) == 1 ) { 
  1270. $post_counts = array( $options["{$this->prefix}posttypes"][0] => $post_counts ); 
  1271. foreach ( $options["{$this->prefix}posttypes"] as $sm ) { 
  1272. if ( 0 == $post_counts[ $sm ] ) { 
  1273. continue; 
  1274. if ( $this->paginate ) { 
  1275. if ( $post_counts[ $sm ] > $this->max_posts ) { 
  1276. $count = 1; 
  1277. for ( $post_count = 0; $post_count < $post_counts[ $sm ]; $post_count += $this->max_posts ) { 
  1278. $files[] = array( 
  1279. 'loc' => $url_base . $prefix . '_' . $sm . '_' . ( $count ++ ) . $suffix,  
  1280. 'priority' => $prio,  
  1281. 'changefreq' => $freq,  
  1282. ); 
  1283. } else { 
  1284. $files[] = array( 
  1285. 'loc' => $url_base . $prefix . '_' . $sm . $suffix,  
  1286. 'priority' => $prio,  
  1287. 'changefreq' => $freq,  
  1288. ); 
  1289. } else { 
  1290. $files[] = array( 
  1291. 'loc' => $url_base . $prefix . '_' . $sm . $suffix,  
  1292. 'priority' => $prio,  
  1293. 'changefreq' => $freq,  
  1294. ); 
  1295. if ( $this->option_isset( 'archive' ) ) { 
  1296. $files[] = array( 
  1297. 'loc' => $url_base . $prefix . '_archive' . $suffix,  
  1298. 'priority' => $this->get_default_priority( 'archive' ),  
  1299. 'changefreq' => $this->get_default_frequency( 'archive' ),  
  1300. ); 
  1301. if ( $this->option_isset( 'author' ) ) { 
  1302. $files[] = array( 
  1303. 'loc' => $url_base . $prefix . '_author' . $suffix,  
  1304. 'priority' => $this->get_default_priority( 'author' ),  
  1305. 'changefreq' => $this->get_default_frequency( 'author' ),  
  1306. ); 
  1307.  
  1308. if ( ! empty( $options["{$this->prefix}taxonomies"] ) ) { 
  1309. foreach ( $options["{$this->prefix}taxonomies"] as $sm ) { 
  1310. $term_count = wp_count_terms( $sm, array( 'hide_empty' => true ) ); 
  1311. if ( ! is_wp_error( $term_count ) && ( $term_count > 0 ) ) { 
  1312. if ( $this->paginate ) { 
  1313. if ( $term_count > $this->max_posts ) { 
  1314. $count = 1; 
  1315. for ( $tc = 0; $tc < $term_count; $tc += $this->max_posts ) { 
  1316. $files[] = array( 
  1317. 'loc' => $url_base . $prefix . '_' . $sm . '_' . ( $count ++ ) . $suffix,  
  1318. 'priority' => $this->get_default_priority( 'taxonomies' ),  
  1319. 'changefreq' => $this->get_default_frequency( 'taxonomies' ),  
  1320. ); 
  1321. } else { 
  1322. $files[] = array( 
  1323. 'loc' => $url_base . $prefix . '_' . $sm . $suffix,  
  1324. 'priority' => $this->get_default_priority( 'taxonomies' ),  
  1325. 'changefreq' => $this->get_default_frequency( 'taxonomies' ),  
  1326. ); 
  1327. } else { 
  1328. $files[] = array( 
  1329. 'loc' => $url_base . $prefix . '_' . $sm . $suffix,  
  1330. 'priority' => $this->get_default_priority( 'taxonomies' ),  
  1331. 'changefreq' => $this->get_default_frequency( 'taxonomies' ),  
  1332. ); 
  1333. foreach ( $this->get_child_sitemap_urls() as $csm ) { 
  1334. $files[] = array( 
  1335. 'loc' => $csm,  
  1336. 'priority' => $this->get_default_priority( 'sitemap' ),  
  1337. 'changefreq' => $this->get_default_frequency( 'sitemap' ),  
  1338. ); 
  1339.  
  1340. return $files; 
  1341.  
  1342. /** 
  1343. * Build the sitemap. 
  1344. * @param $sitemap_type 
  1345. * @param int $page 
  1346. * @param string $filename 
  1347. * @param string $comment 
  1348. * @return string 
  1349. */ 
  1350. function do_build_sitemap( $sitemap_type, $page = 0, $filename = '', $comment = '' ) { 
  1351. if ( empty( $filename ) ) { 
  1352. if ( 'root' === $sitemap_type ) { 
  1353. $filename = $this->options["{$this->prefix}filename"]; 
  1354. } else { 
  1355. $filename = $this->options["{$this->prefix}filename"] . '_' . $sitemap_type; 
  1356. if ( empty( $comment ) ) { 
  1357. $comment = "file '%s' statically"; 
  1358. $sitemap_data = $this->get_sitemap_data( $sitemap_type, $page ); 
  1359. if ( ( 'root' === $sitemap_type ) && ! empty( $this->options["{$this->prefix}indexes"] ) ) { 
  1360. return $this->build_sitemap_index( $sitemap_data, sprintf( $comment, $filename ) ); 
  1361. } else { 
  1362. return $this->build_sitemap( $sitemap_data, sprintf( $comment, $filename ) ); 
  1363.  
  1364. /** 
  1365. * Write the sitemap. 
  1366. * @param $sitemap_type 
  1367. * @param int $page 
  1368. * @param string $filename 
  1369. * @param string $comment 
  1370. */ 
  1371. function do_write_sitemap( $sitemap_type, $page = 0, $filename = '', $comment = '' ) { 
  1372. if ( empty( $filename ) ) { 
  1373. if ( 'root' === $sitemap_type ) { 
  1374. $filename = $this->options["{$this->prefix}filename"]; 
  1375. } else { 
  1376. $filename = $this->options["{$this->prefix}filename"] . '_' . $sitemap_type; 
  1377. if ( empty( $comment ) ) { 
  1378. $comment = "file '%s' statically"; 
  1379. $this->write_sitemaps( $filename, $this->do_build_sitemap( $sitemap_type, $page, $filename, $comment ) ); 
  1380.  
  1381. /** 
  1382. * Build all the indexes. 
  1383. */ 
  1384. function do_indexed_sitemaps() { 
  1385. $this->start_memory_usage = memory_get_peak_usage(); 
  1386. $options = $this->options; 
  1387.  
  1388. $this->do_write_sitemap( 'root' ); 
  1389. $this->do_write_sitemap( 'addl' ); 
  1390.  
  1391. if ( $this->option_isset( 'archive' ) ) { 
  1392. $this->do_write_sitemap( 'archive' ); 
  1393. if ( $this->option_isset( 'author' ) ) { 
  1394. $this->do_write_sitemap( 'author' ); 
  1395.  
  1396. if ( ( ! isset( $options["{$this->prefix}posttypes"] ) ) || ( ! is_array( $options["{$this->prefix}posttypes"] ) ) ) { 
  1397. $options["{$this->prefix}posttypes"] = array(); 
  1398. if ( ( ! isset( $options["{$this->prefix}taxonomies"] ) ) || ( ! is_array( $options["{$this->prefix}taxonomies"] ) ) ) { 
  1399. $options["{$this->prefix}taxonomies"] = array(); 
  1400. $options["{$this->prefix}posttypes"] = array_diff( $options["{$this->prefix}posttypes"], array( 'all' ) ); 
  1401. $options["{$this->prefix}taxonomies"] = array_diff( $options["{$this->prefix}taxonomies"], array( 'all' ) ); 
  1402.  
  1403. if ( ! empty( $options["{$this->prefix}posttypes"] ) ) { 
  1404. $post_counts = $this->get_all_post_counts( array( 
  1405. 'post_type' => $options["{$this->prefix}posttypes"],  
  1406. 'post_status' => 'publish',  
  1407. ) ); 
  1408. foreach ( $options["{$this->prefix}posttypes"] as $posttype ) { 
  1409. if ( 0 === $post_counts[ $posttype ] ) { 
  1410. continue; 
  1411. if ( $this->paginate && ( $post_counts[ $posttype ] > $this->max_posts ) ) { 
  1412. $count = 1; 
  1413. for ( $post_count = 0; $post_count < $post_counts[ $posttype ]; $post_count += $this->max_posts ) { 
  1414. $this->do_write_sitemap( $posttype, $count - 1, $options["{$this->prefix}filename"] . "_{$posttype}_{$count}" ); 
  1415. $count ++; 
  1416. } else { 
  1417. $this->do_write_sitemap( $posttype ); 
  1418.  
  1419. if ( ! empty( $options["{$this->prefix}taxonomies"] ) ) { 
  1420. foreach ( $options["{$this->prefix}taxonomies"] as $taxonomy ) { 
  1421. $term_count = wp_count_terms( $taxonomy, array( 'hide_empty' => true ) ); 
  1422. if ( ! is_wp_error( $term_count ) && ( $term_count > 0 ) ) { 
  1423. if ( $this->paginate ) { 
  1424. if ( $term_count > $this->max_posts ) { 
  1425. $count = 1; 
  1426. for ( $tc = 0; $tc < $term_count; $tc += $this->max_posts ) { 
  1427. $this->do_write_sitemap( $taxonomy, $tc, $options["{$this->prefix}filename"] . "_{$taxonomy}_{$count}" ); 
  1428. $count ++; 
  1429. } else { 
  1430. $this->do_write_sitemap( $taxonomy ); 
  1431. } else { 
  1432. $this->do_write_sitemap( $taxonomy ); 
  1433. $this->log_stats( 'indexed', $options["{$this->prefix}gzipped"], false ); 
  1434.  
  1435. /** 
  1436. * Get simple sitemap. 
  1437. * @return array 
  1438. */ 
  1439. function get_simple_sitemap() { 
  1440. $home = array( 
  1441. 'loc' => get_home_url(),  
  1442. 'priority' => $this->get_default_priority( 'homepage' ),  
  1443. 'changefreq' => $this->get_default_frequency( 'homepage' ),  
  1444. ); 
  1445. $posts = get_option( 'page_for_posts' ); 
  1446. $this->paginate = false; 
  1447. if ( $posts ) { 
  1448. $posts = $this->get_permalink( $posts ); 
  1449. if ( $posts == $home['loc'] ) { 
  1450. $posts = null; 
  1451. } else { 
  1452. $posts = array( 
  1453. 'loc' => $posts,  
  1454. 'priority' => $this->get_default_priority( 'blog' ),  
  1455. 'changefreq' => $this->get_default_frequency( 'blog' ),  
  1456. ); 
  1457. $child = $this->get_child_sitemap_urls(); 
  1458. $options = $this->options; 
  1459. if ( is_array( $options["{$this->prefix}posttypes"] ) ) { 
  1460. $options["{$this->prefix}posttypes"] = array_diff( $options["{$this->prefix}posttypes"], array( 'all' ) ); 
  1461. if ( is_array( $options["{$this->prefix}taxonomies"] ) ) { 
  1462. $options["{$this->prefix}taxonomies"] = array_diff( $options["{$this->prefix}taxonomies"], array( 'all' ) ); 
  1463. $prio = $this->get_all_post_priority_data( $options["{$this->prefix}posttypes"] ); 
  1464. if ( $this->option_isset( 'archive' ) ) { 
  1465. $prio = array_merge( $prio, $this->get_archive_prio_data() ); 
  1466. if ( $this->option_isset( 'author' ) ) { 
  1467. $prio = array_merge( $prio, $this->get_author_prio_data() ); 
  1468. foreach ( $prio as $k => $p ) { 
  1469. if ( untrailingslashit( $p['loc'] ) === untrailingslashit( $home['loc'] ) ) { 
  1470. $prio[ $k ]['priority'] = '1.0'; 
  1471. $home = null; 
  1472. break; 
  1473. if ( ( null != $posts ) && isset( $posts['loc'] ) ) { 
  1474. foreach ( $prio as $k => $p ) { 
  1475. if ( $p['loc'] === $posts['loc'] ) { 
  1476. $prio[ $k ]['priority'] = $this->get_default_priority( 'blog' ); 
  1477. $prio[ $k ]['changefreq'] = $this->get_default_frequency( 'blog' ); 
  1478. $posts = null; 
  1479. break; 
  1480. if ( is_array( $posts ) ) { 
  1481. array_unshift( $prio, $posts ); 
  1482. if ( is_array( $home ) ) { 
  1483. array_unshift( $prio, $home ); 
  1484. $terms = get_terms( $options["{$this->prefix}taxonomies"], $this->get_tax_args() ); 
  1485. $prio2 = $this->get_term_priority_data( $terms ); 
  1486. $prio3 = $this->get_addl_pages_only(); 
  1487. $prio = array_merge( $child, $prio, $prio2, $prio3 ); 
  1488. if ( is_array( $this->extra_sitemaps ) ) { 
  1489. foreach ( $this->extra_sitemaps as $sitemap_type ) { 
  1490. $sitemap_data = array(); 
  1491. $sitemap_data = apply_filters( $this->prefix . 'custom_' . $sitemap_type, $sitemap_data, $page, $this_options ); 
  1492. $prio = array_merge( $prio, $sitemap_data ); 
  1493.  
  1494. return $prio; 
  1495.  
  1496. /** 
  1497. * Build a single, stand-alone sitemap without indexes. 
  1498. * @param string $comment 
  1499. * @return string 
  1500. */ 
  1501. function do_simple_sitemap( $comment = '' ) { 
  1502. $sitemap_data = $this->get_simple_sitemap(); 
  1503. $sitemap_data = apply_filters( $this->prefix . 'data', $sitemap_data, 'root', 0, $this->options ); 
  1504.  
  1505. return $this->build_sitemap( $sitemap_data, $comment ); 
  1506.  
  1507. /** 
  1508. * Gets the sitemap URL. 
  1509. * Has a filter for using something other than the dynamically generated one. 
  1510. * Using the filter you need the full path to the custom xsl file. 
  1511. * @see https://semperplugins.com/documentation/aioseop_sitemap_xsl_url/ 
  1512. * @since 2.3.6 
  1513. */ 
  1514. function get_sitemap_xsl() { 
  1515.  
  1516. return esc_url( apply_filters( 'aioseop_sitemap_xsl_url', home_url( '/sitemap.xsl' ) ) ); 
  1517.  
  1518. /** 
  1519. * Output the XML for a sitemap. 
  1520. * @param $urls 
  1521. * @param string $comment 
  1522. * @return null 
  1523. */ 
  1524. function output_sitemap( $urls, $comment = '' ) { 
  1525. $max_items = 50000; 
  1526. if ( ! is_array( $urls ) ) { 
  1527. return null; 
  1528. echo '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n\r\n"; 
  1529. echo '<!-- ' . sprintf( $this->comment_string, $comment, AIOSEOP_VERSION, date( 'D, d M Y H:i:s e' ) ) . " -->\r\n"; 
  1530. $plugin_path = $this->plugin_path['url']; 
  1531. $plugin_url = parse_url( $plugin_path ); 
  1532. $current_host = $_SERVER['HTTP_HOST']; 
  1533. if ( empty( $current_host ) ) { 
  1534. $current_host = $_SERVER['SERVER_NAME']; 
  1535.  
  1536. if ( ! empty( $current_host ) && ( $current_host !== $plugin_url['host'] ) ) { 
  1537. $plugin_url['host'] = $current_host; 
  1538.  
  1539. // Code unset( $plugin_url['scheme'] );. 
  1540. $plugin_path = $this->unparse_url( $plugin_url ); 
  1541.  
  1542. // Using the filter you need the full path to the custom xsl file. 
  1543. $xsl_url = $this->get_sitemap_xsl(); 
  1544.  
  1545. $xml_header = '<?xml-stylesheet type="text/xsl" href="' . $xsl_url . '"?>' . "\r\n" 
  1546. . '<urlset '; 
  1547. $namespaces = apply_filters( $this->prefix . 'xml_namespace', array( 'xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9' ) ); 
  1548. if ( ! empty( $namespaces ) ) { 
  1549. $ns = array(); 
  1550. foreach ( $namespaces as $k => $v ) { 
  1551. $ns[] = esc_attr( $k ) . '=' . '"' . esc_url( $v, array( 'http', 'https' ) ) . '"'; 
  1552. $xml_header .= join( "\r\n\t", $ns ); 
  1553. $xml_header .= '>' . "\r\n"; 
  1554. echo $xml_header; 
  1555. $count = 0; 
  1556. foreach ( $urls as $url ) { 
  1557. echo "\t<url>\r\n"; 
  1558. if ( is_array( $url ) ) { 
  1559. foreach ( $url as $k => $v ) { 
  1560. if ( ! empty( $v ) ) { 
  1561. if ( 'loc' === $k ) { 
  1562. $v = esc_url( $v ); 
  1563. if ( is_array( $v ) ) { 
  1564. $buf = "\t\t\t<$k>\r\n"; 
  1565. foreach ( $v as $ext => $attr ) { 
  1566. if ( is_array( $attr ) ) { 
  1567. $buf = ''; 
  1568. echo "\t\t<$k>\r\n"; 
  1569. foreach ( $attr as $a => $nested ) { 
  1570. if ( is_array( $nested ) ) { 
  1571. echo "\t\t\t<$a>\r\n"; 
  1572. foreach ( $nested as $next => $nattr ) { 
  1573. echo "\t\t\t\t<$next>$nattr</$next>\r\n"; 
  1574. echo "\t\t\t</$a>\r\n"; 
  1575. } else { 
  1576. echo "\t\t\t<$a>$nested</$a>\r\n"; 
  1577. echo "\t\t</$k>\r\n"; 
  1578. } else { 
  1579. $buf .= "\t\t\t<$ext>$attr</$ext>\r\n"; 
  1580. if ( ! empty( $buf ) ) { 
  1581. echo $buf . "\t\t</$k>\r\n"; 
  1582. } else { 
  1583. echo "\t\t<$k>$v</$k>\r\n"; 
  1584. } else { 
  1585. echo "\t\t<loc>" . esc_url( $url ) . "</loc>\r\n"; 
  1586. echo "\t</url>\r\n"; 
  1587. if ( $count >= $max_items ) { 
  1588. break; 
  1589. echo '</urlset>'; 
  1590.  
  1591. /** 
  1592. * Output the XML for a sitemap index. 
  1593. * @param $urls 
  1594. * @param string $comment 
  1595. * @return null 
  1596. */ 
  1597. function output_sitemap_index( $urls, $comment = '' ) { 
  1598. $max_items = 50000; 
  1599. if ( ! is_array( $urls ) ) { 
  1600. return null; 
  1601. echo '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n\r\n"; 
  1602. echo '<!-- ' . sprintf( $this->comment_string, $comment, AIOSEOP_VERSION, date( 'D, d M Y H:i:s e' ) ) . " -->\r\n"; 
  1603. $xsl_url = $this->get_sitemap_xsl(); 
  1604. echo '<?xml-stylesheet type="text/xsl" href="' . $xsl_url . '"?>' . "\r\n"; 
  1605. echo '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\r\n"; 
  1606. $count = 0; 
  1607. foreach ( $urls as $url ) { 
  1608. echo "\t<sitemap>\r\n"; 
  1609. if ( is_array( $url ) ) { 
  1610. foreach ( $url as $k => $v ) { 
  1611. if ( 'loc' === $k ) { 
  1612. echo "\t\t<$k>" . esc_url( $v ) . "</$k>\r\n"; 
  1613. } elseif ( 'lastmod' === $k ) { 
  1614. echo "\t\t<$k>$v</$k>\r\n"; 
  1615. } else { 
  1616. echo "\t\t<loc>" . esc_url( $url ) . "</loc>\r\n"; 
  1617. echo "\t</sitemap>\r\n"; 
  1618. $count ++; 
  1619. if ( $count >= $max_items ) { 
  1620. break; 
  1621. echo '</sitemapindex>'; 
  1622.  
  1623. /** 
  1624. * Return an XML sitemap index as a string. 
  1625. * @param $urls 
  1626. * @param string $comment 
  1627. * @return string 
  1628. */ 
  1629. function build_sitemap_index( $urls, $comment = '' ) { 
  1630. ob_start(); 
  1631. $this->output_sitemap_index( $urls, $comment ); 
  1632.  
  1633. return ob_get_clean(); 
  1634.  
  1635. /** 
  1636. * Return an XML sitemap as a string. 
  1637. * @param $urls 
  1638. * @param string $comment 
  1639. * @return string 
  1640. */ 
  1641. function build_sitemap( $urls, $comment = '' ) { 
  1642. ob_start(); 
  1643. $this->output_sitemap( $urls, $comment ); 
  1644.  
  1645. return ob_get_clean(); 
  1646.  
  1647. /** 
  1648. * Return sitemap data for an array of terms. 
  1649. * @param $terms 
  1650. * @return array 
  1651. */ 
  1652. function get_term_priority_data( $terms ) { 
  1653. $prio = array(); 
  1654. if ( is_array( $terms ) ) { 
  1655. $def_prio = $this->get_default_priority( 'taxonomies' ); 
  1656. $def_freq = $this->get_default_frequency( 'taxonomies' ); 
  1657. foreach ( $terms as $term ) { 
  1658. $pr_info = array(); 
  1659. $pr_info['loc'] = $this->get_term_link( $term, $term->taxonomy ); 
  1660. if ( ( 'sel' === $this->options[ $this->prefix . 'prio_taxonomies' ] ) && isset( $this->options[ $this->prefix . 'prio_taxonomies_' . $term->taxonomy ] ) && ( 'no' != $this->options[ $this->prefix . 'prio_taxonomies_' . $term->taxonomy ] ) ) { 
  1661. $pr_info['priority'] = $this->options[ $this->prefix . 'prio_taxonomies_' . $term->taxonomy ]; 
  1662. } else { 
  1663. $pr_info['priority'] = $def_prio; 
  1664. if ( ( 'sel' === $this->options[ $this->prefix . 'freq_taxonomies' ] ) && isset( $this->options[ $this->prefix . 'freq_taxonomies_' . $term->taxonomy ] ) && ( 'no' != $this->options[ $this->prefix . 'freq_taxonomies_' . $term->taxonomy ] ) ) { 
  1665. $pr_info['changefreq'] = $this->options[ $this->prefix . 'freq_taxonomies_' . $term->taxonomy ]; 
  1666. } else { 
  1667. $pr_info['changefreq'] = $def_freq; 
  1668. $prio[] = $pr_info; 
  1669.  
  1670. return $prio; 
  1671.  
  1672. /** 
  1673. * Return a list of permalinks for an array of terms. 
  1674. * @param $terms 
  1675. * @return array 
  1676. */ 
  1677. function get_term_permalinks( $terms ) { 
  1678. $links = array(); 
  1679. if ( is_array( $terms ) ) { 
  1680. foreach ( $terms as $term ) { 
  1681. $url = $this->get_term_link( $term ); 
  1682. $links[] = $url; 
  1683.  
  1684. return $links; 
  1685.  
  1686. /** 
  1687. * Return permalinks for archives. 
  1688. * @param $posts 
  1689. * @return array 
  1690. */ 
  1691. function get_archive_permalinks( $posts ) { 
  1692. $links = array(); 
  1693. $archives = array(); 
  1694. if ( is_array( $posts ) ) { 
  1695. foreach ( $posts as $post ) { 
  1696. $date = mysql2date( 'U', $post->post_date ); 
  1697. $year = date( 'Y', $date ); 
  1698. $month = date( 'm', $date ); 
  1699. $archives[ $year . '-' . $month ] = array( $year, $month ); 
  1700. $archives = array_keys( $archives ); 
  1701. foreach ( $archives as $d ) { 
  1702. $links[] = get_month_link( $d[0], $d[1] ); 
  1703.  
  1704. return $links; 
  1705.  
  1706. /** 
  1707. * Return permalinks for authors. 
  1708. * @param $posts 
  1709. * @return array 
  1710. */ 
  1711. function get_author_permalinks( $posts ) { 
  1712. $links = array(); 
  1713. $authors = array(); 
  1714. if ( is_array( $posts ) ) { 
  1715. foreach ( $posts as $post ) { 
  1716. $authors[ $post->author_id ] = 1; 
  1717. $authors = array_keys( $authors ); 
  1718. foreach ( $authors as $auth_id ) { 
  1719. $links[] = get_author_posts_url( $auth_id ); 
  1720.  
  1721. return $links; 
  1722.  
  1723. /** 
  1724. * Return permalinks for posts. 
  1725. * @param $posts 
  1726. * @return array 
  1727. */ 
  1728. function get_post_permalinks( $posts ) { 
  1729. $links = array(); 
  1730. if ( is_array( $posts ) ) { 
  1731. foreach ( $posts as $post ) { 
  1732. $post->filter = 'sample'; 
  1733. $url = $this->get_permalink( $post ); 
  1734. $links[] = $url; 
  1735.  
  1736. return $links; 
  1737.  
  1738. /** 
  1739. * Convert back from parse_url. 
  1740. * Props to thomas at gielfeldt dot com. 
  1741. * @link http://www.php.net/manual/en/function.parse-url.php#106731 
  1742. * @param $parsed_url 
  1743. * @return string 
  1744. */ 
  1745. function unparse_url( $parsed_url ) { 
  1746. $scheme = isset( $parsed_url['scheme'] ) ? $parsed_url['scheme'] . '://' : ''; 
  1747. $host = isset( $parsed_url['host'] ) ? $parsed_url['host'] : ''; 
  1748. if ( ! empty( $host ) && empty( $scheme ) ) { 
  1749. $scheme = '//'; 
  1750. $port = isset( $parsed_url['port'] ) ? ':' . $parsed_url['port'] : ''; 
  1751. $user = isset( $parsed_url['user'] ) ? $parsed_url['user'] : ''; 
  1752. $pass = isset( $parsed_url['pass'] ) ? ':' . $parsed_url['pass'] : ''; 
  1753. $pass = ( $user || $pass ) ? "$pass@" : ''; 
  1754. $path = isset( $parsed_url['path'] ) ? $parsed_url['path'] : ''; 
  1755. $query = isset( $parsed_url['query'] ) ? '?' . $parsed_url['query'] : ''; 
  1756. $fragment = isset( $parsed_url['fragment'] ) ? '#' . $parsed_url['fragment'] : ''; 
  1757.  
  1758. return "$scheme$user$pass$host$port$path$query$fragment"; 
  1759.  
  1760. /** 
  1761. * Gets additional pages. 
  1762. * Return data for user entered additional pages. 
  1763. * @return array|mixed|void 
  1764. */ 
  1765. function get_addl_pages_only() { 
  1766. $pages = array(); 
  1767. if ( ! empty( $this->options[ $this->prefix . 'addl_pages' ] ) ) { 
  1768. $siteurl = parse_url( get_home_url() ); 
  1769. foreach ( $this->options[ $this->prefix . 'addl_pages' ] as $k => $v ) { 
  1770. $url = parse_url( $k ); 
  1771. if ( empty( $url['scheme'] ) ) { 
  1772. $url['scheme'] = $siteurl['scheme']; 
  1773. if ( empty( $url['host'] ) ) { 
  1774. $url['host'] = $siteurl['host']; 
  1775. if ( ! empty( $url['path'] ) && substr( $url['path'], 0, 1 ) !== '/' ) { 
  1776. $url['path'] = '/' . $url['path']; 
  1777. $freq = $prio = $mod = ''; 
  1778. if ( ! empty( $v['mod'] ) ) { 
  1779. $mod = $v['mod']; 
  1780. if ( ! empty( $v['freq'] ) ) { 
  1781. $freq = $v['freq']; 
  1782. if ( ! empty( $v['prio'] ) ) { 
  1783. $prio = $v['prio']; 
  1784. if ( 'no' == $freq ) { 
  1785. $freq = ''; 
  1786. if ( 'no' == $prio ) { 
  1787. $prio = ''; 
  1788. $mod = date( 'Y-m-d\TH:i:s\Z', mysql2date( 'U', $mod ) ); 
  1789. $pages[] = array( 
  1790. 'loc' => $this->unparse_url( $url ),  
  1791. 'lastmod' => $mod,  
  1792. 'changefreq' => $freq,  
  1793. 'priority' => $prio,  
  1794. ); 
  1795. $pages = apply_filters( $this->prefix . 'addl_pages_only', $pages ); 
  1796.  
  1797. return $pages; 
  1798.  
  1799. /** 
  1800. * Return data for user entered additional pages and extra pages. 
  1801. * @return array|mixed|void 
  1802. */ 
  1803. function get_addl_pages() { 
  1804. $home = array(); 
  1805. $home = array( 
  1806. 'loc' => get_home_url(),  
  1807. 'priority' => $this->get_default_priority( 'homepage' ),  
  1808. 'changefreq' => $this->get_default_frequency( 'homepage' ),  
  1809. ); 
  1810. $posts = get_option( 'page_for_posts' ); 
  1811. if ( $posts ) { 
  1812. $posts = $this->get_permalink( $posts ); 
  1813. if ( $posts == $home['loc'] ) { 
  1814. $posts = array(); 
  1815. } else { 
  1816. $posts = array( 
  1817. 'loc' => $posts,  
  1818. 'priority' => $this->get_default_priority( 'blog' ),  
  1819. 'changefreq' => $this->get_default_frequency( 'blog' ),  
  1820. ); 
  1821. } else { 
  1822. $posts = array(); 
  1823. $pages = $this->get_addl_pages_only(); 
  1824. if ( ! empty( $home ) ) { 
  1825. $pages[] = $home; 
  1826. if ( ! empty( $posts ) ) { 
  1827. $pages[] = $posts; 
  1828. $pages = apply_filters( $this->prefix . 'addl_pages', $pages ); 
  1829.  
  1830. return $pages; 
  1831.  
  1832. /** 
  1833. * Return links for user entered additional pages. 
  1834. * @return array 
  1835. */ 
  1836. function get_addl_page_links() { 
  1837. if ( ! empty( $this->options[ $this->prefix . 'addl_pages' ] ) ) { 
  1838. return array_keys( $this->options[ $this->prefix . 'addl_pages' ] ); 
  1839.  
  1840. return array(); 
  1841.  
  1842. /** 
  1843. * Scores posts based on date and relative comment count, if any. 
  1844. * @param $date 
  1845. * @param int $stats 
  1846. * @return array 
  1847. */ 
  1848. function get_prio_calc( $date, $stats = 0 ) { 
  1849. static $cur_time = null; 
  1850. if ( null === $cur_time ) { 
  1851. $cur_time = time(); 
  1852. $time = $cur_time - mysql2date( 'U', $date ); 
  1853. if ( ! empty( $stats ) && isset( $stats['max'] ) && $stats['max'] ) { 
  1854. $minadj = $time >> 3; 
  1855. $maxadj = $time >> 1; 
  1856. $avg = $stats['count'] / $stats['total']; 
  1857. $calc = ( $stats['comment_count'] - $stats['min'] ) / $stats['max']; 
  1858. $calc = $maxadj * $calc; 
  1859. if ( $avg < $stats['comment_count'] ) { 
  1860. $minadj = $time >> 2; 
  1861. } else { 
  1862. $maxadj = $time >> 2; 
  1863. if ( $calc > $maxadj ) { 
  1864. $calc = $maxadj; 
  1865. if ( $calc < $minadj ) { 
  1866. $calc = $minadj; 
  1867. $time -= $calc; 
  1868. $days = $time / ( 60 * 60 * 24 ); 
  1869. $prio_table = array( 
  1870. 'daily' => 7,  
  1871. 'weekly' => 30,  
  1872. 'monthly' => 210,  
  1873. 'yearly' => null,  
  1874. ); 
  1875. $interval = 1.0; 
  1876. $prev_days = 0; 
  1877. foreach ( $prio_table as $change => $max_days ) { 
  1878. $interval -= 0.3; 
  1879. if ( null === $max_days ) { 
  1880. $changefreq = $change; 
  1881. $prio = 0.1; 
  1882. break; 
  1883. if ( $days < $max_days ) { 
  1884. $int_days_max = $max_days - $prev_days; 
  1885. $int_days = $days - $prev_days; 
  1886. $prio = $interval + ( (int) ( 3 * ( ( $max_days - $int_days ) / $int_days_max ) ) / 10.0 ); 
  1887. $changefreq = $change; 
  1888. break; 
  1889. $prev_days = $max_days; 
  1890.  
  1891. return array( 'lastmod' => $date, 'changefreq' => $changefreq, 'priority' => $prio ); 
  1892.  
  1893. /** 
  1894. * Generate sitemap priority data for archives from an array of posts. 
  1895. * @param $posts 
  1896. * @return array 
  1897. */ 
  1898. function get_archive_prio_from_posts( $posts ) { 
  1899. $archives = array(); 
  1900. if ( is_array( $posts ) ) { 
  1901. foreach ( $posts as $p ) { 
  1902. if ( 'post' !== $p->post_type ) { 
  1903. continue; 
  1904. $date = date( 'Y-m', mysql2date( 'U', $p->post_date ) ); 
  1905. if ( empty( $archives[ $date ] ) ) { 
  1906. $archives[ $date ] = $p; 
  1907. } else { 
  1908. if ( $p->post_modified > $archives[ $date ]->post_modified ) { 
  1909. $archives[ $date ] = $p; 
  1910. if ( ! empty( $archives ) ) { 
  1911. return $this->get_prio_from_posts( $archives, $this->get_default_priority( 'archive', true ), $this->get_default_frequency( 'archive', true ), array( 
  1912. $this,  
  1913. 'get_archive_link_from_post',  
  1914. ) ); 
  1915.  
  1916. return $archives; 
  1917.  
  1918. /** 
  1919. * Return an archive link from a post. 
  1920. * @param $post 
  1921. * @return bool|string 
  1922. */ 
  1923. function get_archive_link_from_post( $post ) { 
  1924. if ( 'post' !== $post->post_type ) { 
  1925. return false; 
  1926. $date = mysql2date( 'U', $post->post_date ); 
  1927.  
  1928. return get_month_link( date( 'Y', $date ), date( 'm', $date ) ); 
  1929.  
  1930. /** 
  1931. * Generate sitemap priority data for authors from an array of posts. 
  1932. * @param $posts 
  1933. * @return array 
  1934. */ 
  1935. function get_author_prio_from_posts( $posts ) { 
  1936. $authors = array(); 
  1937. if ( is_array( $posts ) ) { 
  1938. foreach ( $posts as $p ) { 
  1939. if ( 'post' !== $p->post_type ) { 
  1940. continue; 
  1941. if ( empty( $authors[ $p->post_author ] ) ) { 
  1942. $authors[ $p->post_author ] = $p; 
  1943. } else { 
  1944. if ( $p->post_modified > $authors[ $p->post_author ]->post_modified ) { 
  1945. $authors[ $p->post_author ] = $p; 
  1946.  
  1947. return $this->get_prio_from_posts( $authors, $this->get_default_priority( 'author', true ), $this->get_default_frequency( 'author', true ), array( 
  1948. $this,  
  1949. 'get_author_link_from_post',  
  1950. ) ); 
  1951.  
  1952. /** 
  1953. * Return an author link from a post. 
  1954. * @param $post 
  1955. * @return string 
  1956. */ 
  1957. function get_author_link_from_post( $post ) { 
  1958. return get_author_posts_url( $post->post_author ); 
  1959.  
  1960. /** 
  1961. * Return comment statistics on an array of posts. 
  1962. * @param $posts 
  1963. * @return array|int 
  1964. */ 
  1965. function get_comment_count_stats( $posts ) { 
  1966. $count = 0; 
  1967. $total = 0.0; 
  1968. $min = null; 
  1969. $max = 0; 
  1970. if ( is_array( $posts ) ) { 
  1971. foreach ( $posts as $post ) { 
  1972. if ( ! empty( $post->comment_count ) ) { 
  1973. $cnt = $post->comment_count; 
  1974. $count ++; 
  1975. $total += $cnt; 
  1976. if ( null === $min ) { 
  1977. $min = $cnt; 
  1978. if ( $max < $cnt ) { 
  1979. $max = $cnt; 
  1980. if ( $min > $cnt ) { 
  1981. $min = $cnt; 
  1982. if ( $count ) { 
  1983. return array( 'max' => $max, 'min' => $min, 'total' => $total, 'count' => $cnt ); 
  1984. } else { 
  1985. return 0; 
  1986.  
  1987. /** 
  1988. * Generate sitemap priority data from an array of posts. 
  1989. * @param $posts 
  1990. * @param bool $prio_override 
  1991. * @param bool $freq_override 
  1992. * @param string $linkfunc 
  1993. * @return array 
  1994. */ 
  1995. function get_prio_from_posts( $posts, $prio_override = false, $freq_override = false, $linkfunc = 'get_permalink' ) { 
  1996. $prio = array(); 
  1997. $args = array( 
  1998. 'prio_override' => $prio_override,  
  1999. 'freq_override' => $freq_override,  
  2000. 'linkfunc' => $linkfunc,  
  2001. ); 
  2002. if ( $prio_override && $freq_override ) { 
  2003. $stats = 0; 
  2004. } else { 
  2005. $stats = $this->get_comment_count_stats( $posts ); 
  2006. if ( is_array( $posts ) ) { 
  2007. foreach ( $posts as $post ) { 
  2008. $url = ''; 
  2009. $post->filter = 'sample'; 
  2010. if ( 'get_permalink' === $linkfunc ) { 
  2011. $url = $this->get_permalink( $post ); 
  2012. } else { 
  2013. $url = call_user_func( $linkfunc, $post ); 
  2014. $date = $post->post_modified; 
  2015. if ( '0000-00-00 00:00:00' === $date ) { 
  2016. $date = $post->post_date; 
  2017. if ( '0000-00-00 00:00:00' !== $date ) { 
  2018. $date = date( 'Y-m-d\TH:i:s\Z', mysql2date( 'U', $date ) ); 
  2019. } else { 
  2020. $date = 0; 
  2021. if ( $prio_override && $freq_override ) { 
  2022. $pr_info = array( 'lastmod' => $date, 'changefreq' => null, 'priority' => null ); 
  2023. } else { 
  2024. if ( empty( $post->comment_count ) ) { 
  2025. $stat = 0; 
  2026. } else { 
  2027. $stat = $stats; 
  2028. if ( ! empty( $stat ) ) { 
  2029. $stat['comment_count'] = $post->comment_count; 
  2030. $pr_info = $this->get_prio_calc( $date, $stat ); 
  2031. if ( $prio_override ) { 
  2032. $pr_info['priority'] = $prio_override; 
  2033. if ( $freq_override ) { 
  2034. $pr_info['changefreq'] = $freq_override; 
  2035. if ( ( 'sel' === $this->options[ $this->prefix . 'prio_post' ] ) && isset( $this->options[ $this->prefix . 'prio_post_' . $post->post_type ] ) ) { 
  2036. if ( ( 'no' != $this->options[ $this->prefix . 'prio_post_' . $post->post_type ] ) && ( 'sel' !== $this->options[ $this->prefix . 'prio_post_' . $post->post_type ] ) ) { 
  2037. $pr_info['priority'] = $this->options[ $this->prefix . 'prio_post_' . $post->post_type ]; 
  2038. if ( ( 'sel' === $this->options[ $this->prefix . 'freq_post' ] ) && isset( $this->options[ $this->prefix . 'freq_post_' . $post->post_type ] ) ) { 
  2039. if ( ( 'no' != $this->options[ $this->prefix . 'freq_post_' . $post->post_type ] ) && ( 'sel' !== $this->options[ $this->prefix . 'freq_post_' . $post->post_type ] ) ) { 
  2040. $pr_info['changefreq'] = $this->options[ $this->prefix . 'freq_post_' . $post->post_type ]; 
  2041. $pr_info = array( 'loc' => $url ) + $pr_info; // Prepend loc to the array. 
  2042. if ( is_float( $pr_info['priority'] ) ) { 
  2043. $pr_info['priority'] = sprintf( '%0.1F', $pr_info['priority'] ); 
  2044. $pr_info = apply_filters( $this->prefix . 'prio_item_filter', $pr_info, $post, $args ); 
  2045. if ( ! empty( $pr_info ) ) { 
  2046. $prio[] = $pr_info; 
  2047.  
  2048. return $prio; 
  2049.  
  2050. /** 
  2051. * Return excluded categories for taxonomy queries. 
  2052. * @param int $page 
  2053. * @return array 
  2054. */ 
  2055. function get_tax_args( $page = 0 ) { 
  2056. $args = array(); 
  2057. if ( $this->option_isset( 'excl_categories' ) ) { 
  2058. $args['exclude'] = $this->options[ $this->prefix . 'excl_categories' ]; 
  2059. if ( $this->paginate ) { 
  2060. $args['number'] = $this->max_posts; 
  2061. $args['offset'] = $page * $this->max_posts; 
  2062.  
  2063.  
  2064. return $args; 
  2065.  
  2066. /** 
  2067. * Return excluded categories and pages for post queries. 
  2068. * @param $args 
  2069. * @return mixed 
  2070. */ 
  2071. function set_post_args( $args ) { 
  2072. if ( $this->option_isset( 'excl_categories' ) ) { 
  2073. $cats = array(); 
  2074. foreach ( $this->options[ $this->prefix . 'excl_categories' ] as $c ) { 
  2075. $cats[] = - $c; 
  2076. $args['category'] = implode( ', ', $cats ); 
  2077. if ( $this->option_isset( 'excl_pages' ) ) { 
  2078. $args['exclude'] = $this->options[ $this->prefix . 'excl_pages' ]; 
  2079.  
  2080. return $args; 
  2081.  
  2082. /** 
  2083. * Return sitemap data for archives. 
  2084. * @return array 
  2085. */ 
  2086. function get_archive_prio_data() { 
  2087. $args = array( 'numberposts' => 50000, 'post_type' => 'post' ); 
  2088. $args = $this->set_post_args( $args ); 
  2089. $posts = $this->get_all_post_type_data( $args ); 
  2090.  
  2091. return $this->get_archive_prio_from_posts( $posts ); 
  2092.  
  2093. /** 
  2094. * Return sitemap data for authors. 
  2095. * @return array 
  2096. */ 
  2097. function get_author_prio_data() { 
  2098. $args = array( 'numberposts' => 50000, 'post_type' => 'post' ); 
  2099. $args = $this->set_post_args( $args ); 
  2100. $posts = $this->get_all_post_type_data( $args ); 
  2101.  
  2102. return $this->get_author_prio_from_posts( $posts ); 
  2103.  
  2104. /** 
  2105. * Return sitemap data for posts. 
  2106. * @param string $include 
  2107. * @param string $status 
  2108. * @param int $page 
  2109. * @return array 
  2110. */ 
  2111. function get_all_post_priority_data( $include = 'any', $status = 'publish', $page = 0 ) { 
  2112. $posts = $page_query = array(); 
  2113. if ( $this->paginate ) { 
  2114. $page_query = array( 'offset' => $page * $this->max_posts ); 
  2115. if ( ( 'publish' === $status ) && ( 'attachment' === $include ) ) { 
  2116. $status = 'inherit'; 
  2117. if ( is_array( $include ) && ( ( $pos = array_search( 'attachment', $include ) ) !== false ) ) { 
  2118. unset( $include[ $pos ] ); 
  2119. $att_args = array( 'post_type' => 'attachment', 'post_status' => 'inherit' ); 
  2120. $att_args = array_merge( $att_args, $page_query ); 
  2121. $posts = $this->get_all_post_type_data( $att_args ); 
  2122. $args = array( 'post_type' => $include, 'post_status' => $status ); 
  2123. $args = array_merge( $args, $page_query ); 
  2124. $args = $this->set_post_args( $args ); 
  2125. $posts = array_merge( $this->get_all_post_type_data( $args ), $posts ); 
  2126.  
  2127. return $this->get_prio_from_posts( $posts, $this->get_default_priority( 'post', true ), $this->get_default_frequency( 'post', true ) ); 
  2128.  
  2129. /** 
  2130. * Return a list of all permalinks. 
  2131. * @param string $include 
  2132. * @param string $status 
  2133. * @return array 
  2134. */ 
  2135. function get_all_permalinks( $include = 'any', $status = 'publish' ) { 
  2136. $args = array( 'post_type' => $include, 'post_status' => $status ); 
  2137. $args = $this->set_post_args( $args ); 
  2138. $posts = $this->get_all_post_type_data( $args ); 
  2139. $links = $this->get_post_permalinks( $posts ); 
  2140. if ( $this->option_isset( 'archive' ) ) { 
  2141. $links = array_merge( $links, $this->get_archive_permalinks( $posts ) ); 
  2142. if ( $this->option_isset( 'author' ) ) { 
  2143. $links = array_merge( $links, $this->get_author_permalinks( $posts ) ); 
  2144.  
  2145. return $links; 
  2146.  
  2147. /** 
  2148. * Static memory cache for permalink_structure option. 
  2149. * @param $pre 
  2150. * @return null 
  2151. */ 
  2152. function cache_structure( $pre ) { 
  2153. return $this->cache_struct; 
  2154.  
  2155. /** 
  2156. * Static memory cache for home option. 
  2157. * @param $pre 
  2158. * @return null 
  2159. */ 
  2160. function cache_home( $pre ) { 
  2161. return $this->cache_home; 
  2162.  
  2163. /** 
  2164. * Cache permalink_structure and home for repeated sitemap queries. 
  2165. */ 
  2166. function cache_options() { 
  2167. static $start = true; 
  2168. if ( $start ) { 
  2169. $this->cache_struct = get_option( 'permalink_structure' ); 
  2170. if ( ! empty( $this->cache_struct ) ) { 
  2171. add_filter( 'pre_option_permalink_structure', array( $this, 'cache_structure' ) ); 
  2172. $this->cache_home = get_option( 'home' ); 
  2173. if ( ! empty( $this->cache_home ) ) { 
  2174. add_filter( 'pre_option_home', array( $this, 'cache_home' ) ); 
  2175. $start = false; 
  2176.  
  2177. /** 
  2178. * Call get_term_link with caching in place. 
  2179. * @param $term 
  2180. * @param string $taxonomy 
  2181. * @return string|WP_Error 
  2182. */ 
  2183. function get_term_link( $term, $taxonomy = '' ) { 
  2184. static $start = true; 
  2185. if ( $start ) { 
  2186. $this->cache_options(); 
  2187. $start = false; 
  2188.  
  2189. return get_term_link( $term, $taxonomy ); 
  2190.  
  2191. /** 
  2192. * Call get_permalink with caching in place. 
  2193. * @param $post 
  2194. * @return false|string 
  2195. */ 
  2196. function get_permalink( $post ) { 
  2197. static $start = true; 
  2198. if ( $start ) { 
  2199. $this->cache_options(); 
  2200. $start = false; 
  2201.  
  2202. return get_permalink( $post ); 
  2203.  
  2204. /** 
  2205. * Return term counts using wp_count_terms(). 
  2206. * @param $args 
  2207. * @return array|int|mixed|null|void|WP_Error 
  2208. */ 
  2209. function get_all_term_counts( $args ) { 
  2210. $term_counts = null; 
  2211. if ( ! empty( $args ) && ! empty( $args['taxonomy'] ) ) { 
  2212. if ( ! is_array( $args['taxonomy'] ) || ( count( $args['taxonomy'] ) == 1 ) ) { 
  2213. if ( is_array( $args['taxonomy'] ) ) { 
  2214. $args['taxonomy'] = array_shift( $args['taxonomy'] ); 
  2215. $term_counts = wp_count_terms( $args['taxonomy'], array( 'hide_empty' => true ) ); 
  2216. } else { 
  2217. foreach ( $args['taxonomy'] as $taxonomy ) { 
  2218. if ( 'all' === $taxonomy ) { 
  2219. continue; 
  2220. $term_counts[ $taxonomy ] = wp_count_terms( $taxonomy, array( 'hide_empty' => true ) ); 
  2221. $term_counts = apply_filters( $this->prefix . 'term_counts', $term_counts, $args ); 
  2222.  
  2223. return $term_counts; 
  2224.  
  2225. /** 
  2226. * Return post counts using wp_count_posts(). 
  2227. * @param $args 
  2228. * @return mixed|null|void 
  2229. */ 
  2230. function get_all_post_counts( $args ) { 
  2231. $post_counts = null; 
  2232. $status = 'inherit'; 
  2233. if ( ! empty( $args['post_status'] ) ) { 
  2234. $status = $args['post_status']; 
  2235. if ( ! empty( $args ) && ! empty( $args['post_type'] ) ) { 
  2236. if ( ! is_array( $args['post_type'] ) || ( count( $args['post_type'] ) == 1 ) ) { 
  2237. if ( is_array( $args['post_type'] ) ) { 
  2238. $args['post_type'] = array_shift( $args['post_type'] ); 
  2239. $count = (Array) wp_count_posts( $args['post_type'] ); 
  2240. $post_counts = $count[ $status ]; 
  2241. } else { 
  2242. foreach ( $args['post_type'] as $post_type ) { 
  2243. if ( 'all' === $post_type ) { 
  2244. continue; 
  2245. $count = (Array) wp_count_posts( $post_type ); 
  2246.  
  2247. if ( empty( $count ) ) { 
  2248. $post_counts[ $post_type ] = 0; 
  2249. } else { 
  2250. if ( 'attachment' === $post_type ) { 
  2251. $post_counts[ $post_type ] = $count['inherit']; 
  2252. } else { 
  2253. $post_counts[ $post_type ] = $count[ $status ]; 
  2254. $post_counts = apply_filters( $this->prefix . 'post_counts', $post_counts, $args ); 
  2255.  
  2256. return $post_counts; 
  2257.  
  2258. /** 
  2259. * Get total post count. 
  2260. * @param $args 
  2261. * @return int|mixed|null|void 
  2262. */ 
  2263. function get_total_post_count( $args ) { 
  2264. $total = 0; 
  2265. $counts = $this->get_all_post_counts( $args ); 
  2266. if ( ! empty( $counts ) ) { 
  2267. if ( is_array( $counts ) ) { 
  2268. foreach ( $counts as $count ) { 
  2269. $total += $count; 
  2270. } else { 
  2271. $total = $counts; 
  2272.  
  2273. return $total; 
  2274.  
  2275. /** 
  2276. * Return post data using get_posts(). 
  2277. * @param $args 
  2278. * @return array|mixed|void 
  2279. */ 
  2280. function get_all_post_type_data( $args ) { 
  2281. $defaults = array( 
  2282. 'numberposts' => $this->max_posts,  
  2283. 'offset' => 0,  
  2284. 'category' => 0,  
  2285. 'orderby' => 'post_date',  
  2286. 'order' => 'DESC',  
  2287. 'include' => array(),  
  2288. 'exclude' => array(),  
  2289. 'post_type' => 'any',  
  2290. 'meta_key' => '',  
  2291. 'meta_value' => '',  
  2292. 'meta_compare' => '',  
  2293. 'meta_query' => '',  
  2294. 'cache_results' => false,  
  2295. 'no_found_rows' => true,  
  2296. ); 
  2297. if ( defined( 'ICL_SITEPRESS_VERSION' ) ) { 
  2298. $defaults['suppress_filters'] = false; 
  2299. $args = wp_parse_args( $args, $defaults ); 
  2300. if ( empty( $args['post_type'] ) ) { 
  2301. return apply_filters( $this->prefix . 'post_filter', array(), $args ); 
  2302. $exclude_slugs = array(); 
  2303. if ( ! empty( $args['exclude'] ) ) { 
  2304. $exclude = preg_split( '/[\s, ]+/', trim( $args['exclude'] ) ); 
  2305. if ( ! empty( $exclude ) ) { 
  2306. foreach ( $exclude as $k => $v ) { 
  2307. if ( ! is_numeric( $v ) || ( $v != (int) $v ) ) { 
  2308. $exclude_slugs[] = $v; 
  2309. unset( $exclude[ $k ] ); 
  2310. if ( ! empty( $exclude_slugs ) ) { 
  2311. $args['exclude'] = implode( ', ', $exclude ); 
  2312.  
  2313. $ex_args = $args; 
  2314. $ex_args['meta_key'] = '_aioseop_sitemap_exclude'; 
  2315. $ex_args['meta_value'] = 'on'; 
  2316. $ex_args['meta_compare'] = '='; 
  2317. $ex_args['fields'] = 'ids'; 
  2318. $ex_args['posts_per_page'] = - 1; 
  2319. $q = new WP_Query( $ex_args ); 
  2320. if ( ! is_array( $args['exclude'] ) ) { 
  2321. $args['exclude'] = explode( ', ', $args['exclude'] ); 
  2322. if ( ! empty( $q->posts ) ) { 
  2323. $args['exclude'] = array_merge( $args['exclude'], $q->posts ); 
  2324.  
  2325. $posts = get_posts( apply_filters( $this->prefix . 'post_query', $args ) ); 
  2326. if ( ! empty( $exclude_slugs ) ) { 
  2327. foreach ( $posts as $k => $v ) { 
  2328. if ( in_array( $v->post_name, $exclude_slugs ) ) { 
  2329. unset( $posts[ $k ] ); 
  2330. $posts = apply_filters( $this->prefix . 'post_filter', $posts, $args ); 
  2331.  
  2332. return $posts;