PluginProbe
Passster – Password Protect Pages and Content / 4.3.17
Passster – Password Protect Pages and Content v4.3.17
4.3.17 4.3.16 4.3.15 4.3.14 4.3.12 4.3.13 4.3.11 4.3.10 4.3.9 4.3.8 4.3.7 4.3.6 4.3.5 trunk 3.5.4 3.5.5.2 3.5.5.8 3.5.5.9 4.0 4.1.4 4.2.10 4.2.11 4.2.12 4.2.13 4.2.14 All 49 releases
← All changes | inc/class-ps-public.php +449 -254 4.2.13 → 4.3.17 View file →
@@ -1,254 +1,449 @@
1 -<?php
2 -
3 -namespace passster;
4 -
5 -use Exception;
6 -class PS_Public {
7 - /**
8 - * Contains instance or null
9 - *
10 - * @var object|null
11 - */
12 - private static $instance = null;
13 -
14 - /**
15 - * Constructor for PS_Public
16 - */
17 - public function __construct() {
18 - add_shortcode( 'content_protector', array($this, 'render_shortcode') );
19 - add_shortcode( 'passster', array($this, 'render_shortcode') );
20 - add_filter( 'the_content', array($this, 'filter_the_content') );
21 - add_filter( 'acf_the_content', array($this, 'filter_the_content') );
22 - add_filter( 'get_the_excerpt', array($this, 'filter_the_content') );
23 - add_action( 'template_redirect', array($this, 'check_global_proctection') );
24 - }
25 -
26 - /**
27 - * Returns instance of PS_Public.
28 - *
29 - * @return object
30 - */
31 - public static function get_instance() {
32 - if ( null === self::$instance ) {
33 - self::$instance = new self();
34 - }
35 - return self::$instance;
36 - }
37 -
38 - /**
39 - * Render the Passster shortcode.
40 - *
41 - * @param array $atts array of attributes.
42 - * @param string|null $content the current content.
43 - *
44 - * @return string
45 - */
46 - public function render_shortcode( array $atts, string $content = null ) : string {
47 - // check if valid before restrict anything.
48 - $valid = PS_Conditional::is_valid( $atts );
49 - $options = get_option( 'passster' );
50 - if ( $valid ) {
51 - if ( !empty( $atts['area'] ) ) {
52 - $area_id = esc_html( $atts['area'] );
53 - $area = get_post( $area_id );
54 - $content = $area->post_content;
55 - do_action( 'passster_content_unlocked' );
56 - return apply_filters( 'the_content', str_replace( '{post-id}', get_the_id(), $content ) );
57 - } else {
58 - $content = apply_filters( 'the_content', $content );
59 - do_action( 'passster_content_unlocked' );
60 - return apply_filters( 'passster_content', $content );
61 - }
62 - }
63 - // do nothing if no atts.
64 - if ( empty( $atts ) ) {
65 - return $content;
66 - }
67 - // Set default form.
68 - $form = PS_Form::get_password_form();
69 - // Password.
70 - if ( !empty( $atts['password'] ) ) {
71 - $form = PS_Form::get_password_form();
72 - $form = str_replace( '[PASSSTER_TYPE]', 'password', $form );
73 - }
74 - // Area.
75 - if ( !empty( $atts['area'] ) ) {
76 - $area_id = esc_html( $atts['area'] );
77 - $form = str_replace( '[PASSSTER_AREA]', $area_id, $form );
78 - }
79 - // Page.
80 - if ( !empty( $atts['protection'] ) ) {
81 - $form = str_replace( '[PASSSTER_PROTECTION]', 'full', $form );
82 - } else {
83 - if ( !empty( $atts['area'] ) ) {
84 - $form = str_replace( '[PASSSTER_PROTECTION]', 'area', $form );
85 - }
86 - }
87 - // Redirect.
88 - if ( !empty( $atts['redirect'] ) ) {
89 - $form = str_replace( '[PASSSTER_REDIRECT]', esc_url( $atts['redirect'] ), $form );
90 - } else {
91 - $form = str_replace( '[PASSSTER_REDIRECT]', '', $form );
92 - }
93 - // headline.
94 - if ( !empty( $options['hide_headline'] ) ) {
95 - $form = str_replace( '[PASSSTER_FORM_HEADLINE]', '', $form );
96 - } elseif ( !empty( $atts['headline'] ) ) {
97 - $form = str_replace( '[PASSSTER_FORM_HEADLINE]', esc_html( $atts['headline'] ), $form );
98 - } else {
99 - $form = str_replace( '[PASSSTER_FORM_HEADLINE]', $options['headline'], $form );
100 - }
101 - // instruction.
102 - if ( !empty( $atts['instruction'] ) ) {
103 - $form = str_replace( '[PASSSTER_FORM_INSTRUCTIONS]', esc_html( $atts['instruction'] ), $form );
104 - } else {
105 - $form = str_replace( '[PASSSTER_FORM_INSTRUCTIONS]', $options['instruction'], $form );
106 - }
107 - // placeholder.
108 - if ( !empty( $atts['placeholder'] ) ) {
109 - $form = str_replace( '[PASSSTER_PLACEHOLDER]', esc_html( $atts['placeholder'] ), $form );
110 - } else {
111 - $form = str_replace( '[PASSSTER_PLACEHOLDER]', $options['placeholder'], $form );
112 - }
113 - // button.
114 - if ( !empty( $atts['button'] ) ) {
115 - $form = str_replace( '[PASSSTER_BUTTON_LABEL]', esc_html( $atts['button'] ), $form );
116 - } else {
117 - $form = str_replace( '[PASSSTER_BUTTON_LABEL]', $options['button_label'], $form );
118 - }
119 - // modify id.
120 - if ( !empty( $atts['id'] ) ) {
121 - $form = str_replace( '[PASSSTER_ID]', 'ps-' . esc_html( $atts['id'] ), $form );
122 - } else {
123 - $form = str_replace( '[PASSSTER_ID]', 'ps-' . wp_rand( 10, 1000 ), $form );
124 - }
125 - // hide or not.
126 - if ( !empty( $atts['hide'] ) ) {
127 - $form = str_replace( '[PASSSTER_HIDE]', ' passster-hide', $form );
128 - } else {
129 - $form = str_replace( '[PASSSTER_HIDE]', '', $form );
130 - }
131 - // ACF field.
132 - if ( !empty( $atts['acf'] ) ) {
133 - $form = str_replace( '[PASSSTER_ACF]', ' data-acf="' . esc_html( $atts['acf'] ) . '"', $form );
134 - } else {
135 - $form = str_replace( '[PASSSTER_ACF]', '', $form );
136 - }
137 - return $form;
138 - }
139 -
140 - /**
141 - * Filters the_content with Passster.
142 - *
143 - * @param string $content given content.
144 - *
145 - * @return string
146 - * @throws Exception
147 - */
148 - public function filter_the_content( string $content ) : string {
149 - $post_id = get_the_id();
150 - $activate_protection = get_post_meta( $post_id, 'passster_activate_protection', true );
151 - // user restriction.
152 - $user_restriction_type = get_post_meta( $post_id, 'passster_user_restriction_type', true );
153 - $user_restriction = get_post_meta( $post_id, 'passster_user_restriction', true );
154 - // Redirection.
155 - $redirection = get_post_meta( $post_id, 'passster_redirect_url', true );
156 - // texts.
157 - $headline = get_post_meta( $post_id, 'passster_headline', true );
158 - $instruction = get_post_meta( $post_id, 'passster_instruction', true );
159 - $placeholder = get_post_meta( $post_id, 'passster_placeholder', true );
160 - $button = get_post_meta( $post_id, 'passster_button', true );
161 - $id = get_post_meta( $post_id, 'passster_id', true );
162 - if ( !$activate_protection ) {
163 - return $content;
164 - }
165 - // build atts array to validate.
166 - $atts = array();
167 - $shortcode = '';
168 - $password = get_post_meta( $post_id, 'passster_password', true );
169 - $atts['password'] = $password;
170 - $shortcode = '[passster password="' . $password . '" protection="full" ';
171 - if ( !empty( $redirection ) ) {
172 - $shortcode .= 'redirect="' . $redirection . '" ';
173 - }
174 - if ( !empty( $headline ) ) {
175 - $shortcode .= 'headline="' . $headline . '" ';
176 - }
177 - if ( !empty( $instruction ) ) {
178 - $shortcode .= 'instruction="' . $instruction . '" ';
179 - }
180 - if ( !empty( $placeholder ) ) {
181 - $shortcode .= 'placeholder="' . $placeholder . '" ';
182 - }
183 - if ( !empty( $button ) ) {
184 - $shortcode .= 'button="' . $button . '" ';
185 - }
186 - if ( !empty( $id ) ) {
187 - $shortcode .= 'id="' . $id . '" ';
188 - }
189 - $shortcode .= ']{content}[/passster]';
190 - // check if valid before restrict anything.
191 - $valid = PS_Conditional::is_valid( $atts );
192 - if ( $valid ) {
193 - return $content;
194 - }
195 - // replace placeholder with content.
196 - $shortcode = str_replace( '{content}', $content, $shortcode );
197 - return do_shortcode( $shortcode );
198 - }
199 -
200 - /**
201 - * Redirect if global protection is activated and no password is set.
202 - *
203 - * @return void
204 - * @throws Exception
205 - */
206 - public function check_global_proctection() {
207 - $options = get_option( 'passster' );
208 - // Allow Elementor editing the page.
209 - $elementor_preview = filter_input( INPUT_GET, 'elementor-preview', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
210 - if ( $elementor_preview ) {
211 - return;
212 - }
213 - // Allow Live Canvas Editor.
214 - $live_canvas_preview = filter_input( INPUT_GET, 'lc_action_launch_editing', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
215 - if ( $live_canvas_preview ) {
216 - return;
217 - }
218 - if ( !isset( $options['global_protection_id'] ) ) {
219 - return;
220 - }
221 - if ( !isset( $options['activate_global_protection'] ) ) {
222 - return;
223 - }
224 - // Build $atts array based on protection settings.
225 - $post_id = esc_html( $options['global_protection_id'] );
226 - $is_active = esc_html( $options['activate_global_protection'] );
227 - $atts = array();
228 - $password = get_post_meta( $post_id, 'passster_password', true );
229 - $atts['password'] = esc_html( $password );
230 - if ( !empty( $post_id ) ) {
231 - if ( $is_active ) {
232 - if ( is_page( $post_id ) || is_single( $post_id ) ) {
233 - return;
234 - }
235 - // Check excluded pages.
236 - if ( isset( $options['exclude_pages'] ) ) {
237 - foreach ( $options['exclude_pages'] as $excluded_page_id ) {
238 - if ( is_page( $excluded_page_id ) ) {
239 - return;
240 - }
241 - }
242 - }
243 - // Check if cookie is set.
244 - $cookie = esc_html( $_COOKIE['passster'] );
245 - if ( empty( $cookie ) || !PS_Conditional::is_valid( $atts ) ) {
246 - $global_protection_url = get_permalink( $post_id );
247 - wp_redirect( esc_url_raw( $global_protection_url ) );
248 - exit;
249 - }
250 - }
251 - }
252 - }
253 -
254 -}
1 +<?php
2 +
3 +namespace passster;
4 +
5 +use Exception;
6 +class PS_Public {
7 + /**
8 + * Contains instance or null
9 + *
10 + * @var object|null
11 + */
12 + private static $instance = null;
13 +
14 + /**
15 + * Track which posts have already had their protection form rendered
16 + * to prevent duplicate forms on page builders like Avada.
17 + *
18 + * @var array
19 + */
20 + private static $rendered_protection = array();
21 +
22 + /**
23 + * Constructor for PS_Public
24 + */
25 + public function __construct() {
26 + add_shortcode( 'content_protector', array($this, 'render_shortcode') );
27 + add_shortcode( 'passster', array($this, 'render_shortcode') );
28 + add_filter( 'the_content', array($this, 'filter_the_content') );
29 + add_filter( 'acf_the_content', array($this, 'filter_the_content') );
30 + add_filter( 'get_the_excerpt', array($this, 'filter_the_content') );
31 + add_action( 'template_redirect', array($this, 'check_global_proctection') );
32 + add_action( 'wp_enqueue_scripts', array($this, 'add_public_scripts'), 9999 );
33 + }
34 +
35 + /**
36 + * Returns instance of PS_Public.
37 + *
38 + * @return object
39 + */
40 + public static function get_instance() {
41 + if ( null === self::$instance ) {
42 + self::$instance = new self();
43 + }
44 + return self::$instance;
45 + }
46 +
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 + /**
66 + * Render the Passster shortcode.
67 + *
68 + * @param array $atts array of attributes.
69 + * @param string|null $content the current content.
70 + *
71 + * @return string
72 + */
73 + public function render_shortcode( array $atts, string $content = null ) : string {
74 + // Schedule check for protected areas (PRO only).
75 + if ( !empty( $atts['area'] ) && \passster_fs()->is_plan_or_trial__premium_only( 'pro' ) ) {
76 + $area_id = absint( $atts['area'] );
77 + $schedule_enabled = get_post_meta( $area_id, 'passster_schedule_enabled', true );
78 + if ( $schedule_enabled ) {
79 + $schedule_start = get_post_meta( $area_id, 'passster_schedule_start', true );
80 + $schedule_end = get_post_meta( $area_id, 'passster_schedule_end', true );
81 + $now = current_time( 'timestamp' );
82 + $in_schedule = true;
83 + if ( !empty( $schedule_start ) && $now < strtotime( $schedule_start ) ) {
84 + $in_schedule = false;
85 + }
86 + if ( !empty( $schedule_end ) && $now > strtotime( $schedule_end ) ) {
87 + $in_schedule = false;
88 + }
89 + if ( !$in_schedule ) {
90 + $area = get_post( $area_id );
91 + if ( $area && ('publish' === $area->post_status || current_user_can( 'edit_post', $area_id )) ) {
92 + return $this->render_unlocked_content( str_replace( '{post-id}', get_the_id(), $area->post_content ) );
93 + }
94 + return $content ?? '';
95 + }
96 + }
97 + }
98 + // check if valid before restrict anything.
99 + $valid = PS_Conditional::is_valid( $atts );
100 + $options = get_option( 'passster' );
101 + if ( $valid ) {
102 + if ( !empty( $atts['area'] ) ) {
103 + $area_id = esc_html( $atts['area'] );
104 + $area = get_post( $area_id );
105 + if ( 'publish' === $area->post_status || current_user_can( 'edit_post', $area_id ) ) {
106 + $content = $area->post_content;
107 + do_action( 'passster_content_unlocked' );
108 + return $this->render_unlocked_content( str_replace( '{post-id}', get_the_id(), $content ) );
109 + }
110 + } else {
111 + $content = $this->render_unlocked_content( $content );
112 + do_action( 'passster_content_unlocked' );
113 + return apply_filters( 'passster_content', $content );
114 + }
115 + }
116 + // do nothing if no atts.
117 + if ( empty( $atts ) ) {
118 + return $content;
119 + }
120 + // Set default form.
121 + $form = PS_Form::get_password_form();
122 + // Password.
123 + if ( !empty( $atts['password'] ) ) {
124 + $form = PS_Form::get_password_form();
125 + $form = str_replace( '[PASSSTER_TYPE]', 'password', $form );
126 + }
127 + // Area.
128 + if ( !empty( $atts['area'] ) ) {
129 + $area_id = absint( $atts['area'] );
130 + $form = str_replace( '[PASSSTER_AREA]', $area_id, $form );
131 + }
132 + // Page.
133 + if ( !empty( $atts['protection'] ) ) {
134 + $form = str_replace( '[PASSSTER_PROTECTION]', 'full', $form );
135 + } elseif ( !empty( $atts['area'] ) ) {
136 + $form = str_replace( '[PASSSTER_PROTECTION]', 'area', $form );
137 + }
138 + // Redirect.
139 + if ( !empty( $atts['redirect'] ) ) {
140 + $form = str_replace( '[PASSSTER_REDIRECT]', esc_url( $atts['redirect'] ), $form );
141 + } else {
142 + $form = str_replace( '[PASSSTER_REDIRECT]', '', $form );
143 + }
144 + // headline tag.
145 + $allowed_headline_tags = array(
146 + 'span',
147 + 'p',
148 + 'div',
149 + 'h1',
150 + 'h2',
151 + 'h3',
152 + 'h4',
153 + 'h5',
154 + 'h6'
155 + );
156 + $headline_tag = ( isset( $options['headline_tag'] ) && in_array( $options['headline_tag'], $allowed_headline_tags, true ) ? $options['headline_tag'] : 'span' );
157 + $form = str_replace( '[PASSSTER_HEADLINE_TAG]', $headline_tag, $form );
158 + // headline.
159 + if ( !empty( $options['hide_headline'] ) ) {
160 + $form = str_replace( '[PASSSTER_FORM_HEADLINE]', '', $form );
161 + } elseif ( !empty( $atts['headline'] ) ) {
162 + $form = str_replace( '[PASSSTER_FORM_HEADLINE]', esc_html( $atts['headline'] ), $form );
163 + } else {
164 + $form = str_replace( '[PASSSTER_FORM_HEADLINE]', esc_html( $options['headline'] ), $form );
165 + }
166 + // instruction.
167 + if ( !empty( $atts['instruction'] ) ) {
168 + $decoded_instruction = base64_decode( $atts['instruction'] );
169 + $decoded_instruction = html_entity_decode( $decoded_instruction );
170 + $sanitized_instruction = wp_kses_post( $decoded_instruction );
171 + $form = str_replace( '[PASSSTER_FORM_INSTRUCTIONS]', $sanitized_instruction, $form );
172 + } else {
173 + $form = str_replace( '[PASSSTER_FORM_INSTRUCTIONS]', wp_kses_post( $options['instruction'] ), $form );
174 + }
175 + // placeholder.
176 + if ( !empty( $atts['placeholder'] ) ) {
177 + $form = str_replace( '[PASSSTER_PLACEHOLDER]', esc_attr( $atts['placeholder'] ), $form );
178 + } else {
179 + $form = str_replace( '[PASSSTER_PLACEHOLDER]', esc_attr( $options['placeholder'] ), $form );
180 + }
181 + // label.
182 + $form = str_replace( '[PASSSTER_LABEL]', esc_html__( 'Enter your password', 'content-protector' ), $form );
183 + // button.
184 + if ( !empty( $atts['button'] ) ) {
185 + $form = str_replace( '[PASSSTER_BUTTON_LABEL]', esc_html( $atts['button'] ), $form );
186 + } else {
187 + $form = str_replace( '[PASSSTER_BUTTON_LABEL]', esc_html( $options['button_label'] ), $form );
188 + }
189 + // modify id.
190 + if ( !empty( $atts['id'] ) ) {
191 + $form = str_replace( '[PASSSTER_ID]', 'ps-' . esc_attr( $atts['id'] ), $form );
192 + } else {
193 + $form = str_replace( '[PASSSTER_ID]', 'ps-' . wp_rand( 10, 1000 ), $form );
194 + }
195 + // post id (per-form, for correct REST unlock on archive pages with multiple protected posts).
196 + $form = str_replace( '[PASSSTER_POST_ID]', absint( get_the_ID() ), $form );
197 + // term id (for category archive protection — passed to REST API so it can validate against term meta).
198 + $term_id_val = ( !empty( $atts['term_id'] ) ? absint( $atts['term_id'] ) : 0 );
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 );
203 + // hide or not.
204 + if ( !empty( $atts['hide'] ) ) {
205 + $form = str_replace( '[PASSSTER_HIDE]', ' passster-hide', $form );
206 + } else {
207 + $form = str_replace( '[PASSSTER_HIDE]', '', $form );
208 + }
209 + // ACF field.
210 + if ( !empty( $atts['acf'] ) ) {
211 + $form = str_replace( '[PASSSTER_ACF]', ' data-acf="' . esc_url( $atts['acf'] ) . '"', $form );
212 + } else {
213 + $form = str_replace( '[PASSSTER_ACF]', '', $form );
214 + }
215 + return $form;
216 + }
217 +
218 + /**
219 + * Filters the_content with Passster.
220 + *
221 + * @param string $content given content.
222 + *
223 + * @return string
224 + * @throws Exception
225 + */
226 + public function filter_the_content( string $content ) : string {
227 + $post_id = get_the_id();
228 + // Prevent duplicate form rendering (fixes issue with Avada and other page builders)
229 + if ( isset( self::$rendered_protection[$post_id] ) ) {
230 + // Already rendered the protection form for this post, return protected content placeholder
231 + // or the form that was already generated
232 + return self::$rendered_protection[$post_id]['form'] ?? $content;
233 + }
234 + $parent_id = wp_get_post_parent_id( $post_id );
235 + if ( $parent_id ) {
236 + $activate_protection = get_post_meta( $parent_id, 'passster_activate_protection', true );
237 + $children_protection = get_post_meta( $parent_id, 'passster_protect_child_pages', true );
238 + if ( $activate_protection && $children_protection ) {
239 + $post_id = $parent_id;
240 + // Check parent too
241 + if ( isset( self::$rendered_protection[$post_id] ) ) {
242 + return self::$rendered_protection[$post_id]['form'] ?? $content;
243 + }
244 + }
245 + }
246 + $activate_protection = get_post_meta( $post_id, 'passster_activate_protection', true );
247 + // user restriction.
248 + $user_restriction_type = get_post_meta( $post_id, 'passster_user_restriction_type', true );
249 + $user_restriction = get_post_meta( $post_id, 'passster_user_restriction', true );
250 + // Redirection.
251 + $redirection = get_post_meta( $post_id, 'passster_redirect_url', true );
252 + // texts.
253 + $overwrite_defaults = get_post_meta( $post_id, 'passster_activate_overwrite_defaults', true );
254 + $headline = ( $overwrite_defaults ? get_post_meta( $post_id, 'passster_headline', true ) : '' );
255 + $instruction = ( $overwrite_defaults ? get_post_meta( $post_id, 'passster_instruction', true ) : '' );
256 + $placeholder = ( $overwrite_defaults ? get_post_meta( $post_id, 'passster_placeholder', true ) : '' );
257 + $button = ( $overwrite_defaults ? get_post_meta( $post_id, 'passster_button', true ) : '' );
258 + $id = get_post_meta( $post_id, 'passster_id', true );
259 + if ( !$activate_protection ) {
260 + return $content;
261 + }
262 + // build atts array to validate.
263 + $atts = array();
264 + $shortcode = '';
265 + $password = get_post_meta( $post_id, 'passster_password', true );
266 + $atts['password'] = $password;
267 + $shortcode = '[passster password="' . $password . '" protection="full" ';
268 + if ( !empty( $redirection ) ) {
269 + $shortcode .= 'redirect="' . $redirection . '" ';
270 + }
271 + if ( !empty( $headline ) ) {
272 + $shortcode .= 'headline="' . $headline . '" ';
273 + }
274 + if ( !empty( $instruction ) ) {
275 + $shortcode .= 'instruction="' . base64_encode( $instruction ) . '" ';
276 + }
277 + if ( !empty( $placeholder ) ) {
278 + $shortcode .= 'placeholder="' . $placeholder . '" ';
279 + }
280 + if ( !empty( $button ) ) {
281 + $shortcode .= 'button="' . $button . '" ';
282 + }
283 + if ( !empty( $id ) ) {
284 + $shortcode .= 'id="' . $id . '" ';
285 + }
286 + $shortcode .= ']{content}[/passster]';
287 + // check if valid before restrict anything.
288 + $valid = PS_Conditional::is_valid( $atts );
289 + if ( $valid ) {
290 + return $content;
291 + }
292 + // replace placeholder with content.
293 + $shortcode = str_replace( '{content}', $content, $shortcode );
294 + // Generate the form
295 + $rendered_form = do_shortcode( $shortcode );
296 + // Store reference to prevent duplicate rendering (Avada, Elementor, etc.)
297 + self::$rendered_protection[$post_id] = array(
298 + 'form' => $rendered_form,
299 + );
300 + return $rendered_form;
301 + }
302 +
303 + /**
304 + * Redirect if global protection is activated and no password is set.
305 + *
306 + * @return void
307 + * @throws Exception
308 + */
309 + public function check_global_proctection() {
310 + $options = get_option( 'passster' );
311 + $post_id = get_queried_object_id();
312 + if ( !$post_id ) {
313 + return;
314 + }
315 + // Allow Elementor editing the page.
316 + $elementor_preview = filter_input( INPUT_GET, 'elementor-preview', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
317 + // Allow Live Canvas Editor.
318 + $live_canvas_preview = filter_input( INPUT_GET, 'lc_action_launch_editing', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
319 + if ( is_preview() || $elementor_preview || $live_canvas_preview ) {
320 + if ( is_user_logged_in() && current_user_can( 'edit_post', $post_id ) ) {
321 + return;
322 + }
323 + }
324 + if ( !isset( $options['global_protection_id'] ) ) {
325 + return;
326 + }
327 + if ( !isset( $options['activate_global_protection'] ) ) {
328 + return;
329 + }
330 + // Build $atts array based on protection settings.
331 + $post_id = esc_html( $options['global_protection_id'] );
332 + $is_active = esc_html( $options['activate_global_protection'] );
333 + $atts = array();
334 + $password = get_post_meta( $post_id, 'passster_password', true );
335 + $atts['password'] = $password;
336 + if ( !empty( $post_id ) ) {
337 + if ( $is_active ) {
338 + if ( is_page( $post_id ) || is_single( $post_id ) ) {
339 + return;
340 + }
341 + // Check excluded pages.
342 + if ( isset( $options['exclude_pages'] ) ) {
343 + foreach ( $options['exclude_pages'] as $excluded_page_id ) {
344 + if ( is_page( $excluded_page_id ) ) {
345 + return;
346 + }
347 + }
348 + }
349 + // Check if cookie is set.
350 + $cookie = esc_html( $_COOKIE['passster'] );
351 + if ( !PS_Conditional::is_valid( $atts ) ) {
352 + $global_protection_url = get_permalink( $post_id );
353 + $pass_param = filter_input( INPUT_GET, 'pass', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
354 + if ( !empty( $pass_param ) ) {
355 + $global_protection_url = add_query_arg( 'pass', $pass_param, $global_protection_url );
356 + }
357 + wp_redirect( esc_url_raw( $global_protection_url ) );
358 + exit;
359 + }
360 + }
361 + }
362 + }
363 +
364 + /**
365 + * Enqueue scripts for shortcode
366 + *
367 + * @return void
368 + */
369 + public function add_public_scripts() {
370 + $suffix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min' );
371 + $options = get_option( 'passster' );
372 + // Only load CSS if not disabled (allows themes to style the form)
373 + if ( empty( $options['disable_css'] ) ) {
374 + wp_enqueue_style(
375 + 'passster-public',
376 + PASSSTER_URL . '/assets/public/passster-public' . $suffix . '.css',
377 + array(),
378 + PASSSTER_VERSION,
379 + 'all'
380 + );
381 + }
382 + wp_enqueue_script(
383 + 'passster-cookie',
384 + PASSSTER_URL . '/assets/public/cookie.js',
385 + array('jquery', 'wp-api-fetch'),
386 + PASSSTER_VERSION,
387 + false
388 + );
389 + wp_enqueue_script(
390 + 'passster-public',
391 + PASSSTER_URL . '/assets/public/passster-public' . $suffix . '.js',
392 + array('jquery', 'passster-cookie'),
393 + PASSSTER_VERSION,
394 + false
395 + );
396 + $shortcodes = array();
397 + if ( isset( $options['third_party_shortcodes'] ) && !empty( $options['third_party_shortcodes'] ) ) {
398 + $shortcodes_in_options = explode( ',', $options['third_party_shortcodes'] );
399 + if ( is_array( $shortcodes_in_options ) ) {
400 + foreach ( $shortcodes_in_options as $shortcode ) {
401 + $shortcodes[$shortcode] = do_shortcode( str_replace( '{post-id}', get_the_id(), $shortcode ) );
402 + }
403 + }
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' ) ) );
409 + $args = array(
410 + 'ajax_url' => admin_url() . 'admin-ajax.php',
411 + 'rest_url' => get_rest_url(),
412 + 'nonce' => wp_create_nonce( 'ps-password-nonce' ),
413 + 'hash_nonce' => wp_create_nonce( 'ps-hash-nonce' ),
414 + 'logout_nonce' => wp_create_nonce( 'ps-logout-nonce' ),
415 + 'post_id' => $current_post_id,
416 + 'shortcodes' => $shortcodes,
417 + 'permalink' => $reload_url,
418 + );
419 + if ( isset( $options['cookie_duration_unit'] ) ) {
420 + $args['cookie_duration_unit'] = esc_html( $options['cookie_duration_unit'] );
421 + } else {
422 + $args['cookie_duration_unit'] = 'days';
423 + }
424 + if ( isset( $options['cookie_duration'] ) ) {
425 + $args['cookie_duration'] = esc_html( $options['cookie_duration'] );
426 + } else {
427 + $args['cookie_duration'] = 1;
428 + }
429 + if ( isset( $options['disable_cookie'] ) ) {
430 + $args['disable_cookie'] = esc_html( $options['disable_cookie'] );
431 + } else {
432 + $args['disable_cookie'] = false;
433 + }
434 + $args['unlock_mode'] = !empty( $options['unlock_mode'] );
435 + wp_localize_script( 'passster-public', 'ps_ajax', $args );
436 + // if password type hint used.
437 + $password_typing = $options['show_password'];
438 + if ( $password_typing ) {
439 + wp_enqueue_script(
440 + 'password-typing',
441 + PASSSTER_URL . '/assets/public/password-typing.js',
442 + array('jquery'),
443 + PASSSTER_VERSION,
444 + false
445 + );
446 + }
447 + }
448 +
449 +}