wppaste
WordPress

post_password_required( int|WP_Post|null $post = null ): bool

Since
2.7.0
Source
wp-includes/post-template.php:882

Checks whether a post is password protected and whether the current visitor has already supplied the correct password. It accepts a post ID, WP_Post object, or null to use the global $post, and its result runs through the 'post_password_required' filter before being returned. It does not check user capabilities, so a logged-in administrator without the password cookie still gets true unless you filter the result yourself.

Determines whether the post requires password and whether a correct password has been provided.

Compatibility

WordPress
since 2.7.0
PHP
7.4–8.6-dev
  • 6.7.7
  • 6.8.8
  • 6.9.7
  • 7.0.4
  • 7.1.0

Present in every tracked release (6.7.7 to 7.1.0), and compiles on PHP 7.4 through 8.6-dev.

Parameters

$postint|WP_Post|nulloptional
An optional post. Global $post used if not provided.Default: null

Return value

bool
false if a password is not required or the correct password cookie is present, true otherwise.

Code examples

Every example is editable and runs in a real WordPress booted in your browser by WordPress Playground. Press Run, then edit the code: clicking away re-runs it. Nothing is sent anywhere until you do.

Hide post content until the correct password is entered

A single-post template loop that checks the current post in the Loop before printing its content.

$query = new WP_Query( array( 'p' => 2, 'post_type' => 'post' ) );

while ( $query->have_posts() ) :
	$query->the_post();

	if ( post_password_required() ) {
		echo esc_html( 'This post is password protected. Enter the password to view it.' );
	} else {
		echo esc_html( 'Title: ' . get_the_title() );
	}
endwhile;

wp_reset_postdata();

Calling post_password_required() with no argument only works after the_post() has set the global $post inside the loop.

Let editors bypass the password prompt on protected posts

A filter on 'post_password_required' that skips the password check for anyone who can edit posts.

add_filter(
	'post_password_required',
	function ( $required, $post ) {
		if ( current_user_can( 'edit_posts' ) ) {
			return false;
		}
		return $required;
	},
	10,
	2
);

$post     = get_post( 3 );
$required = post_password_required( $post );

printf(
	'Password required for post %d: %s',
	esc_html( $post->ID ),
	esc_html( $required ? 'yes' : 'no' )
);

The logged-in administrator in the sandbox has no 'wp-postpass_' cookie, so without the filter this would print 'yes'.

Common problems and fixes · 4

Why does post_password_required() still return true for a logged-in administrator?

The function only checks the post's password field and the 'wp-postpass_' cookie, it never checks current_user_can() or any capability. An admin who hasn't submitted the password form has no matching cookie, so the check still returns true.

Why does passing an invalid post ID silently return false instead of an error?

post_password_required() runs $post through get_post( $post ) first. If the ID doesn't match any post, get_post() returns null, and empty( $post->post_password ) on a null object evaluates to true, so the function falls through to the first apply_filters() call and reports no password required.

I changed post_password directly with a raw SQL query, why doesn't the function see the change?

get_post() reads from the post object cache first. A direct database update that bypasses wp_update_post() leaves the cached copy, and therefore the value post_password_required() sees, out of date until the cache is cleared.

My 'post_password_required' filter callback assumes $required starts as false, why does it misbehave?

The filter is applied at three different points in the source depending on the path taken: with false when there is no password, with true when the cookie is missing, and with the phpass comparison result once a cookie is present. A callback that hardcodes an expected starting value will misfire on at least one of those paths.

Alternatives and related functions

get_the_password_form
When you need to render the actual password prompt markup to show visitors instead of just testing whether one is needed.
current_user_can
When access should depend on the visitor's role or capability rather than on whether they know the post password.
wp_check_password
When you're validating a plaintext password against a stored hash outside the post-password cookie flow, such as in a custom login form.
get_post
When you only need the post object itself, including its post_password field, without running the cookie check.

Performance profile

How much work a call to post_password_required() does, and what it touches: the algorithmic scaling, the Zend instruction count per call across PHP versions, the hooks it hands control to, and the core code that calls it. Measured from the compiled opcodes, not a stopwatch, so every number is identical on any machine running the same PHP version, and every function in core is ranked by cost.

Cost class
Heavy

Reaches the database via get_post().

Scaling
Constant

No loop in the body: the same number of instructions runs whatever you pass in.

Instructions
13–47

Executed per call on PHP 8.5, depending on the branch taken. The body compiles to 61.

Plugin surface
1 hook

Third-party callbacks on 'post_password_required' run inside this call, and their cost is not bounded by anything here.

Called by
40

40 places in core call this, so the cost is paid more often than your own code shows.

What it touches

  • querycontent queryget_post()called directly
  • hookthird-party callbacksapply_filters()called directly

Further down the call graph this can also reach option, cache, serialize and transient. Those are the worst case, several calls deep and usually down an error path, not what a normal call pays.

What one call costs · 3 distinct outcomes

One number would be a lie: the work depends on which branch runs. These are every distinct cost post_password_required() can have, taken from its control-flow graph on PHP 8.5.

WhenInstructionsCalls it makes
always13–18get_post(), apply_filters()
!empty($post) && isset($value) && !$hash41get_post(), wp_unslash(), apply_filters()
!empty($post) && isset($value) && $hash47get_post(), wp_unslash(), ->CheckPassword(), apply_filters()

Across PHP versions

PHPCompiledExecutedBranchesNotes
8.6-dev6113–473
8.56113–473
8.46113–4733 fewer instructions than PHP 8.3
8.36413–503
8.26413–503
8.16413–503
7.46413–503

An instruction is not a fixed amount of time, so a matching count is not necessarily the same speed; what it rules out is a difference in the work itself.

Hooks and filters fired · 3

3 hooks fire while post_password_required() runs, in this order:

  1. apply_filters( post_password_required )filterline 887 (+5 into the body)

    Filters whether a post requires the user to supply a password.

  2. apply_filters( post_password_required )filterline 892 (+10 into the body)

    Filters whether a post requires the user to supply a password.

  3. apply_filters( post_password_required )filterline 914 (+32 into the body)

    Filters whether a post requires the user to supply a password.

Uses · 5

Used by · 40

Show all 40

Source code

function post_password_required( $post = null ) {	$post = get_post( $post ); 	if ( empty( $post->post_password ) ) {		/** This filter is documented in wp-includes/post-template.php */		return apply_filters( 'post_password_required', false, $post );	} 	if ( ! isset( $_COOKIE[ 'wp-postpass_' . COOKIEHASH ] ) ) {		/** This filter is documented in wp-includes/post-template.php */		return apply_filters( 'post_password_required', true, $post );	} 	require_once ABSPATH . WPINC . '/class-phpass.php';	$hasher = new PasswordHash( 8, true ); 	$hash = wp_unslash( $_COOKIE[ 'wp-postpass_' . COOKIEHASH ] );	if ( ! str_starts_with( $hash, '$P$B' ) ) {		$required = true;	} else {		$required = ! $hasher->CheckPassword( $post->post_password, $hash );	} 	/**	 * Filters whether a post requires the user to supply a password.	 *	 * @since 4.7.0	 *	 * @param bool    $required Whether the user needs to supply a password. True if password has not been	 *                          provided or is incorrect, false if password has been supplied or is not required.	 * @param WP_Post $post     Post object.	 */	return apply_filters( 'post_password_required', $required, $post );}

Changelog

Introduced in 2.7.0. Unchanged from 6.7.7 through 7.1.0.

  1. 6.7.7
  2. 6.8.8
  3. 6.9.7
  4. 7.0.4
  5. 7.1.0

Signature, return type and hooks compared across 5 parsed releases.

About this page

Parsed data
Generated from the wordpress-develop 7.1.0 tag, from src/wp-includes/post-template.php, and regenerated for each WordPress release so it tracks the code rather than a snapshot of it.
Corrections
Something wrong on this page? Report it and it gets fixed in the next regeneration.