: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
class PPW_Content_Protection {
* @var PPW_Content_Protection
protected static $instance;
const POST_TYPE = 'ppwp-section';
const SETTING_META_KEY = 'ppw_pcp_setting';
const PASSWORD_GLOBAL_TYPE = 'PCPSection';
const PASSWORD_ROLE_TYPE = 'PCPSectionRole_';
const COOKIE_NAME = 'ppw_section-';
const ADMIN_PATH = 'edit.php?post_type=ppwp-section';
const SHORTCODE_COLUMN = 'ppw_pcp_shortcode';
* @var PPW_Password_Services
private $password_service;
* @var PPW_Repository_Passwords
* @return PPW_Content_Protection
public static function get_instance() {
if ( null == self::$instance ) {
self::$instance = new self();
public function __construct() {
$this->password_service = new PPW_Password_Services();
$this->password_repo = new PPW_Repository_Passwords();
public function register() {
add_action( 'init', array( $this, 'register_post_type' ) );
add_action( 'wp_ajax_ppw_pcp_validate_password', array( $this, 'validate_password' ) );
add_action( 'wp_ajax_nopriv_ppw_pcp_validate_password', array( $this, 'validate_password' ) );
add_filter( 'ppw_shortcode_render_content', array( $this, 'handle_shortcode_with_area' ), 10, 2 );
add_filter( 'et_builder_load_actions', array( $this, 'add_action_to_divi' ) );
add_filter( 'ppw_pcp_valid_shortcode', array( $this, 'valid_shortcode' ), 10, 2 );
add_action( 'admin_init', array( $this, 'maybe_add_metabox' ) );
add_filter( 'ppw_shortcode_unlock_content', array( $this, 'maybe_unlock_content_by_cookie' ), 15, 2 );
add_filter( 'ppw_pcp_submenu_add_new_tab', array( $this, 'add_pcp_tab' ), 1000 );
add_filter( 'manage_' . self::POST_TYPE . '_posts_columns', array( $this, 'add_shortcode_column' ) );
add_action( 'manage_' . self::POST_TYPE . '_posts_custom_column', array(
'render_content_custom_column',
add_action( 'admin_notices', array( $this, 'handle_admin_notices' ) );
public function add_shortcode_column( $columns ) {
self::SHORTCODE_COLUMN => 'Shortcode'
return array_slice( $columns, 0, 2, true )
+ array_slice( $columns, 2, count( $columns ) - 1, true );
public function render_content_custom_column( $column, $post_id ) {
if ( $column === self::SHORTCODE_COLUMN ) {
echo '[ppwp section="' . absint( $post_id ) . '" /]';
public function add_pcp_tab( $tabs ) {
'tab_name' => 'Section Protection',
'link' => self::ADMIN_PATH,
public function valid_shortcode( $content, $attrs ) {
if ( ! isset( $attrs['section'] ) || ! is_numeric( $attrs['section'] ) ) {
if ( absint( $attrs['section'] ) > 0 ) {
public function register_post_type() {
'name' => __( 'Section Protection', PPW_Constants::DOMAIN ),
'singular_name' => __( 'Section Protection', PPW_Constants::DOMAIN ),
'add_new' => __( 'Add New', PPW_Constants::DOMAIN ),
'add_new_item' => __( 'Add New', PPW_Constants::DOMAIN ),
'edit_item' => __( 'Edit', PPW_Constants::DOMAIN ),
'new_item' => __( 'New', PPW_Constants::DOMAIN ),
'view_item' => __( 'View', PPW_Constants::DOMAIN ),
'search_items' => __( 'Search', PPW_Constants::DOMAIN ),
'not_found' => __( 'No found', PPW_Constants::DOMAIN ),
'not_found_in_trash' => __( 'No found in Trash', PPW_Constants::DOMAIN ),
'show_in_menu' => self::ADMIN_PATH,
'capability_type' => 'post',
'supports' => array( 'title', 'editor' ),
if ( current_user_can( 'administrator' ) ) {
$args['publicly_queryable'] = true;
// global $pagenow, $typenow, $post;
// if ( 'edit.php' === $pagenow || self::POST_TYPE === $typenow ) {
// $args['show_in_menu'] = PPW_Constants::MENU_NAME;
// } elseif ( isset( $_GET['post_type'] ) && self::POST_TYPE === $_GET['post_type'] ) {
// $args['show_in_menu'] = PPW_Constants::MENU_NAME;
// } elseif ( isset( $_GET['post'] ) && isset( $_GET['action'] ) ) {
// $post_type = get_post_type( $_GET['post'] );
// if ( $post_type === self::POST_TYPE ) {
// $args['show_in_menu'] = PPW_Constants::MENU_NAME;
register_post_type( self::POST_TYPE, $args );
* Add ajax support for Divi builder.
* @param array $actions array of allowed actions.
public function add_action_to_divi( $actions ) {
$actions[] = 'ppw_pcp_validate_password';
public function handle_shortcode_with_area( $content, $attrs ) {
if ( ! isset( $attrs['section'] ) ) {
$post_id = absint( $attrs['section'] );
$post = get_post( $post_id );
if ( empty( $post ) || $post->post_type !== self::POST_TYPE ) {
$post_content = $this->massage_post_content( $post_id, $post->post_content );
if ( is_null( $post_content ) ) {
public function massage_post_content( $post_id, $post_content ) {
$post_content = ppw_support_third_party_content_plugin( $post_id, $post_content );
return apply_filters( 'the_content', $post_content );
public function maybe_add_metabox() {
$attributes = apply_filters(
'ppw_pcp_metabox_attributes',
'title' => __( 'Password Protect WordPress', PPW_Constants::DOMAIN ),
'callback' => array( $this, 'display_metabox' ),
'screen' => array( self::POST_TYPE ),
public function display_metabox() {
<div id="ppw-pcp-metabox"></div>
wp_enqueue_script( 'ppw-pcp-metabox', PPW_DIR_URL . 'admin/js/dist/pcp-metabox.js', array(), PPW_VERSION, true );
'rest_url' => get_rest_url( null, '/wppp/v1/pcp' ),
'nonce' => wp_create_nonce( 'wp_rest' ),
'post_id' => get_the_ID(),
'customize_url' => admin_url( 'customize.php' ),
'extra_html' => apply_filters( 'ppw_pcp_metabox_extra_html', '')
echo ob_get_clean(); // phpcs:ignore -- we cannot escape ob_start ob_get_clean(), there are no variable to escape in statement above
public function validate_single_password( $params ) {
$password = $params['password'];
$roles = ppw_core_get_current_role();
'global_type' => self::PASSWORD_GLOBAL_TYPE,
'role_type' => self::PASSWORD_ROLE_TYPE,
$password_info = $this->password_repo->find_activated_password( $password, $args );
if ( empty( $password_info ) ) {
$this->password_service->set_cookie_bypass_cache( $password, self::COOKIE_NAME . $area . 'p' . $password_info->id );
do_action( 'ppw_after_save_section_cookie', $password_info );
public function validate_password() {
if ( ! isset( $_POST['pss'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Processing form data without nonce verification. - Not verify nonce for password validate.
'message' => 'Please enter the correct password!',
if ( ! isset( $_POST['area'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Processing form data without nonce verification. - Not verify nonce for password validate.
'message' => 'Area value is required!',
if ( ! isset( $_POST['post_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Processing form data without nonce verification. - Not verify nonce for password validate.
'message' => 'Post ID is required!',
$password = wp_unslash( $_POST['pss'] ); // phpcs:ignore -- not sanitize password because we allow all character.
$area = absint( $_POST['area'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Processing form data without nonce verification. - Not verify nonce for password validate.
$post_id = absint( $_POST['post_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Processing form data without nonce verification. - Not verify nonce for password validate.
$post = get_post( $area );
'message' => 'Post does not exist',
if ( $post->post_type !== self::POST_TYPE ) {
'message' => 'Post type is not valid',
$setting = get_post_meta( $area, self::SETTING_META_KEY, true );
$is_valid_by_single = $this->validate_single_password( $params );
$is_valid_password = apply_filters( 'ppw_pcp_area_is_valid_password', $is_valid_by_single, $params );
if ( $is_valid_password ) {
'reload' => ! ppw_core_get_setting_type_bool_by_option_name( PPW_Constants::NO_RELOAD_PAGE, PPW_Constants::MISC_OPTIONS ),
'content' => $this->massage_post_content( $area, $post->post_content ),
'message' => get_theme_mod( 'ppwp_pcp_err_msg_text', PPW_Constants::DEFAULT_SHORTCODE_ERROR_MSG ),
public function check_area_exist( $post ) {
if ( $post->post_type !== self::POST_TYPE ) {
public function get_info_from_area_cookie( $area ) {
$_cookie = wp_unslash( $_COOKIE );
if ( empty( $_cookie ) ) {
$cookie_keys = array_filter(
return false !== strpos( $key, self::COOKIE_NAME );
if ( 0 === count( $cookie_keys ) ) {
foreach ( $cookie_keys as $cookie_key ) {
$info = str_replace( self::COOKIE_NAME, '', $cookie_key );
$info = str_replace( COOKIEHASH, '', $info );
$info = explode( 'p', $info );
$password_id = absint( ppw_get_value( $info, 1, 0 ) );
$cookie_area = absint( ppw_get_value( $info, 0, 0 ) );
if ( $area !== $cookie_area ) {
$results[ $password_id ] = array(
'cookie_name' => $cookie_key,
'cookie_value' => $_cookie[ $cookie_key ],
public function validate_cookie( $area ) {
$cookie_passwords = $this->get_info_from_area_cookie( $area );
if ( empty( $cookie_passwords ) ) {
$password_ids = array_keys( $cookie_passwords );
$roles = ppw_core_get_current_role();
'global_type' => self::PASSWORD_GLOBAL_TYPE,
'role_type' => self::PASSWORD_ROLE_TYPE,
'allow_to_check_expired' => false,
$password_infos = $this->password_repo->find_activated_passwords_by_ids(
if ( empty( $password_infos ) ) {
foreach ( $password_infos as $password_info ) {
if ( ! isset( $cookie_passwords[ $password_info->id ] ) ) {
$cookie = $cookie_passwords[ $password_info->id ];
$hashed_password = $cookie['cookie_value'];
if ( ppw_free_check_password( $password_info->password, $hashed_password ) ) {
public function maybe_unlock_content_by_cookie( $is_valid, $attrs ) {
if ( $is_valid || ! isset( $attrs['section'] ) ) {
$area = $attrs['section'];
$setting = get_post_meta( $area, self::SETTING_META_KEY, true );
$post = get_post( $area );
if ( ! $this->check_area_exist( $post ) ) {
'area' => absint( $area ),
$is_valid_cookie = $this->validate_cookie( $params['area'] );
return apply_filters( 'ppw_pcp_valid_area_password', $is_valid_cookie, $params );
public function handle_admin_notices() {
if ( ! function_exists( 'get_current_screen' ) ) {
$current_screen = get_current_screen();
if ( ! isset( $current_screen->post_type ) ) {
if ( $current_screen->post_type !== self::POST_TYPE ) {
$button_contexts = array( 'ppwp-section' );
if ( in_array( $current_screen->id, $button_contexts ) ) {
$edit_url = admin_url( self::ADMIN_PATH );
$button = '<span style="float: right;">
<a href="' . $edit_url . '">
<button class="button button-primary">
<b>Password Protect WordPress: Section Protection</b>