PluginProbe
SurveyX Builder – Easy Feedback, Poll, Quiz & Survey / trunk
SurveyX Builder – Easy Feedback, Poll, Quiz & Survey vtrunk
1.7.0 trunk 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.5.1 1.6.0
surveyx-builder / surveyx-builder.php

surveyx-builder.php in SurveyX Builder – Easy Feedback, Poll, Quiz & Survey trunk, at surveyx-builder.php

322 lines 10.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Plugin Name: SurveyX Builder
5 * Description: Create surveys, polls, quizzes, and feedback forms. Fast, lightweight, and optimized to boost responses and user engagement.
6 * Plugin URI: https://surveyx.co/
7 * Author: ThemeRuby
8 * Tags: poll, survey, quiz, form, feedback
9 * License: GPLv3
10 * License URI: https://www.gnu.org/licenses/gpl-3.0.html
11 * Version: 1.7.0
12 * Requires at least: 6.0
13 * Requires PHP: 7.4
14 * Author URI: https://themeruby.com/
15 * Text Domain: surveyx-builder
16 * Domain Path: /languages
17 *
18 * @package surveyx-builder
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation, either version 3 of the License, or any later version.
23 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
24 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25 */
26 defined( 'ABSPATH' ) || exit;
27
28 defined( 'SURVEYX_PATH' ) || define( 'SURVEYX_PATH', plugin_dir_path( __FILE__ ) );
29 defined( 'SURVEYX_VERSION' ) || define( 'SURVEYX_VERSION', '1.7.0' );
30 defined( 'SURVEYX_URL' ) || define( 'SURVEYX_URL', plugin_dir_url( __FILE__ ) );
31 defined( 'SURVEYX_BASENAME' ) || define( 'SURVEYX_BASENAME', plugin_basename( __FILE__ ) );
32 defined( 'SURVEYX_REST_NAMESPACE' ) || define( 'SURVEYX_REST_NAMESPACE', 'surveyx/v1' );
33 defined( 'SURVEYX_HOST_BASE' ) || define( 'SURVEYX_HOST_BASE', 'https://surveyx.co' );
34
35 if ( ! class_exists( 'SurveyX_Builder', false ) ) {
36 class SurveyX_Builder {
37
38 private static $instance;
39
40 /**
41 * Disable object cloning.
42 *
43 * @return void
44 */
45 public function __clone() {
46 }
47
48 /**
49 * Disable unserializing of the class.
50 *
51 * @return void
52 */
53 public function __wakeup() {
54 }
55
56 public static function get_instance() {
57 if ( null === self::$instance ) {
58 return new self();
59 }
60
61 return self::$instance;
62 }
63
64 public function __construct() {
65 self::$instance = $this;
66
67 // Activation hooks.
68 register_activation_hook( __FILE__, [ $this, 'activation' ] );
69 register_deactivation_hook( __FILE__, [ $this, 'deactivation' ] );
70 add_action( 'plugins_loaded', [ $this, 'load' ], 10 );
71
72 // Provision tables on newly created multisite sub-sites (always listening,
73 // not tied to activation, so a network-active plugin covers sites added later).
74 add_action( 'wp_initialize_site', [ $this, 'initialize_new_site' ], 10, 1 );
75 }
76
77 /**
78 * Provisions SurveyX tables (and cron) on a newly created multisite sub-site.
79 *
80 * Fires on every new-site creation, so a network-active plugin picks up sites
81 * added after network activation. Mirrors the free activation path (create
82 * tables + register cron). Stands down when Pro is active.
83 *
84 * @param WP_Site $new_site The newly created site object.
85 *
86 * @return void
87 */
88 public function initialize_new_site( $new_site ) {
89 // Skip if Pro is active to avoid duplicate function declarations.
90 if ( defined( 'SURVEYX_PRO_VERSION' ) ) {
91 return;
92 }
93
94 // Only provision when this plugin is network-active.
95 require_once ABSPATH . 'wp-admin/includes/plugin.php';
96 if ( ! is_plugin_active_for_network( SURVEYX_BASENAME ) ) {
97 return;
98 }
99
100 switch_to_blog( (int) $new_site->blog_id );
101
102 try {
103 require_once SURVEYX_PATH . 'includes/db-migration.php';
104 require_once SURVEYX_PATH . 'includes/cron-jobs.php';
105 surveyx_create_database();
106 surveyx_register_cron_events();
107 } catch ( \Throwable $e ) {
108 // A failure on one site must not fatal the request that created it.
109 } finally {
110 restore_current_blog();
111 }
112 }
113
114 /**
115 * Handles plugin activation for both single and multisite setups.
116 *
117 * @param bool $network Whether this is a network-wide activation (for multisite).
118 *
119 * @return void
120 */
121 public function activation( $network ) {
122 // Skip if Pro is active to avoid duplicate function declarations.
123 if ( defined( 'SURVEYX_PRO_VERSION' ) ) {
124 return;
125 }
126
127 require_once SURVEYX_PATH . 'includes/db-migration.php';
128 require_once SURVEYX_PATH . 'includes/cron-jobs.php';
129
130 if ( is_multisite() && $network ) {
131 // number=0 → no cap (default is 100); skip archived/deleted/spam sites.
132 $sites = get_sites(
133 [
134 'number' => 0,
135 'archived' => 0,
136 'deleted' => 0,
137 'spam' => 0,
138 ]
139 );
140 foreach ( $sites as $site ) {
141 switch_to_blog( (int) $site->blog_id );
142 surveyx_create_database();
143 surveyx_register_cron_events();
144 restore_current_blog();
145 }
146
147 return;
148 }
149
150 surveyx_create_database();
151 surveyx_register_cron_events();
152 }
153
154 /**
155 * Determine if the current context is admin-related and the user is logged in with admin privileges.
156 * Safe to use in 'plugins_loaded' hook.
157 *
158 * @return bool
159 */
160 public function is_admin_user_context() {
161 wp_get_current_user();
162
163 return is_user_logged_in() && current_user_can( 'manage_options' );
164 }
165
166 /**
167 * Whether the current request is a REST API request.
168 *
169 * Usable at 'plugins_loaded' (before REST_REQUEST is defined) by matching the
170 * REST route/prefix on the request URI. Used to load the admin/REST bundle for
171 * REST calls (admin SPA + public survey endpoints) while keeping it off plain
172 * front-end page loads.
173 *
174 * @return bool
175 */
176 private function is_rest_request() {
177 if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
178 return true;
179 }
180
181 if ( ! empty( $_GET['rest_route'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
182 return true;
183 }
184
185 if ( empty( $_SERVER['REQUEST_URI'] ) || ! function_exists( 'rest_get_url_prefix' ) ) {
186 return false;
187 }
188
189 $rest_prefix = trailingslashit( rest_get_url_prefix() );
190 $request_uri = esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) );
191
192 return false !== strpos( $request_uri, $rest_prefix );
193 }
194
195 /**
196 * Handles plugin deactivation, such as cleaning up options.
197 *
198 * @param bool $network_wide Whether this is a network-wide deactivation (for multisite).
199 *
200 * @return void
201 */
202 public function deactivation( $network_wide = false ) {
203 // Skip if Pro is active - Pro handles its own cron cleanup.
204 if ( defined( 'SURVEYX_PRO_VERSION' ) ) {
205 return;
206 }
207
208 require_once SURVEYX_PATH . 'includes/cron-jobs.php';
209
210 if ( is_multisite() && $network_wide ) {
211 // number=0 → no cap (default is 100); skip archived/deleted/spam sites.
212 $sites = get_sites(
213 [
214 'number' => 0,
215 'archived' => 0,
216 'deleted' => 0,
217 'spam' => 0,
218 ]
219 );
220 foreach ( $sites as $site ) {
221 switch_to_blog( (int) $site->blog_id );
222 surveyx_unregister_cron_events();
223 restore_current_blog();
224 }
225
226 return;
227 }
228
229 surveyx_unregister_cron_events();
230 }
231
232 /**
233 * Loads the necessary plugin files based on the context (admin or frontend).
234 *
235 * @return void
236 */
237 public function load() {
238
239 if ( defined( 'SURVEYX_PRO_VERSION' ) ) {
240 return;
241 }
242
243 // Run database migrations if needed.
244 require_once SURVEYX_PATH . 'includes/db-migration.php';
245
246 // Safety-net self-heal: ensure tables exist on a site that never ran the
247 // activation hook (e.g. an imported, restored, or cloned multisite sub-site).
248 // Gated on a per-site autoloaded flag → a single option read per request once
249 // set. surveyx_create_database() is CREATE IF NOT EXISTS + marks migration
250 // steps done, so this is a no-op where the schema already exists.
251 if ( ! get_option( 'surveyx_db_installed' ) ) {
252 surveyx_create_database();
253 update_option( 'surveyx_db_installed', SURVEYX_VERSION, true );
254 }
255
256 // Load core helper files.
257 require_once SURVEYX_PATH . 'includes/admin-helpers.php';
258 require_once SURVEYX_PATH . 'includes/date-helper.php';
259 require_once SURVEYX_PATH . 'includes/request-helper.php';
260 require_once SURVEYX_PATH . 'includes/session-manager.php';
261 require_once SURVEYX_PATH . 'includes/cron-jobs.php';
262 require_once SURVEYX_PATH . 'includes/response-types.php';
263 require_once SURVEYX_PATH . 'includes/database.php';
264 require_once SURVEYX_PATH . 'includes/revisions.php';
265
266 // Cache invalidation via semantic actions (big-plugin pattern): mutation
267 // sites fire surveyx_survey_saved / surveyx_survey_deleted; the static /init
268 // cache subscribes here ONCE. Registered in the always-loaded core (not the
269 // deferred admin bundle) so it also fires on REST save paths. SurveyX_Db is
270 // already required above.
271 add_action( 'surveyx_survey_saved', [ 'SurveyX_Db', 'flush_survey_init_cache' ], 10, 1 );
272 add_action( 'surveyx_survey_deleted', [ 'SurveyX_Db', 'flush_survey_init_cache' ], 10, 1 );
273
274 // Admin + REST bundle: only needed in wp-admin, on REST requests (admin SPA
275 // and public survey endpoints, since /init is a REST request), or during
276 // cron. Skipped on plain front-end page loads where the shortcode renders
277 // from the core + client includes below.
278 if ( is_admin() || $this->is_rest_request() || wp_doing_cron() || ( defined( 'WP_CLI' ) && WP_CLI ) ) {
279 // Load admin menu panel UI.
280 require_once SURVEYX_PATH . 'admin/admin-menu.php';
281
282 // Load analytics database class with caching.
283 require_once SURVEYX_PATH . 'admin/analytics-database.php';
284 require_once SURVEYX_PATH . 'admin/analytics-handler.php';
285
286 // Load admin database class (needed for REST API).
287 require_once SURVEYX_PATH . 'admin/database.php';
288
289 // Load API endpoints and REST routes (permissions handled at route level).
290 require_once SURVEYX_PATH . 'admin/api-endpoints.php';
291 require_once SURVEYX_PATH . 'admin/rest-routes.php';
292
293 // Load hooks (allow revote on update, etc.)
294 require_once SURVEYX_PATH . 'admin/hooks.php';
295 }
296
297 if ( $this->is_admin_user_context() ) {
298 // Load admin-only helper functions.
299 require_once SURVEYX_PATH . 'admin/media-helpers.php';
300
301 // Review-request admin notice (registers admin_notices + ajax handler).
302 require_once SURVEYX_PATH . 'includes/review-notice.php';
303 }
304
305 // Load client helper functions.
306 require_once SURVEYX_PATH . 'client/helpers.php';
307 require_once SURVEYX_PATH . 'client/captcha-helpers.php';
308
309 // Load data repository and client-side logic.
310 require_once SURVEYX_PATH . 'client/client-services.php';
311
312 // Load REST API functionality.
313 require_once SURVEYX_PATH . 'client/rest-routes.php';
314
315 // Register the feedback form shortcode.
316 require_once SURVEYX_PATH . 'client/form-shortcode.php';
317 }
318 }
319 }
320
321 SurveyX_Builder::get_instance();
322