PluginProbe ʕ •ᴥ•ʔ
JetFormBuilder — Dynamic Blocks Form Builder / 3.6.1
JetFormBuilder — Dynamic Blocks Form Builder v3.6.1
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 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.1.0 2.1.1 2.1.10 2.1.11 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 3.0.0 3.0.0.1 3.0.0.2 3.0.0.3 3.0.1 3.0.1.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.0.1 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.3.2 3.3.3 3.3.3.1 3.3.4 3.3.4.1 3.3.4.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.5.1 3.4.5.2 3.4.6 3.4.7 3.4.7.1 3.5.0 3.5.1 3.5.1.1 3.5.1.2 3.5.2 3.5.2.1 3.5.3 3.5.4 3.5.5 3.5.6 3.5.6.1 3.5.6.2 3.5.6.3 3.6.0
jetformbuilder / modules / validation / module.php
jetformbuilder / modules / validation Last commit date
advanced-rules 4 months ago handlers 4 months ago messages 2 years ago post-type 2 years ago rest-api 4 months ago ssr 1 year ago class-validation-handlers.php 11 months ago module.php 4 months ago rules-controller.php 2 years ago
module.php
409 lines
1 <?php
2
3
4 namespace JFB_Modules\Validation;
5
6 use Jet_Form_Builder\Admin\Editor;
7 use Jet_Form_Builder\Blocks\Types\Base;
8 use Jet_Form_Builder\Classes\Arrayable\Array_Tools;
9 use Jet_Form_Builder\Classes\Tools;
10 use Jet_Form_Builder\Exceptions\Repository_Exception;
11 use Jet_Form_Builder\Plugin;
12 use JFB_Components\Module\Base_Module_After_Install_It;
13 use JFB_Components\Module\Base_Module_Dir_It;
14 use JFB_Components\Module\Base_Module_Dir_Trait;
15 use JFB_Components\Module\Base_Module_Handle_It;
16 use JFB_Components\Module\Base_Module_Handle_Trait;
17 use JFB_Components\Module\Base_Module_It;
18 use JFB_Components\Module\Base_Module_Url_It;
19 use JFB_Components\Module\Base_Module_Url_Trait;
20 use JFB_Modules\Block_Parsers\Field_Data_Parser;
21 use JFB_Modules\Validation\Class_Validation_Handlers;
22 use JFB_Modules\Validation\Rest_Api\Rest_Validation_Endpoint;
23
24 // If this file is called directly, abort.
25 if ( ! defined( 'WPINC' ) ) {
26 die;
27 }
28
29 final class Module implements
30 Base_Module_It,
31 Base_Module_Handle_It,
32 Base_Module_Url_It,
33 Base_Module_Dir_It,
34 Base_Module_After_Install_It {
35
36 use Base_Module_Url_Trait;
37 use Base_Module_Handle_Trait;
38 use Base_Module_Dir_Trait;
39
40 const FORMAT_ADVANCED = 'advanced';
41 const FORMAT_BROWSER = 'browser';
42 const HANDLE = 'jet-fb-advanced-reporting';
43
44 private $messages = array();
45 /**
46 * @var Rules_Controller
47 */
48 private $rules;
49 private $settings;
50 private $inline_messages = array();
51
52 public function rep_item_id() {
53 return 'validation';
54 }
55
56 public function condition(): bool {
57 return true;
58 }
59
60 /**
61 * @throws Repository_Exception
62 */
63 public function on_install() {
64 $handlers = new Class_Validation_Handlers();
65
66 foreach ( $handlers->get_handlers() as $handler ) {
67 if ( method_exists( $handler, 'init' ) ) {
68 $handler->init();
69 }
70 }
71
72 /** @var \JFB_Modules\Post_Type\Module $post_type */
73 $post_type = jet_form_builder()->module( 'post-type' );
74 $post_type->get_meta()->install( new Post_Type\Validation_Meta() );
75
76 /** @var \JFB_Modules\Rest_Api\Module $rest_api */
77 $rest_api = jet_form_builder()->module( 'rest-api' );
78 $rest_api->get_controller()->install( new Rest_Api\Rest_Validation_Endpoint() );
79 }
80
81 /**
82 * @throws Repository_Exception
83 */
84 public function on_uninstall() {
85 $this->rules = null;
86 $this->messages = array();
87
88 /** @var \JFB_Modules\Post_Type\Module $post_type */
89 $post_type = jet_form_builder()->module( 'post-type' );
90 $post_type->get_meta()->uninstall( Post_Type\Validation_Meta::class );
91
92 /** @var \JFB_Modules\Rest_Api\Module $rest_api */
93 $rest_api = jet_form_builder()->module( 'rest-api' );
94 $rest_api->get_controller()->uninstall( new Rest_Api\Rest_Validation_Endpoint() );
95 }
96
97 public function init_hooks() {
98 add_filter(
99 'jet-form-builder/before-start-form',
100 array( $this, 'add_validation_messages_global' )
101 );
102
103 add_action(
104 'jet-form-builder/before-start-form-row',
105 array( $this, 'add_validation_block' )
106 );
107 add_action(
108 'wp_enqueue_scripts',
109 array( $this, 'register_scripts' )
110 );
111
112 /**
113 * @link https://github.com/Crocoblock/issues-tracker/issues/1542
114 */
115 add_action(
116 'jet_plugins/frontend/register_scripts',
117 array( $this, 'register_scripts' )
118 );
119 add_action(
120 'jet-form-builder/validate-field',
121 array( $this, 'validate_block' ),
122 0
123 );
124 add_action(
125 'jet-form-builder/editor-assets/before',
126 array( $this, 'localize_editor_config' )
127 );
128 }
129
130 public function remove_hooks() {
131 remove_filter(
132 'jet-form-builder/before-start-form',
133 array( $this, 'add_validation_messages_global' )
134 );
135 remove_action(
136 'jet-form-builder/before-start-form-row',
137 array( $this, 'add_validation_block' )
138 );
139 remove_action(
140 'wp_enqueue_scripts',
141 array( $this, 'register_scripts' )
142 );
143
144 /**
145 * @link https://github.com/Crocoblock/issues-tracker/issues/1542
146 */
147 remove_action(
148 'jet_plugins/frontend/register_scripts',
149 array( $this, 'register_scripts' )
150 );
151 remove_action(
152 'jet-form-builder/validate-field',
153 array( $this, 'validate_block' ),
154 0
155 );
156 remove_action(
157 'jet-form-builder/editor-assets/before',
158 array( $this, 'localize_editor_config' )
159 );
160 }
161
162 public function register_scripts() {
163 $script_asset = require_once jet_form_builder()->plugin_dir(
164 'assets/build/frontend/advanced.reporting.asset.php'
165 );
166
167 if ( true === $script_asset ) {
168 return;
169 }
170
171 array_push(
172 $script_asset['dependencies'],
173 \Jet_Form_Builder\Blocks\Module::MAIN_SCRIPT_HANDLE
174 );
175
176 wp_register_script(
177 self::HANDLE,
178 jet_form_builder()->plugin_url( 'assets/build/frontend/advanced.reporting.js' ),
179 $script_asset['dependencies'],
180 $script_asset['version'],
181 true
182 );
183 }
184
185 public function add_validation_messages_global( string $markup, bool $force = false ): string {
186 $this->settings = $this->get_settings();
187 $form_id = jet_fb_live()->form_id;
188
189 if (
190 ( ! $this->is_advanced_form() && ! $force ) ||
191 in_array( $form_id, $this->inline_messages, true )
192 ) {
193 return $markup;
194 }
195
196 $data = Tools::encode_json( $this->settings );
197
198 wp_enqueue_script( self::HANDLE );
199
200 wp_add_inline_script(
201 \Jet_Form_Builder\Blocks\Module::MAIN_SCRIPT_HANDLE,
202 "
203 window.JetFormsValidation = window.JetFormsValidation ?? {};
204 window.JetFormsValidation[ {$form_id} ] = $data;
205 "
206 );
207
208 add_action(
209 'wp_enqueue_scripts',
210 function () use ( $form_id, $data ) {
211 wp_add_inline_script(
212 \Jet_Form_Builder\Blocks\Module::MAIN_SCRIPT_HANDLE,
213 "
214 window.JetFormsValidation = window.JetFormsValidation ?? {};
215 window.JetFormsValidation[ {$form_id} ] = $data;
216 "
217 );
218 },
219 20
220 );
221
222 $this->inline_messages[] = $form_id;
223
224 return $markup;
225 }
226
227 public function add_validation_block( Base $block ) {
228 /**
229 * If in post meta enable Advanced validation
230 * or right in block settings
231 */
232 if ( ! $this->is_advanced( $block->block_attrs ) ) {
233 return;
234 }
235
236 $this->add_validation_messages_global( '', true );
237
238 $type = $block->block_attrs['validation']['type'] ?? '';
239 $rules = $block->block_attrs['validation']['rules'] ?? array();
240
241 $block->add_attribute( 'data-validation-type', $type ?: 'inherit' );
242
243 if ( ! empty( $rules ) ) {
244 $this->get_rules()->prepare_rules( $rules );
245
246 // Security: Add signatures for SSR validation rules
247 // For repeater fields, we include the repeater name in the signature
248 // but NOT the row index (which is dynamic). The signature binds the
249 // field to its structural path: [repeater_name, field_name] or just field_name
250 $form_id = jet_fb_live()->form_id;
251 $field_name = $block->block_attrs['name'] ?? '';
252 $repeater_name = $block->get_repeater_name();
253
254 // Build canonical path for signature (without row index)
255 $signature_path = $repeater_name
256 ? array( $repeater_name, $field_name )
257 : $field_name;
258
259 foreach ( $rules as $index => &$rule ) {
260 if ( 'ssr' === ( $rule['type'] ?? '' ) ) {
261 $rule['_sig'] = Rest_Validation_Endpoint::generate_signature(
262 (int) $form_id,
263 $signature_path,
264 (int) $index
265 );
266 }
267 }
268 unset( $rule );
269
270 $block->add_attribute(
271 'data-validation-rules',
272 Tools::encode_json( $rules )
273 );
274 }
275
276 /**
277 * If advanced validation not enabled right in block settings
278 */
279 if ( self::FORMAT_ADVANCED !== $type ) {
280 return;
281 }
282
283 $messages = $block->block_attrs['validation']['messages'] ?? array();
284
285 if ( ! empty( $messages ) ) {
286 $block->add_attribute( 'data-validation-messages', Tools::encode_json( $messages ) );
287 }
288 }
289
290 public function get_settings(): array {
291 /** @var \JFB_Modules\Post_Type\Module $module */
292 /** @noinspection PhpUnhandledExceptionInspection */
293 $module = jet_form_builder()->module( 'post-type' );
294 $validation = $module->query_meta( Post_Type\Validation_Meta::class );
295
296 $response = array(
297 'type' => $validation['type'] ?? self::FORMAT_BROWSER,
298 'messages' => array(),
299 );
300
301 $messages = $this->get_messages();
302
303 foreach ( $messages as $message ) {
304 $response['messages'][ $message->get_id() ] = (
305 $validation['messages'][ $message->get_id() ] ?? $message->get_initial()
306 );
307 }
308
309 return $response;
310 }
311
312 public function is_advanced( array $block_attrs ): bool {
313 $type = $block_attrs['validation']['type'] ?? '';
314
315 return $type
316 ? self::FORMAT_ADVANCED === $type
317 : $this->is_advanced_form();
318 }
319
320 public function is_advanced_form(): bool {
321 if ( is_null( $this->settings ) ) {
322 $this->settings = $this->get_settings();
323 }
324
325 return self::FORMAT_ADVANCED === ( $this->settings['type'] ?? '' );
326 }
327
328 public function formats(): array {
329 return array(
330 array(
331 'value' => self::FORMAT_BROWSER,
332 'label' => __( 'Default', 'jet-form-builder' ),
333 'title' => __( 'Browser native validation', 'jet-form-builder' ),
334 ),
335 array(
336 'value' => self::FORMAT_ADVANCED,
337 'label' => __( 'Advanced', 'jet-form-builder' ),
338 'title' => __( 'More flexible JetFormBuilder\'s validation', 'jet-form-builder' ),
339 ),
340 );
341 }
342
343 public function validate_block( Field_Data_Parser $parser ) {
344 if (
345 ! $this->is_advanced( $parser->get_settings() ) ||
346 ! $parser->get_value() ||
347 $parser->is_inside_conditional()
348 ) {
349 return;
350 }
351
352 $this->get_rules()->validate_block( $parser );
353 }
354
355 public function localize_editor_config() {
356 wp_localize_script(
357 Editor::EDITOR_PACKAGE_HANDLE,
358 'jetFormValidation',
359 array(
360 'messages' => Array_Tools::to_array( $this->get_messages() ),
361 'ssr_callbacks' => Array_Tools::to_array( $this->get_rules()->get_ssr()->get_callbacks() ),
362 'formats' => $this->formats(),
363 'rule_types' => Array_Tools::to_array( $this->get_rules()->rep_get_values() ),
364 )
365 );
366 }
367
368 /**
369 * @return Rules_Controller
370 */
371 public function get_rules(): Rules_Controller {
372 if ( ! is_null( $this->rules ) ) {
373 return $this->rules;
374 }
375
376 $this->rules = new Rules_Controller();
377
378 return $this->rules;
379 }
380
381 public function get_messages(): array {
382 if ( ! empty( $this->messages ) ) {
383 return $this->messages;
384 }
385
386 $this->messages = apply_filters(
387 'jet-form-builder/validation-messages',
388 array(
389 new Messages\Is_Empty_Value(),
390 new Messages\Is_Number_Min(),
391 new Messages\Is_Number_Max(),
392 new Messages\Is_Char_Min(),
393 new Messages\Is_Char_Max(),
394 new Messages\Is_Not_Valid_Email(),
395 new Messages\Is_Not_Valid_Url(),
396 new Messages\Is_Not_Complete_Mask(),
397 new Messages\Is_Files_Max(),
398 new Messages\Is_File_Size(),
399 new Messages\Is_File_Ext(),
400 new Messages\Is_Date_Min(),
401 new Messages\Is_Date_Max(),
402 )
403 );
404
405 return $this->messages;
406 }
407
408 }
409