1 | <?php |
2 | /** |
3 | * WordPress Rewrite API |
4 | * |
5 | * @package WordPress |
6 | * @subpackage Rewrite |
7 | */ |
8 | |
9 | /** |
10 | * Add a straight rewrite rule. |
11 | * |
12 | * @see WP_Rewrite::add_rule() for long description. |
13 | * @since 2.1.0 |
14 | * |
15 | * @param string $regex Regular Expression to match request against. |
16 | * @param string $redirect Page to redirect to. |
17 | * @param string $after Optional, default is 'bottom'. Where to add rule, can also be 'top'. |
18 | */ |
19 | function add_rewrite_rule($regex, $redirect, $after = 'bottom') { |
20 | global $wp_rewrite; |
21 | $wp_rewrite->add_rule($regex, $redirect, $after); |
22 | } |
23 | |
24 | /** |
25 | * Add a new tag (like %postname%). |
26 | * |
27 | * Warning: you must call this on init or earlier, otherwise the query var |
28 | * addition stuff won't work. |
29 | * |
30 | * @since 2.1.0 |
31 | * |
32 | * @param string $tagname |
33 | * @param string $regex |
34 | */ |
35 | function add_rewrite_tag($tagname, $regex) { |
36 | //validation |
37 | if ( strlen($tagname) < 3 || $tagname{0} != '%' || $tagname{strlen($tagname)-1} != '%' ) |
38 | return; |
39 | |
40 | $qv = trim($tagname, '%'); |
41 | |
42 | global $wp_rewrite, $wp; |
43 | $wp->add_query_var($qv); |
44 | $wp_rewrite->add_rewrite_tag($tagname, $regex, $qv . '='); |
45 | } |
46 | |
47 | /** |
48 | * Add permalink structure. |
49 | * |
50 | * @see WP_Rewrite::add_permastruct() |
51 | * @since 3.0.0 |
52 | * |
53 | * @param string $name Name for permalink structure. |
54 | * @param string $struct Permalink structure. |
55 | * @param bool $with_front Prepend front base to permalink structure. |
56 | */ |
57 | function add_permastruct( $name, $struct, $with_front = true, $ep_mask = EP_NONE ) { |
58 | global $wp_rewrite; |
59 | return $wp_rewrite->add_permastruct( $name, $struct, $with_front, $ep_mask ); |
60 | } |
61 | |
62 | /** |
63 | * Add a new feed type like /atom1/. |
64 | * |
65 | * @since 2.1.0 |
66 | * |
67 | * @param string $feedname |
68 | * @param callback $function Callback to run on feed display. |
69 | * @return string Feed action name. |
70 | */ |
71 | function add_feed($feedname, $function) { |
72 | global $wp_rewrite; |
73 | if ( ! in_array($feedname, $wp_rewrite->feeds) ) //override the file if it is |
74 | $wp_rewrite->feeds[] = $feedname; |
75 | $hook = 'do_feed_' . $feedname; |
76 | // Remove default function hook |
77 | remove_action($hook, $hook, 10, 1); |
78 | add_action($hook, $function, 10, 1); |
79 | return $hook; |
80 | } |
81 | |
82 | /** |
83 | * Remove rewrite rules and then recreate rewrite rules. |
84 | * |
85 | * @see WP_Rewrite::flush_rules() |
86 | * @since 3.0.0 |
87 | * |
88 | * @param bool $hard Whether to update .htaccess (hard flush) or just update |
89 | * rewrite_rules transient (soft flush). Default is true (hard). |
90 | */ |
91 | function flush_rewrite_rules( $hard = true ) { |
92 | global $wp_rewrite; |
93 | $wp_rewrite->flush_rules( $hard ); |
94 | } |
95 | |
96 | //pseudo-places |
97 | /** |
98 | * Endpoint Mask for default, which is nothing. |
99 | * |
100 | * @since 2.1.0 |
101 | */ |
102 | define('EP_NONE', 0); |
103 | |
104 | /** |
105 | * Endpoint Mask for Permalink. |
106 | * |
107 | * @since 2.1.0 |
108 | */ |
109 | define('EP_PERMALINK', 1); |
110 | |
111 | /** |
112 | * Endpoint Mask for Attachment. |
113 | * |
114 | * @since 2.1.0 |
115 | */ |
116 | define('EP_ATTACHMENT', 2); |
117 | |
118 | /** |
119 | * Endpoint Mask for date. |
120 | * |
121 | * @since 2.1.0 |
122 | */ |
123 | define('EP_DATE', 4); |
124 | |
125 | /** |
126 | * Endpoint Mask for year |
127 | * |
128 | * @since 2.1.0 |
129 | */ |
130 | define('EP_YEAR', 8); |
131 | |
132 | /** |
133 | * Endpoint Mask for month. |
134 | * |
135 | * @since 2.1.0 |
136 | */ |
137 | define('EP_MONTH', 16); |
138 | |
139 | /** |
140 | * Endpoint Mask for day. |
141 | * |
142 | * @since 2.1.0 |
143 | */ |
144 | define('EP_DAY', 32); |
145 | |
146 | /** |
147 | * Endpoint Mask for root. |
148 | * |
149 | * @since 2.1.0 |
150 | */ |
151 | define('EP_ROOT', 64); |
152 | |
153 | /** |
154 | * Endpoint Mask for comments. |
155 | * |
156 | * @since 2.1.0 |
157 | */ |
158 | define('EP_COMMENTS', 128); |
159 | |
160 | /** |
161 | * Endpoint Mask for searches. |
162 | * |
163 | * @since 2.1.0 |
164 | */ |
165 | define('EP_SEARCH', 256); |
166 | |
167 | /** |
168 | * Endpoint Mask for categories. |
169 | * |
170 | * @since 2.1.0 |
171 | */ |
172 | define('EP_CATEGORIES', 512); |
173 | |
174 | /** |
175 | * Endpoint Mask for tags. |
176 | * |
177 | * @since 2.3.0 |
178 | */ |
179 | define('EP_TAGS', 1024); |
180 | |
181 | /** |
182 | * Endpoint Mask for authors. |
183 | * |
184 | * @since 2.1.0 |
185 | */ |
186 | define('EP_AUTHORS', 2048); |
187 | |
188 | /** |
189 | * Endpoint Mask for pages. |
190 | * |
191 | * @since 2.1.0 |
192 | */ |
193 | define('EP_PAGES', 4096); |
194 | |
195 | /** |
196 | * Endpoint Mask for everything. |
197 | * |
198 | * @since 2.1.0 |
199 | */ |
200 | define('EP_ALL', 8191); |
201 | |
202 | /** |
203 | * Add an endpoint, like /trackback/. |
204 | * |
205 | * The endpoints are added to the end of the request. So a request matching |
206 | * "/2008/10/14/my_post/myep/", the endpoint will be "/myep/". |
207 | * |
208 | * Be sure to flush the rewrite rules (wp_rewrite->flush()) when your plugin gets |
209 | * activated (register_activation_hook()) and deactivated (register_deactivation_hook()) |
210 | * |
211 | * @since 2.1.0 |
212 | * @see WP_Rewrite::add_endpoint() Parameters and more description. |
213 | * @uses $wp_rewrite |
214 | * |
215 | * @param unknown_type $name |
216 | * @param unknown_type $places |
217 | */ |
218 | function add_rewrite_endpoint($name, $places) { |
219 | global $wp_rewrite; |
220 | $wp_rewrite->add_endpoint($name, $places); |
221 | } |
222 | |
223 | /** |
224 | * Filter the URL base for taxonomies. |
225 | * |
226 | * To remove any manually prepended /index.php/. |
227 | * |
228 | * @access private |
229 | * @since 2.6.0 |
230 | * |
231 | * @param string $base The taxonomy base that we're going to filter |
232 | * @return string |
233 | */ |
234 | function _wp_filter_taxonomy_base( $base ) { |
235 | if ( !empty( $base ) ) { |
236 | $base = preg_replace( '|^/index\.php/|', '', $base ); |
237 | $base = trim( $base, '/' ); |
238 | } |
239 | return $base; |
240 | } |
241 | |
242 | /** |
243 | * Examine a url and try to determine the post ID it represents. |
244 | * |
245 | * Checks are supposedly from the hosted site blog. |
246 | * |
247 | * @since 1.0.0 |
248 | * |
249 | * @param string $url Permalink to check. |
250 | * @return int Post ID, or 0 on failure. |
251 | */ |
252 | function url_to_postid($url) { |
253 | global $wp_rewrite; |
254 | |
255 | $url = apply_filters('url_to_postid', $url); |
256 | |
257 | // First, check to see if there is a 'p=N' or 'page_id=N' to match against |
258 | if ( preg_match('#[?&](p|page_id|attachment_id)=(\d+)#', $url, $values) ) { |
259 | $id = absint($values[2]); |
260 | if ( $id ) |
261 | return $id; |
262 | } |
263 | |
264 | // Check to see if we are using rewrite rules |
265 | $rewrite = $wp_rewrite->wp_rewrite_rules(); |
266 | |
267 | // Not using rewrite rules, and 'p=N' and 'page_id=N' methods failed, so we're out of options |
268 | if ( empty($rewrite) ) |
269 | return 0; |
270 | |
271 | // $url cleanup by Mark Jaquith |
272 | // This fixes things like #anchors, ?query=strings, missing 'www.', |
273 | // added 'www.', or added 'index.php/' that will mess up our WP_Query |
274 | // and return a false negative |
275 | |
276 | // Get rid of the #anchor |
277 | $url_split = explode('#', $url); |
278 | $url = $url_split[0]; |
279 | |
280 | // Get rid of URL ?query=string |
281 | $url_split = explode('?', $url); |
282 | $url = $url_split[0]; |
283 | |
284 | // Add 'www.' if it is absent and should be there |
285 | if ( false !== strpos(home_url(), '://www.') && false === strpos($url, '://www.') ) |
286 | $url = str_replace('://', '://www.', $url); |
287 | |
288 | // Strip 'www.' if it is present and shouldn't be |
289 | if ( false === strpos(home_url(), '://www.') ) |
290 | $url = str_replace('://www.', '://', $url); |
291 | |
292 | // Strip 'index.php/' if we're not using path info permalinks |
293 | if ( !$wp_rewrite->using_index_permalinks() ) |
294 | $url = str_replace('index.php/', '', $url); |
295 | |
296 | if ( false !== strpos($url, home_url()) ) { |
297 | // Chop off http://domain.com |
298 | $url = str_replace(home_url(), '', $url); |
299 | } else { |
300 | // Chop off /path/to/blog |
301 | $home_path = parse_url(home_url()); |
302 | $home_path = $home_path['path']; |
303 | $url = str_replace($home_path, '', $url); |
304 | } |
305 | |
306 | // Trim leading and lagging slashes |
307 | $url = trim($url, '/'); |
308 | |
309 | $request = $url; |
310 | |
311 | // Done with cleanup |
312 | |
313 | // Look for matches. |
314 | $request_match = $request; |
315 | foreach ( (array)$rewrite as $match => $query) { |
316 | // If the requesting file is the anchor of the match, prepend it |
317 | // to the path info. |
318 | if ( !empty($url) && ($url != $request) && (strpos($match, $url) === 0) ) |
319 | $request_match = $url . '/' . $request; |
320 | |
321 | if ( preg_match("!^$match!", $request_match, $matches) ) { |
322 | // Got a match. |
323 | // Trim the query of everything up to the '?'. |
324 | $query = preg_replace("!^.+\?!", '', $query); |
325 | |
326 | // Substitute the substring matches into the query. |
327 | $query = addslashes(WP_MatchesMapRegex::apply($query, $matches)); |
328 | |
329 | // Filter out non-public query vars |
330 | global $wp; |
331 | parse_str($query, $query_vars); |
332 | $query = array(); |
333 | foreach ( (array) $query_vars as $key => $value ) { |
334 | if ( in_array($key, $wp->public_query_vars) ) |
335 | $query[$key] = $value; |
336 | } |
337 | |
338 | // Do the query |
339 | $query = new WP_Query($query); |
340 | if ( $query->is_single || $query->is_page ) |
341 | return $query->post->ID; |
342 | else |
343 | return 0; |
344 | } |
345 | } |
346 | return 0; |
347 | } |
348 | |
349 | /** |
350 | * WordPress Rewrite Component. |
351 | * |
352 | * The WordPress Rewrite class writes the rewrite module rules to the .htaccess |
353 | * file. It also handles parsing the request to get the correct setup for the |
354 | * WordPress Query class. |
355 | * |
356 | * The Rewrite along with WP class function as a front controller for WordPress. |
357 | * You can add rules to trigger your page view and processing using this |
358 | * component. The full functionality of a front controller does not exist, |
359 | * meaning you can't define how the template files load based on the rewrite |
360 | * rules. |
361 | * |
362 | * @since 1.5.0 |
363 | */ |
364 | class WP_Rewrite { |
365 | /** |
366 | * Default permalink structure for WordPress. |
367 | * |
368 | * @since 1.5.0 |
369 | * @access private |
370 | * @var string |
371 | */ |
372 | var $permalink_structure; |
373 | |
374 | /** |
375 | * Whether to add trailing slashes. |
376 | * |
377 | * @since 2.2.0 |
378 | * @access private |
379 | * @var bool |
380 | */ |
381 | var $use_trailing_slashes; |
382 | |
383 | /** |
384 | * Customized or default category permalink base ( example.com/xx/tagname ). |
385 | * |
386 | * @since 1.5.0 |
387 | * @access private |
388 | * @var string |
389 | */ |
390 | var $category_base; |
391 | |
392 | /** |
393 | * Customized or default tag permalink base ( example.com/xx/tagname ). |
394 | * |
395 | * @since 2.3.0 |
396 | * @access private |
397 | * @var string |
398 | */ |
399 | var $tag_base; |
400 | |
401 | /** |
402 | * Permalink request structure for categories. |
403 | * |
404 | * @since 1.5.0 |
405 | * @access private |
406 | * @var string |
407 | */ |
408 | var $category_structure; |
409 | |
410 | /** |
411 | * Permalink request structure for tags. |
412 | * |
413 | * @since 2.3.0 |
414 | * @access private |
415 | * @var string |
416 | */ |
417 | var $tag_structure; |
418 | |
419 | /** |
420 | * Permalink author request base ( example.com/author/authorname ). |
421 | * |
422 | * @since 1.5.0 |
423 | * @access private |
424 | * @var string |
425 | */ |
426 | var $author_base = 'author'; |
427 | |
428 | /** |
429 | * Permalink request structure for author pages. |
430 | * |
431 | * @since 1.5.0 |
432 | * @access private |
433 | * @var string |
434 | */ |
435 | var $author_structure; |
436 | |
437 | /** |
438 | * Permalink request structure for dates. |
439 | * |
440 | * @since 1.5.0 |
441 | * @access private |
442 | * @var string |
443 | */ |
444 | var $date_structure; |
445 | |
446 | /** |
447 | * Permalink request structure for pages. |
448 | * |
449 | * @since 1.5.0 |
450 | * @access private |
451 | * @var string |
452 | */ |
453 | var $page_structure; |
454 | |
455 | /** |
456 | * Search permalink base ( example.com/search/query ). |
457 | * |
458 | * @since 1.5.0 |
459 | * @access private |
460 | * @var string |
461 | */ |
462 | var $search_base = 'search'; |
463 | |
464 | /** |
465 | * Permalink request structure for searches. |
466 | * |
467 | * @since 1.5.0 |
468 | * @access private |
469 | * @var string |
470 | */ |
471 | var $search_structure; |
472 | |
473 | /** |
474 | * Comments permalink base. |
475 | * |
476 | * @since 1.5.0 |
477 | * @access private |
478 | * @var string |
479 | */ |
480 | var $comments_base = 'comments'; |
481 | |
482 | /** |
483 | * Feed permalink base. |
484 | * |
485 | * @since 1.5.0 |
486 | * @access private |
487 | * @var string |
488 | */ |
489 | var $feed_base = 'feed'; |
490 | |
491 | /** |
492 | * Comments feed request structure permalink. |
493 | * |
494 | * @since 1.5.0 |
495 | * @access private |
496 | * @var string |
497 | */ |
498 | var $comments_feed_structure; |
499 | |
500 | /** |
501 | * Feed request structure permalink. |
502 | * |
503 | * @since 1.5.0 |
504 | * @access private |
505 | * @var string |
506 | */ |
507 | var $feed_structure; |
508 | |
509 | /** |
510 | * Front URL path. |
511 | * |
512 | * The difference between the root property is that WordPress might be |
513 | * located at example/WordPress/index.php, if permalinks are turned off. The |
514 | * WordPress/index.php will be the front portion. If permalinks are turned |
515 | * on, this will most likely be empty or not set. |
516 | * |
517 | * @since 1.5.0 |
518 | * @access private |
519 | * @var string |
520 | */ |
521 | var $front; |
522 | |
523 | /** |
524 | * Root URL path to WordPress (without domain). |
525 | * |
526 | * The difference between front property is that WordPress might be located |
527 | * at example.com/WordPress/. The root is the 'WordPress/' portion. |
528 | * |
529 | * @since 1.5.0 |
530 | * @access private |
531 | * @var string |
532 | */ |
533 | var $root = ''; |
534 | |
535 | /** |
536 | * Permalink to the home page. |
537 | * |
538 | * @since 1.5.0 |
539 | * @access public |
540 | * @var string |
541 | */ |
542 | var $index = 'index.php'; |
543 | |
544 | /** |
545 | * Request match string. |
546 | * |
547 | * @since 1.5.0 |
548 | * @access private |
549 | * @var string |
550 | */ |
551 | var $matches = ''; |
552 | |
553 | /** |
554 | * Rewrite rules to match against the request to find the redirect or query. |
555 | * |
556 | * @since 1.5.0 |
557 | * @access private |
558 | * @var array |
559 | */ |
560 | var $rules; |
561 | |
562 | /** |
563 | * Additional rules added external to the rewrite class. |
564 | * |
565 | * Those not generated by the class, see add_rewrite_rule(). |
566 | * |
567 | * @since 2.1.0 |
568 | * @access private |
569 | * @var array |
570 | */ |
571 | var $extra_rules = array(); // |
572 | |
573 | /** |
574 | * Additional rules that belong at the beginning to match first. |
575 | * |
576 | * Those not generated by the class, see add_rewrite_rule(). |
577 | * |
578 | * @since 2.3.0 |
579 | * @access private |
580 | * @var array |
581 | */ |
582 | var $extra_rules_top = array(); // |
583 | |
584 | /** |
585 | * Rules that don't redirect to WP's index.php. |
586 | * |
587 | * These rules are written to the mod_rewrite portion of the .htaccess. |
588 | * |
589 | * @since 2.1.0 |
590 | * @access private |
591 | * @var array |
592 | */ |
593 | var $non_wp_rules = array(); // |
594 | |
595 | /** |
596 | * Extra permalink structures. |
597 | * |
598 | * @since 2.1.0 |
599 | * @access private |
600 | * @var array |
601 | */ |
602 | var $extra_permastructs = array(); |
603 | |
604 | /** |
605 | * Endpoints permalinks |
606 | * |
607 | * @since unknown |
608 | * @access private |
609 | * @var array |
610 | */ |
611 | var $endpoints; |
612 | |
613 | /** |
614 | * Whether to write every mod_rewrite rule for WordPress. |
615 | * |
616 | * This is off by default, turning it on might print a lot of rewrite rules |
617 | * to the .htaccess file. |
618 | * |
619 | * @since 2.0.0 |
620 | * @access public |
621 | * @var bool |
622 | */ |
623 | var $use_verbose_rules = false; |
624 | |
625 | /** |
626 | * Whether to write every mod_rewrite rule for WordPress pages. |
627 | * |
628 | * @since 2.5.0 |
629 | * @access public |
630 | * @var bool |
631 | */ |
632 | var $use_verbose_page_rules = true; |
633 | |
634 | /** |
635 | * Permalink structure search for preg_replace. |
636 | * |
637 | * @since 1.5.0 |
638 | * @access private |
639 | * @var array |
640 | */ |
641 | var $rewritecode = |
642 | array( |
643 | '%year%', |
644 | '%monthnum%', |
645 | '%day%', |
646 | '%hour%', |
647 | '%minute%', |
648 | '%second%', |
649 | '%postname%', |
650 | '%post_id%', |
651 | '%category%', |
652 | '%tag%', |
653 | '%author%', |
654 | '%pagename%', |
655 | '%search%' |
656 | ); |
657 | |
658 | /** |
659 | * Preg_replace values for the search, see {@link WP_Rewrite::$rewritecode}. |
660 | * |
661 | * @since 1.5.0 |
662 | * @access private |
663 | * @var array |
664 | */ |
665 | var $rewritereplace = |
666 | array( |
667 | '([0-9]{4})', |
668 | '([0-9]{1,2})', |
669 | '([0-9]{1,2})', |
670 | '([0-9]{1,2})', |
671 | '([0-9]{1,2})', |
672 | '([0-9]{1,2})', |
673 | '([^/]+)', |
674 | '([0-9]+)', |
675 | '(.+?)', |
676 | '(.+?)', |
677 | '([^/]+)', |
678 | '([^/]+?)', |
679 | '(.+)' |
680 | ); |
681 | |
682 | /** |
683 | * Search for the query to look for replacing. |
684 | * |
685 | * @since 1.5.0 |
686 | * @access private |
687 | * @var array |
688 | */ |
689 | var $queryreplace = |
690 | array ( |
691 | 'year=', |
692 | 'monthnum=', |
693 | 'day=', |
694 | 'hour=', |
695 | 'minute=', |
696 | 'second=', |
697 | 'name=', |
698 | 'p=', |
699 | 'category_name=', |
700 | 'tag=', |
701 | 'author_name=', |
702 | 'pagename=', |
703 | 's=' |
704 | ); |
705 | |
706 | /** |
707 | * Supported default feeds. |
708 | * |
709 | * @since 1.5.0 |
710 | * @access private |
711 | * @var array |
712 | */ |
713 | var $feeds = array ( 'feed', 'rdf', 'rss', 'rss2', 'atom' ); |
714 | |
715 | /** |
716 | * Whether permalinks are being used. |
717 | * |
718 | * This can be either rewrite module or permalink in the HTTP query string. |
719 | * |
720 | * @since 1.5.0 |
721 | * @access public |
722 | * |
723 | * @return bool True, if permalinks are enabled. |
724 | */ |
725 | function using_permalinks() { |
726 | return ! empty($this->permalink_structure); |
727 | } |
728 | |
729 | /** |
730 | * Whether permalinks are being used and rewrite module is not enabled. |
731 | * |
732 | * Means that permalink links are enabled and index.php is in the URL. |
733 | * |
734 | * @since 1.5.0 |
735 | * @access public |
736 | * |
737 | * @return bool |
738 | */ |
739 | function using_index_permalinks() { |
740 | if ( empty($this->permalink_structure) ) |
741 | return false; |
742 | |
743 | // If the index is not in the permalink, we're using mod_rewrite. |
744 | if ( preg_match('#^/*' . $this->index . '#', $this->permalink_structure) ) |
745 | return true; |
746 | |
747 | return false; |
748 | } |
749 | |
750 | /** |
751 | * Whether permalinks are being used and rewrite module is enabled. |
752 | * |
753 | * Using permalinks and index.php is not in the URL. |
754 | * |
755 | * @since 1.5.0 |
756 | * @access public |
757 | * |
758 | * @return bool |
759 | */ |
760 | function using_mod_rewrite_permalinks() { |
761 | if ( $this->using_permalinks() && ! $this->using_index_permalinks() ) |
762 | return true; |
763 | else |
764 | return false; |
765 | } |
766 | |
767 | /** |
768 | * Index for matches for usage in preg_*() functions. |
769 | * |
770 | * The format of the string is, with empty matches property value, '$NUM'. |
771 | * The 'NUM' will be replaced with the value in the $number parameter. With |
772 | * the matches property not empty, the value of the returned string will |
773 | * contain that value of the matches property. The format then will be |
774 | * '$MATCHES[NUM]', with MATCHES as the value in the property and NUM the |
775 | * value of the $number parameter. |
776 | * |
777 | * @since 1.5.0 |
778 | * @access public |
779 | * |
780 | * @param int $number Index number. |
781 | * @return string |
782 | */ |
783 | function preg_index($number) { |
784 | $match_prefix = '$'; |
785 | $match_suffix = ''; |
786 | |
787 | if ( ! empty($this->matches) ) { |
788 | $match_prefix = '$' . $this->matches . '['; |
789 | $match_suffix = ']'; |
790 | } |
791 | |
792 | return "$match_prefix$number$match_suffix"; |
793 | } |
794 | |
795 | /** |
796 | * Retrieve all page and attachments for pages URIs. |
797 | * |
798 | * The attachments are for those that have pages as parents and will be |
799 | * retrieved. |
800 | * |
801 | * @since 2.5.0 |
802 | * @access public |
803 | * |
804 | * @return array Array of page URIs as first element and attachment URIs as second element. |
805 | */ |
806 | function page_uri_index() { |
807 | global $wpdb; |
808 | |
809 | //get pages in order of hierarchy, i.e. children after parents |
810 | $posts = get_page_hierarchy($wpdb->get_results("SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE post_type = 'page'")); |
811 | |
812 | // If we have no pages get out quick |
813 | if ( !$posts ) |
814 | return array( array(), array() ); |
815 | |
816 | //now reverse it, because we need parents after children for rewrite rules to work properly |
817 | $posts = array_reverse($posts, true); |
818 | |
819 | $page_uris = array(); |
820 | $page_attachment_uris = array(); |
821 | |
822 | foreach ( $posts as $id => $post ) { |
823 | // URL => page name |
824 | $uri = get_page_uri($id); |
825 | $attachments = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE post_type = 'attachment' AND post_parent = %d", $id )); |
826 | if ( !empty($attachments) ) { |
827 | foreach ( $attachments as $attachment ) { |
828 | $attach_uri = get_page_uri($attachment->ID); |
829 | $page_attachment_uris[$attach_uri] = $attachment->ID; |
830 | } |
831 | } |
832 | |
833 | $page_uris[$uri] = $id; |
834 | } |
835 | |
836 | return array( $page_uris, $page_attachment_uris ); |
837 | } |
838 | |
839 | /** |
840 | * Retrieve all of the rewrite rules for pages. |
841 | * |
842 | * If the 'use_verbose_page_rules' property is false, then there will only |
843 | * be a single rewrite rule for pages for those matching '%pagename%'. With |
844 | * the property set to true, the attachments and the pages will be added for |
845 | * each individual attachment URI and page URI, respectively. |
846 | * |
847 | * @since 1.5.0 |
848 | * @access public |
849 | * |
850 | * @return array |
851 | */ |
852 | function page_rewrite_rules() { |
853 | $rewrite_rules = array(); |
854 | $page_structure = $this->get_page_permastruct(); |
855 | |
856 | if ( ! $this->use_verbose_page_rules ) { |
857 | $this->add_rewrite_tag('%pagename%', "(.+?)", 'pagename='); |
858 | $rewrite_rules = array_merge($rewrite_rules, $this->generate_rewrite_rules($page_structure, EP_PAGES)); |
859 | return $rewrite_rules; |
860 | } |
861 | |
862 | $page_uris = $this->page_uri_index(); |
863 | $uris = $page_uris[0]; |
864 | $attachment_uris = $page_uris[1]; |
865 | |
866 | if ( is_array( $attachment_uris ) ) { |
867 | foreach ( $attachment_uris as $uri => $pagename ) { |
868 | $this->add_rewrite_tag('%pagename%', "($uri)", 'attachment='); |
869 | $rewrite_rules = array_merge($rewrite_rules, $this->generate_rewrite_rules($page_structure, EP_PAGES)); |
870 | } |
871 | } |
872 | if ( is_array( $uris ) ) { |
873 | foreach ( $uris as $uri => $pagename ) { |
874 | $this->add_rewrite_tag('%pagename%', "($uri)", 'pagename='); |
875 | $rewrite_rules = array_merge($rewrite_rules, $this->generate_rewrite_rules($page_structure, EP_PAGES)); |
876 | } |
877 | } |
878 | |
879 | return $rewrite_rules; |
880 | } |
881 | |
882 | /** |
883 | * Retrieve date permalink structure, with year, month, and day. |
884 | * |
885 | * The permalink structure for the date, if not set already depends on the |
886 | * permalink structure. It can be one of three formats. The first is year, |
887 | * month, day; the second is day, month, year; and the last format is month, |
888 | * day, year. These are matched against the permalink structure for which |
889 | * one is used. If none matches, then the default will be used, which is |
890 | * year, month, day. |
891 | * |
892 | * Prevents post ID and date permalinks from overlapping. In the case of |
893 | * post_id, the date permalink will be prepended with front permalink with |
894 | * 'date/' before the actual permalink to form the complete date permalink |
895 | * structure. |
896 | * |
897 | * @since 1.5.0 |
898 | * @access public |
899 | * |
900 | * @return bool|string False on no permalink structure. Date permalink structure. |
901 | */ |
902 | function get_date_permastruct() { |
903 | if ( isset($this->date_structure) ) |
904 | return $this->date_structure; |
905 | |
906 | if ( empty($this->permalink_structure) ) { |
907 | $this->date_structure = ''; |
908 | return false; |
909 | } |
910 | |
911 | // The date permalink must have year, month, and day separated by slashes. |
912 | $endians = array('%year%/%monthnum%/%day%', '%day%/%monthnum%/%year%', '%monthnum%/%day%/%year%'); |
913 | |
914 | $this->date_structure = ''; |
915 | $date_endian = ''; |
916 | |
917 | foreach ( $endians as $endian ) { |
918 | if ( false !== strpos($this->permalink_structure, $endian) ) { |
919 | $date_endian= $endian; |
920 | break; |
921 | } |
922 | } |
923 | |
924 | if ( empty($date_endian) ) |
925 | $date_endian = '%year%/%monthnum%/%day%'; |
926 | |
927 | // Do not allow the date tags and %post_id% to overlap in the permalink |
928 | // structure. If they do, move the date tags to $front/date/. |
929 | $front = $this->front; |
930 | preg_match_all('/%.+?%/', $this->permalink_structure, $tokens); |
931 | $tok_index = 1; |
932 | foreach ( (array) $tokens[0] as $token) { |
933 | if ( '%post_id%' == $token && ($tok_index <= 3) ) { |
934 | $front = $front . 'date/'; |
935 | break; |
936 | } |
937 | $tok_index++; |
938 | } |
939 | |
940 | $this->date_structure = $front . $date_endian; |
941 | |
942 | return $this->date_structure; |
943 | } |
944 | |
945 | /** |
946 | * Retrieve the year permalink structure without month and day. |
947 | * |
948 | * Gets the date permalink structure and strips out the month and day |
949 | * permalink structures. |
950 | * |
951 | * @since 1.5.0 |
952 | * @access public |
953 | * |
954 | * @return bool|string False on failure. Year structure on success. |
955 | */ |
956 | function get_year_permastruct() { |
957 | $structure = $this->get_date_permastruct($this->permalink_structure); |
958 | |
959 | if ( empty($structure) ) |
960 | return false; |
961 | |
962 | $structure = str_replace('%monthnum%', '', $structure); |
963 | $structure = str_replace('%day%', '', $structure); |
964 | |
965 | $structure = preg_replace('#/+#', '/', $structure); |
966 | |
967 | return $structure; |
968 | } |
969 | |
970 | /** |
971 | * Retrieve the month permalink structure without day and with year. |
972 | * |
973 | * Gets the date permalink structure and strips out the day permalink |
974 | * structures. Keeps the year permalink structure. |
975 | * |
976 | * @since 1.5.0 |
977 | * @access public |
978 | * |
979 | * @return bool|string False on failure. Year/Month structure on success. |
980 | */ |
981 | function get_month_permastruct() { |
982 | $structure = $this->get_date_permastruct($this->permalink_structure); |
983 | |
984 | if ( empty($structure) ) |
985 | return false; |
986 | |
987 | $structure = str_replace('%day%', '', $structure); |
988 | |
989 | $structure = preg_replace('#/+#', '/', $structure); |
990 | |
991 | return $structure; |
992 | } |
993 | |
994 | /** |
995 | * Retrieve the day permalink structure with month and year. |
996 | * |
997 | * Keeps date permalink structure with all year, month, and day. |
998 | * |
999 | * @since 1.5.0 |
1000 | * @access public |