: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* The public-facing functionality of the plugin.
* @link https://passwordprotectwp.com
* @package Password_Protect_Page
* @subpackage Password_Protect_Page/public
* The public-facing functionality of the plugin.
* Defines the plugin name, version, and two examples hooks for how to
* enqueue the public-facing stylesheet and JavaScript.
* @package Password_Protect_Page
* @subpackage Password_Protect_Page/public
* @author BWPS <hello@preventdirectaccess.com>
* @var string $plugin_name The ID of this plugin.
* The version of this plugin.
* @var string $version The current version of this plugin.
* Class PPW_Password_Services
* @var PPW_Password_Services
private $password_services;
* Initialize the class and set its properties.
* @param string $plugin_name The name of the plugin.
* @param string $version The version of this plugin.
public function __construct( $plugin_name, $version ) {
$this->plugin_name = $plugin_name;
$this->version = $version;
$this->password_services = new PPW_Password_Services();
* Register the stylesheets and javascript for the public-facing side of the site.
public function enqueue_assets() {
* This function is provided for demonstration purposes only.
* An instance of this class should be passed to the run() function
* defined in Password_Protect_Page_Loader as all of the hooks are defined
* in that particular class.
* The Password_Protect_Page_Loader will then create the relationship
* between the defined hooks and the functions defined in this
* Filter before render content.
* @param string $content Content of post/page.
* @deprecated Because we only use post_password_required to show login form.
* @since 1.2.2 Deprecated for function, we will remove it after 2 release.
public function ppw_filter_content( $content ) {
if ( is_null( $post ) ) {
$is_pro_activate = apply_filters( PPW_Constants::HOOK_IS_PRO_ACTIVATE, false );
if ( $is_pro_activate ) {
return apply_filters( PPW_Constants::HOOK_CHECK_PASSWORD_BEFORE_RENDER_CONTENT, $content, $post_id );
return $this->ppw_free_content_filter( $content, $post_id );
* Filter content for free version
* @param array $post_id Data from client.
* @param string $content Data from client.
private function ppw_free_content_filter( $content, $post_id ) {
// 1. Check page/post is protected.
$result = $this->password_services->is_protected_content( $post_id );
if ( false === $result ) {
// 2. Check password in cookie.
$passwords = $result['passwords'];
if ( $this->password_services->is_valid_cookie( $post_id, $passwords, PPW_Constants::COOKIE_NAME ) ) {
if ( $result['has_global_passwords'] || ( $result['has_role_passwords'] && $result['has_current_role_password'] ) ) {
return ppw_core_render_login_form();
return '<p><strong>' . _e('This page is protected. Please try again or contact the website owner.', PPW_Constants::DOMAIN) . '</strong></p>';
* @param array $classes Classes.
* @since 1.5.0 Mark deprecated function.
public function ppw_post_class( $classes ) {
$classes[] = PPW_Constants::CUSTOM_POST_CLASS;
* Show custom login form which protected by PPW Plugin, it will replace default form of WordPress.
* @param string $output The password form HTML output.
* @return string The password form HTML output.
* @global WP_Post $post Post object
* @since 1.2.2 Init the_password_form
public function ppw_the_password_form( $output ) {
$post = $GLOBALS['post'];
if ( empty( $post->ID ) || ! ppw_is_post_type_selected_in_setting( $post->post_type ) ) {
$should_render_form = apply_filters( PPW_Constants::HOOK_SHOULD_RENDER_PASSWORD_FORM, true );
if ( ! $should_render_form ) {
return ppw_core_render_login_form();
* Only render text in all page diff post/page custom post type which it is not have post_id input.
* Check a site is post/page or custom post type
* Use regex to check it is our password form then render text.
* @param string $content Content of the post.
public function ppw_the_content( $content ) {
// Do not handle on admin page.
$is_show_excerpt = ppw_core_get_setting_type_bool_by_option_name( PPW_Constants::PROTECT_EXCERPT, PPW_Constants::MISC_OPTIONS );
if ( is_singular() && ! $is_show_excerpt ) {
// Check post type is selected.
if ( ! $post || ! ppw_is_post_type_selected_in_setting( $post->post_type ) ) {
// Check it is password form.
if ( post_password_required() ) {
return ppw_handle_protected_content( $post, $content, $is_show_excerpt );
public function register_shortcodes() {
PPW_Shortcode::get_instance();
* Create PPWP Capabilities.
public function create_caps() {
if ( ! class_exists( 'WP_Roles' ) ) {
if ( ! isset( $wp_roles ) ) {
$wp_roles = new WP_Roles(); // @codingStandardsIgnoreLine
foreach ( $capabilities as $cap ) {
$wp_roles->add_cap( 'administrator', $cap );
* Check logic and hide pages/posts protected
* @param string $where The WHERE clause of the query.
* @param WP_Query $wp_query The WP_Query instance (passed by reference).
public function handle_hide_post_protected( $where, $wp_query ) {
return $this->password_services->handle_hide_post_protected( $where, $wp_query );
* Check logic and hide posts protected in recent post
* @param array $posts_args An array of arguments used to retrieve the recent posts.
public function handle_hide_post_protected_recent_post( $posts_args ) {
return $this->password_services->handle_hide_post_protected_recent_post( $posts_args );
* Check logic and hide posts protected in next and previous post
* @param string $where The WHERE clause of the query.
public function handle_hide_post_protected_next_and_previous( $where ) {
return $this->password_services->handle_hide_post_protected_next_and_previous( $where );
* Check condition and exclude protected page in list page get by function get_pages
* @param array $pages List of pages to retrieve.
* @param array $param Array of get_pages() arguments.
public function handle_hide_page_protected( $pages, $param ) {
return $this->password_services->handle_hide_page_protected( $pages );
* Check condition and exclude page/post protected in Yoast SEO XML Sitemaps
* @param array $ids List page_id/post_id exclude in Yoast SEO XML Sitemaps.
public function handle_hide_page_protected_yoast_seo_sitemaps( $ids ) {
return $this->password_services->handle_hide_page_protected_yoast_seo_sitemaps( $ids );
public function ppw_core_validate_login() {
* Should check request have parameter generated by PPF Form.
if ( ! isset( $_GET['action'] ) || ! isset( $_GET['type'] ) || ! isset( $_GET[ PPW_Constants::CALL_BACK_URL_PARAM ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Processing form data without nonce verification. - Not verify nonce for password validate.
if ( 'ppw_postpass' !== $_GET['action'] || 'individual' !== $_GET['type'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Processing form data without nonce verification. - Not verify nonce for password validate.
if ( ! ppw_core_get_setting_type_bool_by_option_name( PPW_Constants::USE_CUSTOM_FORM_ACTION, PPW_Constants::MISC_OPTIONS ) ) {
// It is post method and have post_password input from user.
if ( ! isset( $_POST['post_password'] ) ) {
wp_safe_redirect( $this->password_services->get_referer_url() );
// Get post_id from referer url if Post data is not exist post_id.
$post_id = ppw_get_post_id_from_request();
if ( empty( $post_id ) ) {
wp_safe_redirect( $this->password_services->get_referer_url() );
$password = wp_unslash( $_POST['post_password'] ); // phpcs:ignore -- not sanitize password because we allow all character.
$this->password_services->handle_after_enter_password_in_password_form( $post_id, $password );
* @param string $action_url Action URL.
* @return string Action URL after generated.
public function ppw_core_get_ppf_action_url( $action_url ) {
$_get = wp_unslash( $_GET ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We no need to handle nonce verification for render UI request.
if ( ! ppw_core_get_setting_type_bool_by_option_name( PPW_Constants::USE_CUSTOM_FORM_ACTION, PPW_Constants::MISC_OPTIONS ) ) {
$callback_value = rawurlencode( apply_filters( PPW_Constants::HOOK_CALLBACK_URL, get_permalink() ) );
'action' => 'ppw_postpass',
PPW_Constants::CALL_BACK_URL_PARAM => $callback_value,
if ( isset( $_get['ppws'] ) ) {
$url = add_query_arg( 'ppws', $_get['ppws'], $url );
* Set cookie time for password.
* @param integer $time Expired time of a cookie.
public function set_cookie_time( $time ) {
if ( ! isset( $_GET['ppws'] ) || '1' !== $_GET['ppws'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We no need to handle nonce verification for set cookie function, because already handle in others password checking function.
* Set cookie time for password.
* @param string $form_action Form action URL.
public function set_sitewide_form_action( $form_action ) {
$_get = wp_unslash( $_GET ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We no need to handle nonce verification for render UI function.
if ( isset( $_get['ppws'] ) ) {
$form_action = $form_action . '&ppws=' . $_get['ppws'];
* Handle access link with ppw_ac parameter and without encoding URL.
public function handle_access_link() {
if ( ! isset( $_GET['ppw_ac'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- We no need to handle nonce verification for quick access link.
$password = wp_unslash( $_GET['ppw_ac'] ); // phpcs:ignore -- not sanitize password because we allow all character.
$permalink = get_permalink( $post_id );
$current_url = apply_filters( 'ppwp_access_link', $permalink, $post_id );
$password_service = new PPW_Password_Services();
$is_valid = $password_service->is_valid_password_from_request( $post_id, $password );
// Bypass single password.
add_filter( 'post_password_required', '__return_false', 50 );
* Validate password with "No Reload Page" Option.
public function ppw_validate_password() {
if ( isset( $_POST['nonce'] ) && ! wp_verify_nonce( $_POST['nonce'], 'ppw_password_nonce' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- We no need to sanitize here
'message' => 'Cookie nonce is invalid',
if ( ! isset( $_POST['post_password'] ) ) {
'message' => 'Password doest not exist',
if ( empty( $_POST['post_id'] ) ) {
'message' => 'Post ID is empty',
$post_id = absint( $_POST['post_id'] );
$password = wp_unslash( $_POST['post_password'] ); // phpcs:ignore -- we allow all value for password
// Not check password if post does not exist.
$post = get_post( $post_id );
'message' => 'Post not found',