Issues (2010)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

wp-includes/class-wp-rewrite.php (34 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Rewrite API: WP_Rewrite class
4
 *
5
 * @package WordPress
6
 * @subpackage Rewrite
7
 * @since 1.5.0
8
 */
9
10
/**
11
 * Core class used to implement a rewrite component API.
12
 *
13
 * The WordPress Rewrite class writes the rewrite module rules to the .htaccess
14
 * file. It also handles parsing the request to get the correct setup for the
15
 * WordPress Query class.
16
 *
17
 * The Rewrite along with WP class function as a front controller for WordPress.
18
 * You can add rules to trigger your page view and processing using this
19
 * component. The full functionality of a front controller does not exist,
20
 * meaning you can't define how the template files load based on the rewrite
21
 * rules.
22
 *
23
 * @since 1.5.0
24
 */
25
class WP_Rewrite {
26
	/**
27
	 * Permalink structure for posts.
28
	 *
29
	 * @since 1.5.0
30
	 * @var string
31
	 */
32
	public $permalink_structure;
33
34
	/**
35
	 * Whether to add trailing slashes.
36
	 *
37
	 * @since 2.2.0
38
	 * @var bool
39
	 */
40
	public $use_trailing_slashes;
41
42
	/**
43
	 * Base for the author permalink structure (example.com/$author_base/authorname).
44
	 *
45
	 * @since 1.5.0
46
	 * @access private
47
	 * @var string
48
	 */
49
	var $author_base = 'author';
50
51
	/**
52
	 * Permalink structure for author archives.
53
	 *
54
	 * @since 1.5.0
55
	 * @access private
56
	 * @var string
57
	 */
58
	var $author_structure;
59
60
	/**
61
	 * Permalink structure for date archives.
62
	 *
63
	 * @since 1.5.0
64
	 * @access private
65
	 * @var string
66
	 */
67
	var $date_structure;
68
69
	/**
70
	 * Permalink structure for pages.
71
	 *
72
	 * @since 1.5.0
73
	 * @access private
74
	 * @var string
75
	 */
76
	var $page_structure;
77
78
	/**
79
	 * Base of the search permalink structure (example.com/$search_base/query).
80
	 *
81
	 * @since 1.5.0
82
	 * @access private
83
	 * @var string
84
	 */
85
	var $search_base = 'search';
86
87
	/**
88
	 * Permalink structure for searches.
89
	 *
90
	 * @since 1.5.0
91
	 * @access private
92
	 * @var string
93
	 */
94
	var $search_structure;
95
96
	/**
97
	 * Comments permalink base.
98
	 *
99
	 * @since 1.5.0
100
	 * @access private
101
	 * @var string
102
	 */
103
	var $comments_base = 'comments';
104
105
	/**
106
	 * Pagination permalink base.
107
	 *
108
	 * @since 3.1.0
109
	 * @var string
110
	 */
111
	public $pagination_base = 'page';
112
113
	/**
114
	 * Comments pagination permalink base.
115
	 *
116
	 * @since 4.2.0
117
	 * @access private
118
	 * @var string
119
	 */
120
	var $comments_pagination_base = 'comment-page';
121
122
	/**
123
	 * Feed permalink base.
124
	 *
125
	 * @since 1.5.0
126
	 * @access private
127
	 * @var string
128
	 */
129
	var $feed_base = 'feed';
130
131
	/**
132
	 * Comments feed permalink structure.
133
	 *
134
	 * @since 1.5.0
135
	 * @access private
136
	 * @var string
137
	 */
138
	var $comment_feed_structure;
139
140
	/**
141
	 * Feed request permalink structure.
142
	 *
143
	 * @since 1.5.0
144
	 * @access private
145
	 * @var string
146
	 */
147
	var $feed_structure;
148
149
	/**
150
	 * The static portion of the post permalink structure.
151
	 *
152
	 * If the permalink structure is "/archive/%post_id%" then the front
153
	 * is "/archive/". If the permalink structure is "/%year%/%postname%/"
154
	 * then the front is "/".
155
	 *
156
	 * @since 1.5.0
157
	 * @access public
158
	 * @var string
159
	 *
160
	 * @see WP_Rewrite::init()
161
	 */
162
	public $front;
163
164
	/**
165
	 * The prefix for all permalink structures.
166
	 *
167
	 * If PATHINFO/index permalinks are in use then the root is the value of
168
	 * `WP_Rewrite::$index` with a trailing slash appended. Otherwise the root
169
	 * will be empty.
170
	 *
171
	 * @since 1.5.0
172
	 * @access public
173
	 * @var string
174
	 *
175
	 * @see WP_Rewrite::init()
176
	 * @see WP_Rewrite::using_index_permalinks()
177
	 */
178
	public $root = '';
179
180
	/**
181
	 * The name of the index file which is the entry point to all requests.
182
	 *
183
	 * @since 1.5.0
184
	 * @access public
185
	 * @var string
186
	 */
187
	public $index = 'index.php';
188
189
	/**
190
	 * Variable name to use for regex matches in the rewritten query.
191
	 *
192
	 * @since 1.5.0
193
	 * @access private
194
	 * @var string
195
	 */
196
	var $matches = '';
197
198
	/**
199
	 * Rewrite rules to match against the request to find the redirect or query.
200
	 *
201
	 * @since 1.5.0
202
	 * @access private
203
	 * @var array
204
	 */
205
	var $rules;
206
207
	/**
208
	 * Additional rules added external to the rewrite class.
209
	 *
210
	 * Those not generated by the class, see add_rewrite_rule().
211
	 *
212
	 * @since 2.1.0
213
	 * @access private
214
	 * @var array
215
	 */
216
	var $extra_rules = array();
217
218
	/**
219
	 * Additional rules that belong at the beginning to match first.
220
	 *
221
	 * Those not generated by the class, see add_rewrite_rule().
222
	 *
223
	 * @since 2.3.0
224
	 * @access private
225
	 * @var array
226
	 */
227
	var $extra_rules_top = array();
228
229
	/**
230
	 * Rules that don't redirect to WordPress' index.php.
231
	 *
232
	 * These rules are written to the mod_rewrite portion of the .htaccess,
233
	 * and are added by add_external_rule().
234
	 *
235
	 * @since 2.1.0
236
	 * @access private
237
	 * @var array
238
	 */
239
	var $non_wp_rules = array();
240
241
	/**
242
	 * Extra permalink structures, e.g. categories, added by add_permastruct().
243
	 *
244
	 * @since 2.1.0
245
	 * @access private
246
	 * @var array
247
	 */
248
	var $extra_permastructs = array();
249
250
	/**
251
	 * Endpoints (like /trackback/) added by add_rewrite_endpoint().
252
	 *
253
	 * @since 2.1.0
254
	 * @access private
255
	 * @var array
256
	 */
257
	var $endpoints;
258
259
	/**
260
	 * Whether to write every mod_rewrite rule for WordPress into the .htaccess file.
261
	 *
262
	 * This is off by default, turning it on might print a lot of rewrite rules
263
	 * to the .htaccess file.
264
	 *
265
	 * @since 2.0.0
266
	 * @access public
267
	 * @var bool
268
	 *
269
	 * @see WP_Rewrite::mod_rewrite_rules()
270
	 */
271
	public $use_verbose_rules = false;
272
273
	/**
274
	 * Could post permalinks be confused with those of pages?
275
	 *
276
	 * If the first rewrite tag in the post permalink structure is one that could
277
	 * also match a page name (e.g. %postname% or %author%) then this flag is
278
	 * set to true. Prior to WordPress 3.3 this flag indicated that every page
279
	 * would have a set of rules added to the top of the rewrite rules array.
280
	 * Now it tells WP::parse_request() to check if a URL matching the page
281
	 * permastruct is actually a page before accepting it.
282
	 *
283
	 * @since 2.5.0
284
	 * @access public
285
	 * @var bool
286
	 *
287
	 * @see WP_Rewrite::init()
288
	 */
289
	public $use_verbose_page_rules = true;
290
291
	/**
292
	 * Rewrite tags that can be used in permalink structures.
293
	 *
294
	 * These are translated into the regular expressions stored in
295
	 * `WP_Rewrite::$rewritereplace` and are rewritten to the query
296
	 * variables listed in WP_Rewrite::$queryreplace.
297
	 *
298
	 * Additional tags can be added with add_rewrite_tag().
299
	 *
300
	 * @since 1.5.0
301
	 * @access private
302
	 * @var array
303
	 */
304
	var $rewritecode = array(
305
		'%year%',
306
		'%monthnum%',
307
		'%day%',
308
		'%hour%',
309
		'%minute%',
310
		'%second%',
311
		'%postname%',
312
		'%post_id%',
313
		'%author%',
314
		'%pagename%',
315
		'%search%'
316
	);
317
318
	/**
319
	 * Regular expressions to be substituted into rewrite rules in place
320
	 * of rewrite tags, see WP_Rewrite::$rewritecode.
321
	 *
322
	 * @since 1.5.0
323
	 * @access private
324
	 * @var array
325
	 */
326
	var $rewritereplace = array(
327
		'([0-9]{4})',
328
		'([0-9]{1,2})',
329
		'([0-9]{1,2})',
330
		'([0-9]{1,2})',
331
		'([0-9]{1,2})',
332
		'([0-9]{1,2})',
333
		'([^/]+)',
334
		'([0-9]+)',
335
		'([^/]+)',
336
		'([^/]+?)',
337
		'(.+)'
338
	);
339
340
	/**
341
	 * Query variables that rewrite tags map to, see WP_Rewrite::$rewritecode.
342
	 *
343
	 * @since 1.5.0
344
	 * @access private
345
	 * @var array
346
	 */
347
	var $queryreplace = array(
348
		'year=',
349
		'monthnum=',
350
		'day=',
351
		'hour=',
352
		'minute=',
353
		'second=',
354
		'name=',
355
		'p=',
356
		'author_name=',
357
		'pagename=',
358
		's='
359
	);
360
361
	/**
362
	 * Supported default feeds.
363
	 *
364
	 * @since 1.5.0
365
	 * @var array
366
	 */
367
	public $feeds = array( 'feed', 'rdf', 'rss', 'rss2', 'atom' );
368
369
	/**
370
	 * Determines whether permalinks are being used.
371
	 *
372
	 * This can be either rewrite module or permalink in the HTTP query string.
373
	 *
374
	 * @since 1.5.0
375
	 * @access public
376
	 *
377
	 * @return bool True, if permalinks are enabled.
378
	 */
379
	public function using_permalinks() {
380
		return ! empty($this->permalink_structure);
381
	}
382
383
	/**
384
	 * Determines whether permalinks are being used and rewrite module is not enabled.
385
	 *
386
	 * Means that permalink links are enabled and index.php is in the URL.
387
	 *
388
	 * @since 1.5.0
389
	 * @access public
390
	 *
391
	 * @return bool Whether permalink links are enabled and index.php is in the URL.
392
	 */
393
	public function using_index_permalinks() {
394
		if ( empty( $this->permalink_structure ) ) {
395
			return false;
396
		}
397
398
		// If the index is not in the permalink, we're using mod_rewrite.
399
		return preg_match( '#^/*' . $this->index . '#', $this->permalink_structure );
400
	}
401
402
	/**
403
	 * Determines whether permalinks are being used and rewrite module is enabled.
404
	 *
405
	 * Using permalinks and index.php is not in the URL.
406
	 *
407
	 * @since 1.5.0
408
	 * @access public
409
	 *
410
	 * @return bool Whether permalink links are enabled and index.php is NOT in the URL.
411
	 */
412
	public function using_mod_rewrite_permalinks() {
413
		return $this->using_permalinks() && ! $this->using_index_permalinks();
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->using_index_permalinks() of type false|integer is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
414
	}
415
416
	/**
417
	 * Indexes for matches for usage in preg_*() functions.
418
	 *
419
	 * The format of the string is, with empty matches property value, '$NUM'.
420
	 * The 'NUM' will be replaced with the value in the $number parameter. With
421
	 * the matches property not empty, the value of the returned string will
422
	 * contain that value of the matches property. The format then will be
423
	 * '$MATCHES[NUM]', with MATCHES as the value in the property and NUM the
424
	 * value of the $number parameter.
425
	 *
426
	 * @since 1.5.0
427
	 * @access public
428
	 *
429
	 * @param int $number Index number.
430
	 * @return string
431
	 */
432
	public function preg_index($number) {
433
		$match_prefix = '$';
434
		$match_suffix = '';
435
436
		if ( ! empty($this->matches) ) {
437
			$match_prefix = '$' . $this->matches . '[';
438
			$match_suffix = ']';
439
		}
440
441
		return "$match_prefix$number$match_suffix";
442
	}
443
444
	/**
445
	 * Retrieves all page and attachments for pages URIs.
446
	 *
447
	 * The attachments are for those that have pages as parents and will be
448
	 * retrieved.
449
	 *
450
	 * @since 2.5.0
451
	 * @access public
452
	 *
453
	 * @global wpdb $wpdb WordPress database abstraction object.
454
	 *
455
	 * @return array Array of page URIs as first element and attachment URIs as second element.
456
	 */
457
	public function page_uri_index() {
458
		global $wpdb;
459
460
		// Get pages in order of hierarchy, i.e. children after parents.
461
		$pages = $wpdb->get_results("SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE post_type = 'page' AND post_status != 'auto-draft'");
462
		$posts = get_page_hierarchy( $pages );
463
464
		// If we have no pages get out quick.
465
		if ( !$posts )
466
			return array( array(), array() );
467
468
		// Now reverse it, because we need parents after children for rewrite rules to work properly.
469
		$posts = array_reverse($posts, true);
470
471
		$page_uris = array();
472
		$page_attachment_uris = array();
473
474
		foreach ( $posts as $id => $post ) {
475
			// URL => page name
476
			$uri = get_page_uri($id);
477
			$attachments = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_name, post_parent FROM $wpdb->posts WHERE post_type = 'attachment' AND post_parent = %d", $id ));
478
			if ( !empty($attachments) ) {
479
				foreach ( $attachments as $attachment ) {
480
					$attach_uri = get_page_uri($attachment->ID);
481
					$page_attachment_uris[$attach_uri] = $attachment->ID;
482
				}
483
			}
484
485
			$page_uris[$uri] = $id;
486
		}
487
488
		return array( $page_uris, $page_attachment_uris );
489
	}
490
491
	/**
492
	 * Retrieves all of the rewrite rules for pages.
493
	 *
494
	 * @since 1.5.0
495
	 * @access public
496
	 *
497
	 * @return array Page rewrite rules.
498
	 */
499
	public function page_rewrite_rules() {
500
		// The extra .? at the beginning prevents clashes with other regular expressions in the rules array.
501
		$this->add_rewrite_tag( '%pagename%', '(.?.+?)', 'pagename=' );
502
503
		return $this->generate_rewrite_rules( $this->get_page_permastruct(), EP_PAGES, true, true, false, false );
0 ignored issues
show
It seems like $this->get_page_permastruct() targeting WP_Rewrite::get_page_permastruct() can also be of type false; however, WP_Rewrite::generate_rewrite_rules() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
504
	}
505
506
	/**
507
	 * Retrieves date permalink structure, with year, month, and day.
508
	 *
509
	 * The permalink structure for the date, if not set already depends on the
510
	 * permalink structure. It can be one of three formats. The first is year,
511
	 * month, day; the second is day, month, year; and the last format is month,
512
	 * day, year. These are matched against the permalink structure for which
513
	 * one is used. If none matches, then the default will be used, which is
514
	 * year, month, day.
515
	 *
516
	 * Prevents post ID and date permalinks from overlapping. In the case of
517
	 * post_id, the date permalink will be prepended with front permalink with
518
	 * 'date/' before the actual permalink to form the complete date permalink
519
	 * structure.
520
	 *
521
	 * @since 1.5.0
522
	 * @access public
523
	 *
524
	 * @return string|false False on no permalink structure. Date permalink structure.
525
	 */
526
	public function get_date_permastruct() {
527
		if ( isset($this->date_structure) )
528
			return $this->date_structure;
529
530
		if ( empty($this->permalink_structure) ) {
531
			$this->date_structure = '';
532
			return false;
533
		}
534
535
		// The date permalink must have year, month, and day separated by slashes.
536
		$endians = array('%year%/%monthnum%/%day%', '%day%/%monthnum%/%year%', '%monthnum%/%day%/%year%');
537
538
		$this->date_structure = '';
539
		$date_endian = '';
540
541
		foreach ( $endians as $endian ) {
542
			if ( false !== strpos($this->permalink_structure, $endian) ) {
543
				$date_endian= $endian;
544
				break;
545
			}
546
		}
547
548
		if ( empty($date_endian) )
549
			$date_endian = '%year%/%monthnum%/%day%';
550
551
		/*
552
		 * Do not allow the date tags and %post_id% to overlap in the permalink
553
		 * structure. If they do, move the date tags to $front/date/.
554
		 */
555
		$front = $this->front;
556
		preg_match_all('/%.+?%/', $this->permalink_structure, $tokens);
557
		$tok_index = 1;
558
		foreach ( (array) $tokens[0] as $token) {
559
			if ( '%post_id%' == $token && ($tok_index <= 3) ) {
560
				$front = $front . 'date/';
561
				break;
562
			}
563
			$tok_index++;
564
		}
565
566
		$this->date_structure = $front . $date_endian;
567
568
		return $this->date_structure;
569
	}
570
571
	/**
572
	 * Retrieves the year permalink structure without month and day.
573
	 *
574
	 * Gets the date permalink structure and strips out the month and day
575
	 * permalink structures.
576
	 *
577
	 * @since 1.5.0
578
	 * @access public
579
	 *
580
	 * @return false|string False on failure. Year structure on success.
581
	 */
582
	public function get_year_permastruct() {
583
		$structure = $this->get_date_permastruct();
584
585
		if ( empty($structure) )
586
			return false;
587
588
		$structure = str_replace('%monthnum%', '', $structure);
589
		$structure = str_replace('%day%', '', $structure);
590
		$structure = preg_replace('#/+#', '/', $structure);
591
592
		return $structure;
593
	}
594
595
	/**
596
	 * Retrieves the month permalink structure without day and with year.
597
	 *
598
	 * Gets the date permalink structure and strips out the day permalink
599
	 * structures. Keeps the year permalink structure.
600
	 *
601
	 * @since 1.5.0
602
	 * @access public
603
	 *
604
	 * @return false|string False on failure. Year/Month structure on success.
605
	 */
606
	public function get_month_permastruct() {
607
		$structure = $this->get_date_permastruct();
608
609
		if ( empty($structure) )
610
			return false;
611
612
		$structure = str_replace('%day%', '', $structure);
613
		$structure = preg_replace('#/+#', '/', $structure);
614
615
		return $structure;
616
	}
617
618
	/**
619
	 * Retrieves the day permalink structure with month and year.
620
	 *
621
	 * Keeps date permalink structure with all year, month, and day.
622
	 *
623
	 * @since 1.5.0
624
	 * @access public
625
	 *
626
	 * @return string|false False on failure. Year/Month/Day structure on success.
627
	 */
628
	public function get_day_permastruct() {
629
		return $this->get_date_permastruct();
630
	}
631
632
	/**
633
	 * Retrieves the permalink structure for categories.
634
	 *
635
	 * If the category_base property has no value, then the category structure
636
	 * will have the front property value, followed by 'category', and finally
637
	 * '%category%'. If it does, then the root property will be used, along with
638
	 * the category_base property value.
639
	 *
640
	 * @since 1.5.0
641
	 * @access public
642
	 *
643
	 * @return string|false False on failure. Category permalink structure.
644
	 */
645
	public function get_category_permastruct() {
646
		return $this->get_extra_permastruct('category');
647
	}
648
649
	/**
650
	 * Retrieve the permalink structure for tags.
651
	 *
652
	 * If the tag_base property has no value, then the tag structure will have
653
	 * the front property value, followed by 'tag', and finally '%tag%'. If it
654
	 * does, then the root property will be used, along with the tag_base
655
	 * property value.
656
	 *
657
	 * @since 2.3.0
658
	 * @access public
659
	 *
660
	 * @return string|false False on failure. Tag permalink structure.
661
	 */
662
	public function get_tag_permastruct() {
663
		return $this->get_extra_permastruct('post_tag');
664
	}
665
666
	/**
667
	 * Retrieves an extra permalink structure by name.
668
	 *
669
	 * @since 2.5.0
670
	 * @access public
671
	 *
672
	 * @param string $name Permalink structure name.
673
	 * @return string|false False if not found. Permalink structure string.
674
	 */
675
	public function get_extra_permastruct($name) {
676
		if ( empty($this->permalink_structure) )
677
			return false;
678
679
		if ( isset($this->extra_permastructs[$name]) )
680
			return $this->extra_permastructs[$name]['struct'];
681
682
		return false;
683
	}
684
685
	/**
686
	 * Retrieves the author permalink structure.
687
	 *
688
	 * The permalink structure is front property, author base, and finally
689
	 * '/%author%'. Will set the author_structure property and then return it
690
	 * without attempting to set the value again.
691
	 *
692
	 * @since 1.5.0
693
	 * @access public
694
	 *
695
	 * @return string|false False if not found. Permalink structure string.
696
	 */
697 View Code Duplication
	public function get_author_permastruct() {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
698
		if ( isset($this->author_structure) )
699
			return $this->author_structure;
700
701
		if ( empty($this->permalink_structure) ) {
702
			$this->author_structure = '';
703
			return false;
704
		}
705
706
		$this->author_structure = $this->front . $this->author_base . '/%author%';
707
708
		return $this->author_structure;
709
	}
710
711
	/**
712
	 * Retrieves the search permalink structure.
713
	 *
714
	 * The permalink structure is root property, search base, and finally
715
	 * '/%search%'. Will set the search_structure property and then return it
716
	 * without attempting to set the value again.
717
	 *
718
	 * @since 1.5.0
719
	 * @access public
720
	 *
721
	 * @return string|false False if not found. Permalink structure string.
722
	 */
723 View Code Duplication
	public function get_search_permastruct() {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
724
		if ( isset($this->search_structure) )
725
			return $this->search_structure;
726
727
		if ( empty($this->permalink_structure) ) {
728
			$this->search_structure = '';
729
			return false;
730
		}
731
732
		$this->search_structure = $this->root . $this->search_base . '/%search%';
733
734
		return $this->search_structure;
735
	}
736
737
	/**
738
	 * Retrieves the page permalink structure.
739
	 *
740
	 * The permalink structure is root property, and '%pagename%'. Will set the
741
	 * page_structure property and then return it without attempting to set the
742
	 * value again.
743
	 *
744
	 * @since 1.5.0
745
	 * @access public
746
	 *
747
	 * @return string|false False if not found. Permalink structure string.
748
	 */
749
	public function get_page_permastruct() {
750
		if ( isset($this->page_structure) )
751
			return $this->page_structure;
752
753
		if (empty($this->permalink_structure)) {
754
			$this->page_structure = '';
755
			return false;
756
		}
757
758
		$this->page_structure = $this->root . '%pagename%';
759
760
		return $this->page_structure;
761
	}
762
763
	/**
764
	 * Retrieves the feed permalink structure.
765
	 *
766
	 * The permalink structure is root property, feed base, and finally
767
	 * '/%feed%'. Will set the feed_structure property and then return it
768
	 * without attempting to set the value again.
769
	 *
770
	 * @since 1.5.0
771
	 * @access public
772
	 *
773
	 * @return string|false False if not found. Permalink structure string.
774
	 */
775 View Code Duplication
	public function get_feed_permastruct() {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
776
		if ( isset($this->feed_structure) )
777
			return $this->feed_structure;
778
779
		if ( empty($this->permalink_structure) ) {
780
			$this->feed_structure = '';
781
			return false;
782
		}
783
784
		$this->feed_structure = $this->root . $this->feed_base . '/%feed%';
785
786
		return $this->feed_structure;
787
	}
788
789
	/**
790
	 * Retrieves the comment feed permalink structure.
791
	 *
792
	 * The permalink structure is root property, comment base property, feed
793
	 * base and finally '/%feed%'. Will set the comment_feed_structure property
794
	 * and then return it without attempting to set the value again.
795
	 *
796
	 * @since 1.5.0
797
	 * @access public
798
	 *
799
	 * @return string|false False if not found. Permalink structure string.
800
	 */
801 View Code Duplication
	public function get_comment_feed_permastruct() {
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
802
		if ( isset($this->comment_feed_structure) )
803
			return $this->comment_feed_structure;
804
805
		if (empty($this->permalink_structure)) {
806
			$this->comment_feed_structure = '';
807
			return false;
808
		}
809
810
		$this->comment_feed_structure = $this->root . $this->comments_base . '/' . $this->feed_base . '/%feed%';
811
812
		return $this->comment_feed_structure;
813
	}
814
815
	/**
816
	 * Adds or updates existing rewrite tags (e.g. %postname%).
817
	 *
818
	 * If the tag already exists, replace the existing pattern and query for
819
	 * that tag, otherwise add the new tag.
820
	 *
821
	 * @since 1.5.0
822
	 * @access public
823
	 *
824
	 * @see WP_Rewrite::$rewritecode
825
	 * @see WP_Rewrite::$rewritereplace
826
	 * @see WP_Rewrite::$queryreplace
827
	 *
828
	 * @param string $tag   Name of the rewrite tag to add or update.
829
	 * @param string $regex Regular expression to substitute the tag for in rewrite rules.
830
	 * @param string $query String to append to the rewritten query. Must end in '='.
831
	 */
832
	public function add_rewrite_tag( $tag, $regex, $query ) {
833
		$position = array_search( $tag, $this->rewritecode );
834
		if ( false !== $position && null !== $position ) {
835
			$this->rewritereplace[ $position ] = $regex;
836
			$this->queryreplace[ $position ] = $query;
837
		} else {
838
			$this->rewritecode[] = $tag;
839
			$this->rewritereplace[] = $regex;
840
			$this->queryreplace[] = $query;
841
		}
842
	}
843
844
845
	/**
846
	 * Removes an existing rewrite tag.
847
	 *
848
	 * @since 4.5.0
849
	 * @access public
850
	 *
851
	 * @see WP_Rewrite::$rewritecode
852
	 * @see WP_Rewrite::$rewritereplace
853
	 * @see WP_Rewrite::$queryreplace
854
	 *
855
	 * @param string $tag Name of the rewrite tag to remove.
856
	 */
857
	public function remove_rewrite_tag( $tag ) {
858
		$position = array_search( $tag, $this->rewritecode );
859
		if ( false !== $position && null !== $position ) {
860
			unset( $this->rewritecode[ $position ] );
861
			unset( $this->rewritereplace[ $position ] );
862
			unset( $this->queryreplace[ $position ] );
863
		}
864
	}
865
866
	/**
867
	 * Generates rewrite rules from a permalink structure.
868
	 *
869
	 * The main WP_Rewrite function for building the rewrite rule list. The
870
	 * contents of the function is a mix of black magic and regular expressions,
871
	 * so best just ignore the contents and move to the parameters.
872
	 *
873
	 * @since 1.5.0
874
	 * @access public
875
	 *
876
	 * @param string $permalink_structure The permalink structure.
877
	 * @param int    $ep_mask             Optional. Endpoint mask defining what endpoints are added to the structure.
878
	 *                                    Accepts `EP_NONE`, `EP_PERMALINK`, `EP_ATTACHMENT`, `EP_DATE`, `EP_YEAR`,
879
	 *                                    `EP_MONTH`, `EP_DAY`, `EP_ROOT`, `EP_COMMENTS`, `EP_SEARCH`, `EP_CATEGORIES`,
880
	 *                                    `EP_TAGS`, `EP_AUTHORS`, `EP_PAGES`, `EP_ALL_ARCHIVES`, and `EP_ALL`.
881
	 *                                    Default `EP_NONE`.
882
	 * @param bool   $paged               Optional. Whether archive pagination rules should be added for the structure.
883
	 *                                    Default true.
884
	 * @param bool   $feed                Optional Whether feed rewrite rules should be added for the structure.
885
	 *                                    Default true.
886
	 * @param bool   $forcomments         Optional. Whether the feed rules should be a query for a comments feed.
887
	 *                                    Default false.
888
	 * @param bool   $walk_dirs           Optional. Whether the 'directories' making up the structure should be walked
889
	 *                                    over and rewrite rules built for each in-turn. Default true.
890
	 * @param bool   $endpoints           Optional. Whether endpoints should be applied to the generated rewrite rules.
891
	 *                                    Default true.
892
	 * @return array Rewrite rule list.
893
	 */
894
	public function generate_rewrite_rules($permalink_structure, $ep_mask = EP_NONE, $paged = true, $feed = true, $forcomments = false, $walk_dirs = true, $endpoints = true) {
895
		// Build a regex to match the feed section of URLs, something like (feed|atom|rss|rss2)/?
896
		$feedregex2 = '';
897
		foreach ( (array) $this->feeds as $feed_name)
898
			$feedregex2 .= $feed_name . '|';
899
		$feedregex2 = '(' . trim($feedregex2, '|') . ')/?$';
900
901
		/*
902
		 * $feedregex is identical but with /feed/ added on as well, so URLs like <permalink>/feed/atom
903
		 * and <permalink>/atom are both possible
904
		 */
905
		$feedregex = $this->feed_base . '/' . $feedregex2;
906
907
		// Build a regex to match the trackback and page/xx parts of URLs.
908
		$trackbackregex = 'trackback/?$';
909
		$pageregex = $this->pagination_base . '/?([0-9]{1,})/?$';
910
		$commentregex = $this->comments_pagination_base . '-([0-9]{1,})/?$';
911
		$embedregex = 'embed/?$';
912
913
		// Build up an array of endpoint regexes to append => queries to append.
914
		if ( $endpoints ) {
915
			$ep_query_append = array ();
916
			foreach ( (array) $this->endpoints as $endpoint) {
917
				// Match everything after the endpoint name, but allow for nothing to appear there.
918
				$epmatch = $endpoint[1] . '(/(.*))?/?$';
919
920
				// This will be appended on to the rest of the query for each dir.
921
				$epquery = '&' . $endpoint[2] . '=';
922
				$ep_query_append[$epmatch] = array ( $endpoint[0], $epquery );
923
			}
924
		}
925
926
		// Get everything up to the first rewrite tag.
927
		$front = substr($permalink_structure, 0, strpos($permalink_structure, '%'));
928
929
		// Build an array of the tags (note that said array ends up being in $tokens[0]).
930
		preg_match_all('/%.+?%/', $permalink_structure, $tokens);
931
932
		$num_tokens = count($tokens[0]);
933
934
		$index = $this->index; //probably 'index.php'
935
		$feedindex = $index;
936
		$trackbackindex = $index;
937
		$embedindex = $index;
938
939
		/*
940
		 * Build a list from the rewritecode and queryreplace arrays, that will look something
941
		 * like tagname=$matches[i] where i is the current $i.
942
		 */
943
		$queries = array();
944
		for ( $i = 0; $i < $num_tokens; ++$i ) {
945
			if ( 0 < $i )
946
				$queries[$i] = $queries[$i - 1] . '&';
947
			else
948
				$queries[$i] = '';
949
950
			$query_token = str_replace($this->rewritecode, $this->queryreplace, $tokens[0][$i]) . $this->preg_index($i+1);
951
			$queries[$i] .= $query_token;
952
		}
953
954
		// Get the structure, minus any cruft (stuff that isn't tags) at the front.
955
		$structure = $permalink_structure;
956
		if ( $front != '/' )
957
			$structure = str_replace($front, '', $structure);
958
959
		/*
960
		 * Create a list of dirs to walk over, making rewrite rules for each level
961
		 * so for example, a $structure of /%year%/%monthnum%/%postname% would create
962
		 * rewrite rules for /%year%/, /%year%/%monthnum%/ and /%year%/%monthnum%/%postname%
963
		 */
964
		$structure = trim($structure, '/');
965
		$dirs = $walk_dirs ? explode('/', $structure) : array( $structure );
966
		$num_dirs = count($dirs);
967
968
		// Strip slashes from the front of $front.
969
		$front = preg_replace('|^/+|', '', $front);
970
971
		// The main workhorse loop.
972
		$post_rewrite = array();
973
		$struct = $front;
974
		for ( $j = 0; $j < $num_dirs; ++$j ) {
975
			// Get the struct for this dir, and trim slashes off the front.
976
			$struct .= $dirs[$j] . '/'; // Accumulate. see comment near explode('/', $structure) above.
977
			$struct = ltrim($struct, '/');
978
979
			// Replace tags with regexes.
980
			$match = str_replace($this->rewritecode, $this->rewritereplace, $struct);
981
982
			// Make a list of tags, and store how many there are in $num_toks.
983
			$num_toks = preg_match_all('/%.+?%/', $struct, $toks);
984
985
			// Get the 'tagname=$matches[i]'.
986
			$query = ( ! empty( $num_toks ) && isset( $queries[$num_toks - 1] ) ) ? $queries[$num_toks - 1] : '';
987
988
			// Set up $ep_mask_specific which is used to match more specific URL types.
989
			switch ( $dirs[$j] ) {
990
				case '%year%':
991
					$ep_mask_specific = EP_YEAR;
992
					break;
993
				case '%monthnum%':
994
					$ep_mask_specific = EP_MONTH;
995
					break;
996
				case '%day%':
997
					$ep_mask_specific = EP_DAY;
998
					break;
999
				default:
1000
					$ep_mask_specific = EP_NONE;
1001
			}
1002
1003
			// Create query for /page/xx.
1004
			$pagematch = $match . $pageregex;
1005
			$pagequery = $index . '?' . $query . '&paged=' . $this->preg_index($num_toks + 1);
1006
1007
			// Create query for /comment-page-xx.
1008
			$commentmatch = $match . $commentregex;
1009
			$commentquery = $index . '?' . $query . '&cpage=' . $this->preg_index($num_toks + 1);
1010
1011
			if ( get_option('page_on_front') ) {
1012
				// Create query for Root /comment-page-xx.
1013
				$rootcommentmatch = $match . $commentregex;
1014
				$rootcommentquery = $index . '?' . $query . '&page_id=' . get_option('page_on_front') . '&cpage=' . $this->preg_index($num_toks + 1);
1015
			}
1016
1017
			// Create query for /feed/(feed|atom|rss|rss2|rdf).
1018
			$feedmatch = $match . $feedregex;
1019
			$feedquery = $feedindex . '?' . $query . '&feed=' . $this->preg_index($num_toks + 1);
1020
1021
			// Create query for /(feed|atom|rss|rss2|rdf) (see comment near creation of $feedregex).
1022
			$feedmatch2 = $match . $feedregex2;
1023
			$feedquery2 = $feedindex . '?' . $query . '&feed=' . $this->preg_index($num_toks + 1);
1024
1025
			// Create query and regex for embeds.
1026
			$embedmatch = $match . $embedregex;
1027
			$embedquery = $embedindex . '?' . $query . '&embed=true';
1028
1029
			// If asked to, turn the feed queries into comment feed ones.
1030
			if ( $forcomments ) {
1031
				$feedquery .= '&withcomments=1';
1032
				$feedquery2 .= '&withcomments=1';
1033
			}
1034
1035
			// Start creating the array of rewrites for this dir.
1036
			$rewrite = array();
1037
1038
			// ...adding on /feed/ regexes => queries
1039
			if ( $feed ) {
1040
				$rewrite = array( $feedmatch => $feedquery, $feedmatch2 => $feedquery2, $embedmatch => $embedquery );
1041
			}
1042
1043
			//...and /page/xx ones
1044
			if ( $paged ) {
1045
				$rewrite = array_merge( $rewrite, array( $pagematch => $pagequery ) );
1046
			}
1047
1048
			// Only on pages with comments add ../comment-page-xx/.
1049
			if ( EP_PAGES & $ep_mask || EP_PERMALINK & $ep_mask ) {
1050
				$rewrite = array_merge($rewrite, array($commentmatch => $commentquery));
1051
			} elseif ( EP_ROOT & $ep_mask && get_option('page_on_front') ) {
1052
				$rewrite = array_merge($rewrite, array($rootcommentmatch => $rootcommentquery));
0 ignored issues
show
The variable $rootcommentmatch does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
The variable $rootcommentquery does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1053
			}
1054
1055
			// Do endpoints.
1056
			if ( $endpoints ) {
1057
				foreach ( (array) $ep_query_append as $regex => $ep) {
0 ignored issues
show
The variable $ep_query_append does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1058
					// Add the endpoints on if the mask fits.
1059
					if ( $ep[0] & $ep_mask || $ep[0] & $ep_mask_specific )
1060
						$rewrite[$match . $regex] = $index . '?' . $query . $ep[1] . $this->preg_index($num_toks + 2);
1061
				}
1062
			}
1063
1064
			// If we've got some tags in this dir.
1065
			if ( $num_toks ) {
1066
				$post = false;
1067
				$page = false;
1068
1069
				/*
1070
				 * Check to see if this dir is permalink-level: i.e. the structure specifies an
1071
				 * individual post. Do this by checking it contains at least one of 1) post name,
1072
				 * 2) post ID, 3) page name, 4) timestamp (year, month, day, hour, second and
1073
				 * minute all present). Set these flags now as we need them for the endpoints.
1074
				 */
1075
				if ( strpos($struct, '%postname%') !== false
1076
						|| strpos($struct, '%post_id%') !== false
1077
						|| strpos($struct, '%pagename%') !== false
1078
						|| (strpos($struct, '%year%') !== false && strpos($struct, '%monthnum%') !== false && strpos($struct, '%day%') !== false && strpos($struct, '%hour%') !== false && strpos($struct, '%minute%') !== false && strpos($struct, '%second%') !== false)
1079
						) {
1080
					$post = true;
1081
					if ( strpos($struct, '%pagename%') !== false )
1082
						$page = true;
1083
				}
1084
1085
				if ( ! $post ) {
1086
					// For custom post types, we need to add on endpoints as well.
1087
					foreach ( get_post_types( array('_builtin' => false ) ) as $ptype ) {
1088
						if ( strpos($struct, "%$ptype%") !== false ) {
1089
							$post = true;
1090
1091
							// This is for page style attachment URLs.
1092
							$page = is_post_type_hierarchical( $ptype );
1093
							break;
1094
						}
1095
					}
1096
				}
1097
1098
				// If creating rules for a permalink, do all the endpoints like attachments etc.
1099
				if ( $post ) {
1100
					// Create query and regex for trackback.
1101
					$trackbackmatch = $match . $trackbackregex;
1102
					$trackbackquery = $trackbackindex . '?' . $query . '&tb=1';
1103
1104
					// Create query and regex for embeds.
1105
					$embedmatch = $match . $embedregex;
1106
					$embedquery = $embedindex . '?' . $query . '&embed=true';
1107
1108
					// Trim slashes from the end of the regex for this dir.
1109
					$match = rtrim($match, '/');
1110
1111
					// Get rid of brackets.
1112
					$submatchbase = str_replace( array('(', ')'), '', $match);
1113
1114
					// Add a rule for at attachments, which take the form of <permalink>/some-text.
1115
					$sub1 = $submatchbase . '/([^/]+)/';
1116
1117
					// Add trackback regex <permalink>/trackback/...
1118
					$sub1tb = $sub1 . $trackbackregex;
1119
1120
					// And <permalink>/feed/(atom|...)
1121
					$sub1feed = $sub1 . $feedregex;
1122
1123
					// And <permalink>/(feed|atom...)
1124
					$sub1feed2 = $sub1 . $feedregex2;
1125
1126
					// And <permalink>/comment-page-xx
1127
					$sub1comment = $sub1 . $commentregex;
1128
1129
					// And <permalink>/embed/...
1130
					$sub1embed = $sub1 . $embedregex;
1131
1132
					/*
1133
					 * Add another rule to match attachments in the explicit form:
1134
					 * <permalink>/attachment/some-text
1135
					 */
1136
					$sub2 = $submatchbase . '/attachment/([^/]+)/';
1137
1138
					// And add trackbacks <permalink>/attachment/trackback.
1139
					$sub2tb = $sub2 . $trackbackregex;
1140
1141
					// Feeds, <permalink>/attachment/feed/(atom|...)
1142
					$sub2feed = $sub2 . $feedregex;
1143
1144
					// And feeds again on to this <permalink>/attachment/(feed|atom...)
1145
					$sub2feed2 = $sub2 . $feedregex2;
1146
1147
					// And <permalink>/comment-page-xx
1148
					$sub2comment = $sub2 . $commentregex;
1149
1150
					// And <permalink>/embed/...
1151
					$sub2embed = $sub2 . $embedregex;
1152
1153
					// Create queries for these extra tag-ons we've just dealt with.
1154
					$subquery = $index . '?attachment=' . $this->preg_index(1);
1155
					$subtbquery = $subquery . '&tb=1';
1156
					$subfeedquery = $subquery . '&feed=' . $this->preg_index(2);
1157
					$subcommentquery = $subquery . '&cpage=' . $this->preg_index(2);
1158
					$subembedquery = $subquery . '&embed=true';
1159
1160
					// Do endpoints for attachments.
1161
					if ( !empty($endpoints) ) {
1162
						foreach ( (array) $ep_query_append as $regex => $ep ) {
1163
							if ( $ep[0] & EP_ATTACHMENT ) {
1164
								$rewrite[$sub1 . $regex] = $subquery . $ep[1] . $this->preg_index(3);
1165
								$rewrite[$sub2 . $regex] = $subquery . $ep[1] . $this->preg_index(3);
1166
							}
1167
						}
1168
					}
1169
1170
					/*
1171
					 * Now we've finished with endpoints, finish off the $sub1 and $sub2 matches
1172
					 * add a ? as we don't have to match that last slash, and finally a $ so we
1173
					 * match to the end of the URL
1174
					 */
1175
					$sub1 .= '?$';
1176
					$sub2 .= '?$';
1177
1178
					/*
1179
					 * Post pagination, e.g. <permalink>/2/
1180
					 * Previously: '(/[0-9]+)?/?$', which produced '/2' for page.
1181
					 * When cast to int, returned 0.
1182
					 */
1183
					$match = $match . '(?:/([0-9]+))?/?$';
1184
					$query = $index . '?' . $query . '&page=' . $this->preg_index($num_toks + 1);
1185
1186
				// Not matching a permalink so this is a lot simpler.
1187
				} else {
1188
					// Close the match and finalise the query.
1189
					$match .= '?$';
1190
					$query = $index . '?' . $query;
1191
				}
1192
1193
				/*
1194
				 * Create the final array for this dir by joining the $rewrite array (which currently
1195
				 * only contains rules/queries for trackback, pages etc) to the main regex/query for
1196
				 * this dir
1197
				 */
1198
				$rewrite = array_merge($rewrite, array($match => $query));
1199
1200
				// If we're matching a permalink, add those extras (attachments etc) on.
1201
				if ( $post ) {
1202
					// Add trackback.
1203
					$rewrite = array_merge(array($trackbackmatch => $trackbackquery), $rewrite);
0 ignored issues
show
The variable $trackbackmatch does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
The variable $trackbackquery does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1204
1205
					// Add embed.
1206
					$rewrite = array_merge( array( $embedmatch => $embedquery ), $rewrite );
1207
1208
					// Add regexes/queries for attachments, attachment trackbacks and so on.
1209
					if ( ! $page ) {
1210
						// Require <permalink>/attachment/stuff form for pages because of confusion with subpages.
1211
						$rewrite = array_merge( $rewrite, array(
1212
							$sub1        => $subquery,
0 ignored issues
show
The variable $sub1 does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
The variable $subquery does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1213
							$sub1tb      => $subtbquery,
0 ignored issues
show
The variable $sub1tb does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
The variable $subtbquery does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1214
							$sub1feed    => $subfeedquery,
0 ignored issues
show
The variable $sub1feed does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
The variable $subfeedquery does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1215
							$sub1feed2   => $subfeedquery,
0 ignored issues
show
The variable $sub1feed2 does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1216
							$sub1comment => $subcommentquery,
0 ignored issues
show
The variable $sub1comment does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
The variable $subcommentquery does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1217
							$sub1embed   => $subembedquery
0 ignored issues
show
The variable $sub1embed does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
The variable $subembedquery does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1218
						) );
1219
					}
1220
1221
					$rewrite = array_merge( array( $sub2 => $subquery, $sub2tb => $subtbquery, $sub2feed => $subfeedquery, $sub2feed2 => $subfeedquery, $sub2comment => $subcommentquery, $sub2embed => $subembedquery ), $rewrite );
0 ignored issues
show
The variable $sub2 does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
The variable $sub2tb does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
The variable $sub2feed does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
The variable $sub2feed2 does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
The variable $sub2comment does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
The variable $sub2embed does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1222
				}
1223
			}
1224
			// Add the rules for this dir to the accumulating $post_rewrite.
1225
			$post_rewrite = array_merge($rewrite, $post_rewrite);
1226
		}
1227
1228
		// The finished rules. phew!
1229
		return $post_rewrite;
1230
	}
1231
1232
	/**
1233
	 * Generates rewrite rules with permalink structure and walking directory only.
1234
	 *
1235
	 * Shorten version of WP_Rewrite::generate_rewrite_rules() that allows for shorter
1236
	 * list of parameters. See the method for longer description of what generating
1237
	 * rewrite rules does.
1238
	 *
1239
	 * @since 1.5.0
1240
	 * @access public
1241
	 *
1242
	 * @see WP_Rewrite::generate_rewrite_rules() See for long description and rest of parameters.
1243
	 *
1244
	 * @param string $permalink_structure The permalink structure to generate rules.
1245
	 * @param bool   $walk_dirs           Optional, default is false. Whether to create list of directories to walk over.
1246
	 * @return array
1247
	 */
1248
	public function generate_rewrite_rule($permalink_structure, $walk_dirs = false) {
1249
		return $this->generate_rewrite_rules($permalink_structure, EP_NONE, false, false, false, $walk_dirs);
1250
	}
1251
1252
	/**
1253
	 * Constructs rewrite matches and queries from permalink structure.
1254
	 *
1255
	 * Runs the action {@see 'generate_rewrite_rules'} with the parameter that is an
1256
	 * reference to the current WP_Rewrite instance to further manipulate the
1257
	 * permalink structures and rewrite rules. Runs the {@see 'rewrite_rules_array'}
1258
	 * filter on the full rewrite rule array.
1259
	 *
1260
	 * There are two ways to manipulate the rewrite rules, one by hooking into
1261
	 * the {@see 'generate_rewrite_rules'} action and gaining full control of the
1262
	 * object or just manipulating the rewrite rule array before it is passed
1263
	 * from the function.
1264
	 *
1265
	 * @since 1.5.0
1266
	 * @access public
1267
	 *
1268
	 * @return array An associate array of matches and queries.
1269
	 */
1270
	public function rewrite_rules() {
1271
		$rewrite = array();
1272
1273
		if ( empty($this->permalink_structure) )
1274
			return $rewrite;
1275
1276
		// robots.txt -only if installed at the root
1277
		$home_path = parse_url( home_url() );
1278
		$robots_rewrite = ( empty( $home_path['path'] ) || '/' == $home_path['path'] ) ? array( 'robots\.txt$' => $this->index . '?robots=1' ) : array();
1279
1280
		// Old feed and service files.
1281
		$deprecated_files = array(
1282
			'.*wp-(atom|rdf|rss|rss2|feed|commentsrss2)\.php$' => $this->index . '?feed=old',
1283
			'.*wp-app\.php(/.*)?$' => $this->index . '?error=403',
1284
		);
1285
1286
		// Registration rules.
1287
		$registration_pages = array();
1288
		if ( is_multisite() && is_main_site() ) {
1289
			$registration_pages['.*wp-signup.php$'] = $this->index . '?signup=true';
1290
			$registration_pages['.*wp-activate.php$'] = $this->index . '?activate=true';
1291
		}
1292
1293
		// Deprecated.
1294
		$registration_pages['.*wp-register.php$'] = $this->index . '?register=true';
1295
1296
		// Post rewrite rules.
1297
		$post_rewrite = $this->generate_rewrite_rules( $this->permalink_structure, EP_PERMALINK );
1298
1299
		/**
1300
		 * Filters rewrite rules used for "post" archives.
1301
		 *
1302
		 * @since 1.5.0
1303
		 *
1304
		 * @param array $post_rewrite The rewrite rules for posts.
1305
		 */
1306
		$post_rewrite = apply_filters( 'post_rewrite_rules', $post_rewrite );
1307
1308
		// Date rewrite rules.
1309
		$date_rewrite = $this->generate_rewrite_rules($this->get_date_permastruct(), EP_DATE);
0 ignored issues
show
It seems like $this->get_date_permastruct() targeting WP_Rewrite::get_date_permastruct() can also be of type false; however, WP_Rewrite::generate_rewrite_rules() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
1310
1311
		/**
1312
		 * Filters rewrite rules used for date archives.
1313
		 *
1314
		 * Likely date archives would include /yyyy/, /yyyy/mm/, and /yyyy/mm/dd/.
1315
		 *
1316
		 * @since 1.5.0
1317
		 *
1318
		 * @param array $date_rewrite The rewrite rules for date archives.
1319
		 */
1320
		$date_rewrite = apply_filters( 'date_rewrite_rules', $date_rewrite );
1321
1322
		// Root-level rewrite rules.
1323
		$root_rewrite = $this->generate_rewrite_rules($this->root . '/', EP_ROOT);
1324
1325
		/**
1326
		 * Filters rewrite rules used for root-level archives.
1327
		 *
1328
		 * Likely root-level archives would include pagination rules for the homepage
1329
		 * as well as site-wide post feeds (e.g. /feed/, and /feed/atom/).
1330
		 *
1331
		 * @since 1.5.0
1332
		 *
1333
		 * @param array $root_rewrite The root-level rewrite rules.
1334
		 */
1335
		$root_rewrite = apply_filters( 'root_rewrite_rules', $root_rewrite );
1336
1337
		// Comments rewrite rules.
1338
		$comments_rewrite = $this->generate_rewrite_rules($this->root . $this->comments_base, EP_COMMENTS, false, true, true, false);
1339
1340
		/**
1341
		 * Filters rewrite rules used for comment feed archives.
1342
		 *
1343
		 * Likely comments feed archives include /comments/feed/, and /comments/feed/atom/.
1344
		 *
1345
		 * @since 1.5.0
1346
		 *
1347
		 * @param array $comments_rewrite The rewrite rules for the site-wide comments feeds.
1348
		 */
1349
		$comments_rewrite = apply_filters( 'comments_rewrite_rules', $comments_rewrite );
1350
1351
		// Search rewrite rules.
1352
		$search_structure = $this->get_search_permastruct();
1353
		$search_rewrite = $this->generate_rewrite_rules($search_structure, EP_SEARCH);
0 ignored issues
show
It seems like $search_structure defined by $this->get_search_permastruct() on line 1352 can also be of type false; however, WP_Rewrite::generate_rewrite_rules() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
1354
1355
		/**
1356
		 * Filters rewrite rules used for search archives.
1357
		 *
1358
		 * Likely search-related archives include /search/search+query/ as well as
1359
		 * pagination and feed paths for a search.
1360
		 *
1361
		 * @since 1.5.0
1362
		 *
1363
		 * @param array $search_rewrite The rewrite rules for search queries.
1364
		 */
1365
		$search_rewrite = apply_filters( 'search_rewrite_rules', $search_rewrite );
1366
1367
		// Author rewrite rules.
1368
		$author_rewrite = $this->generate_rewrite_rules($this->get_author_permastruct(), EP_AUTHORS);
0 ignored issues
show
It seems like $this->get_author_permastruct() targeting WP_Rewrite::get_author_permastruct() can also be of type false; however, WP_Rewrite::generate_rewrite_rules() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
1369
1370
		/**
1371
		 * Filters rewrite rules used for author archives.
1372
		 *
1373
		 * Likely author archives would include /author/author-name/, as well as
1374
		 * pagination and feed paths for author archives.
1375
		 *
1376
		 * @since 1.5.0
1377
		 *
1378
		 * @param array $author_rewrite The rewrite rules for author archives.
1379
		 */
1380
		$author_rewrite = apply_filters( 'author_rewrite_rules', $author_rewrite );
1381
1382
		// Pages rewrite rules.
1383
		$page_rewrite = $this->page_rewrite_rules();
1384
1385
		/**
1386
		 * Filters rewrite rules used for "page" post type archives.
1387
		 *
1388
		 * @since 1.5.0
1389
		 *
1390
		 * @param array $page_rewrite The rewrite rules for the "page" post type.
1391
		 */
1392
		$page_rewrite = apply_filters( 'page_rewrite_rules', $page_rewrite );
1393
1394
		// Extra permastructs.
1395
		foreach ( $this->extra_permastructs as $permastructname => $struct ) {
1396
			if ( is_array( $struct ) ) {
1397
				if ( count( $struct ) == 2 )
1398
					$rules = $this->generate_rewrite_rules( $struct[0], $struct[1] );
1399
				else
1400
					$rules = $this->generate_rewrite_rules( $struct['struct'], $struct['ep_mask'], $struct['paged'], $struct['feed'], $struct['forcomments'], $struct['walk_dirs'], $struct['endpoints'] );
1401
			} else {
1402
				$rules = $this->generate_rewrite_rules( $struct );
1403
			}
1404
1405
			/**
1406
			 * Filters rewrite rules used for individual permastructs.
1407
			 *
1408
			 * The dynamic portion of the hook name, `$permastructname`, refers
1409
			 * to the name of the registered permastruct, e.g. 'post_tag' (tags),
1410
			 * 'category' (categories), etc.
1411
			 *
1412
			 * @since 3.1.0
1413
			 *
1414
			 * @param array $rules The rewrite rules generated for the current permastruct.
1415
			 */
1416
			$rules = apply_filters( "{$permastructname}_rewrite_rules", $rules );
1417
			if ( 'post_tag' == $permastructname ) {
1418
1419
				/**
1420
				 * Filters rewrite rules used specifically for Tags.
1421
				 *
1422
				 * @since 2.3.0
1423
				 * @deprecated 3.1.0 Use 'post_tag_rewrite_rules' instead
1424
				 *
1425
				 * @param array $rules The rewrite rules generated for tags.
1426
				 */
1427
				$rules = apply_filters( 'tag_rewrite_rules', $rules );
1428
			}
1429
1430
			$this->extra_rules_top = array_merge($this->extra_rules_top, $rules);
1431
		}
1432
1433
		// Put them together.
1434
		if ( $this->use_verbose_page_rules )
1435
			$this->rules = array_merge($this->extra_rules_top, $robots_rewrite, $deprecated_files, $registration_pages, $root_rewrite, $comments_rewrite, $search_rewrite,  $author_rewrite, $date_rewrite, $page_rewrite, $post_rewrite, $this->extra_rules);
1436
		else
1437
			$this->rules = array_merge($this->extra_rules_top, $robots_rewrite, $deprecated_files, $registration_pages, $root_rewrite, $comments_rewrite, $search_rewrite,  $author_rewrite, $date_rewrite, $post_rewrite, $page_rewrite, $this->extra_rules);
1438
1439
		/**
1440
		 * Fires after the rewrite rules are generated.
1441
		 *
1442
		 * @since 1.5.0
1443
		 *
1444
		 * @param WP_Rewrite $this Current WP_Rewrite instance, passed by reference.
1445
		 */
1446
		do_action_ref_array( 'generate_rewrite_rules', array( &$this ) );
1447
1448
		/**
1449
		 * Filters the full set of generated rewrite rules.
1450
		 *
1451
		 * @since 1.5.0
1452
		 *
1453
		 * @param array $this->rules The compiled array of rewrite rules.
1454
		 */
1455
		$this->rules = apply_filters( 'rewrite_rules_array', $this->rules );
0 ignored issues
show
Documentation Bug introduced by
It seems like apply_filters('rewrite_r...s_array', $this->rules) of type * is incompatible with the declared type array of property $rules.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1456
1457
		return $this->rules;
1458
	}
1459
1460
	/**
1461
	 * Retrieves the rewrite rules.
1462
	 *
1463
	 * The difference between this method and WP_Rewrite::rewrite_rules() is that
1464
	 * this method stores the rewrite rules in the 'rewrite_rules' option and retrieves
1465
	 * it. This prevents having to process all of the permalinks to get the rewrite rules
1466
	 * in the form of caching.
1467
	 *
1468
	 * @since 1.5.0
1469
	 * @access public
1470
	 *
1471
	 * @return array Rewrite rules.
1472
	 */
1473
	public function wp_rewrite_rules() {
1474
		$this->rules = get_option('rewrite_rules');
0 ignored issues
show
Documentation Bug introduced by
It seems like get_option('rewrite_rules') of type * is incompatible with the declared type array of property $rules.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
1475
		if ( empty($this->rules) ) {
1476
			$this->matches = 'matches';
1477
			$this->rewrite_rules();
1478
			update_option('rewrite_rules', $this->rules);
1479
		}
1480
1481
		return $this->rules;
1482
	}
1483
1484
	/**
1485
	 * Retrieves mod_rewrite-formatted rewrite rules to write to .htaccess.
1486
	 *
1487
	 * Does not actually write to the .htaccess file, but creates the rules for
1488
	 * the process that will.
1489
	 *
1490
	 * Will add the non_wp_rules property rules to the .htaccess file before
1491
	 * the WordPress rewrite rules one.
1492
	 *
1493
	 * @since 1.5.0
1494
	 * @access public
1495
	 *
1496
	 * @return string
1497
	 */
1498
	public function mod_rewrite_rules() {
1499
		if ( ! $this->using_permalinks() )
1500
			return '';
1501
1502
		$site_root = parse_url( site_url() );
1503
		if ( isset( $site_root['path'] ) )
1504
			$site_root = trailingslashit($site_root['path']);
1505
1506
		$home_root = parse_url(home_url());
1507
		if ( isset( $home_root['path'] ) )
1508
			$home_root = trailingslashit($home_root['path']);
1509
		else
1510
			$home_root = '/';
1511
1512
		$rules = "<IfModule mod_rewrite.c>\n";
1513
		$rules .= "RewriteEngine On\n";
1514
		$rules .= "RewriteBase $home_root\n";
1515
1516
		// Prevent -f checks on index.php.
1517
		$rules .= "RewriteRule ^index\.php$ - [L]\n";
1518
1519
		// Add in the rules that don't redirect to WP's index.php (and thus shouldn't be handled by WP at all).
1520
		foreach ( (array) $this->non_wp_rules as $match => $query) {
1521
			// Apache 1.3 does not support the reluctant (non-greedy) modifier.
1522
			$match = str_replace('.+?', '.+', $match);
1523
1524
			$rules .= 'RewriteRule ^' . $match . ' ' . $home_root . $query . " [QSA,L]\n";
1525
		}
1526
1527
		if ( $this->use_verbose_rules ) {
1528
			$this->matches = '';
1529
			$rewrite = $this->rewrite_rules();
1530
			$num_rules = count($rewrite);
1531
			$rules .= "RewriteCond %{REQUEST_FILENAME} -f [OR]\n" .
1532
				"RewriteCond %{REQUEST_FILENAME} -d\n" .
1533
				"RewriteRule ^.*$ - [S=$num_rules]\n";
1534
1535
			foreach ( (array) $rewrite as $match => $query) {
1536
				// Apache 1.3 does not support the reluctant (non-greedy) modifier.
1537
				$match = str_replace('.+?', '.+', $match);
1538
1539
				if ( strpos($query, $this->index) !== false )
1540
					$rules .= 'RewriteRule ^' . $match . ' ' . $home_root . $query . " [QSA,L]\n";
1541
				else
1542
					$rules .= 'RewriteRule ^' . $match . ' ' . $site_root . $query . " [QSA,L]\n";
1543
			}
1544
		} else {
1545
			$rules .= "RewriteCond %{REQUEST_FILENAME} !-f\n" .
1546
				"RewriteCond %{REQUEST_FILENAME} !-d\n" .
1547
				"RewriteRule . {$home_root}{$this->index} [L]\n";
1548
		}
1549
1550
		$rules .= "</IfModule>\n";
1551
1552
		/**
1553
		 * Filters the list of rewrite rules formatted for output to an .htaccess file.
1554
		 *
1555
		 * @since 1.5.0
1556
		 *
1557
		 * @param string $rules mod_rewrite Rewrite rules formatted for .htaccess.
1558
		 */
1559
		$rules = apply_filters( 'mod_rewrite_rules', $rules );
1560
1561
		/**
1562
		 * Filters the list of rewrite rules formatted for output to an .htaccess file.
1563
		 *
1564
		 * @since 1.5.0
1565
		 * @deprecated 1.5.0 Use the mod_rewrite_rules filter instead.
1566
		 *
1567
		 * @param string $rules mod_rewrite Rewrite rules formatted for .htaccess.
1568
		 */
1569
		return apply_filters( 'rewrite_rules', $rules );
1570
	}
1571
1572
	/**
1573
	 * Retrieves IIS7 URL Rewrite formatted rewrite rules to write to web.config file.
1574
	 *
1575
	 * Does not actually write to the web.config file, but creates the rules for
1576
	 * the process that will.
1577
	 *
1578
	 * @since 2.8.0
1579
	 * @access public
1580
	 *
1581
	 * @param bool $add_parent_tags Optional. Whether to add parent tags to the rewrite rule sets.
1582
	 *                              Default false.
1583
	 * @return string IIS7 URL rewrite rule sets.
1584
	 */
1585
	public function iis7_url_rewrite_rules( $add_parent_tags = false ) {
1586
		if ( ! $this->using_permalinks() )
1587
			return '';
1588
		$rules = '';
1589
		if ( $add_parent_tags ) {
1590
			$rules .= '<configuration>
1591
	<system.webServer>
1592
		<rewrite>
1593
			<rules>';
1594
		}
1595
1596
		$rules .= '
1597
			<rule name="WordPress: ' . esc_attr( home_url() ) . '" patternSyntax="Wildcard">
1598
				<match url="*" />
1599
					<conditions>
1600
						<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
1601
						<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
1602
					</conditions>
1603
				<action type="Rewrite" url="index.php" />
1604
			</rule>';
1605
1606
		if ( $add_parent_tags ) {
1607
			$rules .= '
1608
			</rules>
1609
		</rewrite>
1610
	</system.webServer>
1611
</configuration>';
1612
		}
1613
1614
		/**
1615
		 * Filters the list of rewrite rules formatted for output to a web.config.
1616
		 *
1617
		 * @since 2.8.0
1618
		 *
1619
		 * @param string $rules Rewrite rules formatted for IIS web.config.
1620
		 */
1621
		return apply_filters( 'iis7_url_rewrite_rules', $rules );
1622
	}
1623
1624
	/**
1625
	 * Adds a rewrite rule that transforms a URL structure to a set of query vars.
1626
	 *
1627
	 * Any value in the $after parameter that isn't 'bottom' will result in the rule
1628
	 * being placed at the top of the rewrite rules.
1629
	 *
1630
	 * @since 2.1.0
1631
	 * @since 4.4.0 Array support was added to the `$query` parameter.
1632
	 * @access public
1633
	 *
1634
	 * @param string       $regex Regular expression to match request against.
1635
	 * @param string|array $query The corresponding query vars for this rewrite rule.
1636
	 * @param string       $after Optional. Priority of the new rule. Accepts 'top'
1637
	 *                            or 'bottom'. Default 'bottom'.
1638
	 */
1639
	public function add_rule( $regex, $query, $after = 'bottom' ) {
1640
		if ( is_array( $query ) ) {
1641
			$external = false;
1642
			$query = add_query_arg( $query, 'index.php' );
1643
		} else {
1644
			$index = false === strpos( $query, '?' ) ? strlen( $query ) : strpos( $query, '?' );
1645
			$front = substr( $query, 0, $index );
1646
1647
			$external = $front != $this->index;
1648
		}
1649
1650
		// "external" = it doesn't correspond to index.php.
1651
		if ( $external ) {
1652
			$this->add_external_rule( $regex, $query );
1653
		} else {
1654
			if ( 'bottom' == $after ) {
1655
				$this->extra_rules = array_merge( $this->extra_rules, array( $regex => $query ) );
1656
			} else {
1657
				$this->extra_rules_top = array_merge( $this->extra_rules_top, array( $regex => $query ) );
1658
			}
1659
		}
1660
	}
1661
1662
	/**
1663
	 * Adds a rewrite rule that doesn't correspond to index.php.
1664
	 *
1665
	 * @since 2.1.0
1666
	 * @access public
1667
	 *
1668
	 * @param string $regex Regular expression to match request against.
1669
	 * @param string $query The corresponding query vars for this rewrite rule.
1670
	 */
1671
	public function add_external_rule( $regex, $query ) {
1672
		$this->non_wp_rules[ $regex ] = $query;
1673
	}
1674
1675
	/**
1676
	 * Adds an endpoint, like /trackback/.
1677
	 *
1678
	 * @since 2.1.0
1679
	 * @since 3.9.0 $query_var parameter added.
1680
	 * @since 4.3.0 Added support for skipping query var registration by passing `false` to `$query_var`.
1681
	 * @access public
1682
	 *
1683
	 * @see add_rewrite_endpoint() for full documentation.
1684
	 * @global WP $wp
1685
	 *
1686
	 * @param string      $name      Name of the endpoint.
1687
	 * @param int         $places    Endpoint mask describing the places the endpoint should be added.
1688
	 * @param string|bool $query_var Optional. Name of the corresponding query variable. Pass `false` to
1689
	 *                               skip registering a query_var for this endpoint. Defaults to the
1690
	 *                               value of `$name`.
1691
	 */
1692
	public function add_endpoint( $name, $places, $query_var = true ) {
1693
		global $wp;
1694
1695
		// For backward compatibility, if null has explicitly been passed as `$query_var`, assume `true`.
1696
		if ( true === $query_var || null === func_get_arg( 2 ) ) {
1697
			$query_var = $name;
1698
		}
1699
		$this->endpoints[] = array( $places, $name, $query_var );
1700
1701
		if ( $query_var ) {
1702
			$wp->add_query_var( $query_var );
1703
		}
1704
	}
1705
1706
	/**
1707
	 * Adds a new permalink structure.
1708
	 *
1709
	 * A permalink structure (permastruct) is an abstract definition of a set of rewrite rules;
1710
	 * it is an easy way of expressing a set of regular expressions that rewrite to a set of
1711
	 * query strings. The new permastruct is added to the WP_Rewrite::$extra_permastructs array.
1712
	 *
1713
	 * When the rewrite rules are built by WP_Rewrite::rewrite_rules(), all of these extra
1714
	 * permastructs are passed to WP_Rewrite::generate_rewrite_rules() which transforms them
1715
	 * into the regular expressions that many love to hate.
1716
	 *
1717
	 * The `$args` parameter gives you control over how WP_Rewrite::generate_rewrite_rules()
1718
	 * works on the new permastruct.
1719
	 *
1720
	 * @since 2.5.0
1721
	 * @access public
1722
	 *
1723
	 * @param string $name   Name for permalink structure.
1724
	 * @param string $struct Permalink structure (e.g. category/%category%)
1725
	 * @param array  $args   {
1726
	 *     Optional. Arguments for building rewrite rules based on the permalink structure.
1727
	 *     Default empty array.
1728
	 *
1729
	 *     @type bool $with_front  Whether the structure should be prepended with `WP_Rewrite::$front`.
1730
	 *                             Default true.
1731
	 *     @type int  $ep_mask     The endpoint mask defining which endpoints are added to the structure.
1732
	 *                             Accepts `EP_NONE`, `EP_PERMALINK`, `EP_ATTACHMENT`, `EP_DATE`, `EP_YEAR`,
1733
	 *                             `EP_MONTH`, `EP_DAY`, `EP_ROOT`, `EP_COMMENTS`, `EP_SEARCH`, `EP_CATEGORIES`,
1734
	 *                             `EP_TAGS`, `EP_AUTHORS`, `EP_PAGES`, `EP_ALL_ARCHIVES`, and `EP_ALL`.
1735
	 *                             Default `EP_NONE`.
1736
	 *     @type bool $paged       Whether archive pagination rules should be added for the structure.
1737
	 *                             Default true.
1738
	 *     @type bool $feed        Whether feed rewrite rules should be added for the structure. Default true.
1739
	 *     @type bool $forcomments Whether the feed rules should be a query for a comments feed. Default false.
1740
	 *     @type bool $walk_dirs   Whether the 'directories' making up the structure should be walked over
1741
	 *                             and rewrite rules built for each in-turn. Default true.
1742
	 *     @type bool $endpoints   Whether endpoints should be applied to the generated rules. Default true.
1743
	 * }
1744
	 */
1745
	public function add_permastruct( $name, $struct, $args = array() ) {
1746
		// Back-compat for the old parameters: $with_front and $ep_mask.
1747
		if ( ! is_array( $args ) )
1748
			$args = array( 'with_front' => $args );
1749
		if ( func_num_args() == 4 )
1750
			$args['ep_mask'] = func_get_arg( 3 );
1751
1752
		$defaults = array(
1753
			'with_front' => true,
1754
			'ep_mask' => EP_NONE,
1755
			'paged' => true,
1756
			'feed' => true,
1757
			'forcomments' => false,
1758
			'walk_dirs' => true,
1759
			'endpoints' => true,
1760
		);
1761
		$args = array_intersect_key( $args, $defaults );
1762
		$args = wp_parse_args( $args, $defaults );
1763
1764
		if ( $args['with_front'] )
1765
			$struct = $this->front . $struct;
1766
		else
1767
			$struct = $this->root . $struct;
1768
		$args['struct'] = $struct;
1769
1770
		$this->extra_permastructs[ $name ] = $args;
1771
	}
1772
1773
	/**
1774
	 * Removes a permalink structure.
1775
	 *
1776
	 * @since 4.5.0
1777
	 * @access public
1778
	 *
1779
	 * @param string $name Name for permalink structure.
1780
	 */
1781
	public function remove_permastruct( $name ) {
1782
		unset( $this->extra_permastructs[ $name ] );
1783
	}
1784
1785
	/**
1786
	 * Removes rewrite rules and then recreate rewrite rules.
1787
	 *
1788
	 * Calls WP_Rewrite::wp_rewrite_rules() after removing the 'rewrite_rules' option.
1789
	 * If the function named 'save_mod_rewrite_rules' exists, it will be called.
1790
	 *
1791
	 * @since 2.0.1
1792
	 * @access public
1793
	 *
1794
	 * @staticvar bool $do_hard_later
1795
	 *
1796
	 * @param bool $hard Whether to update .htaccess (hard flush) or just update rewrite_rules option (soft flush). Default is true (hard).
1797
	 */
1798
	public function flush_rules( $hard = true ) {
1799
		static $do_hard_later = null;
1800
1801
		// Prevent this action from running before everyone has registered their rewrites.
1802
		if ( ! did_action( 'wp_loaded' ) ) {
1803
			add_action( 'wp_loaded', array( $this, 'flush_rules' ) );
1804
			$do_hard_later = ( isset( $do_hard_later ) ) ? $do_hard_later || $hard : $hard;
1805
			return;
1806
		}
1807
1808
		if ( isset( $do_hard_later ) ) {
1809
			$hard = $do_hard_later;
1810
			unset( $do_hard_later );
1811
		}
1812
1813
		update_option( 'rewrite_rules', '' );
1814
		$this->wp_rewrite_rules();
1815
1816
		/**
1817
		 * Filters whether a "hard" rewrite rule flush should be performed when requested.
1818
		 *
1819
		 * A "hard" flush updates .htaccess (Apache) or web.config (IIS).
1820
		 *
1821
		 * @since 3.7.0
1822
		 *
1823
		 * @param bool $hard Whether to flush rewrite rules "hard". Default true.
1824
		 */
1825
		if ( ! $hard || ! apply_filters( 'flush_rewrite_rules_hard', true ) ) {
1826
			return;
1827
		}
1828
		if ( function_exists( 'save_mod_rewrite_rules' ) )
1829
			save_mod_rewrite_rules();
1830
		if ( function_exists( 'iis7_save_url_rewrite_rules' ) )
1831
			iis7_save_url_rewrite_rules();
1832
	}
1833
1834
	/**
1835
	 * Sets up the object's properties.
1836
	 *
1837
	 * The 'use_verbose_page_rules' object property will be set to true if the
1838
	 * permalink structure begins with one of the following: '%postname%', '%category%',
1839
	 * '%tag%', or '%author%'.
1840
	 *
1841
	 * @since 1.5.0
1842
	 * @access public
1843
	 */
1844
	public function init() {
1845
		$this->extra_rules = $this->non_wp_rules = $this->endpoints = array();
1846
		$this->permalink_structure = get_option('permalink_structure');
1847
		$this->front = substr($this->permalink_structure, 0, strpos($this->permalink_structure, '%'));
1848
		$this->root = '';
1849
1850
		if ( $this->using_index_permalinks() )
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->using_index_permalinks() of type false|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1851
			$this->root = $this->index . '/';
1852
1853
		unset($this->author_structure);
1854
		unset($this->date_structure);
1855
		unset($this->page_structure);
1856
		unset($this->search_structure);
1857
		unset($this->feed_structure);
1858
		unset($this->comment_feed_structure);
1859
		$this->use_trailing_slashes = ( '/' == substr($this->permalink_structure, -1, 1) );
1860
1861
		// Enable generic rules for pages if permalink structure doesn't begin with a wildcard.
1862
		if ( preg_match("/^[^%]*%(?:postname|category|tag|author)%/", $this->permalink_structure) )
1863
			 $this->use_verbose_page_rules = true;
1864
		else
1865
			$this->use_verbose_page_rules = false;
1866
	}
1867
1868
	/**
1869
	 * Sets the main permalink structure for the site.
1870
	 *
1871
	 * Will update the 'permalink_structure' option, if there is a difference
1872
	 * between the current permalink structure and the parameter value. Calls
1873
	 * WP_Rewrite::init() after the option is updated.
1874
	 *
1875
	 * Fires the {@see 'permalink_structure_changed'} action once the init call has
1876
	 * processed passing the old and new values
1877
	 *
1878
	 * @since 1.5.0
1879
	 * @access public
1880
	 *
1881
	 * @param string $permalink_structure Permalink structure.
1882
	 */
1883
	public function set_permalink_structure($permalink_structure) {
1884
		if ( $permalink_structure != $this->permalink_structure ) {
1885
			$old_permalink_structure = $this->permalink_structure;
1886
			update_option('permalink_structure', $permalink_structure);
1887
1888
			$this->init();
1889
1890
			/**
1891
			 * Fires after the permalink structure is updated.
1892
			 *
1893
			 * @since 2.8.0
1894
			 *
1895
			 * @param string $old_permalink_structure The previous permalink structure.
1896
			 * @param string $permalink_structure     The new permalink structure.
1897
			 */
1898
			do_action( 'permalink_structure_changed', $old_permalink_structure, $permalink_structure );
1899
		}
1900
	}
1901
1902
	/**
1903
	 * Sets the category base for the category permalink.
1904
	 *
1905
	 * Will update the 'category_base' option, if there is a difference between
1906
	 * the current category base and the parameter value. Calls WP_Rewrite::init()
1907
	 * after the option is updated.
1908
	 *
1909
	 * @since 1.5.0
1910
	 * @access public
1911
	 *
1912
	 * @param string $category_base Category permalink structure base.
1913
	 */
1914
	public function set_category_base($category_base) {
1915
		if ( $category_base != get_option('category_base') ) {
1916
			update_option('category_base', $category_base);
1917
			$this->init();
1918
		}
1919
	}
1920
1921
	/**
1922
	 * Sets the tag base for the tag permalink.
1923
	 *
1924
	 * Will update the 'tag_base' option, if there is a difference between the
1925
	 * current tag base and the parameter value. Calls WP_Rewrite::init() after
1926
	 * the option is updated.
1927
	 *
1928
	 * @since 2.3.0
1929
	 * @access public
1930
	 *
1931
	 * @param string $tag_base Tag permalink structure base.
1932
	 */
1933
	public function set_tag_base( $tag_base ) {
1934
		if ( $tag_base != get_option( 'tag_base') ) {
1935
			update_option( 'tag_base', $tag_base );
1936
			$this->init();
1937
		}
1938
	}
1939
1940
	/**
1941
	 * Constructor - Calls init(), which runs setup.
1942
	 *
1943
	 * @since 1.5.0
1944
	 * @access public
1945
	 *
1946
	 */
1947
	public function __construct() {
1948
		$this->init();
1949
	}
1950
}
1951