PluginProbe ʕ •ᴥ•ʔ
WPForms – Easy Form Builder for WordPress – Contact Forms, Payment Forms, Surveys, & More / 1.9.9.4
WPForms – Easy Form Builder for WordPress – Contact Forms, Payment Forms, Surveys, & More v1.9.9.4
1.10.1 1.10.0.5 trunk 1.1.4 1.1.4.2 1.1.5 1.1.5.1 1.1.6 1.1.6.1 1.1.7 1.1.7.1 1.1.7.2 1.1.8 1.1.8.1 1.1.8.2 1.1.8.3 1.1.8.4 1.10.0.1 1.10.0.2 1.10.0.3 1.10.0.4 1.2.0 1.2.0.1 1.2.1 1.2.2 1.2.2.1 1.2.2.2 1.2.3 1.2.3.1 1.2.3.2 1.2.4 1.2.4.1 1.2.5 1.2.5.1 1.2.6 1.2.7 1.2.8 1.2.8.1 1.2.9 1.3.0 1.3.1 1.3.1.1 1.3.1.2 1.3.2 1.3.3 1.3.5 1.3.6 1.3.6.1 1.3.6.2 1.3.7.2 1.3.7.3 1.3.7.4 1.3.8 1.3.9.1 1.4.0.1 1.4.1.1 1.4.2 1.4.2.1 1.4.2.2 1.4.3 1.4.4 1.4.4.1 1.4.5 1.4.5.1 1.4.5.2 1.4.5.3 1.4.6 1.4.7.1 1.4.7.2 1.4.8.1 1.4.9 1.5.0.1 1.5.0.3 1.5.0.4 1.5.1 1.5.1.1 1.5.1.3 1.5.2.1 1.5.2.2 1.5.2.3 1.5.3 1.5.3.1 1.5.4.1 1.5.4.2 1.5.5 1.5.5.1 1.5.6 1.5.6.2 1.5.7 1.5.8.2 1.5.9.1 1.5.9.4 1.5.9.5 1.6.0.1 1.6.0.2 1.6.1 1.6.2.2 1.6.2.3 1.6.3.1 1.6.4 1.6.4.1 1.6.5 1.6.6 1.6.7 1.6.7.1 1.6.7.2 1.6.7.3 1.6.8 1.6.8.1 1.6.9 1.7.0 1.7.1.1 1.7.1.2 1.7.2 1.7.2.1 1.7.3 1.7.4 1.7.4.1 1.7.4.2 1.7.5.1 1.7.5.2 1.7.5.3 1.7.5.5 1.7.6 1.7.7 1.7.7.1 1.7.7.2 1.7.8 1.7.9 1.7.9.1 1.8.0.1 1.8.0.2 1.8.1.1 1.8.1.2 1.8.1.3 1.8.2.1 1.8.2.2 1.8.2.3 1.8.3 1.8.3.1 1.8.4 1.8.4.1 1.8.5.2 1.8.5.3 1.8.5.4 1.8.6.2 1.8.6.3 1.8.6.4 1.8.7.2 1.8.8.2 1.8.8.3 1.8.9.1 1.8.9.2 1.8.9.4 1.8.9.5 1.8.9.6 1.9.0.1 1.9.0.2 1.9.0.3 1.9.0.4 1.9.1.1 1.9.1.2 1.9.1.3 1.9.1.4 1.9.1.5 1.9.1.6 1.9.2.1 1.9.2.2 1.9.2.3 1.9.3.1 1.9.3.2 1.9.4.1 1.9.4.2 1.9.5 1.9.5.1 1.9.5.2 1.9.6 1.9.6.1 1.9.6.2 1.9.7.1 1.9.7.2 1.9.7.3 1.9.8.1 1.9.8.2 1.9.8.4 1.9.8.7 1.9.9.2 1.9.9.3 1.9.9.4
wpforms-lite / src / WPForms.php
wpforms-lite / src Last commit date
Access 3 years ago Admin 3 months ago Db 1 year ago Emails 4 months ago Forms 3 months ago Frontend 3 months ago Helpers 5 months ago Integrations 3 months ago Lite 4 months ago Logger 8 months ago Migrations 5 months ago Providers 4 months ago Requirements 3 months ago SmartTags 4 months ago Tasks 11 months ago API.php 2 years ago ErrorHandler.php 11 months ago Loader.php 3 months ago WPForms.php 8 months ago
WPForms.php
624 lines
1 <?php
2
3 // phpcs:ignore Generic.Commenting.DocComment.MissingShort
4 /** @noinspection PhpIllegalPsrClassPathInspection */
5
6 // phpcs:ignore Universal.Namespaces.DisallowCurlyBraceSyntax.Forbidden
7 namespace WPForms {
8
9 use AllowDynamicProperties;
10 use stdClass;
11 use WPForms\Helpers\DB;
12 use WPForms_Form_Handler;
13 use WPForms_Process;
14 use WPForms_Settings;
15
16 /**
17 * Main WPForms class.
18 *
19 * @since 1.0.0
20 */
21 #[AllowDynamicProperties]
22 final class WPForms {
23
24 /**
25 * List of screen IDs where heartbeat requests are allowed.
26 *
27 * @since 1.9.3
28 *
29 * @var string[]
30 */
31 private const HEARTBEAT_ALLOWED_SCREEN_IDS = [
32 'wpforms_page_wpforms-entries',
33 ];
34
35 /**
36 * One is the loneliest number that you'll ever do.
37 *
38 * @since 1.0.0
39 *
40 * @var WPForms
41 */
42 private static $instance;
43
44 /**
45 * Plugin version for enqueueing, etc.
46 * The value is got from WPFORMS_VERSION constant.
47 *
48 * @since 1.0.0
49 *
50 * @var string
51 */
52 public $version = '';
53
54 /**
55 * Classes registry.
56 *
57 * @since 1.5.7
58 *
59 * @var array
60 */
61 private $registry = [];
62
63 /**
64 * List of legacy public properties.
65 *
66 * @since 1.6.8
67 *
68 * @var string[]
69 */
70 private $legacy_properties = [
71 'form',
72 'entry',
73 'entry_fields',
74 'entry_meta',
75 'frontend',
76 'process',
77 'smart_tags',
78 'license',
79 ];
80
81 /**
82 * Paid returns true, free (Lite) returns false.
83 *
84 * @since 1.3.9
85 * @since 1.7.3 changed to private.
86 *
87 * @var bool
88 */
89 private $pro = false;
90
91 /**
92 * Backward compatibility method for accessing the class registry in an old way,
93 * e.g. 'wpforms()->form' or 'wpforms()->entry'.
94 *
95 * @since 1.5.7
96 *
97 * @param string $name Name of the object to get.
98 *
99 * @return mixed|null
100 * @noinspection MagicMethodsValidityInspection
101 * @noinspection PhpDeprecationInspection
102 */
103 public function __get( $name ) {
104
105 if ( $name === 'smart_tags' ) {
106 _deprecated_argument(
107 'wpforms()->smart_tags',
108 '1.6.7 of the WPForms plugin',
109 "Please use `wpforms()->obj( 'smart_tags' )` instead."
110 );
111 }
112
113 if ( $name === 'pro' ) {
114 _deprecated_argument(
115 'wpforms()->pro',
116 '1.8.2.2 of the WPForms plugin',
117 'Please use `wpforms()->is_pro()` instead.'
118 );
119
120 return wpforms()->is_pro();
121 }
122
123 return $this->get( $name );
124 }
125
126 /**
127 * Main WPForms Instance.
128 *
129 * Only one instance of WPForms exists in memory at any one time.
130 * Also, prevent the need to define globals all over the place.
131 *
132 * @since 1.0.0
133 *
134 * @return WPForms
135 */
136 public static function instance(): WPForms {
137
138 if ( self::$instance === null || ! self::$instance instanceof self ) {
139 self::$instance = new self();
140
141 self::$instance->init();
142 }
143
144 return self::$instance;
145 }
146
147 /**
148 * Initialize the plugin.
149 *
150 * @since 1.9.3
151 *
152 * @noinspection UsingInclusionOnceReturnValueInspection
153 */
154 private function init(): void {
155
156 if ( self::is_restricted_heartbeat() ) {
157 return;
158 }
159
160 $this->constants();
161 $this->includes();
162
163 // Load Pro or Lite specific files.
164 if ( $this->is_pro() ) {
165 $this->registry['pro'] = require_once WPFORMS_PLUGIN_DIR . 'pro/wpforms-pro.php';
166 } else {
167 require_once WPFORMS_PLUGIN_DIR . 'lite/wpforms-lite.php';
168 }
169
170 $this->hooks();
171 }
172
173 /**
174 * Setup plugin constants.
175 * All the path/URL-related constants are defined in the main plugin file.
176 *
177 * @since 1.0.0
178 */
179 private function constants(): void {
180
181 $this->version = WPFORMS_VERSION;
182
183 // Plugin Slug - Determine a plugin type and set slug accordingly.
184 // This filter is documented in \WPForms\WPForms::is_pro.
185 if ( apply_filters( 'wpforms_allow_pro_version', file_exists( WPFORMS_PLUGIN_DIR . 'pro/wpforms-pro.php' ) ) ) {
186 $this->pro = true;
187
188 /**
189 * Pro plugin slug.
190 *
191 * @since 1.5.0
192 */
193 define( 'WPFORMS_PLUGIN_SLUG', 'wpforms' );
194 } else {
195 /**
196 * Lite plugin slug.
197 *
198 * @since 1.5.0
199 */
200 define( 'WPFORMS_PLUGIN_SLUG', 'wpforms-lite' );
201 }
202 }
203
204 /**
205 * Include files.
206 *
207 * @since 1.0.0
208 */
209 private function includes(): void {
210
211 $this->error_handler();
212
213 // Action Scheduler requires a special loading procedure.
214 require_once WPFORMS_PLUGIN_DIR . 'vendor/woocommerce/action-scheduler/action-scheduler.php';
215
216 // Autoload Composer packages.
217 require_once WPFORMS_PLUGIN_DIR . 'vendor/autoload.php';
218
219 // Base class and functions.
220 require_once WPFORMS_PLUGIN_DIR . 'includes/class-db.php';
221 require_once WPFORMS_PLUGIN_DIR . 'includes/functions.php';
222 require_once WPFORMS_PLUGIN_DIR . 'includes/fields/class-base.php';
223
224 $this->includes_magic();
225
226 // Global includes.
227 require_once WPFORMS_PLUGIN_DIR . 'includes/class-install.php';
228 require_once WPFORMS_PLUGIN_DIR . 'includes/class-form.php';
229 require_once WPFORMS_PLUGIN_DIR . 'includes/class-fields.php';
230 // TODO: class-templates.php should be loaded in admin area only.
231 require_once WPFORMS_PLUGIN_DIR . 'includes/class-templates.php';
232 // TODO: class-providers.php should be loaded in admin area only.
233 require_once WPFORMS_PLUGIN_DIR . 'includes/class-providers.php';
234 require_once WPFORMS_PLUGIN_DIR . 'includes/class-process.php';
235 require_once WPFORMS_PLUGIN_DIR . 'includes/class-widget.php';
236 require_once WPFORMS_PLUGIN_DIR . 'includes/emails/class-emails.php';
237 require_once WPFORMS_PLUGIN_DIR . 'includes/integrations.php';
238 require_once WPFORMS_PLUGIN_DIR . 'includes/deprecated.php';
239
240 // Admin/Dashboard only includes, also in ajax.
241 if ( is_admin() ) {
242 require_once WPFORMS_PLUGIN_DIR . 'includes/admin/admin.php';
243 require_once WPFORMS_PLUGIN_DIR . 'includes/admin/class-notices.php';
244 require_once WPFORMS_PLUGIN_DIR . 'includes/admin/class-menu.php';
245 require_once WPFORMS_PLUGIN_DIR . 'includes/admin/builder/class-builder.php';
246 require_once WPFORMS_PLUGIN_DIR . 'includes/admin/builder/functions.php';
247 require_once WPFORMS_PLUGIN_DIR . 'includes/admin/class-settings.php';
248 require_once WPFORMS_PLUGIN_DIR . 'includes/admin/class-welcome.php';
249 require_once WPFORMS_PLUGIN_DIR . 'includes/admin/class-editor.php';
250 require_once WPFORMS_PLUGIN_DIR . 'includes/admin/class-review.php';
251 require_once WPFORMS_PLUGIN_DIR . 'includes/admin/class-about.php';
252 require_once WPFORMS_PLUGIN_DIR . 'includes/admin/ajax-actions.php';
253 }
254 }
255
256 /**
257 * Hooks.
258 *
259 * @since 1.9.0
260 * @since 1.9.3 No longer static.
261 *
262 * @return void
263 */
264 private function hooks(): void {
265
266 add_action( 'plugins_loaded', [ self::$instance, 'objects' ] );
267 add_action( 'wpforms_settings_init', [ self::$instance, 'reinstall_custom_tables' ] );
268 }
269
270 /**
271 * Include the error handler to suppress deprecated messages from vendor folders.
272 *
273 * @since 1.8.5
274 */
275 private function error_handler(): void {
276
277 require_once WPFORMS_PLUGIN_DIR . 'src/ErrorHandler.php';
278
279 ( new ErrorHandler() )->init();
280 }
281
282 /**
283 * Including the new files with PHP 5.3 style.
284 *
285 * @since 1.4.7
286 */
287 private function includes_magic(): void { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
288
289 // Load the class loader.
290 $this->register(
291 [
292 'name' => 'Loader',
293 'hook' => false,
294 ]
295 );
296
297 $this->register(
298 [
299 'name' => 'Integrations\SolidCentral\SolidCentral',
300 'hook' => 'plugins_loaded',
301 'priority' => 0,
302 'condition' => ! empty( $_GET['ithemes-sync-request'] ), // phpcs:ignore WordPress.Security.NonceVerification.Recommended
303 ]
304 );
305
306 /*
307 * Load admin components. Exclude from the frontend.
308 */
309 if ( is_admin() ) {
310 add_action( 'wpforms_loaded', [ '\WPForms\Admin\Loader', 'get_instance' ] );
311 }
312
313 /*
314 * Properly init the providers' loader that will handle all the related logic and further loading.
315 */
316 add_action( 'wpforms_loaded', [ '\WPForms\Providers\Providers', 'get_instance' ] );
317
318 /*
319 * Properly init the integration loader that will handle all the related logic and further loading.
320 */
321 add_action( 'wpforms_loaded', [ '\WPForms\Integrations\Loader', 'get_instance' ] );
322 }
323
324 /**
325 * Setup objects.
326 *
327 * @since 1.0.0
328 */
329 public function objects(): void {
330
331 // Global objects.
332 $this->registry['form'] = new WPForms_Form_Handler();
333 $this->registry['process'] = new WPForms_Process();
334
335 /**
336 * Executes when all the WPForms stuff was loaded.
337 *
338 * @since 1.4.0
339 */
340 do_action( 'wpforms_loaded' );
341 }
342
343 /**
344 * Re-create plugin custom tables if they don't exist.
345 *
346 * @since 1.9.0
347 *
348 * @param WPForms_Settings $wpforms_settings WPForms settings object.
349 */
350 public function reinstall_custom_tables( WPForms_Settings $wpforms_settings ): void {
351
352 if ( empty( $wpforms_settings->view ) ) {
353 return;
354 }
355
356 // Proceed on the Settings plugin admin area page only.
357 if ( $wpforms_settings->view !== 'general' ) {
358 return;
359 }
360
361 // Install on the current site only.
362 if ( ! DB::custom_tables_exist() ) {
363 DB::create_custom_tables();
364 }
365 }
366
367 /**
368 * Register a class.
369 *
370 * @since 1.5.7
371 *
372 * @param array $class_data Class registration info.
373 *
374 * $class_data array accepts these params: name, id, hook, run, condition.
375 * - name: required -- class name to register.
376 * - id: optional -- class ID to register.
377 * - hook: optional -- hook to register the class on -- default wpforms_loaded.
378 * - run: optional -- method to run on class instantiation -- default init.
379 * - condition: optional -- condition to check before registering the class.
380 *
381 * @noinspection OnlyWritesOnParameterInspection
382 */
383 public function register( $class_data ): void { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh, WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
384
385 if ( empty( $class_data['name'] ) || ! is_string( $class_data['name'] ) ) {
386 return;
387 }
388
389 if ( isset( $class_data['condition'] ) && empty( $class_data['condition'] ) ) {
390 return;
391 }
392
393 $full_name = $this->is_pro() ? '\WPForms\Pro\\' . $class_data['name'] : '\WPForms\Lite\\' . $class_data['name'];
394 $full_name = class_exists( $full_name ) ? $full_name : '\WPForms\\' . $class_data['name'];
395
396 // Register an addon class.
397 if ( ! empty( $class_data['addon_class'] ) && ! empty( $class_data['addon_slug'] ) ) {
398 $is_initialized = wpforms_is_addon_initialized( $class_data['addon_slug'] ) && $this->is_pro();
399 $full_name = $is_initialized ? $class_data['addon_class'] : $full_name;
400 $full_name = strpos( $full_name, '\\' ) !== 0 ? '\\' . $full_name : $full_name;
401
402 // The core plugin classes have priority 10.
403 // Addon classes should be initialized after the core.
404 $class_data['priority'] = 100;
405 }
406
407 // Bail if the class doesn't exist AND it is not an addon class.
408 if ( ! class_exists( $full_name ) && empty( $class_data['addon_class'] ) ) {
409 return;
410 }
411
412 $id = $class_data['id'] ?? '';
413 $id = $id ? preg_replace( '/[^a-z_]/', '', (string) $id ) : $id;
414 $hook = isset( $class_data['hook'] ) ? (string) $class_data['hook'] : 'wpforms_loaded';
415 $run = $class_data['run'] ?? 'init';
416 $priority = isset( $class_data['priority'] ) && is_int( $class_data['priority'] ) ? $class_data['priority'] : 10;
417
418 $callback = function () use ( $full_name, $id, $run, $hook ) {
419 if ( ! class_exists( $full_name ) ) {
420 return;
421 }
422
423 // Instantiate class.
424 $instance = new $full_name();
425
426 $this->register_instance( $id, $instance );
427
428 if ( $run && method_exists( $instance, $run ) ) {
429 $instance->{$run}();
430 }
431 };
432
433 if ( $hook ) {
434 add_action( $hook, $callback, $priority );
435 } else {
436 $callback();
437 }
438 }
439
440 /**
441 * Register any class instance.
442 *
443 * @since 1.8.6
444 *
445 * @param string $id Class ID.
446 * @param object $instance Any class instance (object).
447 */
448 public function register_instance( $id, $instance ): void {
449
450 if ( $id && is_object( $instance ) && ! array_key_exists( $id, $this->registry ) ) {
451 $this->registry[ $id ] = $instance;
452 }
453 }
454
455 /**
456 * Register classes in bulk.
457 *
458 * @since 1.5.7
459 *
460 * @param array $classes Classes to register.
461 */
462 public function register_bulk( $classes ): void {
463
464 if ( ! is_array( $classes ) ) {
465 return;
466 }
467
468 foreach ( $classes as $class ) {
469 $this->register( $class );
470 }
471 }
472
473 /**
474 * Get a class instance from a registry.
475 * Use \WPForms\WPForms::obj() instead.
476 *
477 * @since 1.5.7
478 * @deprecated 1.9.1
479 *
480 * @param string $name Class name or an alias.
481 *
482 * @return mixed|stdClass|null
483 */
484 public function get( $name ) {
485
486 if ( ! empty( $this->registry[ $name ] ) ) {
487 return $this->registry[ $name ];
488 }
489
490 // Backward compatibility for old public properties.
491 // Return null to save old condition for these properties.
492 if ( in_array( $name, $this->legacy_properties, true ) ) {
493 return $this->{$name} ?? null;
494 }
495
496 return new stdClass();
497 }
498
499 /**
500 * Get a class instance from a registry.
501 *
502 * @since 1.9.1
503 *
504 * @param string $name Class name or an alias.
505 *
506 * @return object|null
507 */
508 public function obj( string $name ): ?object {
509
510 return $this->registry[ $name ] ?? null;
511 }
512
513 /**
514 * Get the list of all custom tables starting with `wpforms_*`.
515 *
516 * @since 1.6.3
517 *
518 * @return array List of table names.
519 */
520 public function get_existing_custom_tables(): array {
521
522 // phpcs:ignore WPForms.Formatting.EmptyLineBeforeReturn.RemoveEmptyLineBeforeReturnStatement
523 return DB::get_existing_custom_tables();
524 }
525
526 /**
527 * Whether the current instance of the plugin is a paid version, or free.
528 *
529 * @since 1.7.3
530 *
531 * @return bool
532 */
533 public function is_pro(): bool {
534
535 /**
536 * Filters whether the current plugin version is pro.
537 *
538 * @since 1.7.3
539 *
540 * @param bool $pro Whether the current plugin version is pro.
541 */
542 return (bool) apply_filters( 'wpforms_allow_pro_version', $this->pro );
543 }
544
545 /**
546 * Whether the current request is restricted heartbeat.
547 *
548 * @since 1.9.3
549 *
550 * @return bool
551 */
552 public static function is_restricted_heartbeat(): bool {
553
554 // phpcs:disable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
555 $action = $_POST['action'] ?? '';
556
557 if ( $action !== 'heartbeat' || ! wp_doing_ajax() ) {
558 return false;
559 }
560
561 $screen_id = sanitize_key( $_POST['screen_id'] ?? '' );
562 $data = array_map( 'sanitize_text_field', $_POST['data'] ?? [] );
563 // phpcs:enable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
564
565 /**
566 * Filters the screen ids where the heartbeat is allowed.
567 *
568 * @since 1.9.3
569 *
570 * @param array $allowed_screen_ids Screen IDs where the heartbeat is allowed.
571 */
572 $allowed_screen_ids = (array) apply_filters( 'wpforms_heartbeat_allowed_screen_ids', self::HEARTBEAT_ALLOWED_SCREEN_IDS );
573
574 // Allow heartbeat requests on specific screens.
575 if ( in_array( $screen_id, $allowed_screen_ids, true ) ) {
576 return false;
577 }
578
579 /**
580 * Filters whether the current request is restricted heartbeat.
581 *
582 * @since 1.9.3
583 *
584 * @param bool $is_restricted Whether the current request is restricted heartbeat.
585 * @param string $screen_id Screen ID.
586 * @param array $data Heartbeat request data.
587 */
588 return (bool) apply_filters( 'wpforms_is_restricted_heartbeat', true, $screen_id, $data );
589 }
590 }
591 }
592
593 // phpcs:ignore Universal.Namespaces.DisallowCurlyBraceSyntax.Forbidden, Universal.Namespaces.DisallowDeclarationWithoutName.Forbidden, Universal.Namespaces.OneDeclarationPerFile.MultipleFound
594 namespace {
595
596 // Define `wpforms()` function only if it's not the restricted heartbeat request.
597 if ( ! WPForms\WPForms::is_restricted_heartbeat() ) {
598
599 /**
600 * The function which returns the one WPForms instance.
601 *
602 * @since 1.0.0
603 *
604 * @return WPForms\WPForms
605 */
606 function wpforms(): WPForms\WPForms { // phpcs:ignore Universal.Files.SeparateFunctionsFromOO.Mixed
607
608 return WPForms\WPForms::instance();
609 }
610
611 /**
612 * Adding an alias for backward-compatibility with plugins
613 * that still use class_exists( 'WPForms' )
614 * instead of function_exists( 'wpforms' ), which is preferred.
615 *
616 * In 1.5.0 we removed support for PHP 5.2
617 * and moved the former WPForms class to a namespace: WPForms\WPForms.
618 *
619 * @since 1.5.1
620 */
621 class_alias( 'WPForms\WPForms', 'WPForms' );
622 }
623 }
624