| @@ -28,9 +28,9 @@ | ||
| 28 | 28 | add_filter( 'the_content', array($this, 'filter_the_content') ); |
| 29 | 29 | add_filter( 'acf_the_content', array($this, 'filter_the_content') ); |
| 30 | 30 | add_filter( 'get_the_excerpt', array($this, 'filter_the_content') ); |
| 31 | 31 | add_action( 'template_redirect', array($this, 'check_global_proctection') ); |
| 32 | - add_action( 'wp_enqueue_scripts', array($this, 'add_public_scripts') ); | |
| 32 | + add_action( 'wp_enqueue_scripts', array($this, 'add_public_scripts'), 9999 ); | |
| 33 | 33 | } |
| 34 | 34 | |
| 35 | 35 | /** |
| 36 | 36 | * Returns instance of PS_Public. |
| @@ -44,8 +44,26 @@ | ||
| 44 | 44 | return self::$instance; |
| 45 | 45 | } |
| 46 | 46 | |
| 47 | 47 | /** |
| 48 | + * Avoids re-entering the_content recursively. | |
| 49 | + * | |
| 50 | + * @param string $content the unlocked content. | |
| 51 | + * | |
| 52 | + * @return string | |
| 53 | + */ | |
| 54 | + private function render_unlocked_content( string $content ) : string { | |
| 55 | + if ( doing_filter( 'the_content' ) ) { | |
| 56 | + // Mirror the_content order: blocks first, wpautop only for classic content. | |
| 57 | + if ( has_blocks( $content ) ) { | |
| 58 | + return do_shortcode( do_blocks( $content ) ); | |
| 59 | + } | |
| 60 | + return wpautop( do_shortcode( $content ) ); | |
| 61 | + } | |
| 62 | + return apply_filters( 'the_content', $content ); | |
| 63 | + } | |
| 64 | + | |
| 65 | + /** | |
| 48 | 66 | * Render the Passster shortcode. |
| 49 | 67 | * |
| 50 | 68 | * @param array $atts array of attributes. |
| 51 | 69 | * @param string|null $content the current content. |
| @@ -70,9 +88,9 @@ | ||
| 70 | 88 | } |
| 71 | 89 | if ( !$in_schedule ) { |
| 72 | 90 | $area = get_post( $area_id ); |
| 73 | 91 | if ( $area && ('publish' === $area->post_status || current_user_can( 'edit_post', $area_id )) ) { |
| 74 | - return apply_filters( 'the_content', str_replace( '{post-id}', get_the_id(), $area->post_content ) ); | |
| 92 | + return $this->render_unlocked_content( str_replace( '{post-id}', get_the_id(), $area->post_content ) ); | |
| 75 | 93 | } |
| 76 | 94 | return $content ?? ''; |
| 77 | 95 | } |
| 78 | 96 | } |
| @@ -86,12 +104,12 @@ | ||
| 86 | 104 | $area = get_post( $area_id ); |
| 87 | 105 | if ( 'publish' === $area->post_status || current_user_can( 'edit_post', $area_id ) ) { |
| 88 | 106 | $content = $area->post_content; |
| 89 | 107 | do_action( 'passster_content_unlocked' ); |
| 90 | - return apply_filters( 'the_content', str_replace( '{post-id}', get_the_id(), $content ) ); | |
| 108 | + return $this->render_unlocked_content( str_replace( '{post-id}', get_the_id(), $content ) ); | |
| 91 | 109 | } |
| 92 | 110 | } else { |
| 93 | - $content = apply_filters( 'the_content', $content ); | |
| 111 | + $content = $this->render_unlocked_content( $content ); | |
| 94 | 112 | do_action( 'passster_content_unlocked' ); |
| 95 | 113 | return apply_filters( 'passster_content', $content ); |
| 96 | 114 | } |
| 97 | 115 | } |
| @@ -178,8 +196,11 @@ | ||
| 178 | 196 | $form = str_replace( '[PASSSTER_POST_ID]', absint( get_the_ID() ), $form ); |
| 179 | 197 | // term id (for category archive protection — passed to REST API so it can validate against term meta). |
| 180 | 198 | $term_id_val = ( !empty( $atts['term_id'] ) ? absint( $atts['term_id'] ) : 0 ); |
| 181 | 199 | $form = str_replace( '[PASSSTER_TERM_ID]', $term_id_val, $form ); |
| 200 | + // post type (for post type archive protection — passed to REST API so it can validate against post type config). | |
| 201 | + $post_type_val = ( !empty( $atts['post_type'] ) ? sanitize_key( $atts['post_type'] ) : '' ); | |
| 202 | + $form = str_replace( '[PASSSTER_POST_TYPE]', esc_attr( $post_type_val ), $form ); | |
| 182 | 203 | // hide or not. |
| 183 | 204 | if ( !empty( $atts['hide'] ) ) { |
| 184 | 205 | $form = str_replace( '[PASSSTER_HIDE]', ' passster-hide', $form ); |
| 185 | 206 | } else { |
| @@ -310,9 +331,9 @@ | ||
| 310 | 331 | $post_id = esc_html( $options['global_protection_id'] ); |
| 311 | 332 | $is_active = esc_html( $options['activate_global_protection'] ); |
| 312 | 333 | $atts = array(); |
| 313 | 334 | $password = get_post_meta( $post_id, 'passster_password', true ); |
| 314 | - $atts['password'] = esc_html( $password ); | |
| 335 | + $atts['password'] = $password; | |
| 315 | 336 | if ( !empty( $post_id ) ) { |
| 316 | 337 | if ( $is_active ) { |
| 317 | 338 | if ( is_page( $post_id ) || is_single( $post_id ) ) { |
| 318 | 339 | return; |
| @@ -380,8 +401,12 @@ | ||
| 380 | 401 | $shortcodes[$shortcode] = do_shortcode( str_replace( '{post-id}', get_the_id(), $shortcode ) ); |
| 381 | 402 | } |
| 382 | 403 | } |
| 383 | 404 | } |
| 405 | + // Archive/taxonomy pages have no singular post, so get_permalink() can't be used | |
| 406 | + // to build the "reload after unlock" URL for links generated by area/CPT-level protection. | |
| 407 | + $current_post_id = get_the_id(); | |
| 408 | + $reload_url = ( $current_post_id ? get_permalink( $current_post_id ) : esc_url_raw( remove_query_arg( 'pass' ) ) ); | |
| 384 | 409 | $args = array( |
| 385 | 410 | 'ajax_url' => admin_url() . 'admin-ajax.php', |
| 386 | 411 | 'rest_url' => get_rest_url(), |
| 387 | 412 | 'nonce' => wp_create_nonce( 'ps-password-nonce' ), |
| @@ -386,11 +411,11 @@ | ||
| 386 | 411 | 'rest_url' => get_rest_url(), |
| 387 | 412 | 'nonce' => wp_create_nonce( 'ps-password-nonce' ), |
| 388 | 413 | 'hash_nonce' => wp_create_nonce( 'ps-hash-nonce' ), |
| 389 | 414 | 'logout_nonce' => wp_create_nonce( 'ps-logout-nonce' ), |
| 390 | - 'post_id' => get_the_id(), | |
| 415 | + 'post_id' => $current_post_id, | |
| 391 | 416 | 'shortcodes' => $shortcodes, |
| 392 | - 'permalink' => get_permalink( get_the_id() ), | |
| 417 | + 'permalink' => $reload_url, | |
| 393 | 418 | ); |
| 394 | 419 | if ( isset( $options['cookie_duration_unit'] ) ) { |
| 395 | 420 | $args['cookie_duration_unit'] = esc_html( $options['cookie_duration_unit'] ); |
| 396 | 421 | } else { |