PluginProbe ʕ •ᴥ•ʔ
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 2.12.1
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v2.12.1
2.12.2 2.12.1 2.12.0 2.11.1 2.11.0 2.10.1 2.10.0 2.9.1 2.9.0 2.8.2 2.8.1 2.7.0 2.7.1 2.8.0 trunk 0.0.10 0.0.11 0.0.12 0.0.13 0.0.2 0.0.3 0.0.4 0.0.5 0.0.6 0.0.7 0.0.8 0.0.9 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.1.0 1.1.1 1.1.2 1.10.0 1.10.1 1.11.0 1.12.0 1.12.1 1.12.2 1.12.3 1.13.0 1.13.1 1.13.2 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.5.0 1.5.1 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.8.0 1.9.0 1.9.1 2.0.0 2.0.1 2.0.2 2.1.0 2.1.1 2.2.0 2.2.1 2.2.2 2.3.0 2.4.0 2.5.0 2.5.2 2.6.0
sureforms / inc / admin-ajax.php
sureforms / inc Last commit date
abilities 2 weeks ago admin 1 month ago ai-form-builder 2 weeks ago blocks 1 month ago compatibility 4 weeks ago database 4 weeks ago email 3 months ago fields 4 weeks ago global-settings 2 weeks ago lib 2 weeks ago migrator 4 weeks ago page-builders 4 weeks ago payments 2 weeks ago single-form-settings 1 month ago traits 1 month ago activator.php 1 year ago admin-ajax.php 4 weeks ago background-process.php 8 months ago create-new-form.php 2 months ago duplicate-form.php 1 month ago entries.php 4 weeks ago events-scheduler.php 2 years ago export.php 1 month ago field-validation.php 2 weeks ago form-restriction.php 1 month ago form-styling.php 3 months ago form-submit.php 4 weeks ago forms-data.php 4 months ago frontend-assets.php 2 weeks ago generate-form-markup.php 4 weeks ago gutenberg-hooks.php 1 month ago helper.php 4 weeks ago learn.php 3 months ago onboarding.php 1 month ago post-types.php 1 month ago rest-api.php 2 weeks ago smart-tags.php 2 months ago submit-token.php 3 months ago translatable.php 2 weeks ago updater-callbacks.php 1 year ago updater.php 1 year ago
admin-ajax.php
462 lines
1 <?php
2 /**
3 * Sureforms Admin Ajax Class.
4 *
5 * Class file for public functions.
6 *
7 * @package sureforms
8 */
9
10 namespace SRFM\Inc;
11
12 use BSF_UTM_Analytics;
13 use SRFM\Inc\Traits\Get_Instance;
14
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit; // Exit if accessed directly.
17 }
18
19 if ( ! function_exists( 'get_plugins' ) ) {
20 require_once ABSPATH . 'wp-admin/includes/plugin.php';
21 }
22
23 /**
24 * Public Class
25 *
26 * @since 0.0.1
27 */
28 class Admin_Ajax {
29 use Get_Instance;
30
31 /**
32 * Constructor
33 *
34 * @since 0.0.1
35 */
36 public function __construct() {
37 add_action( 'wp_ajax_sureforms_recommended_plugin_activate', [ $this, 'required_plugin_activate' ] );
38 add_action( 'wp_ajax_sureforms_recommended_plugin_install', 'wp_ajax_install_plugin' );
39 add_action( 'wp_ajax_sureforms_integration', [ $this, 'generate_data_for_suretriggers_integration' ] );
40 add_action( 'wp_ajax_srfm_download_export', [ $this, 'download_export_file' ] );
41
42 add_filter( SRFM_SLUG . '_admin_filter', [ $this, 'localize_script_integration' ] );
43 }
44
45 /**
46 * Required Plugin Activate
47 *
48 * @return void
49 * @since 0.0.1
50 */
51 public function required_plugin_activate() {
52
53 $response_data = [ 'message' => $this->get_error_msg( 'permission' ) ];
54
55 if ( ! Helper::current_user_can() ) {
56 wp_send_json_error( $response_data );
57 }
58
59 if ( empty( $_POST ) ) {
60 $response_data = [ 'message' => $this->get_error_msg( 'invalid' ) ];
61 wp_send_json_error( $response_data );
62 }
63
64 /**
65 * Nonce verification.
66 */
67 if ( ! check_ajax_referer( 'sf_plugin_manager_nonce', 'security', false ) ) {
68 $response_data = [ 'message' => $this->get_error_msg( 'nonce' ) ];
69 wp_send_json_error( $response_data );
70 }
71
72 if ( ! isset( $_POST['init'] ) || ! sanitize_text_field( wp_unslash( $_POST['init'] ) ) ) {
73 wp_send_json_error(
74 [
75 'success' => false,
76 'message' => __( 'No plugin specified', 'sureforms' ),
77 ]
78 );
79 }
80
81 $plugin_init = isset( $_POST['init'] ) ? sanitize_text_field( wp_unslash( $_POST['init'] ) ) : '';
82
83 $plugin_slug = isset( $_POST['slug'] ) ? sanitize_text_field( wp_unslash( $_POST['slug'] ) ) : '';
84
85 $activate = activate_plugin( $plugin_init, '', false, true );
86
87 if ( is_wp_error( $activate ) ) {
88 wp_send_json_error(
89 [
90 'success' => false,
91 'message' => $activate->get_error_message(),
92 ]
93 );
94 }
95
96 if ( class_exists( 'BSF_UTM_Analytics' ) && is_callable( 'BSF_UTM_Analytics::update_referer' ) ) {
97 $plugin_slug = pathinfo( $plugin_slug, PATHINFO_FILENAME );
98 BSF_UTM_Analytics::update_referer( 'sureforms', $plugin_slug );
99 }
100
101 wp_send_json_success(
102 [
103 'success' => true,
104 'message' => __( 'Plugin Successfully Activated', 'sureforms' ),
105 ]
106 );
107 }
108
109 /**
110 * Get ajax error message.
111 *
112 * @param string $type Message type.
113 * @return string
114 * @since 0.0.2
115 */
116 public function get_error_msg( $type ) {
117
118 if ( ! isset( $this->errors[ $type ] ) ) {
119 $type = 'default';
120 }
121 if ( ! isset( $this->errors ) ) {
122 return '';
123 }
124 return $this->errors[ $type ];
125 }
126
127 /**
128 * Localize the variables required for integration plugins.
129 *
130 * @param array<mixed> $values localized values.
131 * @return array<mixed>
132 * @since 0.0.1
133 */
134 public function localize_script_integration( $values ) {
135 $is_screen_sureforms_menu = Helper::validate_request_context( 'sureforms_menu', 'page' );
136 return array_merge(
137 $values,
138 [
139 'ajax_url' => admin_url( 'admin-ajax.php' ),
140 'sfPluginManagerNonce' => wp_create_nonce( 'sf_plugin_manager_nonce' ),
141 'plugin_installer_nonce' => wp_create_nonce( 'updates' ),
142 'isRTL' => is_rtl(),
143 'current_screen_id' => $is_screen_sureforms_menu ? 'sureforms_menu' : '',
144 'form_id' => get_post() ? get_post()->ID : '',
145 'suretriggers_nonce' => wp_create_nonce( 'suretriggers_nonce' ),
146 ]
147 );
148 }
149
150 /**
151 * Generates data required for suretriggers integration
152 *
153 * @since 0.0.8
154 * @return void
155 */
156 public function generate_data_for_suretriggers_integration() {
157 if ( ! Helper::current_user_can() ) {
158 wp_send_json_error( [ 'message' => __( 'You do not have permission to access this page.', 'sureforms' ) ] );
159 }
160
161 if ( ! check_ajax_referer( 'suretriggers_nonce', 'security', false ) ) {
162 wp_send_json_error( [ 'message' => __( 'Invalid nonce.', 'sureforms' ) ] );
163 }
164
165 if ( empty( $_POST['formId'] ) ) {
166 wp_send_json_error( [ 'message' => __( 'Form ID is required.', 'sureforms' ) ] );
167 }
168
169 if ( ! Helper::is_suretriggers_ready() ) {
170 wp_send_json_error(
171 [
172 'code' => 'invalid_secret_key',
173 'message' => __( 'OttoKit is not configured properly.', 'sureforms' ),
174 ]
175 );
176 }
177
178 $form_id = Helper::get_integer_value( sanitize_text_field( wp_unslash( $_POST['formId'] ) ) );
179 $form = get_post( $form_id );
180
181 if ( is_null( $form ) || SRFM_FORMS_POST_TYPE !== $form->post_type ) {
182 wp_send_json_error( [ 'message' => __( 'Invalid form ID.', 'sureforms' ) ] );
183 }
184
185 // Translators: %s: Form ID.
186 $form_name = ! empty( $form->post_title ) ? $form->post_title : sprintf( __( 'SureForms id: %s', 'sureforms' ), $form_id );
187 $api_url = apply_filters( 'suretriggers_get_iframe_url', SRFM_SURETRIGGERS_INTEGRATION_BASE_URL ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- SureTriggers' own filter; the name must match SureTriggers exactly to integrate.
188
189 // This is the format of data required by SureTriggers for adding iframe in target id.
190 $body = [
191 'client_id' => 'SureForms',
192 'st_embed_url' => $api_url,
193 'embedded_identifier' => $form_id,
194 'target' => 'suretriggers-iframe-wrapper', // div where we want SureTriggers to add iframe should have this target id.
195 'event' => [
196 'label' => __( 'Form Submitted', 'sureforms' ),
197 'value' => 'sureforms_form_submitted',
198 'description' => __( 'Runs when a form is submitted', 'sureforms' ),
199 ],
200 'summary' => $form_name,
201 'selected_options' => [
202 'form_id' => [
203 'value' => $form_id,
204 'label' => $form_name,
205 ],
206 ],
207 'integration' => 'SureForms',
208 'sample_response' => [
209 'form_id' => $form_id,
210 'to_emails' => [
211 'dev-email@wpengine.local',
212 ],
213 'form_name' => $form_name,
214 'data' => $this->get_form_fields( $form_id ),
215 ],
216 ];
217
218 // Adding entry_id in body sample response if do_not_store_entries is not enabled.
219 $compliance = get_post_meta( $form_id, '_srfm_compliance', true );
220 $do_not_store_entries = is_array( $compliance ) && isset( $compliance[0]['do_not_store_entries'] )
221 ? $compliance[0]['do_not_store_entries']
222 : null;
223
224 if ( ! $do_not_store_entries ) {
225 $body['sample_response']['entry_id'] = 12;
226 }
227
228 wp_send_json_success(
229 [
230 'message' => 'success',
231 'data' => apply_filters( 'srfm_suretriggers_integration_data_filter', $body, $form_id ),
232 ]
233 );
234 }
235
236 /**
237 * This function populates data for particular form.
238 *
239 * @param int $form_id Form ID.
240 * @since 0.0.8
241 * @return array<mixed>
242 */
243 public function get_form_fields( $form_id ) {
244 if ( empty( $form_id ) || ! is_int( $form_id ) ) {
245 return [];
246 }
247
248 if ( SRFM_FORMS_POST_TYPE !== get_post_type( $form_id ) ) {
249 return [];
250 }
251
252 $post = get_post( $form_id );
253
254 if ( is_null( $post ) ) {
255 return [];
256 }
257
258 $blocks = parse_blocks( $post->post_content );
259
260 $blocks = array_filter(
261 $blocks,
262 static function( $block ) {
263 if ( 'srfm/html' === $block['blockName'] ) {
264 return false;
265 }
266 return true;
267 }
268 );
269
270 $blocks = array_values( $blocks );
271
272 if ( empty( $blocks ) ) {
273 return [];
274 }
275
276 $data = [];
277
278 foreach ( $blocks as $block ) {
279 if ( ! empty( $block['blockName'] ) && 0 === strpos( $block['blockName'], 'srfm/' ) ) {
280
281 /**
282 * Determine whether to skip this field from the sample data.
283 *
284 * @param bool $should_skip Default value indicating if field should be skipped.
285 * @param array $block_details Array containing block attributes, including 'block_name'.
286 *
287 * @since 2.0.0
288 *
289 * @hook srfm_should_skip_field_from_sample_data
290 */
291 $should_skip_this_field = apply_filters(
292 'srfm_should_skip_field_from_sample_data',
293 false,
294 [
295 'block_name' => $block['blockName'],
296 ]
297 );
298
299 if ( $should_skip_this_field ) {
300 continue;
301 }
302
303 if ( ! empty( $block['attrs']['slug'] ) ) {
304 $data[ $block['attrs']['slug'] ] = $this->get_sample_data( $block['blockName'] );
305 }
306 }
307 }
308
309 if ( empty( $data ) ) {
310 return [];
311 }
312
313 return $data;
314 }
315
316 /**
317 * Returns sample data for a block.
318 *
319 * @param string $block_name Block name.
320 * @since 0.0.8
321 * @return mixed
322 */
323 public function get_sample_data( $block_name ) {
324 if ( empty( $block_name ) ) {
325 return __( 'Sample data', 'sureforms' );
326 }
327
328 $dummy_data = [
329 'srfm/input' => __( 'Sample input data', 'sureforms' ),
330 'srfm/email' => 'noreply@sureforms.com',
331 'srfm/textarea' => __( 'Sample textarea data', 'sureforms' ),
332 'srfm/number' => 123,
333 'srfm/checkbox' => 'checkbox value',
334 'srfm/gdpr' => 'GDPR value',
335 'srfm/phone' => '1234567890',
336 'srfm/address' => __( 'Address data', 'sureforms' ),
337 'srfm/address-compact' => __( 'Address data', 'sureforms' ),
338 'srfm/dropdown' => __( 'Selected dropdown option', 'sureforms' ),
339 'srfm/multi-choice' => __( 'Selected Multichoice option', 'sureforms' ),
340 'srfm/radio' => __( 'Selected radio option', 'sureforms' ),
341 'srfm/submit' => __( 'Submit', 'sureforms' ),
342 'srfm/url' => 'https://example.com',
343 'srfm/date-time-picker' => '2022-01-01 12:00:00',
344 'srfm/hidden' => __( 'Hidden Value', 'sureforms' ),
345 'srfm/slider' => 50,
346 'srfm/password' => 'DummyPassword123',
347 'srfm/rating' => 4,
348 'srfm/upload' => 'https://example.com/uploads/file.pdf',
349 ];
350
351 /**
352 * Filter the sample data for specific block types.
353 *
354 * Allows plugins and themes to add custom sample data for their block types
355 * or modify existing sample data. This is particularly useful for dynamic
356 * block types that require complex sample data structures.
357 *
358 * @since 0.0.8
359 *
360 * @param array $dummy_data {
361 * Array of sample data keyed by block name.
362 *
363 * @type string|array $block_name Sample data for the block.
364 * }
365 * @param array $filter_args {
366 * Additional filter arguments.
367 *
368 * @type string $block_name The name of the block being processed.
369 * }
370 */
371 $dummy_data = Helper::apply_filters_as_array( 'srfm_sample_data_filter', $dummy_data, [ 'block_name' => $block_name ] );
372
373 if ( ! empty( $dummy_data[ $block_name ] ) ) {
374 return $dummy_data[ $block_name ];
375 }
376 return __( 'Sample data', 'sureforms' );
377 }
378
379 /**
380 * Download exported file.
381 *
382 * @since 2.0.0
383 * @return void
384 */
385 public function download_export_file() {
386 // Check user permissions.
387 if ( ! Helper::current_user_can() ) {
388 wp_die( esc_html__( 'You do not have permission to access this file.', 'sureforms' ) );
389 }
390
391 // Verify nonce for security.
392 if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'srfm_download_export' ) ) {
393 wp_die( esc_html__( 'Security check failed.', 'sureforms' ) );
394 }
395
396 // Get and sanitize the file parameter.
397 $file = isset( $_GET['file'] ) ? sanitize_file_name( wp_unslash( $_GET['file'] ) ) : '';
398
399 if ( empty( $file ) ) {
400 wp_die( esc_html__( 'Invalid file request.', 'sureforms' ) );
401 }
402
403 // Build the full file path.
404 $temp_dir = wp_normalize_path( trailingslashit( get_temp_dir() ) );
405 $filepath = $temp_dir . $file;
406
407 // Security check: ensure the file is in the temp directory.
408 if ( strpos( wp_normalize_path( $filepath ), $temp_dir ) !== 0 ) {
409 wp_die( esc_html__( 'Invalid file path.', 'sureforms' ) );
410 }
411
412 // Check if file exists.
413 if ( ! file_exists( $filepath ) ) {
414 wp_die( esc_html__( 'File not found.', 'sureforms' ) );
415 }
416
417 // Get file info.
418 $file_size = filesize( $filepath );
419 $file_info = pathinfo( $filepath );
420
421 // Determine content type and filename based on file extension.
422 $content_type = 'application/octet-stream';
423 $filename = $file_info['basename'];
424 if ( isset( $file_info['extension'] ) ) {
425 if ( 'csv' === $file_info['extension'] ) {
426 $content_type = 'text/csv';
427 } elseif ( 'zip' === $file_info['extension'] ) {
428 $content_type = 'application/zip';
429 /**
430 * Filter the user-facing filename used when serving an exported ZIP archive.
431 *
432 * @since 2.9.0
433 *
434 * @param string $filename Default ZIP filename.
435 * @param array<string,mixed> $file_info pathinfo() result for the file being served.
436 */
437 $filename = (string) apply_filters( 'srfm_export_zip_filename', 'SureForms Entries.zip', $file_info );
438 }
439 }
440
441 // Set headers for download.
442 header( 'Content-Type: ' . $content_type );
443 header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
444 header( 'Content-Length: ' . $file_size );
445 header( 'Cache-Control: private, max-age=0, must-revalidate' );
446 header( 'Pragma: public' );
447
448 // Clear output buffers.
449 if ( ob_get_level() ) {
450 ob_end_clean();
451 }
452
453 // Output the file.
454 readfile( $filepath ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_readfile, WordPress.WP.AlternativeFunctions.file_system_operations_readfile -- Direct file output is required to stream the download.
455
456 // Clean up the temporary file.
457 wp_delete_file( $filepath );
458
459 exit;
460 }
461 }
462