PluginProbe
Passster – Password Protect Pages and Content / 4.3.16
Passster – Password Protect Pages and Content v4.3.16
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 4.2.15 All 48 releases
← All changes | inc/class-ps-block-editor.php +360 -360 4.3.144.3.16 View file →
@@ -1,360 +1,360 @@
1 -<?php
2 -
3 -namespace passster;
4 -
5 -class PS_Block_Editor {
6 - /**
7 - * Contains instance or null
8 - *
9 - * @var object|null
10 - */
11 - private static $instance = null;
12 -
13 - /**
14 - * Returns instance of PS_Block_Editor.
15 - *
16 - * @return object
17 - */
18 - public static function get_instance() {
19 - if ( null === self::$instance ) {
20 - self::$instance = new self();
21 - }
22 - return self::$instance;
23 - }
24 -
25 - /**
26 - * Constructor for PS_Block_Editor
27 - */
28 - public function __construct() {
29 - add_action( 'wp_enqueue_scripts', array($this, 'register_block_scripts') );
30 - add_action( 'enqueue_block_editor_assets', array($this, 'add_block_editor_assets') );
31 - add_action( 'init', array($this, 'register_area_block') );
32 - add_action( 'init', array($this, 'register_protected_content_block') );
33 - add_action(
34 - 'save_post',
35 - array($this, 'sync_protected_content_blocks'),
36 - 10,
37 - 2
38 - );
39 - add_filter(
40 - 'block_categories_all',
41 - array($this, 'register_block_category'),
42 - 10,
43 - 2
44 - );
45 - }
46 -
47 - /**
48 - * Register Passster block category.
49 - *
50 - * @param array $categories Block categories.
51 - * @param WP_Block_Editor_Context $context Block editor context.
52 - *
53 - * @return array Modified categories.
54 - */
55 - public function register_block_category( $categories, $context ) {
56 - return array_merge( array(array(
57 - 'slug' => 'passster',
58 - 'title' => __( 'Passster', 'content-protector' ),
59 - 'icon' => 'lock',
60 - )), $categories );
61 - }
62 -
63 - /**
64 - * Enqueue scripts for blocks.
65 - *
66 - * @return void
67 - */
68 - public function register_block_scripts() {
69 - $area_asset_file = (include PASSSTER_PATH . '/build/area/index.asset.php');
70 - wp_register_script(
71 - 'area-script',
72 - PASSSTER_URL . '/build/area/index.js',
73 - $area_asset_file['dependencies'],
74 - $area_asset_file['version']
75 - );
76 - }
77 -
78 - /**
79 - * Add block editor scripts and styles.
80 - *
81 - * @return void
82 - */
83 - public function add_block_editor_assets() {
84 - // Area block.
85 - $area_asset_file = (include PASSSTER_PATH . '/build/area/index.asset.php');
86 - wp_enqueue_script(
87 - 'area-script',
88 - PASSSTER_URL . '/build/area/index.js',
89 - $area_asset_file['dependencies'],
90 - $area_asset_file['version']
91 - );
92 - wp_localize_script( 'area-script', 'area_data', array(
93 - 'is_pro' => \passster_fs()->is_plan_or_trial__premium_only( 'pro' ),
94 - 'create_area_url' => admin_url( 'post-new.php?post_type=protected_areas' ),
95 - 'options' => get_option( 'passster' ),
96 - ) );
97 - wp_enqueue_style( 'area-style', PASSSTER_URL . '/build/area/index.css' );
98 - // Protected Content block.
99 - $protected_content_asset = PASSSTER_PATH . '/build/blocks/protected-content/index.asset.php';
100 - if ( file_exists( $protected_content_asset ) ) {
101 - $protected_content_asset_file = (include $protected_content_asset);
102 - wp_enqueue_script(
103 - 'passster-protected-content-script',
104 - PASSSTER_URL . '/build/blocks/protected-content/index.js',
105 - $protected_content_asset_file['dependencies'],
106 - $protected_content_asset_file['version']
107 - );
108 - wp_localize_script( 'passster-protected-content-script', 'passster_block_data', array(
109 - 'is_pro' => \passster_fs()->is_plan_or_trial__premium_only( 'pro' ),
110 - 'options' => get_option( 'passster' ),
111 - 'date_format' => get_option( 'date_format' ),
112 - 'time_format' => get_option( 'time_format' ),
113 - 'timezone' => wp_timezone_string(),
114 - 'now' => current_time( 'c' ),
115 - ) );
116 - wp_enqueue_style(
117 - 'passster-protected-content-style',
118 - PASSSTER_URL . '/build/blocks/protected-content/index.css',
119 - array(),
120 - $protected_content_asset_file['version']
121 - );
122 - if ( function_exists( 'wp_set_script_translations' ) ) {
123 - wp_set_script_translations( 'passster-protected-content-script', 'content-protector', PASSSTER_PATH . '/languages' );
124 - }
125 - }
126 - // Make the blocks translatable.
127 - if ( function_exists( 'wp_set_script_translations' ) ) {
128 - wp_set_script_translations( 'area-script', 'content-protector', PASSSTER_PATH . '/languages' );
129 - }
130 - }
131 -
132 - /**
133 - * Register area block in WordPress.
134 - *
135 - * @return void
136 - */
137 - public function register_area_block() {
138 - $options = get_option( 'passster' );
139 - $settings = array(
140 - 'render_callback' => array($this, 'render_area_block'),
141 - 'attributes' => array(
142 - 'area_id' => array(
143 - 'type' => 'string',
144 - 'default' => 0,
145 - ),
146 - 'headline' => array(
147 - 'type' => 'string',
148 - 'default' => esc_html( $options['headline'] ),
149 - ),
150 - 'instruction' => array(
151 - 'type' => 'string',
152 - 'default' => wp_kses_post( $options['instruction'] ),
153 - ),
154 - 'buttonLabel' => array(
155 - 'type' => 'string',
156 - 'default' => esc_html( $options['button_label'] ),
157 - ),
158 - 'placeholder' => array(
159 - 'type' => 'string',
160 - 'default' => esc_html( $options['placeholder'] ),
161 - ),
162 - ),
163 - );
164 - register_block_type( 'content-protector/area', array_merge( array(
165 - 'editor_script' => 'area-script',
166 - 'editor_style' => 'area-style',
167 - ), $settings ) );
168 - }
169 -
170 - /**
171 - * Returns the shortcode for an area based on block attributes.
172 - *
173 - * @param array $attributes the list attributes from the block.
174 - *
175 - * @return string
176 - */
177 - public function render_area_block( array $attributes ) {
178 - $area_id = esc_attr( $attributes['area_id'] );
179 - $area = get_post( $area_id );
180 - if ( !$area ) {
181 - return '';
182 - }
183 - // Build dynamic shortcode.
184 - $content = $area->post_content;
185 - $shortcode = '';
186 - // texts.
187 - $headline = esc_attr( $attributes['headline'] );
188 - $instruction = wp_kses_post( $attributes['instruction'] );
189 - $button = esc_attr( $attributes['buttonLabel'] );
190 - $placeholder = esc_attr( $attributes['placeholder'] );
191 - $id = get_post_meta( $area_id, 'passster_id', true );
192 - // Redirection.
193 - $redirection = get_post_meta( $area_id, 'passster_redirect_url', true );
194 - $atts = array();
195 - $password = get_post_meta( $area_id, 'passster_password', true );
196 - $atts['password'] = $password;
197 - $shortcode = '[passster password="' . $password . '" area="' . $area_id . '" ';
198 - // Building the actual shortcode.
199 - if ( !empty( $redirection ) ) {
200 - $shortcode .= 'redirect="' . $redirection . '" ';
201 - }
202 - if ( !empty( $headline ) ) {
203 - $shortcode .= 'headline="' . $headline . '" ';
204 - }
205 - if ( !empty( $instruction ) ) {
206 - $shortcode .= 'instruction="' . base64_encode( $instruction ) . '" ';
207 - }
208 - if ( !empty( $placeholder ) ) {
209 - $shortcode .= 'placeholder="' . $placeholder . '" ';
210 - }
211 - if ( !empty( $button ) ) {
212 - $shortcode .= 'button="' . $button . '" ';
213 - }
214 - if ( !empty( $id ) ) {
215 - $shortcode .= 'id="' . $id . '" ';
216 - }
217 - $shortcode = rtrim( $shortcode );
218 - $shortcode .= ']';
219 - // check if valid before restrict anything.
220 - $valid = PS_Conditional::is_valid( $atts );
221 - if ( $valid ) {
222 - return $content;
223 - }
224 - return do_shortcode( $shortcode );
225 - }
226 -
227 - /**
228 - * Register protected content block.
229 - *
230 - * @return void
231 - */
232 - public function register_protected_content_block() {
233 - // Check if build files exist.
234 - $block_path = PASSSTER_PATH . '/build/blocks/protected-content';
235 - if ( !file_exists( $block_path . '/block.json' ) ) {
236 - return;
237 - }
238 - register_block_type( $block_path );
239 - }
240 -
241 - /**
242 - * Sync protected content blocks with Protected Areas CPT.
243 - *
244 - * @param int $post_id Post ID being saved.
245 - * @param WP_Post $post Post object.
246 - *
247 - * @return void
248 - */
249 - public function sync_protected_content_blocks( $post_id, $post ) {
250 - // Skip auto-saves and revisions.
251 - if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
252 - return;
253 - }
254 - if ( wp_is_post_revision( $post_id ) ) {
255 - return;
256 - }
257 - // Skip protected areas CPT to avoid loops.
258 - if ( 'protected_areas' === $post->post_type ) {
259 - return;
260 - }
261 - // Parse blocks from content.
262 - $blocks = parse_blocks( $post->post_content );
263 - $protected_blocks = $this->find_protected_content_blocks( $blocks );
264 - // Get existing synced areas for this post.
265 - $existing_areas = get_posts( array(
266 - 'post_type' => 'protected_areas',
267 - 'posts_per_page' => -1,
268 - 'meta_query' => array(array(
269 - 'key' => '_passster_source',
270 - 'value' => 'block',
271 - ), array(
272 - 'key' => '_passster_source_post_id',
273 - 'value' => $post_id,
274 - )),
275 - ) );
276 - $existing_block_ids = array();
277 - foreach ( $existing_areas as $area ) {
278 - $block_id = get_post_meta( $area->ID, '_passster_block_id', true );
279 - $existing_block_ids[$block_id] = $area->ID;
280 - }
281 - $synced_block_ids = array();
282 - // Sync each protected block.
283 - foreach ( $protected_blocks as $block ) {
284 - $attrs = $block['attrs'];
285 - $block_id = ( !empty( $attrs['blockId'] ) ? $attrs['blockId'] : '' );
286 - if ( empty( $block_id ) ) {
287 - continue;
288 - }
289 - $synced_block_ids[] = $block_id;
290 - // Prepare area data.
291 - $area_title = ( !empty( $attrs['areaTitle'] ) ? $attrs['areaTitle'] : sprintf(
292 - /* translators: %s: Post title */
293 - __( 'Protected block in %s', 'content-protector' ),
294 - $post->post_title
295 - ) );
296 - $area_data = array(
297 - 'post_title' => $area_title,
298 - 'post_type' => 'protected_areas',
299 - 'post_status' => 'publish',
300 - );
301 - // Check if area already exists.
302 - if ( isset( $existing_block_ids[$block_id] ) ) {
303 - $area_data['ID'] = $existing_block_ids[$block_id];
304 - $area_id = wp_update_post( $area_data );
305 - } else {
306 - $area_id = wp_insert_post( $area_data );
307 - }
308 - if ( !$area_id || is_wp_error( $area_id ) ) {
309 - continue;
310 - }
311 - // Save source meta.
312 - update_post_meta( $area_id, '_passster_source', 'block' );
313 - update_post_meta( $area_id, '_passster_source_post_id', $post_id );
314 - update_post_meta( $area_id, '_passster_block_id', $block_id );
315 - // Save protection settings.
316 - $protection_type = ( !empty( $attrs['protectionType'] ) ? $attrs['protectionType'] : 'password' );
317 - update_post_meta( $area_id, 'passster_activate_protection', true );
318 - update_post_meta( $area_id, 'passster_protection_type', $protection_type );
319 - switch ( $protection_type ) {
320 - case 'password':
321 - update_post_meta( $area_id, 'passster_password', ( !empty( $attrs['password'] ) ? $attrs['password'] : '' ) );
322 - break;
323 - case 'passwords':
324 - update_post_meta( $area_id, 'passster_passwords', ( !empty( $attrs['passwords'] ) ? $attrs['passwords'] : '' ) );
325 - break;
326 - case 'password_list':
327 - update_post_meta( $area_id, 'passster_password_list', ( !empty( $attrs['passwordList'] ) ? absint( $attrs['passwordList'] ) : 0 ) );
328 - break;
329 - }
330 - }
331 - // Delete areas for blocks that no longer exist.
332 - foreach ( $existing_block_ids as $block_id => $area_id ) {
333 - if ( !in_array( $block_id, $synced_block_ids, true ) ) {
334 - wp_delete_post( $area_id, true );
335 - }
336 - }
337 - }
338 -
339 - /**
340 - * Recursively find protected content blocks.
341 - *
342 - * @param array $blocks Parsed blocks.
343 - *
344 - * @return array Protected content blocks.
345 - */
346 - private function find_protected_content_blocks( $blocks ) {
347 - $found = array();
348 - foreach ( $blocks as $block ) {
349 - if ( 'passster/content-lock' === $block['blockName'] ) {
350 - $found[] = $block;
351 - }
352 - // Check inner blocks recursively.
353 - if ( !empty( $block['innerBlocks'] ) ) {
354 - $found = array_merge( $found, $this->find_protected_content_blocks( $block['innerBlocks'] ) );
355 - }
356 - }
357 - return $found;
358 - }
359 -
360 -}
1 +<?php
2 +
3 +namespace passster;
4 +
5 +class PS_Block_Editor {
6 + /**
7 + * Contains instance or null
8 + *
9 + * @var object|null
10 + */
11 + private static $instance = null;
12 +
13 + /**
14 + * Returns instance of PS_Block_Editor.
15 + *
16 + * @return object
17 + */
18 + public static function get_instance() {
19 + if ( null === self::$instance ) {
20 + self::$instance = new self();
21 + }
22 + return self::$instance;
23 + }
24 +
25 + /**
26 + * Constructor for PS_Block_Editor
27 + */
28 + public function __construct() {
29 + add_action( 'wp_enqueue_scripts', array($this, 'register_block_scripts') );
30 + add_action( 'enqueue_block_editor_assets', array($this, 'add_block_editor_assets') );
31 + add_action( 'init', array($this, 'register_area_block') );
32 + add_action( 'init', array($this, 'register_protected_content_block') );
33 + add_action(
34 + 'save_post',
35 + array($this, 'sync_protected_content_blocks'),
36 + 10,
37 + 2
38 + );
39 + add_filter(
40 + 'block_categories_all',
41 + array($this, 'register_block_category'),
42 + 10,
43 + 2
44 + );
45 + }
46 +
47 + /**
48 + * Register Passster block category.
49 + *
50 + * @param array $categories Block categories.
51 + * @param WP_Block_Editor_Context $context Block editor context.
52 + *
53 + * @return array Modified categories.
54 + */
55 + public function register_block_category( $categories, $context ) {
56 + return array_merge( array(array(
57 + 'slug' => 'passster',
58 + 'title' => __( 'Passster', 'content-protector' ),
59 + 'icon' => 'lock',
60 + )), $categories );
61 + }
62 +
63 + /**
64 + * Enqueue scripts for blocks.
65 + *
66 + * @return void
67 + */
68 + public function register_block_scripts() {
69 + $area_asset_file = (include PASSSTER_PATH . '/build/area/index.asset.php');
70 + wp_register_script(
71 + 'area-script',
72 + PASSSTER_URL . '/build/area/index.js',
73 + $area_asset_file['dependencies'],
74 + $area_asset_file['version']
75 + );
76 + }
77 +
78 + /**
79 + * Add block editor scripts and styles.
80 + *
81 + * @return void
82 + */
83 + public function add_block_editor_assets() {
84 + // Area block.
85 + $area_asset_file = (include PASSSTER_PATH . '/build/area/index.asset.php');
86 + wp_enqueue_script(
87 + 'area-script',
88 + PASSSTER_URL . '/build/area/index.js',
89 + $area_asset_file['dependencies'],
90 + $area_asset_file['version']
91 + );
92 + wp_localize_script( 'area-script', 'area_data', array(
93 + 'is_pro' => \passster_fs()->is_plan_or_trial__premium_only( 'pro' ),
94 + 'create_area_url' => admin_url( 'post-new.php?post_type=protected_areas' ),
95 + 'options' => get_option( 'passster' ),
96 + ) );
97 + wp_enqueue_style( 'area-style', PASSSTER_URL . '/build/area/index.css' );
98 + // Protected Content block.
99 + $protected_content_asset = PASSSTER_PATH . '/build/blocks/protected-content/index.asset.php';
100 + if ( file_exists( $protected_content_asset ) ) {
101 + $protected_content_asset_file = (include $protected_content_asset);
102 + wp_enqueue_script(
103 + 'passster-protected-content-script',
104 + PASSSTER_URL . '/build/blocks/protected-content/index.js',
105 + $protected_content_asset_file['dependencies'],
106 + $protected_content_asset_file['version']
107 + );
108 + wp_localize_script( 'passster-protected-content-script', 'passster_block_data', array(
109 + 'is_pro' => \passster_fs()->is_plan_or_trial__premium_only( 'pro' ),
110 + 'options' => get_option( 'passster' ),
111 + 'date_format' => get_option( 'date_format' ),
112 + 'time_format' => get_option( 'time_format' ),
113 + 'timezone' => wp_timezone_string(),
114 + 'now' => current_time( 'c' ),
115 + ) );
116 + wp_enqueue_style(
117 + 'passster-protected-content-style',
118 + PASSSTER_URL . '/build/blocks/protected-content/index.css',
119 + array(),
120 + $protected_content_asset_file['version']
121 + );
122 + if ( function_exists( 'wp_set_script_translations' ) ) {
123 + wp_set_script_translations( 'passster-protected-content-script', 'content-protector', PASSSTER_PATH . '/languages' );
124 + }
125 + }
126 + // Make the blocks translatable.
127 + if ( function_exists( 'wp_set_script_translations' ) ) {
128 + wp_set_script_translations( 'area-script', 'content-protector', PASSSTER_PATH . '/languages' );
129 + }
130 + }
131 +
132 + /**
133 + * Register area block in WordPress.
134 + *
135 + * @return void
136 + */
137 + public function register_area_block() {
138 + $options = get_option( 'passster' );
139 + $settings = array(
140 + 'render_callback' => array($this, 'render_area_block'),
141 + 'attributes' => array(
142 + 'area_id' => array(
143 + 'type' => 'string',
144 + 'default' => 0,
145 + ),
146 + 'headline' => array(
147 + 'type' => 'string',
148 + 'default' => esc_html( $options['headline'] ),
149 + ),
150 + 'instruction' => array(
151 + 'type' => 'string',
152 + 'default' => wp_kses_post( $options['instruction'] ),
153 + ),
154 + 'buttonLabel' => array(
155 + 'type' => 'string',
156 + 'default' => esc_html( $options['button_label'] ),
157 + ),
158 + 'placeholder' => array(
159 + 'type' => 'string',
160 + 'default' => esc_html( $options['placeholder'] ),
161 + ),
162 + ),
163 + );
164 + register_block_type( 'content-protector/area', array_merge( array(
165 + 'editor_script' => 'area-script',
166 + 'editor_style' => 'area-style',
167 + ), $settings ) );
168 + }
169 +
170 + /**
171 + * Returns the shortcode for an area based on block attributes.
172 + *
173 + * @param array $attributes the list attributes from the block.
174 + *
175 + * @return string
176 + */
177 + public function render_area_block( array $attributes ) {
178 + $area_id = esc_attr( $attributes['area_id'] );
179 + $area = get_post( $area_id );
180 + if ( !$area ) {
181 + return '';
182 + }
183 + // Build dynamic shortcode.
184 + $content = $area->post_content;
185 + $shortcode = '';
186 + // texts.
187 + $headline = esc_attr( $attributes['headline'] );
188 + $instruction = wp_kses_post( $attributes['instruction'] );
189 + $button = esc_attr( $attributes['buttonLabel'] );
190 + $placeholder = esc_attr( $attributes['placeholder'] );
191 + $id = get_post_meta( $area_id, 'passster_id', true );
192 + // Redirection.
193 + $redirection = get_post_meta( $area_id, 'passster_redirect_url', true );
194 + $atts = array();
195 + $password = get_post_meta( $area_id, 'passster_password', true );
196 + $atts['password'] = $password;
197 + $shortcode = '[passster password="' . $password . '" area="' . $area_id . '" ';
198 + // Building the actual shortcode.
199 + if ( !empty( $redirection ) ) {
200 + $shortcode .= 'redirect="' . $redirection . '" ';
201 + }
202 + if ( !empty( $headline ) ) {
203 + $shortcode .= 'headline="' . $headline . '" ';
204 + }
205 + if ( !empty( $instruction ) ) {
206 + $shortcode .= 'instruction="' . base64_encode( $instruction ) . '" ';
207 + }
208 + if ( !empty( $placeholder ) ) {
209 + $shortcode .= 'placeholder="' . $placeholder . '" ';
210 + }
211 + if ( !empty( $button ) ) {
212 + $shortcode .= 'button="' . $button . '" ';
213 + }
214 + if ( !empty( $id ) ) {
215 + $shortcode .= 'id="' . $id . '" ';
216 + }
217 + $shortcode = rtrim( $shortcode );
218 + $shortcode .= ']';
219 + // check if valid before restrict anything.
220 + $valid = PS_Conditional::is_valid( $atts );
221 + if ( $valid ) {
222 + return $content;
223 + }
224 + return do_shortcode( $shortcode );
225 + }
226 +
227 + /**
228 + * Register protected content block.
229 + *
230 + * @return void
231 + */
232 + public function register_protected_content_block() {
233 + // Check if build files exist.
234 + $block_path = PASSSTER_PATH . '/build/blocks/protected-content';
235 + if ( !file_exists( $block_path . '/block.json' ) ) {
236 + return;
237 + }
238 + register_block_type( $block_path );
239 + }
240 +
241 + /**
242 + * Sync protected content blocks with Protected Areas CPT.
243 + *
244 + * @param int $post_id Post ID being saved.
245 + * @param WP_Post $post Post object.
246 + *
247 + * @return void
248 + */
249 + public function sync_protected_content_blocks( $post_id, $post ) {
250 + // Skip auto-saves and revisions.
251 + if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
252 + return;
253 + }
254 + if ( wp_is_post_revision( $post_id ) ) {
255 + return;
256 + }
257 + // Skip protected areas CPT to avoid loops.
258 + if ( 'protected_areas' === $post->post_type ) {
259 + return;
260 + }
261 + // Parse blocks from content.
262 + $blocks = parse_blocks( $post->post_content );
263 + $protected_blocks = $this->find_protected_content_blocks( $blocks );
264 + // Get existing synced areas for this post.
265 + $existing_areas = get_posts( array(
266 + 'post_type' => 'protected_areas',
267 + 'posts_per_page' => -1,
268 + 'meta_query' => array(array(
269 + 'key' => '_passster_source',
270 + 'value' => 'block',
271 + ), array(
272 + 'key' => '_passster_source_post_id',
273 + 'value' => $post_id,
274 + )),
275 + ) );
276 + $existing_block_ids = array();
277 + foreach ( $existing_areas as $area ) {
278 + $block_id = get_post_meta( $area->ID, '_passster_block_id', true );
279 + $existing_block_ids[$block_id] = $area->ID;
280 + }
281 + $synced_block_ids = array();
282 + // Sync each protected block.
283 + foreach ( $protected_blocks as $block ) {
284 + $attrs = $block['attrs'];
285 + $block_id = ( !empty( $attrs['blockId'] ) ? $attrs['blockId'] : '' );
286 + if ( empty( $block_id ) ) {
287 + continue;
288 + }
289 + $synced_block_ids[] = $block_id;
290 + // Prepare area data.
291 + $area_title = ( !empty( $attrs['areaTitle'] ) ? $attrs['areaTitle'] : sprintf(
292 + /* translators: %s: Post title */
293 + __( 'Protected block in %s', 'content-protector' ),
294 + $post->post_title
295 + ) );
296 + $area_data = array(
297 + 'post_title' => $area_title,
298 + 'post_type' => 'protected_areas',
299 + 'post_status' => 'publish',
300 + );
301 + // Check if area already exists.
302 + if ( isset( $existing_block_ids[$block_id] ) ) {
303 + $area_data['ID'] = $existing_block_ids[$block_id];
304 + $area_id = wp_update_post( $area_data );
305 + } else {
306 + $area_id = wp_insert_post( $area_data );
307 + }
308 + if ( !$area_id || is_wp_error( $area_id ) ) {
309 + continue;
310 + }
311 + // Save source meta.
312 + update_post_meta( $area_id, '_passster_source', 'block' );
313 + update_post_meta( $area_id, '_passster_source_post_id', $post_id );
314 + update_post_meta( $area_id, '_passster_block_id', $block_id );
315 + // Save protection settings.
316 + $protection_type = ( !empty( $attrs['protectionType'] ) ? $attrs['protectionType'] : 'password' );
317 + update_post_meta( $area_id, 'passster_activate_protection', true );
318 + update_post_meta( $area_id, 'passster_protection_type', $protection_type );
319 + switch ( $protection_type ) {
320 + case 'password':
321 + update_post_meta( $area_id, 'passster_password', ( !empty( $attrs['password'] ) ? $attrs['password'] : '' ) );
322 + break;
323 + case 'passwords':
324 + update_post_meta( $area_id, 'passster_passwords', ( !empty( $attrs['passwords'] ) ? $attrs['passwords'] : '' ) );
325 + break;
326 + case 'password_list':
327 + update_post_meta( $area_id, 'passster_password_list', ( !empty( $attrs['passwordList'] ) ? absint( $attrs['passwordList'] ) : 0 ) );
328 + break;
329 + }
330 + }
331 + // Delete areas for blocks that no longer exist.
332 + foreach ( $existing_block_ids as $block_id => $area_id ) {
333 + if ( !in_array( $block_id, $synced_block_ids, true ) ) {
334 + wp_delete_post( $area_id, true );
335 + }
336 + }
337 + }
338 +
339 + /**
340 + * Recursively find protected content blocks.
341 + *
342 + * @param array $blocks Parsed blocks.
343 + *
344 + * @return array Protected content blocks.
345 + */
346 + private function find_protected_content_blocks( $blocks ) {
347 + $found = array();
348 + foreach ( $blocks as $block ) {
349 + if ( 'passster/content-lock' === $block['blockName'] ) {
350 + $found[] = $block;
351 + }
352 + // Check inner blocks recursively.
353 + if ( !empty( $block['innerBlocks'] ) ) {
354 + $found = array_merge( $found, $this->find_protected_content_blocks( $block['innerBlocks'] ) );
355 + }
356 + }
357 + return $found;
358 + }
359 +
360 +}