PluginProbe ʕ •ᴥ•ʔ
JetFormBuilder — Dynamic Blocks Form Builder / trunk
JetFormBuilder — Dynamic Blocks Form Builder vtrunk
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 week ago messages 2 years ago post-type 2 years ago rest-api 4 months ago ssr 1 year ago class-validation-handlers.php 1 year ago module.php 1 week ago rules-controller.php 1 week ago
module.php
417 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 return $type
324 ? self::FORMAT_ADVANCED === $type
325 : $this->is_advanced_form();
326 }
327
328 public function is_advanced_form(): bool {
329 if ( is_null( $this->settings ) ) {
330 $this->settings = $this->get_settings();
331 }
332
333 return self::FORMAT_ADVANCED === ( $this->settings['type'] ?? '' );
334 }
335
336 public function formats(): array {
337 return array(
338 array(
339 'value' => self::FORMAT_BROWSER,
340 'label' => __( 'Default', 'jet-form-builder' ),
341 'title' => __( 'Browser native validation', 'jet-form-builder' ),
342 ),
343 array(
344 'value' => self::FORMAT_ADVANCED,
345 'label' => __( 'Advanced', 'jet-form-builder' ),
346 'title' => __( 'More flexible JetFormBuilder\'s validation', 'jet-form-builder' ),
347 ),
348 );
349 }
350
351 public function validate_block( Field_Data_Parser $parser ) {
352 if (
353 ! $this->is_advanced( $parser->get_settings() ) ||
354 ! $parser->get_value() ||
355 $parser->is_inside_conditional()
356 ) {
357 return;
358 }
359
360 $this->get_rules()->validate_block( $parser );
361 }
362
363 public function localize_editor_config() {
364 wp_localize_script(
365 Editor::EDITOR_PACKAGE_HANDLE,
366 'jetFormValidation',
367 array(
368 'messages' => Array_Tools::to_array( $this->get_messages() ),
369 'ssr_callbacks' => Array_Tools::to_array( $this->get_rules()->get_ssr()->get_callbacks() ),
370 'formats' => $this->formats(),
371 'rule_types' => Array_Tools::to_array( $this->get_rules()->rep_get_values() ),
372 )
373 );
374 }
375
376 /**
377 * @return Rules_Controller
378 */
379 public function get_rules(): Rules_Controller {
380 if ( ! is_null( $this->rules ) ) {
381 return $this->rules;
382 }
383
384 $this->rules = new Rules_Controller();
385
386 return $this->rules;
387 }
388
389 public function get_messages(): array {
390 if ( ! empty( $this->messages ) ) {
391 return $this->messages;
392 }
393
394 $this->messages = apply_filters(
395 'jet-form-builder/validation-messages',
396 array(
397 new Messages\Is_Empty_Value(),
398 new Messages\Is_Number_Min(),
399 new Messages\Is_Number_Max(),
400 new Messages\Is_Char_Min(),
401 new Messages\Is_Char_Max(),
402 new Messages\Is_Not_Valid_Email(),
403 new Messages\Is_Not_Valid_Url(),
404 new Messages\Is_Not_Complete_Mask(),
405 new Messages\Is_Files_Max(),
406 new Messages\Is_File_Size(),
407 new Messages\Is_File_Ext(),
408 new Messages\Is_Date_Min(),
409 new Messages\Is_Date_Max(),
410 )
411 );
412
413 return $this->messages;
414 }
415
416 }
417