Completed
Push — develop ( 206f78...cc1a69 )
by Zack
06:34 queued 06:30
created

GravityView_Ajax::get_available_fields_html()   B

Complexity

Conditions 6
Paths 10

Size

Total Lines 40

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
cc 6
nc 10
nop 0
dl 0
loc 40
ccs 0
cts 18
cp 0
crap 42
rs 8.6577
c 0
b 0
f 0
1
<?php
2
3
class GravityView_Ajax {
4
5
	function __construct() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
6
7
		//get field options
8
		add_action( 'wp_ajax_gv_field_options', array( $this, 'get_field_options' ) );
9
10
		// get available fields
11
		add_action( 'wp_ajax_gv_available_fields', array( $this, 'get_available_fields_html' ) );
12
13
		// get active areas
14
		add_action( 'wp_ajax_gv_get_active_areas', array( $this, 'get_active_areas' ) );
15
16
		// get preset fields
17
		add_action( 'wp_ajax_gv_get_preset_fields', array( $this, 'get_preset_fields_config' ) );
18
19
		// get preset fields
20
		add_action( 'wp_ajax_gv_set_preset_form', array( $this, 'create_preset_form' ) );
21
22
		add_action( 'wp_ajax_gv_sortable_fields_form', array( $this, 'get_sortable_fields' ) );
23
	}
24
25
	/**
26
	 * Handle exiting the script (for unit testing)
27
	 *
28
	 * @since 1.15
29
	 * @param bool|false $mixed
30
	 *
31
	 * @return bool
32
	 */
33
	private function _exit( $mixed = NULL ) {
34
35
		/**
36
		 * Don't exit if we're running test suite.
37
		 * @since 1.15
38
		 */
39
		if( defined( 'DOING_GRAVITYVIEW_TESTS' ) && DOING_GRAVITYVIEW_TESTS ) {
40
			return $mixed;
41
		}
42
43
		exit( $mixed );
44
	}
45
46
	/** -------- AJAX ---------- */
47
48
	/**
49
	 * Verify the nonce. Exit if not verified.
50
	 * @return void
51
	 */
52
	function check_ajax_nonce() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
53
		if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'gravityview_ajaxviews' ) ) {
54
			$this->_exit( false );
55
		}
56
	}
57
58
	/**
59
	 * AJAX action to get HTML markup for form(s) or template fields
60
	 * AJAX callback
61
	 *
62
	 * @access public
63
	 * @return array|void Terminate request, exit with JSON response or return HTML markup
64
	 */
65
	function get_available_fields_html() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
66
67
		$this->check_ajax_nonce();
68
69
		$context = rgpost( 'context' );
70
71
		// Return markup for a single or multiple contexts
72
		if( $context ) {
73
			$data = array(
74
				esc_attr( $context ) => ''
75
			);
76
		} else {
77
			$data = array(
78
				'directory' => '',
79
				'edit' => '',
80
				'single' => ''
81
			);
82
		}
83
84
		if ( is_array( rgpost( 'form_preset_ids' ) ) ) {
85
			$form_ids = rgpost( 'form_preset_ids' );
86
		} else {
87
			$this->_exit( false );
88
			return; // If inside unit tests, which don't exit, don't continue.
89
		}
90
91
		foreach ( $data as $context => $markup ) {
92
			ob_start();
93
94
			do_action( 'gravityview_render_field_pickers', $context, $form_ids );
95
96
			$data[ $context ] = trim( ob_get_clean() );
97
		}
98
99
		if ( defined( 'DOING_GRAVITYVIEW_TESTS' ) && DOING_GRAVITYVIEW_TESTS ) {
100
			return $data;
101
		}
102
103
		wp_send_json_success( $data );
104
	}
105
106
	/**
107
	 * Returns template active areas given a template ID
108
	 * AJAX callback
109
	 *
110
	 * @access public
111
	 * @return void
112
	 */
113
	function get_active_areas() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
114
		$this->check_ajax_nonce();
115
116
		if( empty( $_POST['template_id'] ) ) {
117
			$this->_exit( false );
118
		}
119
120
		ob_start();
121
		do_action( 'gravityview_render_directory_active_areas', $_POST['template_id'], 'directory', '', true );
122
		$response['directory'] = ob_get_clean();
0 ignored issues
show
Coding Style Comprehensibility introduced by
$response was never initialized. Although not strictly required by PHP, it is generally a good practice to add $response = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
123
124
		ob_start();
125
		do_action( 'gravityview_render_directory_active_areas',  $_POST['template_id'], 'single', '', true );
126
		$response['single'] = ob_get_clean();
127
128
		$response = array_map( 'gravityview_strip_whitespace', $response );
129
130
		$this->_exit( json_encode( $response ) );
131
	}
132
133
	/**
134
	 * Fill in active areas with preset configuration according to the template selected
135
	 * @return void
136
	 */
137
	function get_preset_fields_config() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
138
139
		$this->check_ajax_nonce();
140
141
		if( empty( $_POST['template_id'] ) ) {
142
			$this->_exit( false );
143
		}
144
145
		// get the fields xml config file for this specific preset
146
		$preset_fields_path = apply_filters( 'gravityview_template_fieldsxml', array(), $_POST['template_id'] );
147
		// import fields
148
		if( !empty( $preset_fields_path ) ) {
149
			$presets = $this->import_fields( $preset_fields_path );
150
		} else {
151
			$presets = array( 'widgets' => array(), 'fields' => array() );
152
		}
153
154
		$template_id = esc_attr( $_POST['template_id'] );
155
156
		// template areas
157
		$template_areas_directory = apply_filters( 'gravityview_template_active_areas', array(), $template_id, 'directory' );
158
        $template_areas_single = apply_filters( 'gravityview_template_active_areas', array(), $template_id, 'single' );
159
160
		// widget areas
161
		$default_widget_areas = \GV\Widget::get_default_widget_areas();
162
163
		ob_start();
164
		do_action('gravityview_render_active_areas', $template_id, 'widget', 'header', $default_widget_areas, $presets['widgets'] );
165
		$response['header'] = ob_get_clean();
0 ignored issues
show
Coding Style Comprehensibility introduced by
$response was never initialized. Although not strictly required by PHP, it is generally a good practice to add $response = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
166
167
		ob_start();
168
		do_action('gravityview_render_active_areas', $template_id, 'widget', 'footer', $default_widget_areas, $presets['widgets'] );
169
		$response['footer'] = ob_get_clean();
170
171
		ob_start();
172
		do_action('gravityview_render_active_areas', $template_id, 'field', 'directory', $template_areas_directory, $presets['fields'] );
173
		$response['directory'] = ob_get_clean();
174
175
		ob_start();
176
		do_action('gravityview_render_active_areas', $template_id, 'field', 'single', $template_areas_single, $presets['fields'] );
177
		$response['single'] = ob_get_clean();
178
179
		$response = array_map( 'gravityview_strip_whitespace', $response );
180
181
		gravityview()->log->debug( '[get_preset_fields_config] AJAX Response', array( 'data' => $response ) );
182
183
		$this->_exit( json_encode( $response ) );
184
	}
185
186
	/**
187
	 * Create the preset form requested before the View save
188
	 *
189
	 * @return void
190
	 */
191
	function create_preset_form() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
192
193
		$this->check_ajax_nonce();
194
195
		if( empty( $_POST['template_id'] ) ) {
196
			gravityview()->log->error( 'Cannot create preset form; the template_id is empty.' );
197
			$this->_exit( false );
198
		}
199
200
		// get the xml for this specific template_id
201
		$preset_form_xml_path = apply_filters( 'gravityview_template_formxml', '', $_POST['template_id'] );
202
203
		// import form
204
		$form = $this->import_form( $preset_form_xml_path );
205
206
		// get the form ID
207
		if( false === $form ) {
208
			// send error to user
209
			gravityview()->log->error( 'Error importing form for template id: {template_id}', array( 'template_id' => (int) $_POST['template_id'] ) );
210
211
			$this->_exit( false );
212
		}
213
214
		$this->_exit( '<option value="'.esc_attr( $form['id'] ).'" selected="selected">'.esc_html( $form['title'] ).'</option>' );
215
216
	}
217
218
	/**
219
	 * Import Gravity Form XML or JSON
220
	 *
221
	 * @param  string $xml_or_json_path Path to form XML or JSON file
222
	 * @return int|bool       Imported form ID or false
223
	 */
224 1
	function import_form( $xml_or_json_path = '' ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
225
226 1
		gravityview()->log->debug( '[import_form] Import Preset Form. (File) {path}', array( 'path' => $xml_or_json_path ) );
227
228 1
		if( empty( $xml_or_json_path ) || !class_exists('GFExport') || !file_exists( $xml_or_json_path ) ) {
229
			gravityview()->log->error( 'Class GFExport or file not found. file: {path}', array( 'path' => $xml_or_json_path ) );
230
			return false;
231
		}
232
233
		// import form
234 1
		$forms = '';
235 1
		$count = GFExport::import_file( $xml_or_json_path, $forms );
236
237 1
		gravityview()->log->debug( '[import_form] Importing form (Result) {count}', array( 'count' => $count ) );
238 1
		gravityview()->log->debug( '[import_form] Importing form (Form) ', array( 'data' => $forms ) );
239
240 1
		if( $count != 1 || empty( $forms[0]['id'] ) ) {
241
			gravityview()->log->error( 'Form Import Failed!' );
242
			return false;
243
		}
244
245
		// import success - return form id
246 1
		return $forms[0];
247
	}
248
249
250
	/**
251
	 * Returns field options - called by ajax when dropping fields into active areas
252
	 * AJAX callback
253
	 *
254
	 * @access public
255
	 * @return void
256
	 */
257
	function get_field_options() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
258
		$this->check_ajax_nonce();
259
260
		if( empty( $_POST['template'] ) || empty( $_POST['area'] ) || empty( $_POST['field_id'] ) || empty( $_POST['field_type'] ) ) {
261
			gravityview()->log->error( 'Required fields were not set in the $_POST request. ' );
262
			$this->_exit( false );
263
		}
264
265
		// Fix apostrophes added by JSON response
266
		$_post = array_map( 'stripslashes_deep', $_POST );
267
268
		// Sanitize
269
		$_post = array_map( 'esc_attr', $_post );
270
271
		// The GF type of field: `product`, `name`, `creditcard`, `id`, `text`
272
		$input_type = isset($_post['input_type']) ? esc_attr( $_post['input_type'] ) : NULL;
273
		$context = isset($_post['context']) ? esc_attr( $_post['context'] ) : NULL;
274
275
		$form_id = empty( $_post['form_id'] ) ? null : $_post['form_id'];
276
		$response = GravityView_Render_Settings::render_field_options( $form_id, $_post['field_type'], $_post['template'], $_post['field_id'], $_post['field_label'], $_post['area'], $input_type, '', '', $context  );
277
278
		$response = gravityview_strip_whitespace( $response );
279
280
		$this->_exit( $response );
281
	}
282
283
	/**
284
	 * Given a View id, calculates the assigned form, and returns the form fields (only the sortable ones )
285
	 * AJAX callback
286
	 *
287
	 *
288
	 * @access public
289
	 * @return void
290
	 */
291
	function get_sortable_fields() {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
292
		$this->check_ajax_nonce();
293
294
		$form = '';
295
296
		// if form id is set, use it, else, get form from preset
297
		if( !empty( $_POST['form_id'] ) ) {
298
299
			$form = (int) $_POST['form_id'];
300
301
		}
302
		// get form from preset
303
		elseif( !empty( $_POST['template_id'] ) ) {
304
305
			$form = GravityView_Ajax::pre_get_form_fields( $_POST['template_id'] );
306
307
		}
308
309
		$response = gravityview_get_sortable_fields( $form );
310
311
		$response = gravityview_strip_whitespace( $response );
312
313
		$this->_exit( $response );
314
	}
315
316
	/**
317
	 * Get the the form fields for a preset (no form created yet)
318
	 * @param  string $template_id Preset template
319
	 *
320
	 */
321 1
	static function pre_get_form_fields( $template_id = '') {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
322
323 1
		if( empty( $template_id ) ) {
324
			gravityview()->log->error( 'Template ID not set.' );
325
			return false;
326
		} else {
327 1
			$form_file = apply_filters( 'gravityview_template_formxml', '', $template_id );
328 1
			if( !file_exists( $form_file )  ) {
329
				gravityview()->log->error( 'Importing Form Fields for preset [{template_id}]. File not found. file: {path}', array( 'template_id' => $template_id, 'path' => $form_file ) );
330
				return false;
331
			}
332
		}
333
334
		// Load xml parser (from GravityForms)
335 1
		if( class_exists( 'GFCommon' ) ) {
336 1
			$xml_parser = GFCommon::get_base_path() . '/xml.php';
337
		} else {
338
			$xml_parser = trailingslashit( WP_PLUGIN_DIR ) . 'gravityforms/xml.php';
339
		}
340
341 1
		if( file_exists( $xml_parser ) ) {
342 1
			require_once( $xml_parser );
343
		} else {
344
			gravityview()->log->debug( ' - Gravity Forms XML Parser not found {path}.', array( 'path' => $xml_parser ) );
345
			return false;
346
		}
347
348
		// load file
349 1
		$xmlstr = file_get_contents( $form_file );
350
351
        $options = array(
352 1
            "page" => array("unserialize_as_array" => true),
353
            "form"=> array("unserialize_as_array" => true),
354
            "field"=> array("unserialize_as_array" => true),
355
            "rule"=> array("unserialize_as_array" => true),
356
            "choice"=> array("unserialize_as_array" => true),
357
            "input"=> array("unserialize_as_array" => true),
358
            "routing_item"=> array("unserialize_as_array" => true),
359
            "creditCard"=> array("unserialize_as_array" => true),
360
            "routin"=> array("unserialize_as_array" => true),
361
            "confirmation" => array("unserialize_as_array" => true),
362
            "notification" => array("unserialize_as_array" => true)
363
        );
364
365 1
		$xml = new RGXML($options);
366 1
        $forms = $xml->unserialize($xmlstr);
367
368 1
        if( !$forms ) {
369
        	gravityview()->log->error( 'Importing Form Fields for preset [{template_id}]. Error importing file. (File) {path}', array( 'template_id' => $template_id, 'path' => $form_file ) );
370
        	return false;
371
        }
372
373 1
        if( !empty( $forms[0] ) && is_array( $forms[0] ) ) {
374 1
        	$form = $forms[0];
375
        }
376
377 1
        if( empty( $form ) ) {
378
        	gravityview()->log->error( '$form not set.', array( 'data' => $forms ) );
379
        	return false;
380
        }
381
382 1
        gravityview()->log->debug( '[pre_get_available_fields] Importing Form Fields for preset [{template_id}]. (Form)', array( 'template_id' => $template_id, 'data' => $form ) );
383
384 1
        return $form;
385
386
	}
387
388
389
	/**
390
	 * Import fields configuration from an exported WordPress View preset
391
	 * @param  string $file path to file
392
	 * @return array       Fields config array (unserialized)
393
	 */
394
	function import_fields( $file ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
395
396
		if( empty( $file ) || !file_exists(  $file ) ) {
397
			gravityview()->log->error( 'Importing Preset Fields. File not found. (File) {path}', array( 'path' => $file ) );
398
			return false;
399
		}
400
401
		if( !class_exists('WXR_Parser') ) {
402
			include_once GRAVITYVIEW_DIR . 'includes/lib/xml-parsers/parsers.php';
403
		}
404
405
		$parser = new WXR_Parser();
406
		$presets = $parser->parse( $file );
407
408
		if(is_wp_error( $presets )) {
409
			gravityview()->log->error( 'Importing Preset Fields failed. Threw WP_Error.', array( 'data' => $presets ) );
410
			return false;
411
		}
412
413
		if( empty( $presets['posts'][0]['postmeta'] ) && !is_array( $presets['posts'][0]['postmeta'] ) ) {
414
			gravityview()->log->error( 'Importing Preset Fields failed. Meta not found in file. {path}', array( 'path' => $file ) );
415
			return false;
416
		}
417
418
		gravityview()->log->debug( '[import_fields] postmeta', array( 'data' => $presets['posts'][0]['postmeta'] ) );
419
420
		$fields = $widgets = array();
421
		foreach( $presets['posts'][0]['postmeta'] as $meta ) {
422
			switch ($meta['key']) {
423
				case '_gravityview_directory_fields':
424
					$fields = maybe_unserialize( $meta['value'] );
425
					break;
426
				case '_gravityview_directory_widgets':
427
					$widgets = maybe_unserialize( $meta['value'] );
428
					break;
429
			}
430
		}
431
432
		gravityview()->log->debug( '[import_fields] Imported Preset (Fields)', array( 'data' => $fields ) );
433
		gravityview()->log->debug( '[import_fields] Imported Preset (Widgets)', array( 'data' => $widgets ) );
434
435
		return array(
436
			'fields' => $fields,
437
			'widgets' => $widgets
438
		);
439
	}
440
}
441
442
new GravityView_Ajax;
443