PluginProbe
JetFormBuilder — Dynamic Blocks Form Builder / 3.6.6
JetFormBuilder — Dynamic Blocks Form Builder v3.6.6
3.6.6.1 3.6.6 3.6.5.4 3.6.5.3 3.6.5.2 3.6.5.1 3.6.5 3.6.4.2 3.6.4.1 3.6.4 3.6.3.1 3.6.3 3.6.2.2 3.6.2.1 3.6.2 3.6.1.1 3.6.1 3.6.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 All 134 releases
← All changes | includes/blocks/block-helper.php +116 -7 3.6.2.1 → 3.6.6 View file →
@@ -4,8 +4,9 @@
4 4 namespace Jet_Form_Builder\Blocks;
5 5
6 6 use Jet_Form_Builder\Blocks\Types\Base;
7 7 use Jet_Form_Builder\Form_Manager;
8 +use JFB_Modules\Post_Type\Module as Post_Type_Module;
8 9
9 10 // If this file is called directly, abort.
10 11 if ( ! defined( 'WPINC' ) ) {
11 12 die;
@@ -17,8 +18,11 @@
17 18 * @package Jet_Form_Builder\Blocks
18 19 */
19 20 class Block_Helper {
20 21
22 + const PREVIEW_NONCE_FIELD = 'jfb_preview_nonce';
23 + const PREVIEW_NONCE_ACTION = 'jfb-preview-form';
24 +
21 25 /**
22 26 * @since 3.1.1
23 27 *
24 28 * @param $parsed_block
@@ -182,29 +186,111 @@
182 186 }
183 187 }
184 188 }
185 189
186 - public static function get_blocks_by_post( $post_id ): array {
190 + public static function is_valid_form_post( $post_id, bool $allow_preview = false ): bool {
187 191 $post = get_post( $post_id );
188 192
189 193 if ( ! is_a( $post, \WP_Post::class ) ) {
194 + return false;
195 + }
196 +
197 + if (
198 + Post_Type_Module::SLUG === $post->post_type
199 + && 'publish' === $post->post_status
200 + ) {
201 + return true;
202 + }
203 +
204 + return $allow_preview && self::is_valid_preview_form_post( $post );
205 + }
206 +
207 + public static function is_valid_preview_form_post( $post_id ): bool {
208 + $post = get_post( $post_id );
209 +
210 + if ( ! is_a( $post, \WP_Post::class ) ) {
211 + return false;
212 + }
213 +
214 + $nonce = self::get_preview_nonce();
215 +
216 + if ( ! $nonce || ! wp_verify_nonce( $nonce, self::PREVIEW_NONCE_ACTION ) ) {
217 + return false;
218 + }
219 +
220 + if ( Post_Type_Module::SLUG === $post->post_type ) {
221 + return current_user_can( 'edit_jet_fb_form', $post->ID );
222 + }
223 +
224 + if ( 'revision' !== $post->post_type ) {
225 + return false;
226 + }
227 +
228 + $parent_form_id = (int) $post->post_parent;
229 + $parent_form = $parent_form_id ? get_post( $parent_form_id ) : null;
230 +
231 + if ( ! $parent_form || Post_Type_Module::SLUG !== $parent_form->post_type ) {
232 + return false;
233 + }
234 +
235 + return current_user_can( 'edit_jet_fb_form', $parent_form_id );
236 + }
237 +
238 + public static function get_preview_nonce(): string {
239 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended
240 + if ( empty( $_REQUEST[ self::PREVIEW_NONCE_FIELD ] ) ) {
241 + return '';
242 + }
243 +
244 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended
245 + return sanitize_text_field( wp_unslash( $_REQUEST[ self::PREVIEW_NONCE_FIELD ] ) );
246 + }
247 +
248 + public static function get_blocks_by_post(
249 + $post_id,
250 + bool $require_form_post = true,
251 + bool $allow_preview = false
252 + ): array {
253 + $post = get_post( $post_id );
254 +
255 + if ( ! is_a( $post, \WP_Post::class ) ) {
190 256 return array();
191 257 }
192 258
259 + if ( $require_form_post && ! self::is_valid_form_post( $post, $allow_preview ) ) {
260 + return array();
261 + }
262 +
263 + return self::get_blocks_from_content( $post->post_content );
264 + }
265 +
266 + /**
267 + * Parses block content and expands reusable (`core/block`) references in exactly the
268 + * same way as `get_blocks_by_post()`.
269 + *
270 + * @param string $post_content
271 + *
272 + * @return array
273 + */
274 + public static function get_blocks_from_content( string $post_content ): array {
193 275 return array_map(
194 276 function ( $block ) {
195 - self::walk_by_reusable( $block );
277 + self::walk_by_reusable( $block, array() );
196 278
197 279 return $block;
198 280 },
199 - parse_blocks( $post->post_content )
281 + parse_blocks( $post_content )
200 282 );
201 283 }
202 284
203 - private static function walk_by_reusable( array &$block ) {
285 + /**
286 + * @param array $block
287 + * @param array $visited_reusable_ids IDs already visited in the current reference path.
288 + */
289 + private static function walk_by_reusable( array &$block, array $visited_reusable_ids ) {
204 290 if ( ! empty( $block['innerBlocks'] ) ) {
205 291 foreach ( $block['innerBlocks'] as &$current ) {
206 - self::walk_by_reusable( $current );
292 + self::walk_by_reusable( $current, $visited_reusable_ids );
207 293 }
208 294
209 295 return;
210 296 }
@@ -212,10 +298,33 @@
212 298 if ( 'core/block' !== $block['blockName'] ) {
213 299 return;
214 300 }
215 301
216 - $reusable_id = $block['attrs']['ref'] ?? 0;
217 - $block['innerBlocks'] = self::get_blocks_by_post( $reusable_id );
302 + $reusable_id = (int) ( $block['attrs']['ref'] ?? 0 );
303 +
304 + if ( ! $reusable_id || isset( $visited_reusable_ids[ $reusable_id ] ) ) {
305 + $block['innerBlocks'] = array();
306 +
307 + return;
308 + }
309 +
310 + $reusable = get_post( $reusable_id );
311 +
312 + if ( ! $reusable instanceof \WP_Post ) {
313 + $block['innerBlocks'] = array();
314 +
315 + return;
316 + }
317 +
318 + $visited_reusable_ids[ $reusable_id ] = true;
319 + $block['innerBlocks'] = array_map(
320 + function ( $inner_block ) use ( $visited_reusable_ids ) {
321 + self::walk_by_reusable( $inner_block, $visited_reusable_ids );
322 +
323 + return $inner_block;
324 + },
325 + parse_blocks( $reusable->post_content )
326 + );
218 327 }
219 328
220 329 public static function delete_namespace( $block ): string {
221 330 if ( is_array( $block ) ) {