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/post-template.php (22 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
 * WordPress Post Template Functions.
4
 *
5
 * Gets content for the current post in the loop.
6
 *
7
 * @package WordPress
8
 * @subpackage Template
9
 */
10
11
/**
12
 * Display the ID of the current item in the WordPress Loop.
13
 *
14
 * @since 0.71
15
 */
16
function the_ID() {
17
	echo get_the_ID();
18
}
19
20
/**
21
 * Retrieve the ID of the current item in the WordPress Loop.
22
 *
23
 * @since 2.1.0
24
 *
25
 * @return int|false The ID of the current item in the WordPress Loop. False if $post is not set.
26
 */
27
function get_the_ID() {
28
	$post = get_post();
29
	return ! empty( $post ) ? $post->ID : false;
30
}
31
32
/**
33
 * Display or retrieve the current post title with optional content.
34
 *
35
 * @since 0.71
36
 *
37
 * @param string $before Optional. Content to prepend to the title.
38
 * @param string $after  Optional. Content to append to the title.
39
 * @param bool   $echo   Optional, default to true.Whether to display or return.
40
 * @return string|void String if $echo parameter is false.
41
 */
42
function the_title( $before = '', $after = '', $echo = true ) {
43
	$title = get_the_title();
44
45
	if ( strlen($title) == 0 )
46
		return;
47
48
	$title = $before . $title . $after;
49
50
	if ( $echo )
51
		echo $title;
52
	else
53
		return $title;
54
}
55
56
/**
57
 * Sanitize the current title when retrieving or displaying.
58
 *
59
 * Works like the_title(), except the parameters can be in a string or
60
 * an array. See the function for what can be override in the $args parameter.
61
 *
62
 * The title before it is displayed will have the tags stripped and esc_attr()
63
 * before it is passed to the user or displayed. The default as with the_title(),
64
 * is to display the title.
65
 *
66
 * @since 2.3.0
67
 *
68
 * @param string|array $args {
69
 *     Title attribute arguments. Optional.
70
 *
71
 *     @type string  $before Markup to prepend to the title. Default empty.
72
 *     @type string  $after  Markup to append to the title. Default empty.
73
 *     @type bool    $echo   Whether to echo or return the title. Default true for echo.
74
 *     @type WP_Post $post   Current post object to retrieve the title for.
75
 * }
76
 * @return string|void String when echo is false.
77
 */
78
function the_title_attribute( $args = '' ) {
79
	$defaults = array( 'before' => '', 'after' =>  '', 'echo' => true, 'post' => get_post() );
80
	$r = wp_parse_args( $args, $defaults );
81
82
	$title = get_the_title( $r['post'] );
83
84
	if ( strlen( $title ) == 0 ) {
85
		return;
86
	}
87
88
	$title = $r['before'] . $title . $r['after'];
89
	$title = esc_attr( strip_tags( $title ) );
90
91
	if ( $r['echo'] ) {
92
		echo $title;
93
	} else {
94
		return $title;
95
	}
96
}
97
98
/**
99
 * Retrieve post title.
100
 *
101
 * If the post is protected and the visitor is not an admin, then "Protected"
102
 * will be displayed before the post title. If the post is private, then
103
 * "Private" will be located before the post title.
104
 *
105
 * @since 0.71
106
 *
107
 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
108
 * @return string
109
 */
110
function get_the_title( $post = 0 ) {
111
	$post = get_post( $post );
112
113
	$title = isset( $post->post_title ) ? $post->post_title : '';
114
	$id = isset( $post->ID ) ? $post->ID : 0;
115
116
	if ( ! is_admin() ) {
117
		if ( ! empty( $post->post_password ) ) {
118
119
			/**
120
			 * Filters the text prepended to the post title for protected posts.
121
			 *
122
			 * The filter is only applied on the front end.
123
			 *
124
			 * @since 2.8.0
125
			 *
126
			 * @param string  $prepend Text displayed before the post title.
127
			 *                         Default 'Protected: %s'.
128
			 * @param WP_Post $post    Current post object.
129
			 */
130
			$protected_title_format = apply_filters( 'protected_title_format', __( 'Protected: %s' ), $post );
131
			$title = sprintf( $protected_title_format, $title );
132
		} elseif ( isset( $post->post_status ) && 'private' == $post->post_status ) {
133
134
			/**
135
			 * Filters the text prepended to the post title of private posts.
136
			 *
137
			 * The filter is only applied on the front end.
138
			 *
139
			 * @since 2.8.0
140
			 *
141
			 * @param string  $prepend Text displayed before the post title.
142
			 *                         Default 'Private: %s'.
143
			 * @param WP_Post $post    Current post object.
144
			 */
145
			$private_title_format = apply_filters( 'private_title_format', __( 'Private: %s' ), $post );
146
			$title = sprintf( $private_title_format, $title );
147
		}
148
	}
149
150
	/**
151
	 * Filters the post title.
152
	 *
153
	 * @since 0.71
154
	 *
155
	 * @param string $title The post title.
156
	 * @param int    $id    The post ID.
157
	 */
158
	return apply_filters( 'the_title', $title, $id );
159
}
160
161
/**
162
 * Display the Post Global Unique Identifier (guid).
163
 *
164
 * The guid will appear to be a link, but should not be used as a link to the
165
 * post. The reason you should not use it as a link, is because of moving the
166
 * blog across domains.
167
 *
168
 * URL is escaped to make it XML-safe.
169
 *
170
 * @since 1.5.0
171
 *
172
 * @param int|WP_Post $post Optional. Post ID or post object. Default is global $post.
173
 */
174 View Code Duplication
function the_guid( $post = 0 ) {
0 ignored issues
show
This function 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...
175
	$post = get_post( $post );
176
177
	$guid = isset( $post->guid ) ? get_the_guid( $post ) : '';
0 ignored issues
show
$post is of type object<WP_Post>|array, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
178
	$id   = isset( $post->ID ) ? $post->ID : 0;
179
180
	/**
181
	 * Filters the escaped Global Unique Identifier (guid) of the post.
182
	 *
183
	 * @since 4.2.0
184
	 *
185
	 * @see get_the_guid()
186
	 *
187
	 * @param string $guid Escaped Global Unique Identifier (guid) of the post.
188
	 * @param int    $id   The post ID.
189
	 */
190
	echo apply_filters( 'the_guid', $guid, $id );
191
}
192
193
/**
194
 * Retrieve the Post Global Unique Identifier (guid).
195
 *
196
 * The guid will appear to be a link, but should not be used as an link to the
197
 * post. The reason you should not use it as a link, is because of moving the
198
 * blog across domains.
199
 *
200
 * @since 1.5.0
201
 *
202
 * @param int|WP_Post $post Optional. Post ID or post object. Default is global $post.
203
 * @return string
204
 */
205 View Code Duplication
function get_the_guid( $post = 0 ) {
0 ignored issues
show
This function 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...
206
	$post = get_post( $post );
207
208
	$guid = isset( $post->guid ) ? $post->guid : '';
209
	$id   = isset( $post->ID ) ? $post->ID : 0;
210
211
	/**
212
	 * Filters the Global Unique Identifier (guid) of the post.
213
	 *
214
	 * @since 1.5.0
215
	 *
216
	 * @param string $guid Global Unique Identifier (guid) of the post.
217
	 * @param int    $id   The post ID.
218
	 */
219
	return apply_filters( 'get_the_guid', $guid, $id );
220
}
221
222
/**
223
 * Display the post content.
224
 *
225
 * @since 0.71
226
 *
227
 * @param string $more_link_text Optional. Content for when there is more text.
228
 * @param bool   $strip_teaser   Optional. Strip teaser content before the more text. Default is false.
229
 */
230
function the_content( $more_link_text = null, $strip_teaser = false) {
231
	$content = get_the_content( $more_link_text, $strip_teaser );
232
233
	/**
234
	 * Filters the post content.
235
	 *
236
	 * @since 0.71
237
	 *
238
	 * @param string $content Content of the current post.
239
	 */
240
	$content = apply_filters( 'the_content', $content );
241
	$content = str_replace( ']]>', ']]&gt;', $content );
242
	echo $content;
243
}
244
245
/**
246
 * Retrieve the post content.
247
 *
248
 * @since 0.71
249
 *
250
 * @global int   $page
251
 * @global int   $more
252
 * @global bool  $preview
253
 * @global array $pages
254
 * @global int   $multipage
255
 *
256
 * @param string $more_link_text Optional. Content for when there is more text.
257
 * @param bool   $strip_teaser   Optional. Strip teaser content before the more text. Default is false.
258
 * @return string
259
 */
260
function get_the_content( $more_link_text = null, $strip_teaser = false ) {
261
	global $page, $more, $preview, $pages, $multipage;
262
263
	$post = get_post();
264
265
	if ( null === $more_link_text ) {
266
		$more_link_text = sprintf(
267
			'<span aria-label="%1$s">%2$s</span>',
268
			sprintf(
269
				/* translators: %s: Name of current post */
270
				__( 'Continue reading %s' ),
271
				the_title_attribute( array( 'echo' => false ) )
272
			),
273
			__( '(more&hellip;)' )
274
		);
275
	}
276
277
	$output = '';
278
	$has_teaser = false;
279
280
	// If post password required and it doesn't match the cookie.
281
	if ( post_password_required( $post ) )
0 ignored issues
show
It seems like $post defined by get_post() on line 263 can also be of type array; however, post_password_required() does only seem to accept integer|object<WP_Post>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
282
		return get_the_password_form( $post );
0 ignored issues
show
$post is of type object<WP_Post>|array|null, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
283
284
	if ( $page > count( $pages ) ) // if the requested page doesn't exist
285
		$page = count( $pages ); // give them the highest numbered page that DOES exist
286
287
	$content = $pages[$page - 1];
288
	if ( preg_match( '/<!--more(.*?)?-->/', $content, $matches ) ) {
289
		$content = explode( $matches[0], $content, 2 );
290
		if ( ! empty( $matches[1] ) && ! empty( $more_link_text ) )
291
			$more_link_text = strip_tags( wp_kses_no_null( trim( $matches[1] ) ) );
292
293
		$has_teaser = true;
294
	} else {
295
		$content = array( $content );
296
	}
297
298
	if ( false !== strpos( $post->post_content, '<!--noteaser-->' ) && ( ! $multipage || $page == 1 ) )
299
		$strip_teaser = true;
300
301
	$teaser = $content[0];
302
303
	if ( $more && $strip_teaser && $has_teaser )
304
		$teaser = '';
305
306
	$output .= $teaser;
307
308
	if ( count( $content ) > 1 ) {
309
		if ( $more ) {
310
			$output .= '<span id="more-' . $post->ID . '"></span>' . $content[1];
311
		} else {
312
			if ( ! empty( $more_link_text ) )
313
314
				/**
315
				 * Filters the Read More link text.
316
				 *
317
				 * @since 2.8.0
318
				 *
319
				 * @param string $more_link_element Read More link element.
320
				 * @param string $more_link_text    Read More text.
321
				 */
322
				$output .= apply_filters( 'the_content_more_link', ' <a href="' . get_permalink() . "#more-{$post->ID}\" class=\"more-link\">$more_link_text</a>", $more_link_text );
323
			$output = force_balance_tags( $output );
324
		}
325
	}
326
327
	if ( $preview ) // Preview fix for JavaScript bug with foreign languages.
328
		$output =	preg_replace_callback( '/\%u([0-9A-F]{4})/', '_convert_urlencoded_to_entities', $output );
329
330
	return $output;
331
}
332
333
/**
334
 * Preview fix for JavaScript bug with foreign languages.
335
 *
336
 * @since 3.1.0
337
 * @access private
338
 *
339
 * @param array $match Match array from preg_replace_callback.
340
 * @return string
341
 */
342
function _convert_urlencoded_to_entities( $match ) {
343
	return '&#' . base_convert( $match[1], 16, 10 ) . ';';
344
}
345
346
/**
347
 * Display the post excerpt.
348
 *
349
 * @since 0.71
350
 */
351
function the_excerpt() {
352
353
	/**
354
	 * Filters the displayed post excerpt.
355
	 *
356
	 * @since 0.71
357
	 *
358
	 * @see get_the_excerpt()
359
	 *
360
	 * @param string $post_excerpt The post excerpt.
361
	 */
362
	echo apply_filters( 'the_excerpt', get_the_excerpt() );
363
}
364
365
/**
366
 * Retrieves the post excerpt.
367
 *
368
 * @since 0.71
369
 * @since 4.5.0 Introduced the `$post` parameter.
370
 *
371
 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
372
 * @return string Post excerpt.
373
 */
374
function get_the_excerpt( $post = null ) {
375
	if ( is_bool( $post ) ) {
376
		_deprecated_argument( __FUNCTION__, '2.3.0' );
377
	}
378
379
	$post = get_post( $post );
380
	if ( empty( $post ) ) {
381
		return '';
382
	}
383
384
	if ( post_password_required( $post ) ) {
0 ignored issues
show
It seems like $post defined by get_post($post) on line 379 can also be of type array; however, post_password_required() does only seem to accept integer|object<WP_Post>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
385
		return __( 'There is no excerpt because this is a protected post.' );
386
	}
387
388
	/**
389
	 * Filters the retrieved post excerpt.
390
	 *
391
	 * @since 1.2.0
392
	 * @since 4.5.0 Introduced the `$post` parameter.
393
	 *
394
	 * @param string $post_excerpt The post excerpt.
395
	 * @param WP_Post $post Post object.
396
	 */
397
	return apply_filters( 'get_the_excerpt', $post->post_excerpt, $post );
398
}
399
400
/**
401
 * Whether post has excerpt.
402
 *
403
 * @since 2.3.0
404
 *
405
 * @param int|WP_Post $id Optional. Post ID or post object.
406
 * @return bool
407
 */
408
function has_excerpt( $id = 0 ) {
409
	$post = get_post( $id );
410
	return ( !empty( $post->post_excerpt ) );
411
}
412
413
/**
414
 * Display the classes for the post div.
415
 *
416
 * @since 2.7.0
417
 *
418
 * @param string|array $class   One or more classes to add to the class list.
419
 * @param int|WP_Post  $post_id Optional. Post ID or post object. Defaults to the global `$post`.
420
 */
421
function post_class( $class = '', $post_id = null ) {
422
	// Separates classes with a single space, collates classes for post DIV
423
	echo 'class="' . join( ' ', get_post_class( $class, $post_id ) ) . '"';
424
}
425
426
/**
427
 * Retrieves the classes for the post div as an array.
428
 *
429
 * The class names are many. If the post is a sticky, then the 'sticky'
430
 * class name. The class 'hentry' is always added to each post. If the post has a
431
 * post thumbnail, 'has-post-thumbnail' is added as a class. For each taxonomy that
432
 * the post belongs to, a class will be added of the format '{$taxonomy}-{$slug}' -
433
 * eg 'category-foo' or 'my_custom_taxonomy-bar'.
434
 *
435
 * The 'post_tag' taxonomy is a special
436
 * case; the class has the 'tag-' prefix instead of 'post_tag-'. All classes are
437
 * passed through the filter, {@see 'post_class'}, with the list of classes, followed by
438
 * $class parameter value, with the post ID as the last parameter.
439
 *
440
 * @since 2.7.0
441
 * @since 4.2.0 Custom taxonomy classes were added.
442
 *
443
 * @param string|array $class   One or more classes to add to the class list.
444
 * @param int|WP_Post  $post_id Optional. Post ID or post object.
445
 * @return array Array of classes.
446
 */
447
function get_post_class( $class = '', $post_id = null ) {
448
	$post = get_post( $post_id );
449
450
	$classes = array();
451
452 View Code Duplication
	if ( $class ) {
453
		if ( ! is_array( $class ) ) {
454
			$class = preg_split( '#\s+#', $class );
455
		}
456
		$classes = array_map( 'esc_attr', $class );
457
	} else {
458
		// Ensure that we always coerce class to being an array.
459
		$class = array();
460
	}
461
462
	if ( ! $post ) {
463
		return $classes;
464
	}
465
466
	$classes[] = 'post-' . $post->ID;
467
	if ( ! is_admin() )
468
		$classes[] = $post->post_type;
469
	$classes[] = 'type-' . $post->post_type;
470
	$classes[] = 'status-' . $post->post_status;
471
472
	// Post Format
473 View Code Duplication
	if ( post_type_supports( $post->post_type, 'post-formats' ) ) {
474
		$post_format = get_post_format( $post->ID );
475
476
		if ( $post_format && !is_wp_error($post_format) )
477
			$classes[] = 'format-' . sanitize_html_class( $post_format );
478
		else
479
			$classes[] = 'format-standard';
480
	}
481
482
	$post_password_required = post_password_required( $post->ID );
483
484
	// Post requires password.
485
	if ( $post_password_required ) {
486
		$classes[] = 'post-password-required';
487
	} elseif ( ! empty( $post->post_password ) ) {
488
		$classes[] = 'post-password-protected';
489
	}
490
491
	// Post thumbnails.
492
	if ( current_theme_supports( 'post-thumbnails' ) && has_post_thumbnail( $post->ID ) && ! is_attachment( $post ) && ! $post_password_required ) {
493
		$classes[] = 'has-post-thumbnail';
494
	}
495
496
	// sticky for Sticky Posts
497
	if ( is_sticky( $post->ID ) ) {
498
		if ( is_home() && ! is_paged() ) {
499
			$classes[] = 'sticky';
500
		} elseif ( is_admin() ) {
501
			$classes[] = 'status-sticky';
502
		}
503
	}
504
505
	// hentry for hAtom compliance
506
	$classes[] = 'hentry';
507
508
	// All public taxonomies
509
	$taxonomies = get_taxonomies( array( 'public' => true ) );
510
	foreach ( (array) $taxonomies as $taxonomy ) {
511
		if ( is_object_in_taxonomy( $post->post_type, $taxonomy ) ) {
512
			foreach ( (array) get_the_terms( $post->ID, $taxonomy ) as $term ) {
513
				if ( empty( $term->slug ) ) {
514
					continue;
515
				}
516
517
				$term_class = sanitize_html_class( $term->slug, $term->term_id );
518
				if ( is_numeric( $term_class ) || ! trim( $term_class, '-' ) ) {
519
					$term_class = $term->term_id;
520
				}
521
522
				// 'post_tag' uses the 'tag' prefix for backward compatibility.
523
				if ( 'post_tag' == $taxonomy ) {
524
					$classes[] = 'tag-' . $term_class;
525
				} else {
526
					$classes[] = sanitize_html_class( $taxonomy . '-' . $term_class, $taxonomy . '-' . $term->term_id );
527
				}
528
			}
529
		}
530
	}
531
532
	$classes = array_map( 'esc_attr', $classes );
533
534
	/**
535
	 * Filters the list of CSS classes for the current post.
536
	 *
537
	 * @since 2.7.0
538
	 *
539
	 * @param array $classes An array of post classes.
540
	 * @param array $class   An array of additional classes added to the post.
541
	 * @param int   $post_id The post ID.
542
	 */
543
	$classes = apply_filters( 'post_class', $classes, $class, $post->ID );
544
545
	return array_unique( $classes );
546
}
547
548
/**
549
 * Display the classes for the body element.
550
 *
551
 * @since 2.8.0
552
 *
553
 * @param string|array $class One or more classes to add to the class list.
554
 */
555
function body_class( $class = '' ) {
556
	// Separates classes with a single space, collates classes for body element
557
	echo 'class="' . join( ' ', get_body_class( $class ) ) . '"';
558
}
559
560
/**
561
 * Retrieve the classes for the body element as an array.
562
 *
563
 * @since 2.8.0
564
 *
565
 * @global WP_Query $wp_query
566
 *
567
 * @param string|array $class One or more classes to add to the class list.
568
 * @return array Array of classes.
569
 */
570
function get_body_class( $class = '' ) {
571
	global $wp_query;
572
573
	$classes = array();
574
575
	if ( is_rtl() )
576
		$classes[] = 'rtl';
577
578
	if ( is_front_page() )
579
		$classes[] = 'home';
580
	if ( is_home() )
581
		$classes[] = 'blog';
582
	if ( is_archive() )
583
		$classes[] = 'archive';
584
	if ( is_date() )
585
		$classes[] = 'date';
586
	if ( is_search() ) {
587
		$classes[] = 'search';
588
		$classes[] = $wp_query->posts ? 'search-results' : 'search-no-results';
589
	}
590
	if ( is_paged() )
591
		$classes[] = 'paged';
592
	if ( is_attachment() )
593
		$classes[] = 'attachment';
594
	if ( is_404() )
595
		$classes[] = 'error404';
596
597
	if ( is_single() ) {
598
		$post_id = $wp_query->get_queried_object_id();
599
		$post = $wp_query->get_queried_object();
600
601
		$classes[] = 'single';
602
		if ( isset( $post->post_type ) ) {
603
			$classes[] = 'single-' . sanitize_html_class($post->post_type, $post_id);
604
			$classes[] = 'postid-' . $post_id;
605
606
			// Post Format
607 View Code Duplication
			if ( post_type_supports( $post->post_type, 'post-formats' ) ) {
608
				$post_format = get_post_format( $post->ID );
609
610
				if ( $post_format && !is_wp_error($post_format) )
611
					$classes[] = 'single-format-' . sanitize_html_class( $post_format );
612
				else
613
					$classes[] = 'single-format-standard';
614
			}
615
		}
616
617
		if ( is_attachment() ) {
618
			$mime_type = get_post_mime_type($post_id);
619
			$mime_prefix = array( 'application/', 'image/', 'text/', 'audio/', 'video/', 'music/' );
620
			$classes[] = 'attachmentid-' . $post_id;
621
			$classes[] = 'attachment-' . str_replace( $mime_prefix, '', $mime_type );
622
		}
623
	} elseif ( is_archive() ) {
624
		if ( is_post_type_archive() ) {
625
			$classes[] = 'post-type-archive';
626
			$post_type = get_query_var( 'post_type' );
627
			if ( is_array( $post_type ) )
628
				$post_type = reset( $post_type );
629
			$classes[] = 'post-type-archive-' . sanitize_html_class( $post_type );
630
		} elseif ( is_author() ) {
631
			$author = $wp_query->get_queried_object();
632
			$classes[] = 'author';
633
			if ( isset( $author->user_nicename ) ) {
634
				$classes[] = 'author-' . sanitize_html_class( $author->user_nicename, $author->ID );
635
				$classes[] = 'author-' . $author->ID;
636
			}
637 View Code Duplication
		} elseif ( is_category() ) {
638
			$cat = $wp_query->get_queried_object();
639
			$classes[] = 'category';
640
			if ( isset( $cat->term_id ) ) {
641
				$cat_class = sanitize_html_class( $cat->slug, $cat->term_id );
642
				if ( is_numeric( $cat_class ) || ! trim( $cat_class, '-' ) ) {
643
					$cat_class = $cat->term_id;
644
				}
645
646
				$classes[] = 'category-' . $cat_class;
647
				$classes[] = 'category-' . $cat->term_id;
648
			}
649
		} elseif ( is_tag() ) {
650
			$tag = $wp_query->get_queried_object();
651
			$classes[] = 'tag';
652
			if ( isset( $tag->term_id ) ) {
653
				$tag_class = sanitize_html_class( $tag->slug, $tag->term_id );
654
				if ( is_numeric( $tag_class ) || ! trim( $tag_class, '-' ) ) {
655
					$tag_class = $tag->term_id;
656
				}
657
658
				$classes[] = 'tag-' . $tag_class;
659
				$classes[] = 'tag-' . $tag->term_id;
660
			}
661 View Code Duplication
		} elseif ( is_tax() ) {
662
			$term = $wp_query->get_queried_object();
663
			if ( isset( $term->term_id ) ) {
664
				$term_class = sanitize_html_class( $term->slug, $term->term_id );
665
				if ( is_numeric( $term_class ) || ! trim( $term_class, '-' ) ) {
666
					$term_class = $term->term_id;
667
				}
668
669
				$classes[] = 'tax-' . sanitize_html_class( $term->taxonomy );
670
				$classes[] = 'term-' . $term_class;
671
				$classes[] = 'term-' . $term->term_id;
672
			}
673
		}
674
	} elseif ( is_page() ) {
675
		$classes[] = 'page';
676
677
		$page_id = $wp_query->get_queried_object_id();
678
679
		$post = get_post($page_id);
680
681
		$classes[] = 'page-id-' . $page_id;
682
683
		if ( get_pages( array( 'parent' => $page_id, 'number' => 1 ) ) ) {
684
			$classes[] = 'page-parent';
685
		}
686
687
		if ( $post->post_parent ) {
688
			$classes[] = 'page-child';
689
			$classes[] = 'parent-pageid-' . $post->post_parent;
690
		}
691
		if ( is_page_template() ) {
692
			$classes[] = 'page-template';
693
694
			$template_slug  = get_page_template_slug( $page_id );
695
			$template_parts = explode( '/', $template_slug );
696
697
			foreach ( $template_parts as $part ) {
698
				$classes[] = 'page-template-' . sanitize_html_class( str_replace( array( '.', '/' ), '-', basename( $part, '.php' ) ) );
699
			}
700
			$classes[] = 'page-template-' . sanitize_html_class( str_replace( '.', '-', $template_slug ) );
701
		} else {
702
			$classes[] = 'page-template-default';
703
		}
704
	}
705
706
	if ( is_user_logged_in() )
707
		$classes[] = 'logged-in';
708
709
	if ( is_admin_bar_showing() ) {
710
		$classes[] = 'admin-bar';
711
		$classes[] = 'no-customize-support';
712
	}
713
714
	if ( get_background_color() !== get_theme_support( 'custom-background', 'default-color' ) || get_background_image() )
715
		$classes[] = 'custom-background';
716
717
	if ( has_custom_logo() ) {
718
		$classes[] = 'wp-custom-logo';
719
	}
720
721
	$page = $wp_query->get( 'page' );
722
723
	if ( ! $page || $page < 2 )
724
		$page = $wp_query->get( 'paged' );
725
726
	if ( $page && $page > 1 && ! is_404() ) {
727
		$classes[] = 'paged-' . $page;
728
729
		if ( is_single() )
730
			$classes[] = 'single-paged-' . $page;
731
		elseif ( is_page() )
732
			$classes[] = 'page-paged-' . $page;
733
		elseif ( is_category() )
734
			$classes[] = 'category-paged-' . $page;
735
		elseif ( is_tag() )
736
			$classes[] = 'tag-paged-' . $page;
737
		elseif ( is_date() )
738
			$classes[] = 'date-paged-' . $page;
739
		elseif ( is_author() )
740
			$classes[] = 'author-paged-' . $page;
741
		elseif ( is_search() )
742
			$classes[] = 'search-paged-' . $page;
743
		elseif ( is_post_type_archive() )
744
			$classes[] = 'post-type-paged-' . $page;
745
	}
746
747 View Code Duplication
	if ( ! empty( $class ) ) {
748
		if ( !is_array( $class ) )
749
			$class = preg_split( '#\s+#', $class );
750
		$classes = array_merge( $classes, $class );
751
	} else {
752
		// Ensure that we always coerce class to being an array.
753
		$class = array();
754
	}
755
756
	$classes = array_map( 'esc_attr', $classes );
757
758
	/**
759
	 * Filters the list of CSS body classes for the current post or page.
760
	 *
761
	 * @since 2.8.0
762
	 *
763
	 * @param array $classes An array of body classes.
764
	 * @param array $class   An array of additional classes added to the body.
765
	 */
766
	$classes = apply_filters( 'body_class', $classes, $class );
767
768
	return array_unique( $classes );
769
}
770
771
/**
772
 * Whether post requires password and correct password has been provided.
773
 *
774
 * @since 2.7.0
775
 *
776
 * @param int|WP_Post|null $post An optional post. Global $post used if not provided.
777
 * @return bool false if a password is not required or the correct password cookie is present, true otherwise.
778
 */
779
function post_password_required( $post = null ) {
780
	$post = get_post($post);
781
782
	if ( empty( $post->post_password ) )
783
		return false;
784
785
	if ( ! isset( $_COOKIE['wp-postpass_' . COOKIEHASH] ) )
786
		return true;
787
788
	require_once ABSPATH . WPINC . '/class-phpass.php';
789
	$hasher = new PasswordHash( 8, true );
790
791
	$hash = wp_unslash( $_COOKIE[ 'wp-postpass_' . COOKIEHASH ] );
792
	if ( 0 !== strpos( $hash, '$P$B' ) )
793
		return true;
794
795
	return ! $hasher->CheckPassword( $post->post_password, $hash );
796
}
797
798
//
799
// Page Template Functions for usage in Themes
800
//
801
802
/**
803
 * The formatted output of a list of pages.
804
 *
805
 * Displays page links for paginated posts (i.e. includes the <!--nextpage-->.
806
 * Quicktag one or more times). This tag must be within The Loop.
807
 *
808
 * @since 1.2.0
809
 *
810
 * @global int $page
811
 * @global int $numpages
812
 * @global int $multipage
813
 * @global int $more
814
 *
815
 * @param string|array $args {
816
 *     Optional. Array or string of default arguments.
817
 *
818
 *     @type string       $before           HTML or text to prepend to each link. Default is `<p> Pages:`.
819
 *     @type string       $after            HTML or text to append to each link. Default is `</p>`.
820
 *     @type string       $link_before      HTML or text to prepend to each link, inside the `<a>` tag.
821
 *                                          Also prepended to the current item, which is not linked. Default empty.
822
 *     @type string       $link_after       HTML or text to append to each Pages link inside the `<a>` tag.
823
 *                                          Also appended to the current item, which is not linked. Default empty.
824
 *     @type string       $next_or_number   Indicates whether page numbers should be used. Valid values are number
825
 *                                          and next. Default is 'number'.
826
 *     @type string       $separator        Text between pagination links. Default is ' '.
827
 *     @type string       $nextpagelink     Link text for the next page link, if available. Default is 'Next Page'.
828
 *     @type string       $previouspagelink Link text for the previous page link, if available. Default is 'Previous Page'.
829
 *     @type string       $pagelink         Format string for page numbers. The % in the parameter string will be
830
 *                                          replaced with the page number, so 'Page %' generates "Page 1", "Page 2", etc.
831
 *                                          Defaults to '%', just the page number.
832
 *     @type int|bool     $echo             Whether to echo or not. Accepts 1|true or 0|false. Default 1|true.
833
 * }
834
 * @return string Formatted output in HTML.
835
 */
836
function wp_link_pages( $args = '' ) {
837
	global $page, $numpages, $multipage, $more;
838
839
	$defaults = array(
840
		'before'           => '<p>' . __( 'Pages:' ),
841
		'after'            => '</p>',
842
		'link_before'      => '',
843
		'link_after'       => '',
844
		'next_or_number'   => 'number',
845
		'separator'        => ' ',
846
		'nextpagelink'     => __( 'Next page' ),
847
		'previouspagelink' => __( 'Previous page' ),
848
		'pagelink'         => '%',
849
		'echo'             => 1
850
	);
851
852
	$params = wp_parse_args( $args, $defaults );
853
854
	/**
855
	 * Filters the arguments used in retrieving page links for paginated posts.
856
	 *
857
	 * @since 3.0.0
858
	 *
859
	 * @param array $params An array of arguments for page links for paginated posts.
860
	 */
861
	$r = apply_filters( 'wp_link_pages_args', $params );
862
863
	$output = '';
864
	if ( $multipage ) {
865
		if ( 'number' == $r['next_or_number'] ) {
866
			$output .= $r['before'];
867
			for ( $i = 1; $i <= $numpages; $i++ ) {
868
				$link = $r['link_before'] . str_replace( '%', $i, $r['pagelink'] ) . $r['link_after'];
869
				if ( $i != $page || ! $more && 1 == $page ) {
870
					$link = _wp_link_page( $i ) . $link . '</a>';
871
				}
872
				/**
873
				 * Filters the HTML output of individual page number links.
874
				 *
875
				 * @since 3.6.0
876
				 *
877
				 * @param string $link The page number HTML output.
878
				 * @param int    $i    Page number for paginated posts' page links.
879
				 */
880
				$link = apply_filters( 'wp_link_pages_link', $link, $i );
881
882
				// Use the custom links separator beginning with the second link.
883
				$output .= ( 1 === $i ) ? ' ' : $r['separator'];
884
				$output .= $link;
885
			}
886
			$output .= $r['after'];
887
		} elseif ( $more ) {
888
			$output .= $r['before'];
889
			$prev = $page - 1;
890
			if ( $prev > 0 ) {
891
				$link = _wp_link_page( $prev ) . $r['link_before'] . $r['previouspagelink'] . $r['link_after'] . '</a>';
892
893
				/** This filter is documented in wp-includes/post-template.php */
894
				$output .= apply_filters( 'wp_link_pages_link', $link, $prev );
895
			}
896
			$next = $page + 1;
897
			if ( $next <= $numpages ) {
898
				if ( $prev ) {
899
					$output .= $r['separator'];
900
				}
901
				$link = _wp_link_page( $next ) . $r['link_before'] . $r['nextpagelink'] . $r['link_after'] . '</a>';
902
903
				/** This filter is documented in wp-includes/post-template.php */
904
				$output .= apply_filters( 'wp_link_pages_link', $link, $next );
905
			}
906
			$output .= $r['after'];
907
		}
908
	}
909
910
	/**
911
	 * Filters the HTML output of page links for paginated posts.
912
	 *
913
	 * @since 3.6.0
914
	 *
915
	 * @param string $output HTML output of paginated posts' page links.
916
	 * @param array  $args   An array of arguments.
917
	 */
918
	$html = apply_filters( 'wp_link_pages', $output, $args );
919
920
	if ( $r['echo'] ) {
921
		echo $html;
922
	}
923
	return $html;
924
}
925
926
/**
927
 * Helper function for wp_link_pages().
928
 *
929
 * @since 3.1.0
930
 * @access private
931
 *
932
 * @global WP_Rewrite $wp_rewrite
933
 *
934
 * @param int $i Page number.
935
 * @return string Link.
936
 */
937
function _wp_link_page( $i ) {
938
	global $wp_rewrite;
939
	$post = get_post();
940
	$query_args = array();
941
942
	if ( 1 == $i ) {
943
		$url = get_permalink();
944
	} else {
945
		if ( '' == get_option('permalink_structure') || in_array($post->post_status, array('draft', 'pending')) )
946
			$url = add_query_arg( 'page', $i, get_permalink() );
947
		elseif ( 'page' == get_option('show_on_front') && get_option('page_on_front') == $post->ID )
948
			$url = trailingslashit(get_permalink()) . user_trailingslashit("$wp_rewrite->pagination_base/" . $i, 'single_paged');
0 ignored issues
show
It seems like get_permalink() can also be of type false; however, trailingslashit() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
949
		else
950
			$url = trailingslashit(get_permalink()) . user_trailingslashit($i, 'single_paged');
0 ignored issues
show
It seems like get_permalink() can also be of type false; however, trailingslashit() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
951
	}
952
953
	if ( is_preview() ) {
954
955
		if ( ( 'draft' !== $post->post_status ) && isset( $_GET['preview_id'], $_GET['preview_nonce'] ) ) {
956
			$query_args['preview_id'] = wp_unslash( $_GET['preview_id'] );
957
			$query_args['preview_nonce'] = wp_unslash( $_GET['preview_nonce'] );
958
		}
959
960
		$url = get_preview_post_link( $post, $query_args, $url );
0 ignored issues
show
It seems like $post defined by get_post() on line 939 can also be of type array; however, get_preview_post_link() does only seem to accept integer|object<WP_Post>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
It seems like $url defined by get_preview_post_link($post, $query_args, $url) on line 960 can also be of type false; however, get_preview_post_link() 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...
961
	}
962
963
	return '<a href="' . esc_url( $url ) . '">';
0 ignored issues
show
It seems like $url can also be of type false or null; however, esc_url() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
964
}
965
966
//
967
// Post-meta: Custom per-post fields.
968
//
969
970
/**
971
 * Retrieve post custom meta data field.
972
 *
973
 * @since 1.5.0
974
 *
975
 * @param string $key Meta data key name.
976
 * @return false|string|array Array of values or single value, if only one element exists. False will be returned if key does not exist.
977
 */
978
function post_custom( $key = '' ) {
979
	$custom = get_post_custom();
980
981
	if ( !isset( $custom[$key] ) )
982
		return false;
983
	elseif ( 1 == count($custom[$key]) )
984
		return $custom[$key][0];
985
	else
986
		return $custom[$key];
987
}
988
989
/**
990
 * Display list of post custom fields.
991
 *
992
 * @since 1.2.0
993
 *
994
 * @internal This will probably change at some point...
995
 *
996
 */
997
function the_meta() {
998
	if ( $keys = get_post_custom_keys() ) {
999
		echo "<ul class='post-meta'>\n";
1000
		foreach ( (array) $keys as $key ) {
1001
			$keyt = trim($key);
1002
			if ( is_protected_meta( $keyt, 'post' ) )
1003
				continue;
1004
			$values = array_map('trim', get_post_custom_values($key));
1005
			$value = implode($values,', ');
1006
1007
			/**
1008
			 * Filters the HTML output of the li element in the post custom fields list.
1009
			 *
1010
			 * @since 2.2.0
1011
			 *
1012
			 * @param string $html  The HTML output for the li element.
1013
			 * @param string $key   Meta key.
1014
			 * @param string $value Meta value.
1015
			 */
1016
			echo apply_filters( 'the_meta_key', "<li><span class='post-meta-key'>$key:</span> $value</li>\n", $key, $value );
1017
		}
1018
		echo "</ul>\n";
1019
	}
1020
}
1021
1022
//
1023
// Pages
1024
//
1025
1026
/**
1027
 * Retrieve or display list of pages as a dropdown (select list).
1028
 *
1029
 * @since 2.1.0
1030
 * @since 4.2.0 The `$value_field` argument was added.
1031
 * @since 4.3.0 The `$class` argument was added.
1032
 *
1033
 * @param array|string $args {
1034
 *     Optional. Array or string of arguments to generate a pages drop-down element.
1035
 *
1036
 *     @type int          $depth                 Maximum depth. Default 0.
1037
 *     @type int          $child_of              Page ID to retrieve child pages of. Default 0.
1038
 *     @type int|string   $selected              Value of the option that should be selected. Default 0.
1039
 *     @type bool|int     $echo                  Whether to echo or return the generated markup. Accepts 0, 1,
1040
 *                                               or their bool equivalents. Default 1.
1041
 *     @type string       $name                  Value for the 'name' attribute of the select element.
1042
 *                                               Default 'page_id'.
1043
 *     @type string       $id                    Value for the 'id' attribute of the select element.
1044
 *     @type string       $class                 Value for the 'class' attribute of the select element. Default: none.
1045
 *                                               Defaults to the value of `$name`.
1046
 *     @type string       $show_option_none      Text to display for showing no pages. Default empty (does not display).
1047
 *     @type string       $show_option_no_change Text to display for "no change" option. Default empty (does not display).
1048
 *     @type string       $option_none_value     Value to use when no page is selected. Default empty.
1049
 *     @type string       $value_field           Post field used to populate the 'value' attribute of the option
1050
 *                                               elements. Accepts any valid post field. Default 'ID'.
1051
 * }
1052
 * @return string HTML content, if not displaying.
1053
 */
1054
function wp_dropdown_pages( $args = '' ) {
1055
	$defaults = array(
1056
		'depth' => 0, 'child_of' => 0,
1057
		'selected' => 0, 'echo' => 1,
1058
		'name' => 'page_id', 'id' => '',
1059
		'class' => '',
1060
		'show_option_none' => '', 'show_option_no_change' => '',
1061
		'option_none_value' => '',
1062
		'value_field' => 'ID',
1063
	);
1064
1065
	$r = wp_parse_args( $args, $defaults );
1066
1067
	$pages = get_pages( $r );
1068
	$output = '';
1069
	// Back-compat with old system where both id and name were based on $name argument
1070
	if ( empty( $r['id'] ) ) {
1071
		$r['id'] = $r['name'];
1072
	}
1073
1074
	if ( ! empty( $pages ) ) {
1075
		$class = '';
1076
		if ( ! empty( $r['class'] ) ) {
1077
			$class = " class='" . esc_attr( $r['class'] ) . "'";
1078
		}
1079
1080
		$output = "<select name='" . esc_attr( $r['name'] ) . "'" . $class . " id='" . esc_attr( $r['id'] ) . "'>\n";
1081
		if ( $r['show_option_no_change'] ) {
1082
			$output .= "\t<option value=\"-1\">" . $r['show_option_no_change'] . "</option>\n";
1083
		}
1084
		if ( $r['show_option_none'] ) {
1085
			$output .= "\t<option value=\"" . esc_attr( $r['option_none_value'] ) . '">' . $r['show_option_none'] . "</option>\n";
1086
		}
1087
		$output .= walk_page_dropdown_tree( $pages, $r['depth'], $r );
1088
		$output .= "</select>\n";
1089
	}
1090
1091
	/**
1092
	 * Filters the HTML output of a list of pages as a drop down.
1093
	 *
1094
	 * @since 2.1.0
1095
	 * @since 4.4.0 `$r` and `$pages` added as arguments.
1096
	 *
1097
	 * @param string $output HTML output for drop down list of pages.
1098
	 * @param array  $r      The parsed arguments array.
1099
	 * @param array  $pages  List of WP_Post objects returned by `get_pages()`
1100
 	 */
1101
	$html = apply_filters( 'wp_dropdown_pages', $output, $r, $pages );
1102
1103
	if ( $r['echo'] ) {
1104
		echo $html;
1105
	}
1106
	return $html;
1107
}
1108
1109
/**
1110
 * Retrieve or display list of pages in list (li) format.
1111
 *
1112
 * @since 1.5.0
1113
 *
1114
 * @see get_pages()
1115
 *
1116
 * @global WP_Query $wp_query
1117
 *
1118
 * @param array|string $args {
1119
 *     Array or string of arguments. Optional.
1120
 *
1121
 *     @type int    $child_of     Display only the sub-pages of a single page by ID. Default 0 (all pages).
1122
 *     @type string $authors      Comma-separated list of author IDs. Default empty (all authors).
1123
 *     @type string $date_format  PHP date format to use for the listed pages. Relies on the 'show_date' parameter.
1124
 *                                Default is the value of 'date_format' option.
1125
 *     @type int    $depth        Number of levels in the hierarchy of pages to include in the generated list.
1126
 *                                Accepts -1 (any depth), 0 (all pages), 1 (top-level pages only), and n (pages to
1127
 *                                the given n depth). Default 0.
1128
 *     @type bool   $echo         Whether or not to echo the list of pages. Default true.
1129
 *     @type string $exclude      Comma-separated list of page IDs to exclude. Default empty.
1130
 *     @type array  $include      Comma-separated list of page IDs to include. Default empty.
1131
 *     @type string $link_after   Text or HTML to follow the page link label. Default null.
1132
 *     @type string $link_before  Text or HTML to precede the page link label. Default null.
1133
 *     @type string $post_type    Post type to query for. Default 'page'.
1134
 *     @type string $post_status  Comma-separated list of post statuses to include. Default 'publish'.
1135
 *     @type string $show_date	  Whether to display the page publish or modified date for each page. Accepts
1136
 *                                'modified' or any other value. An empty value hides the date. Default empty.
1137
 *     @type string $sort_column  Comma-separated list of column names to sort the pages by. Accepts 'post_author',
1138
 *                                'post_date', 'post_title', 'post_name', 'post_modified', 'post_modified_gmt',
1139
 *                                'menu_order', 'post_parent', 'ID', 'rand', or 'comment_count'. Default 'post_title'.
1140
 *     @type string $title_li     List heading. Passing a null or empty value will result in no heading, and the list
1141
 *                                will not be wrapped with unordered list `<ul>` tags. Default 'Pages'.
1142
 *     @type Walker $walker       Walker instance to use for listing pages. Default empty (Walker_Page).
1143
 * }
1144
 * @return string|void HTML list of pages.
1145
 */
1146
function wp_list_pages( $args = '' ) {
1147
	$defaults = array(
1148
		'depth' => 0, 'show_date' => '',
1149
		'date_format' => get_option( 'date_format' ),
1150
		'child_of' => 0, 'exclude' => '',
1151
		'title_li' => __( 'Pages' ), 'echo' => 1,
1152
		'authors' => '', 'sort_column' => 'menu_order, post_title',
1153
		'link_before' => '', 'link_after' => '', 'walker' => '',
1154
	);
1155
1156
	$r = wp_parse_args( $args, $defaults );
1157
1158
	$output = '';
1159
	$current_page = 0;
1160
1161
	// sanitize, mostly to keep spaces out
1162
	$r['exclude'] = preg_replace( '/[^0-9,]/', '', $r['exclude'] );
1163
1164
	// Allow plugins to filter an array of excluded pages (but don't put a nullstring into the array)
1165
	$exclude_array = ( $r['exclude'] ) ? explode( ',', $r['exclude'] ) : array();
1166
1167
	/**
1168
	 * Filters the array of pages to exclude from the pages list.
1169
	 *
1170
	 * @since 2.1.0
1171
	 *
1172
	 * @param array $exclude_array An array of page IDs to exclude.
1173
	 */
1174
	$r['exclude'] = implode( ',', apply_filters( 'wp_list_pages_excludes', $exclude_array ) );
1175
1176
	// Query pages.
1177
	$r['hierarchical'] = 0;
1178
	$pages = get_pages( $r );
1179
1180
	if ( ! empty( $pages ) ) {
1181
		if ( $r['title_li'] ) {
1182
			$output .= '<li class="pagenav">' . $r['title_li'] . '<ul>';
1183
		}
1184
		global $wp_query;
1185
		if ( is_page() || is_attachment() || $wp_query->is_posts_page ) {
1186
			$current_page = get_queried_object_id();
1187
		} elseif ( is_singular() ) {
1188
			$queried_object = get_queried_object();
1189
			if ( is_post_type_hierarchical( $queried_object->post_type ) ) {
1190
				$current_page = $queried_object->ID;
1191
			}
1192
		}
1193
1194
		$output .= walk_page_tree( $pages, $r['depth'], $current_page, $r );
1195
1196
		if ( $r['title_li'] ) {
1197
			$output .= '</ul></li>';
1198
		}
1199
	}
1200
1201
	/**
1202
	 * Filters the HTML output of the pages to list.
1203
	 *
1204
	 * @since 1.5.1
1205
	 * @since 4.4.0 `$pages` added as arguments.
1206
	 *
1207
	 * @see wp_list_pages()
1208
	 *
1209
	 * @param string $output HTML output of the pages list.
1210
	 * @param array  $r      An array of page-listing arguments.
1211
	 * @param array  $pages  List of WP_Post objects returned by `get_pages()`
1212
	 */
1213
	$html = apply_filters( 'wp_list_pages', $output, $r, $pages );
1214
1215
	if ( $r['echo'] ) {
1216
		echo $html;
1217
	} else {
1218
		return $html;
1219
	}
1220
}
1221
1222
/**
1223
 * Displays or retrieves a list of pages with an optional home link.
1224
 *
1225
 * The arguments are listed below and part of the arguments are for wp_list_pages()} function.
1226
 * Check that function for more info on those arguments.
1227
 *
1228
 * @since 2.7.0
1229
 * @since 4.4.0 Added `menu_id`, `container`, `before`, `after`, and `walker` arguments.
1230
 *
1231
 * @param array|string $args {
1232
 *     Optional. Arguments to generate a page menu. See wp_list_pages() for additional arguments.
1233
 *
1234
 *     @type string          $sort_column How to short the list of pages. Accepts post column names.
1235
 *                                        Default 'menu_order, post_title'.
1236
 *     @type string          $menu_id     ID for the div containing the page list. Default is empty string.
1237
 *     @type string          $menu_class  Class to use for the element containing the page list. Default 'menu'.
1238
 *     @type string          $container   Element to use for the element containing the page list. Default 'div'.
1239
 *     @type bool            $echo        Whether to echo the list or return it. Accepts true (echo) or false (return).
1240
 *                                        Default true.
1241
 *     @type int|bool|string $show_home   Whether to display the link to the home page. Can just enter the text
1242
 *                                        you'd like shown for the home link. 1|true defaults to 'Home'.
1243
 *     @type string          $link_before The HTML or text to prepend to $show_home text. Default empty.
1244
 *     @type string          $link_after  The HTML or text to append to $show_home text. Default empty.
1245
 *     @type string          $before      The HTML or text to prepend to the menu. Default is '<ul>'.
1246
 *     @type string          $after       The HTML or text to append to the menu. Default is '</ul>'.
1247
 *     @type Walker          $walker      Walker instance to use for listing pages. Default empty (Walker_Page).
1248
 * }
1249
 * @return string|void HTML menu
1250
 */
1251
function wp_page_menu( $args = array() ) {
1252
	$defaults = array(
1253
		'sort_column' => 'menu_order, post_title',
1254
		'menu_id'     => '',
1255
		'menu_class'  => 'menu',
1256
		'container'   => 'div',
1257
		'echo'        => true,
1258
		'link_before' => '',
1259
		'link_after'  => '',
1260
		'before'      => '<ul>',
1261
		'after'       => '</ul>',
1262
		'walker'      => '',
1263
	);
1264
	$args = wp_parse_args( $args, $defaults );
1265
1266
	/**
1267
	 * Filters the arguments used to generate a page-based menu.
1268
	 *
1269
	 * @since 2.7.0
1270
	 *
1271
	 * @see wp_page_menu()
1272
	 *
1273
	 * @param array $args An array of page menu arguments.
1274
	 */
1275
	$args = apply_filters( 'wp_page_menu_args', $args );
1276
1277
	$menu = '';
1278
1279
	$list_args = $args;
1280
1281
	// Show Home in the menu
1282
	if ( ! empty($args['show_home']) ) {
1283
		if ( true === $args['show_home'] || '1' === $args['show_home'] || 1 === $args['show_home'] )
1284
			$text = __('Home');
1285
		else
1286
			$text = $args['show_home'];
1287
		$class = '';
1288
		if ( is_front_page() && !is_paged() )
1289
			$class = 'class="current_page_item"';
1290
		$menu .= '<li ' . $class . '><a href="' . home_url( '/' ) . '">' . $args['link_before'] . $text . $args['link_after'] . '</a></li>';
1291
		// If the front page is a page, add it to the exclude list
1292
		if (get_option('show_on_front') == 'page') {
1293
			if ( !empty( $list_args['exclude'] ) ) {
1294
				$list_args['exclude'] .= ',';
1295
			} else {
1296
				$list_args['exclude'] = '';
1297
			}
1298
			$list_args['exclude'] .= get_option('page_on_front');
1299
		}
1300
	}
1301
1302
	$list_args['echo'] = false;
1303
	$list_args['title_li'] = '';
1304
	$menu .= str_replace( array( "\r", "\n", "\t" ), '', wp_list_pages($list_args) );
1305
1306
	$container = sanitize_text_field( $args['container'] );
1307
1308
	// Fallback in case `wp_nav_menu()` was called without a container.
1309
	if ( empty( $container ) ) {
1310
		$container = 'div';
1311
	}
1312
1313
	if ( $menu ) {
1314
1315
		// wp_nav_menu doesn't set before and after
1316
		if ( isset( $args['fallback_cb'] ) &&
1317
			'wp_page_menu' === $args['fallback_cb'] &&
1318
			'ul' !== $container ) {
1319
			$args['before'] = '<ul>';
1320
			$args['after'] = '</ul>';
1321
		}
1322
1323
		$menu = $args['before'] . $menu . $args['after'];
1324
	}
1325
1326
	$attrs = '';
1327
	if ( ! empty( $args['menu_id'] ) ) {
1328
		$attrs .= ' id="' . esc_attr( $args['menu_id'] ) . '"';
1329
	}
1330
1331
	if ( ! empty( $args['menu_class'] ) ) {
1332
		$attrs .= ' class="' . esc_attr( $args['menu_class'] ) . '"';
1333
	}
1334
1335
	$menu = "<{$container}{$attrs}>" . $menu . "</{$container}>\n";
1336
1337
	/**
1338
	 * Filters the HTML output of a page-based menu.
1339
	 *
1340
	 * @since 2.7.0
1341
	 *
1342
	 * @see wp_page_menu()
1343
	 *
1344
	 * @param string $menu The HTML output.
1345
	 * @param array  $args An array of arguments.
1346
	 */
1347
	$menu = apply_filters( 'wp_page_menu', $menu, $args );
1348
	if ( $args['echo'] )
1349
		echo $menu;
1350
	else
1351
		return $menu;
1352
}
1353
1354
//
1355
// Page helpers
1356
//
1357
1358
/**
1359
 * Retrieve HTML list content for page list.
1360
 *
1361
 * @uses Walker_Page to create HTML list content.
1362
 * @since 2.1.0
1363
 *
1364
 * @param array $pages
1365
 * @param int   $depth
1366
 * @param int   $current_page
1367
 * @param array $r
1368
 * @return string
1369
 */
1370
function walk_page_tree( $pages, $depth, $current_page, $r ) {
1371
	if ( empty($r['walker']) )
1372
		$walker = new Walker_Page;
1373
	else
1374
		$walker = $r['walker'];
1375
1376
	foreach ( (array) $pages as $page ) {
1377
		if ( $page->post_parent )
1378
			$r['pages_with_children'][ $page->post_parent ] = true;
1379
	}
1380
1381
	$args = array($pages, $depth, $r, $current_page);
1382
	return call_user_func_array(array($walker, 'walk'), $args);
1383
}
1384
1385
/**
1386
 * Retrieve HTML dropdown (select) content for page list.
1387
 *
1388
 * @uses Walker_PageDropdown to create HTML dropdown content.
1389
 * @since 2.1.0
1390
 * @see Walker_PageDropdown::walk() for parameters and return description.
1391
 *
1392
 * @return string
1393
 */
1394
function walk_page_dropdown_tree() {
1395
	$args = func_get_args();
1396
	if ( empty($args[2]['walker']) ) // the user's options are the third parameter
1397
		$walker = new Walker_PageDropdown;
1398
	else
1399
		$walker = $args[2]['walker'];
1400
1401
	return call_user_func_array(array($walker, 'walk'), $args);
1402
}
1403
1404
//
1405
// Attachments
1406
//
1407
1408
/**
1409
 * Display an attachment page link using an image or icon.
1410
 *
1411
 * @since 2.0.0
1412
 *
1413
 * @param int|WP_Post $id Optional. Post ID or post object.
1414
 * @param bool        $fullsize     Optional, default is false. Whether to use full size.
1415
 * @param bool        $deprecated   Deprecated. Not used.
1416
 * @param bool        $permalink    Optional, default is false. Whether to include permalink.
1417
 */
1418
function the_attachment_link( $id = 0, $fullsize = false, $deprecated = false, $permalink = false ) {
1419
	if ( !empty( $deprecated ) )
1420
		_deprecated_argument( __FUNCTION__, '2.5.0' );
1421
1422
	if ( $fullsize )
1423
		echo wp_get_attachment_link($id, 'full', $permalink);
1424
	else
1425
		echo wp_get_attachment_link($id, 'thumbnail', $permalink);
1426
}
1427
1428
/**
1429
 * Retrieve an attachment page link using an image or icon, if possible.
1430
 *
1431
 * @since 2.5.0
1432
 * @since 4.4.0 The `$id` parameter can now accept either a post ID or `WP_Post` object.
1433
 *
1434
 * @param int|WP_Post  $id        Optional. Post ID or post object.
1435
 * @param string|array $size      Optional. Image size. Accepts any valid image size, or an array
1436
 *                                of width and height values in pixels (in that order).
1437
 *                                Default 'thumbnail'.
1438
 * @param bool         $permalink Optional, Whether to add permalink to image. Default false.
1439
 * @param bool         $icon      Optional. Whether the attachment is an icon. Default false.
1440
 * @param string|false $text      Optional. Link text to use. Activated by passing a string, false otherwise.
1441
 *                                Default false.
1442
 * @param array|string $attr      Optional. Array or string of attributes. Default empty.
1443
 * @return string HTML content.
1444
 */
1445
function wp_get_attachment_link( $id = 0, $size = 'thumbnail', $permalink = false, $icon = false, $text = false, $attr = '' ) {
1446
	$_post = get_post( $id );
1447
1448
	if ( empty( $_post ) || ( 'attachment' !== $_post->post_type ) || ! $url = wp_get_attachment_url( $_post->ID ) ) {
1449
		return __( 'Missing Attachment' );
1450
	}
1451
1452
	if ( $permalink ) {
1453
		$url = get_attachment_link( $_post->ID );
1454
	}
1455
1456
	if ( $text ) {
1457
		$link_text = $text;
1458
	} elseif ( $size && 'none' != $size ) {
1459
		$link_text = wp_get_attachment_image( $_post->ID, $size, $icon, $attr );
1460
	} else {
1461
		$link_text = '';
1462
	}
1463
1464
	if ( '' === trim( $link_text ) ) {
1465
		$link_text = $_post->post_title;
1466
	}
1467
1468
	if ( '' === trim( $link_text ) ) {
1469
		$link_text = esc_html( pathinfo( get_attached_file( $_post->ID ), PATHINFO_FILENAME ) );
1470
	}
1471
	/**
1472
	 * Filters a retrieved attachment page link.
1473
	 *
1474
	 * @since 2.7.0
1475
	 *
1476
	 * @param string       $link_html The page link HTML output.
1477
	 * @param int          $id        Post ID.
1478
	 * @param string|array $size      Size of the image. Image size or array of width and height values (in that order).
1479
	 *                                Default 'thumbnail'.
1480
	 * @param bool         $permalink Whether to add permalink to image. Default false.
1481
	 * @param bool         $icon      Whether to include an icon. Default false.
1482
	 * @param string|bool  $text      If string, will be link text. Default false.
1483
	 */
1484
	return apply_filters( 'wp_get_attachment_link', "<a href='" . esc_url( $url ) . "'>$link_text</a>", $id, $size, $permalink, $icon, $text );
1485
}
1486
1487
/**
1488
 * Wrap attachment in paragraph tag before content.
1489
 *
1490
 * @since 2.0.0
1491
 *
1492
 * @param string $content
1493
 * @return string
1494
 */
1495
function prepend_attachment($content) {
1496
	$post = get_post();
1497
1498
	if ( empty($post->post_type) || $post->post_type != 'attachment' )
1499
		return $content;
1500
1501
	if ( wp_attachment_is( 'video', $post ) ) {
0 ignored issues
show
It seems like $post defined by get_post() on line 1496 can also be of type array; however, wp_attachment_is() does only seem to accept integer|object<WP_Post>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1502
		$meta = wp_get_attachment_metadata( get_the_ID() );
0 ignored issues
show
It seems like get_the_ID() can also be of type false; however, wp_get_attachment_metadata() does only seem to accept integer, did you maybe forget to handle an error condition?
Loading history...
1503
		$atts = array( 'src' => wp_get_attachment_url() );
1504
		if ( ! empty( $meta['width'] ) && ! empty( $meta['height'] ) ) {
1505
			$atts['width'] = (int) $meta['width'];
1506
			$atts['height'] = (int) $meta['height'];
1507
		}
1508
		if ( has_post_thumbnail() ) {
1509
			$atts['poster'] = wp_get_attachment_url( get_post_thumbnail_id() );
1510
		}
1511
		$p = wp_video_shortcode( $atts );
1512
	} elseif ( wp_attachment_is( 'audio', $post ) ) {
0 ignored issues
show
It seems like $post defined by get_post() on line 1496 can also be of type array; however, wp_attachment_is() does only seem to accept integer|object<WP_Post>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1513
		$p = wp_audio_shortcode( array( 'src' => wp_get_attachment_url() ) );
1514
	} else {
1515
		$p = '<p class="attachment">';
1516
		// show the medium sized image representation of the attachment if available, and link to the raw file
1517
		$p .= wp_get_attachment_link(0, 'medium', false);
1518
		$p .= '</p>';
1519
	}
1520
1521
	/**
1522
	 * Filters the attachment markup to be prepended to the post content.
1523
	 *
1524
	 * @since 2.0.0
1525
	 *
1526
	 * @see prepend_attachment()
1527
	 *
1528
	 * @param string $p The attachment HTML output.
1529
	 */
1530
	$p = apply_filters( 'prepend_attachment', $p );
1531
1532
	return "$p\n$content";
1533
}
1534
1535
//
1536
// Misc
1537
//
1538
1539
/**
1540
 * Retrieve protected post password form content.
1541
 *
1542
 * @since 1.0.0
1543
 *
1544
 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
1545
 * @return string HTML content for password form for password protected post.
1546
 */
1547
function get_the_password_form( $post = 0 ) {
1548
	$post = get_post( $post );
1549
	$label = 'pwbox-' . ( empty($post->ID) ? rand() : $post->ID );
1550
	$output = '<form action="' . esc_url( site_url( 'wp-login.php?action=postpass', 'login_post' ) ) . '" class="post-password-form" method="post">
1551
	<p>' . __( 'This content is password protected. To view it please enter your password below:' ) . '</p>
1552
	<p><label for="' . $label . '">' . __( 'Password:' ) . ' <input name="post_password" id="' . $label . '" type="password" size="20" /></label> <input type="submit" name="Submit" value="' . esc_attr_x( 'Enter', 'post password form' ) . '" /></p></form>
1553
	';
1554
1555
	/**
1556
	 * Filters the HTML output for the protected post password form.
1557
	 *
1558
	 * If modifying the password field, please note that the core database schema
1559
	 * limits the password field to 20 characters regardless of the value of the
1560
	 * size attribute in the form input.
1561
	 *
1562
	 * @since 2.7.0
1563
	 *
1564
	 * @param string $output The password form HTML output.
1565
	 */
1566
	return apply_filters( 'the_password_form', $output );
1567
}
1568
1569
/**
1570
 * Whether currently in a page template.
1571
 *
1572
 * This template tag allows you to determine if you are in a page template.
1573
 * You can optionally provide a template name or array of template names
1574
 * and then the check will be specific to that template.
1575
 *
1576
 * @since 2.5.0
1577
 * @since 4.2.0 The `$template` parameter was changed to also accept an array of page templates.
1578
 *
1579
 * @param string|array $template The specific template name or array of templates to match.
1580
 * @return bool True on success, false on failure.
1581
 */
1582
function is_page_template( $template = '' ) {
1583
	if ( ! is_page() )
1584
		return false;
1585
1586
	$page_template = get_page_template_slug( get_queried_object_id() );
1587
1588
	if ( empty( $template ) )
1589
		return (bool) $page_template;
1590
1591
	if ( $template == $page_template )
1592
		return true;
1593
1594
	if ( is_array( $template ) ) {
1595
		if ( ( in_array( 'default', $template, true ) && ! $page_template )
1596
			|| in_array( $page_template, $template, true )
1597
		) {
1598
			return true;
1599
		}
1600
	}
1601
1602
	return ( 'default' === $template && ! $page_template );
1603
}
1604
1605
/**
1606
 * Get the specific template name for a page.
1607
 *
1608
 * @since 3.4.0
1609
 *
1610
 * @param int $post_id Optional. The page ID to check. Defaults to the current post, when used in the loop.
1611
 * @return string|false Page template filename. Returns an empty string when the default page template
1612
 * 	is in use. Returns false if the post is not a page.
1613
 */
1614
function get_page_template_slug( $post_id = null ) {
1615
	$post = get_post( $post_id );
1616
	if ( ! $post || 'page' != $post->post_type )
1617
		return false;
1618
	$template = get_post_meta( $post->ID, '_wp_page_template', true );
1619
	if ( ! $template || 'default' == $template )
1620
		return '';
1621
	return $template;
1622
}
1623
1624
/**
1625
 * Retrieve formatted date timestamp of a revision (linked to that revisions's page).
1626
 *
1627
 * @since 2.6.0
1628
 *
1629
 * @param int|object $revision Revision ID or revision object.
1630
 * @param bool       $link     Optional, default is true. Link to revisions's page?
1631
 * @return string|false i18n formatted datetimestamp or localized 'Current Revision'.
1632
 */
1633
function wp_post_revision_title( $revision, $link = true ) {
1634
	if ( !$revision = get_post( $revision ) )
0 ignored issues
show
It seems like $revision defined by get_post($revision) on line 1634 can also be of type object; however, get_post() does only seem to accept integer|object<WP_Post>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1635
		return $revision;
1636
1637 View Code Duplication
	if ( !in_array( $revision->post_type, array( 'post', 'page', 'revision' ) ) )
1638
		return false;
1639
1640
	/* translators: revision date format, see https://secure.php.net/date */
1641
	$datef = _x( 'F j, Y @ H:i:s', 'revision date format' );
1642
	/* translators: %s: revision date */
1643
	$autosavef = __( '%s [Autosave]' );
1644
	/* translators: %s: revision date */
1645
	$currentf  = __( '%s [Current Revision]' );
1646
1647
	$date = date_i18n( $datef, strtotime( $revision->post_modified ) );
1648 View Code Duplication
	if ( $link && current_user_can( 'edit_post', $revision->ID ) && $link = get_edit_post_link( $revision->ID ) )
1649
		$date = "<a href='$link'>$date</a>";
1650
1651 View Code Duplication
	if ( !wp_is_post_revision( $revision ) )
0 ignored issues
show
It seems like $revision defined by get_post($revision) on line 1634 can also be of type array; however, wp_is_post_revision() does only seem to accept integer|object<WP_Post>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1652
		$date = sprintf( $currentf, $date );
1653
	elseif ( wp_is_post_autosave( $revision ) )
0 ignored issues
show
It seems like $revision defined by get_post($revision) on line 1634 can also be of type array; however, wp_is_post_autosave() does only seem to accept integer|object<WP_Post>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1654
		$date = sprintf( $autosavef, $date );
1655
1656
	return $date;
1657
}
1658
1659
/**
1660
 * Retrieve formatted date timestamp of a revision (linked to that revisions's page).
1661
 *
1662
 * @since 3.6.0
1663
 *
1664
 * @param int|object $revision Revision ID or revision object.
1665
 * @param bool       $link     Optional, default is true. Link to revisions's page?
1666
 * @return string|false gravatar, user, i18n formatted datetimestamp or localized 'Current Revision'.
1667
 */
1668
function wp_post_revision_title_expanded( $revision, $link = true ) {
1669
	if ( !$revision = get_post( $revision ) )
0 ignored issues
show
It seems like $revision defined by get_post($revision) on line 1669 can also be of type object; however, get_post() does only seem to accept integer|object<WP_Post>|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1670
		return $revision;
1671
1672 View Code Duplication
	if ( !in_array( $revision->post_type, array( 'post', 'page', 'revision' ) ) )
1673
		return false;
1674
1675
	$author = get_the_author_meta( 'display_name', $revision->post_author );
1676
	/* translators: revision date format, see https://secure.php.net/date */
1677
	$datef = _x( 'F j, Y @ H:i:s', 'revision date format' );
1678
1679
	$gravatar = get_avatar( $revision->post_author, 24 );
1680
1681
	$date = date_i18n( $datef, strtotime( $revision->post_modified ) );
1682 View Code Duplication
	if ( $link && current_user_can( 'edit_post', $revision->ID ) && $link = get_edit_post_link( $revision->ID ) )
1683
		$date = "<a href='$link'>$date</a>";
1684
1685
	$revision_date_author = sprintf(
1686
		/* translators: post revision title: 1: author avatar, 2: author name, 3: time ago, 4: date */
1687
		__( '%1$s %2$s, %3$s ago (%4$s)' ),
1688
		$gravatar,
1689
		$author,
1690
		human_time_diff( strtotime( $revision->post_modified ), current_time( 'timestamp' ) ),
1691
		$date
1692
	);
1693
1694
	/* translators: %s: revision date with author avatar */
1695
	$autosavef = __( '%s [Autosave]' );
1696
	/* translators: %s: revision date with author avatar */
1697
	$currentf  = __( '%s [Current Revision]' );
1698
1699 View Code Duplication
	if ( !wp_is_post_revision( $revision ) )
0 ignored issues
show
It seems like $revision defined by get_post($revision) on line 1669 can also be of type array; however, wp_is_post_revision() does only seem to accept integer|object<WP_Post>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1700
		$revision_date_author = sprintf( $currentf, $revision_date_author );
1701
	elseif ( wp_is_post_autosave( $revision ) )
0 ignored issues
show
It seems like $revision defined by get_post($revision) on line 1669 can also be of type array; however, wp_is_post_autosave() does only seem to accept integer|object<WP_Post>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1702
		$revision_date_author = sprintf( $autosavef, $revision_date_author );
1703
1704
	/**
1705
	 * Filters the formatted author and date for a revision.
1706
	 *
1707
	 * @since 4.4.0
1708
	 *
1709
	 * @param string  $revision_date_author The formatted string.
1710
	 * @param WP_Post $revision             The revision object.
1711
	 * @param bool    $link                 Whether to link to the revisions page, as passed into
1712
	 *                                      wp_post_revision_title_expanded().
1713
	 */
1714
	return apply_filters( 'wp_post_revision_title_expanded', $revision_date_author, $revision, $link );
1715
}
1716
1717
/**
1718
 * Display list of a post's revisions.
1719
 *
1720
 * Can output either a UL with edit links or a TABLE with diff interface, and
1721
 * restore action links.
1722
 *
1723
 * @since 2.6.0
1724
 *
1725
 * @param int|WP_Post $post_id Optional. Post ID or WP_Post object. Default is global $post.
1726
 * @param string      $type    'all' (default), 'revision' or 'autosave'
1727
 */
1728
function wp_list_post_revisions( $post_id = 0, $type = 'all' ) {
1729
	if ( ! $post = get_post( $post_id ) )
1730
		return;
1731
1732
	// $args array with (parent, format, right, left, type) deprecated since 3.6
1733
	if ( is_array( $type ) ) {
1734
		$type = ! empty( $type['type'] ) ? $type['type']  : $type;
1735
		_deprecated_argument( __FUNCTION__, '3.6.0' );
1736
	}
1737
1738
	if ( ! $revisions = wp_get_post_revisions( $post->ID ) )
1739
		return;
1740
1741
	$rows = '';
1742
	foreach ( $revisions as $revision ) {
1743
		if ( ! current_user_can( 'read_post', $revision->ID ) )
1744
			continue;
1745
1746
		$is_autosave = wp_is_post_autosave( $revision );
1747
		if ( ( 'revision' === $type && $is_autosave ) || ( 'autosave' === $type && ! $is_autosave ) )
0 ignored issues
show
Bug Best Practice introduced by
The expression $is_autosave 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...
Bug Best Practice introduced by
The expression $is_autosave 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...
1748
			continue;
1749
1750
		$rows .= "\t<li>" . wp_post_revision_title_expanded( $revision ) . "</li>\n";
1751
	}
1752
1753
	echo "<div class='hide-if-js'><p>" . __( 'JavaScript must be enabled to use this feature.' ) . "</p></div>\n";
1754
1755
	echo "<ul class='post-revisions hide-if-no-js'>\n";
1756
	echo $rows;
1757
	echo "</ul>";
1758
}
1759