Completed
Pull Request — master (#187)
by
unknown
02:17
created

Rich_Text_Field::admin_init()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
namespace Carbon_Fields\Field;
4
5
use Carbon_Fields\Datastore\Datastore_Interface;
6
use Carbon_Fields\Helper\Helper;
7
use Carbon_Fields\Field\Field;
8
use Carbon_Fields\Field\Group_Field;
9
use Carbon_Fields\Exception\Incorrect_Syntax_Exception;
10
11
/**
12
 * Complex field class.
13
 * Allows nested repeaters with multiple field groups to be created.
14
 */
15
class Complex_Field extends Field {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The type Carbon_Fields\Field\Complex_Field has been defined more than once; this definition is ignored, only the first definition in core/Field/Complex_Field.php (L15-670) is considered.

This check looks for classes that have been defined more than once.

If you can, we would recommend to use standard object-oriented programming techniques. For example, to avoid multiple types, it might make sense to create a common interface, and then multiple, different implementations for that interface.

This also has the side-effect of providing you with better IDE auto-completion, static analysis and also better OPCode caching from PHP.

Loading history...
16
	const LAYOUT_GRID = 'grid'; // default
17
	const LAYOUT_LIST = 'list'; // deprecated
18
	const LAYOUT_TABBED = 'tabbed'; // deprecated
19
	const LAYOUT_TABBED_HORIZONTAL = 'tabbed-horizontal';
20
	const LAYOUT_TABBED_VERTICAL = 'tabbed-vertical';
21
22
	protected $fields = array();
23
	protected $values = array();
24
	protected $groups = array();
25
26
	protected $layout = self::LAYOUT_GRID;
27
	protected $values_min = -1;
28
	protected $values_max = -1;
29
	protected $collapsed = false;
30
31
	public $labels = array(
32
		'singular_name' => 'Entry',
33
		'plural_name' => 'Entries',
34
	);
35
36
	/**
37
	 * Initialization tasks.
38
	 */
39 View Code Duplication
	public function init() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
40
		$this->labels = array(
41
			'singular_name' => __( 'Entry', 'carbon-fields' ),
42
			'plural_name' => __( 'Entries', 'carbon-fields' ),
43
		);
44
45
		// Include the complex group Underscore templates
46
		$this->add_template( 'Complex-Group', array( $this, 'template_group' ) );
47
		$this->add_template( 'Complex-Group-Tab-Item', array( $this, 'template_group_tab_item' ) );
48
49
		parent::init();
50
	}
51
52
	/**
53
	 * Add a set/group of fields.
54
	 *
55
	 * @return $this
56
	 */
57 View Code Duplication
	public function add_fields() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
58
		$argv = func_get_args();
59
		$argc = count( $argv );
60
61
		if ( $argc == 1 ) {
62
			$fields = $argv[0];
63
			$name = '';
64
			$label = null;
65
		} else if ( $argc == 2 ) {
66
			if ( is_array( $argv[0] ) ) {
67
				list( $fields, $name ) = $argv;
68
			} else {
69
				list( $name, $fields ) = $argv;
70
			}
71
			$label = null;
72
		} else if ( $argc == 3 ) {
73
			if ( is_array( $argv[0] ) ) {
74
				list( $fields, $name, $label ) = $argv;
75
			} else {
76
				list( $name, $label, $fields ) = $argv;
77
			}
78
		}
79
80
		if ( array_key_exists( '_' . $name, $this->groups ) ) {
81
			Incorrect_Syntax_Exception::raise( 'Group with name "' . $name . '" in Complex Field "' . $this->get_label() . '" already exists.' );
0 ignored issues
show
Bug introduced by
The variable $name does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
82
		}
83
84
		$group = new Group_Field($name, $label, $fields);
0 ignored issues
show
Bug introduced by
The variable $label does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $fields does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
85
86
		$this->groups[ $group->get_name() ] = $group;
87
88
		return $this;
89
	}
90
91
	/**
92
	 * Set the group label Underscore template.
93
	 *
94
	 * @param  string|callable $template
95
	 * @return $this
96
	 */
97 View Code Duplication
	public function set_header_template( $template ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
98
		if ( count($this->groups) === 0 ) {
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
99
			Incorrect_Syntax_Exception::raise( "Can't set group label template. There are no present groups for Complex Field " . $this->get_label() . "." );
0 ignored issues
show
Coding Style Comprehensibility introduced by
The string literal . does not require double quotes, as per coding-style, please use single quotes.

PHP provides two ways to mark string literals. Either with single quotes 'literal' or with double quotes "literal". The difference between these is that string literals in double quotes may contain variables with are evaluated at run-time as well as escape sequences.

String literals in single quotes on the other hand are evaluated very literally and the only two characters that needs escaping in the literal are the single quote itself (\') and the backslash (\\). Every other character is displayed as is.

Double quoted string literals may contain other variables or more complex escape sequences.

<?php

$singleQuoted = 'Value';
$doubleQuoted = "\tSingle is $singleQuoted";

print $doubleQuoted;

will print an indented: Single is Value

If your string literal does not contain variables or escape sequences, it should be defined using single quotes to make that fact clear.

For more information on PHP string literals and available escape sequences see the PHP core documentation.

Loading history...
100
		}
101
102
		$template = is_callable( $template ) ? call_user_func( $template ) : $template;
103
104
		// Assign the template to the group that was added last
105
		$values = array_values( $this->groups );
106
		$group = end( $values );
107
		$group->set_label_template( $template );
108
109
		// Include the group label Underscore template
110
		$this->add_template( $group->get_group_id(), array( $group, 'template_label' ) );
111
112
		$this->groups[ $group->get_name() ] = $group;
113
114
		return $this;
115
	}
116
117
	/**
118
	 * Retrieve all groups of fields.
119
	 *
120
	 * @return array $fields
121
	 */
122 View Code Duplication
	public function get_fields() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
123
		$fields = array();
124
125
		foreach ( $this->groups as $group ) {
126
			$group_fields = $group->get_fields();
127
128
			$fields = array_merge( $fields, $group_fields );
129
		}
130
131
		return $fields;
132
	}
133
134
	/**
135
	 * Set the field labels.
136
	 * Currently supported values:
137
	 *  - singular_name - the singular entry label
138
	 *  - plural_name - the plural entries label
139
	 *
140
	 * @param  array $labels Labels
141
	 */
142
	public function setup_labels( $labels ) {
143
		$this->labels = array_merge( $this->labels, $labels );
144
		return $this;
145
	}
146
147
	/**
148
	 * Set the datastore of this field.
149
	 *
150
	 * @param Datastore_Interface $store
151
	 */
152
	public function set_datastore( Datastore_Interface $store ) {
153
		$this->store = $store;
154
155
		foreach ( $this->groups as $group ) {
156
			$group->set_datastore( $this->store );
157
		}
158
	}
159
160
	/**
161
	 * Load the field value from an input array based on it's name.
162
	 *
163
	 * @param array $input (optional) Array of field names and values. Defaults to $_POST
164
	 **/
165
	public function set_value_from_input( $input = null ) {
166
		$this->values = array();
167
168
		if ( is_null( $input ) ) {
169
			$input = $_POST;
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
170
		}
171
172
		if ( ! isset( $input[ $this->get_name() ] ) ) {
173
			return;
174
		}
175
176
		$input_groups = $input[ $this->get_name() ];
177
		$index = 0;
178
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
179
180
		foreach ( $input_groups as $values ) {
181
			$value_group = array();
182 View Code Duplication
			if ( ! isset( $values['group'] ) || ! isset( $this->groups[ $values['group'] ] ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
183
				continue;
184
			}
185
186
			$group = $this->groups[ $values['group'] ];
187
			unset( $values['group'] );
188
189
			$group_fields = $group->get_fields();
190
191
			// trim input values to those used by the field
192
			$group_field_names = array_flip( $group->get_field_names() );
193
			$values = array_intersect_key( $values, $group_field_names );
194
195
			foreach ( $group_fields as $field ) {
196
				// set value from the group
197
				$tmp_field = clone $field;
198
				if ( is_a( $tmp_field, __NAMESPACE__ . '\\Complex_Field' ) ) {
199
200
					if ( ! isset( $values[ $tmp_field->get_name() ] ) ) {
201
						continue; // bail if the complex field is empty
202
					}
203
204
					$new_name = $this->get_name() . $group->get_name() . '-' . $field->get_name() . '_' . $index;
205
					$new_values = array( $new_name => $values[ $tmp_field->get_name() ] );
206
207
					$tmp_field->set_name( $new_name );
208
					$tmp_field->set_value_from_input( $new_values );
209
				} else {
210
          if ( ! isset( $values[ $tmp_field->get_name() ] ) ) {
211
						continue; // bail if the field is empty
212
					}
213
214
          if ( $tmp_field->type === 'Rich_Text' && empty( $values[ $tmp_field->get_name() ] ) ) {
215
            continue; // bail if the field is empty
216
          }
217
218
					$tmp_field->set_value_from_input( $values );
219
				}
220
221
				// update name to group name
222
				$tmp_field->set_name( $this->get_name() . $group->get_name() . '-' . $field->get_name() . '_' . $index );
223
				$value_group[] = $tmp_field;
224
			}
225
226
			$this->values[] = $value_group;
227
			$index++;
228
		}
229
	}
230
231
	/**
232
	 * Load all groups of fields and their data.
233
	 */
234
	public function load() {
235
		// load existing groups
236
		$this->load_values();
237
	}
238
239
	/**
240
	 * Save all contained groups of fields.
241
	 */
242
	public function save() {
243
		$this->delete();
244
245
		foreach ( $this->values as $value ) {
246
			foreach ( $value as $field ) {
247
				$field->save();
248
			}
249
		}
250
	}
251
252
	/**
253
	 * Delete the values of all contained fields.
254
	 */
255
	public function delete() {
256
		return $this->store->delete_values( $this );
257
	}
258
259
	/**
260
	 * Load and parse the field data.
261
	 */
262
	public function load_values() {
263
		return $this->load_values_from_db();
264
	}
265
266
	/**
267
	 * Load and parse the field data from the database.
268
	 */
269
	public function load_values_from_db() {
270
		$this->values = array();
271
272
		$group_rows = $this->store->load_values( $this );
273
274
		return $this->process_loaded_values( $group_rows );
275
	}
276
277
	/**
278
	 * Load and parse a raw set of field data.
279
	 *
280
	 * @param  array $values Raw data entries
281
	 * @return array 		 Processed data entries
282
	 */
283 View Code Duplication
	public function load_values_from_array( $values ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
284
		$this->values = array();
285
286
		$group_rows = array();
287
288
		$meta_key = $this->get_name();
289
290
		foreach ( $values as $key => $value ) {
291
			if ( strpos( $key, $meta_key ) !== 0 ) {
292
				continue;
293
			}
294
295
			$group_rows[] = array(
296
				'field_key' => preg_replace( '~^(' . preg_quote( $this->name, '~' ) . ')_\d+_~', '$1_', $key ),
297
				'field_value' => $value,
298
			);
299
		}
300
301
		return $this->process_loaded_values( $group_rows );
302
	}
303
304
	/**
305
	 * Parse groups of raw field data into the actual field hierarchy.
306
	 *
307
	 * @param  array $group_rows Group rows
308
	 */
309 View Code Duplication
	public function process_loaded_values( $group_rows ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
310
		$input_groups = array();
311
312
		// Set default values
313
		$field_names = array();
314
		foreach ( $this->groups as $group ) {
315
			$group_fields = $group->get_fields();
316
			foreach ( $group_fields as $field ) {
317
				$field_names[] = $field->get_name();
318
				$field->set_value( $field->get_default_value() );
319
			}
320
		}
321
322
		if ( empty( $group_rows ) ) {
323
			return;
324
		}
325
326
		// load and parse values and group type
327
		foreach ( $group_rows as $row ) {
328
			if ( ! preg_match( Helper::get_complex_field_regex( $this->name, array_keys( $this->groups ), $field_names ), $row['field_key'], $field_name ) ) {
329
				continue;
330
			}
331
332
			$row['field_value'] = maybe_unserialize( $row['field_value'] );
333
			$input_groups[ $field_name['index'] ]['type'] = $field_name['group'];
334
335
			if ( ! empty( $field_name['trailing'] ) ) {
336
				$input_groups[ $field_name['index'] ][ $field_name['key'] . '_' . $field_name['sub'] . '-' . $field_name['trailing'] ] = $row['field_value'];
337
			} else if ( ! empty( $field_name['sub'] ) ) {
338
				$input_groups[ $field_name['index'] ][ $field_name['key'] ][ $field_name['sub'] ] = $row['field_value'];
339
			} else {
340
				$input_groups[ $field_name['index'] ][ $field_name['key'] ] = $row['field_value'];
341
			}
342
		}
343
344
		// create groups list with loaded fields
345
		ksort( $input_groups );
346
347
		foreach ( $input_groups as $index => $values ) {
348
			$value_group = array( 'type' => $values['type'] );
349
			$group_fields = $this->groups[ $values['type'] ]->get_fields();
350
			unset( $values['type'] );
351
352
			foreach ( $group_fields as $field ) {
353
				// set value from the group
354
				$tmp_field = clone $field;
355
356
				if ( is_a( $field, __NAMESPACE__ . '\\Complex_Field' ) ) {
357
					$tmp_field->load_values_from_array( $values );
358
				} else {
359
					$tmp_field->set_value_from_input( $values );
360
				}
361
362
				$value_group[] = $tmp_field;
363
			}
364
365
			$this->values[] = $value_group;
366
		}
367
	}
368
369
	/**
370
	 * Retrieve the field values.
371
	 * @return array
372
	 */
373
	public function get_values() {
374
		return $this->values;
375
	}
376
377
	/**
378
	 * Generate and set the field prefix.
379
	 * @param string $prefix
380
	 */
381
	public function set_prefix( $prefix ) {
382
		parent::set_prefix( $prefix );
383
384
		foreach ( $this->groups as $group ) {
385
			$group->set_prefix( $prefix );
386
		}
387
	}
388
389
	/**
390
	 * Returns an array that holds the field data, suitable for JSON representation.
391
	 * This data will be available in the Underscore template and the Backbone Model.
392
	 *
393
	 * @param bool $load  Should the value be loaded from the database or use the value from the current instance.
394
	 * @return array
395
	 */
396 View Code Duplication
	public function to_json( $load ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
397
		$complex_data = parent::to_json( $load );
398
399
		$groups_data = array();
400
		$values_data = array();
401
402
		foreach ( $this->groups as $group ) {
403
			$groups_data[] = $group->to_json( false );
404
		}
405
406
		foreach ( $this->values as $fields ) {
407
			$group = $this->get_group_by_name( $fields['type'] );
408
			unset( $fields['type'] );
409
410
			$data = array(
411
				'name' => $group->get_name(),
412
				'label' => $group->get_label(),
413
				'group_id' => $group->get_group_id(),
414
				'fields' => array(),
415
			);
416
417
			foreach ( $fields as $index => $field ) {
418
				$data['fields'][] = $field->to_json( false );
419
			}
420
421
			$values_data[] = $data;
422
		}
423
424
		$complex_data = array_merge( $complex_data, array(
425
			'layout' => $this->layout,
426
			'labels' => $this->labels,
427
			'min' => $this->get_min(),
428
			'max' => $this->get_max(),
429
			'multiple_groups' => count( $groups_data ) > 1,
430
			'groups' => $groups_data,
431
			'value' => $values_data,
432
			'collapsed' => $this->collapsed,
433
		) );
434
435
		return $complex_data;
436
	}
437
438
	/**
439
	 * The main Underscore template.
440
	 */
441
	public function template() {
442
		?>
443
		<div class="carbon-subcontainer carbon-grid {{ multiple_groups ? 'multiple-groups' : '' }}">
444
			<div class="carbon-empty-row carbon-empty-row-visible">
445
				{{{ crbl10n.complex_no_rows.replace('%s', labels.plural_name) }}}
446
			</div>
447
448
			<div class="groups-wrapper layout-{{ layout }}">
449
				<# if (layout === '<?php echo self::LAYOUT_TABBED_HORIZONTAL ?>' || layout === '<?php echo self::LAYOUT_TABBED_VERTICAL ?>' ) { #>
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not 'self'
Loading history...
450
					<div class="group-tabs-nav-holder">
451
						<ul class="group-tabs-nav"></ul>
452
453
						<div class="carbon-actions">
454
							<div class="carbon-button">
455
								<a href="#" class="button" data-group="{{{ multiple_groups ? '' : groups[0].name }}}">
456
									+
457
								</a>
458
459
								<# if (multiple_groups) { #>
460
									<ul>
461
										<# _.each(groups, function(group) { #>
462
											<li><a href="#" data-group="{{{ group.name }}}">{{{ group.label }}}</a></li>
463
										<# }); #>
464
									</ul>
465
								<# } #>
466
							</div>
467
						</div>
468
					</div><!-- /.group-tabs-nav-holder -->
469
				<# } #>
470
471
				<div class="carbon-groups-holder"></div>
472
				<div class="clear"></div>
473
			</div>
474
475
			<div class="carbon-actions">
476
				<div class="carbon-button">
477
					<a href="#" class="button" data-group="{{{ multiple_groups ? '' : groups[0].name }}}">
478
						{{{ crbl10n.complex_add_button.replace('%s', labels.singular_name) }}}
479
					</a>
480
481
					<# if (multiple_groups) { #>
482
						<ul>
483
							<# _.each(groups, function(group) { #>
484
								<li><a href="#" data-group="{{{ group.name }}}">{{{ group.label }}}</a></li>
485
							<# }); #>
486
						</ul>
487
					<# } #>
488
				</div>
489
			</div>
490
		</div>
491
		<?php
492
	}
493
494
	/**
495
	 * The Underscore template for the complex field group.
496
	 */
497 View Code Duplication
	public function template_group() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
498
		?>
499
		<div id="carbon-{{{ complex_name }}}-complex-container" class="carbon-row carbon-group-row" data-group-id="{{ id }}">
500
			<input type="hidden" name="{{{ complex_name + '[' + index + ']' }}}[group]" value="{{ name }}" />
501
502
			<div class="carbon-drag-handle">
503
				<span class="group-number">{{{ order + 1 }}}</span><span class="group-name">{{{ label_template || label }}}</span>
504
			</div>
505
506
			<div class="carbon-group-actions carbon-group-actions-{{ layout }}">
507
				<a class="carbon-btn-duplicate dashicons-before dashicons-admin-page" href="#" title="<?php esc_attr_e( 'Clone', 'carbon_fields' ); ?>">
508
					<?php _e( 'Clone', 'carbon_fields' ); ?>
509
				</a>
510
511
				<a class="carbon-btn-remove dashicons-before dashicons-trash" href="#" title="<?php esc_attr_e( 'Remove', 'carbon_fields' ); ?>">
512
					<?php _e( 'Remove', 'carbon_fields' ); ?>
513
				</a>
514
515
				<a class="carbon-btn-collapse dashicons-before dashicons-arrow-up" href="#" title="<?php esc_attr_e( 'Collapse/Expand', 'carbon_fields' ); ?>">
516
					<?php _e( 'Collapse/Expand', 'carbon_fields' ); ?>
517
				</a>
518
			</div>
519
520
			<div class="fields-container">
521
				<# _.each(fields, function(field) { #>
522
					<div class="carbon-row carbon-subrow subrow-{{{ field.type }}} {{{ field.classes.join(' ') }}}">
523
						<label for="{{{ complex_id + '-' + field.id + '-' + index }}}">
524
							{{ field.label }}
525
526
							<# if (field.required) { #>
527
								 <span class="carbon-required">*</span>
528
							<# } #>
529
						</label>
530
531
						<div class="field-holder {{{ complex_id + '-' + field.id + '-' + index }}}"></div>
532
533
						<# if (field.help_text) { #>
534
							<em class="help-text">
535
								{{{ field.help_text }}}
536
							</em>
537
						<# } #>
538
539
						<em class="carbon-error"></em>
540
					</div>
541
				<# }) #>
542
			</div>
543
		</div>
544
		<?php
545
	}
546
547
	 /**
548
	 * The Underscore template for the group item tab.
549
	 */
550
	public function template_group_tab_item() {
551
		?>
552
		<li class="group-tab-item" data-group-id="{{ id }}">
553
			<a href="#">
554
				<span class="group-handle"></span>
555
556
				<# if (label_template || label) { #>
557
					<span class="group-name">{{{ label_template || label }}}</span>
558
				<# } #>
559
				<span class="group-number">{{{ order + 1 }}}</span>
560
				<span class="dashicons dashicons-warning carbon-complex-group-error-badge" ></span>
561
			</a>
562
		</li>
563
		<?php
564
	}
565
566
	/**
567
	 * Modify the layout of this field.
568
	 *
569
	 * @param string $layout
570
	 */
571 View Code Duplication
	public function set_layout( $layout ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
572
		$available_layouts = array(
573
			self::LAYOUT_GRID,
574
			self::LAYOUT_TABBED_HORIZONTAL,
575
			self::LAYOUT_TABBED_VERTICAL,
576
			self::LAYOUT_LIST,
577
		);
578
579
		if ( $layout === self::LAYOUT_TABBED ) {
580
			// The library used to provide just one kind of tabs -- horizontal ones. Later vertical tabs were added.
581
			// So the "tabbed" name was renamed to "tabbed-horizontal" and "tabbed-vertical" layout was introduced.
582
			_doing_it_wrong( __METHOD__, sprintf( __( 'Complex field "%1$s" layout is deprecated, please use "%2$s" or "%3$s" instead.', 'carbon_fields' ), self::LAYOUT_TABBED, self::LAYOUT_TABBED_HORIZONTAL, self::LAYOUT_TABBED_VERTICAL ), null );
583
584
			$layout = self::LAYOUT_TABBED_HORIZONTAL;
585
		}
586
587
		if ( ! in_array( $layout,  $available_layouts ) ) {
588
			$error_message = 'Incorrect layout ``' . $layout . '" specified. ' .
589
				'Available layouts: ' . implode( ', ', $available_layouts );
590
591
			Incorrect_Syntax_Exception::raise( $error_message );
592
		}
593
594
		if ( $layout === self::LAYOUT_LIST ) {
595
			_doing_it_wrong( __METHOD__, __( 'Complex field <code>' . self::LAYOUT_LIST . '</code> layout is deprecated, please use <code>set_width()</code> instead.', 'carbon_fields' ), null );
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not 'self'
Loading history...
596
		}
597
598
		$this->layout = $layout;
599
600
		return $this;
601
	}
602
603
	/**
604
	 * Set the minimum number of entries.
605
	 *
606
	 * @param int $min
607
	 */
608
	public function set_min( $min ) {
609
		$this->values_min = intval( $min );
610
		return $this;
611
	}
612
613
	/**
614
	 * Get the minimum number of entries.
615
	 *
616
	 * @return int $min
617
	 */
618
	public function get_min() {
619
		return $this->values_min;
620
	}
621
622
	/**
623
	 * Set the maximum number of entries.
624
	 *
625
	 * @param int $max
626
	 */
627
	public function set_max( $max ) {
628
		$this->values_max = intval( $max );
629
		return $this;
630
	}
631
632
	/**
633
	 * Get the maximum number of entries.
634
	 *
635
	 * @return int $max
636
	 */
637
	public function get_max() {
638
		return $this->values_max;
639
	}
640
641
	/**
642
	 * Change the groups initial collapse state.
643
	 * This state relates to the state of which the groups are rendered.
644
	 *
645
	 * @param bool $collapsed
646
	 */
647
	public function set_collapsed( $collapsed = true ) {
648
		$this->collapsed = $collapsed;
649
650
		return $this;
651
	}
652
653
	/**
654
	 * Retrieve the groups of this field.
655
	 *
656
	 * @return array
657
	 */
658
	public function get_group_names() {
659
		return array_keys( $this->groups );
660
	}
661
662
	/**
663
	 * Retrieve a group by its name.
664
	 *
665
	 * @param  string $group_name        Group name
666
	 * @return Group_Field $group_object Group object
667
	 */
668 View Code Duplication
	public function get_group_by_name( $group_name ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
669
		$group_object = null;
670
671
		foreach ( $this->groups as $group ) {
672
			if ( $group->get_name() == $group_name ) {
673
				$group_object = $group;
674
			}
675
		}
676
677
		return $group_object;
678
	}
679
}
680