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