PluginProbe
Scrollsequence – Cinematic Scroll Image Animation Plugin / 1.5.5
Scrollsequence – Cinematic Scroll Image Animation Plugin v1.5.5
1.4.3 1.4.4 1.4.5 1.4.6 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 trunk 0.9.92 0.9.93 0.9.94 0.9.96 1.0.072 1.0.073 All 61 releases
scrollsequence / includes / carbonfields / htmlburger / carbon-fields / core / Container / Container.php

Container.php in Scrollsequence – Cinematic Scroll Image Animation Plugin 1.5.5, at includes/carbonfields/htmlburger/carbon-fields/core/Container/Container.php

919 lines 22.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Carbon_Fields\Container;
4
5 use Carbon_Fields\Carbon_Fields;
6 use Carbon_Fields\Helper\Helper;
7 use Carbon_Fields\Field\Field;
8 use Carbon_Fields\Field\Group_Field;
9 use Carbon_Fields\Container\Fulfillable\Fulfillable_Collection;
10 use Carbon_Fields\Datastore\Datastore_Interface;
11 use Carbon_Fields\Datastore\Datastore_Holder_Interface;
12 use Carbon_Fields\Exception\Incorrect_Syntax_Exception;
13
14 /**
15 * Base container class.
16 * Defines the key container methods and their default implementations.
17 */
18 abstract class Container implements Datastore_Holder_Interface {
19 /**
20 * Where to put a particular tab -- at the head or the tail. Tail by default
21 */
22 const TABS_TAIL = 1;
23 const TABS_HEAD = 2;
24
25 /**
26 * Separator signifying field hierarchy relation
27 * Used when searching for fields in a specific complex field
28 */
29 const HIERARCHY_FIELD_SEPARATOR = '/';
30
31 /**
32 * Separator signifying complex_field->group relation
33 * Used when searching for fields in a specific complex field group
34 */
35 const HIERARCHY_GROUP_SEPARATOR = ':';
36
37 /**
38 * Visual layout type constants
39 */
40 const LAYOUT_TABBED_HORIZONTAL = 'tabbed-horizontal';
41 const LAYOUT_TABBED_VERTICAL = 'tabbed-vertical';
42
43
44 /**
45 * Stores if the container is active on the current page
46 *
47 * @see activate()
48 * @var bool
49 */
50 protected $active = false;
51
52 /**
53 * List of registered unique field names for this container instance
54 *
55 * @see register_field_name()
56 * @var array
57 */
58 protected $registered_field_names = array();
59
60 /**
61 * Complex field layout
62 *
63 * @var string static::LAYOUT_* constant
64 */
65 protected $layout = self::LAYOUT_TABBED_HORIZONTAL;
66
67 /**
68 * Tabs available
69 */
70 protected $tabs = array();
71
72 /**
73 * List of default container settings
74 *
75 * @see init()
76 * @var array
77 */
78 public $settings = array();
79
80 /**
81 * Unique ID of the container
82 *
83 * @var string
84 */
85 public $id;
86
87 /**
88 * Title of the container
89 *
90 * @var string
91 */
92 public $title = '';
93
94 /**
95 * Type of the container
96 *
97 * @var string
98 */
99 public $type;
100
101 /**
102 * List of notification messages to be displayed on the front-end
103 *
104 * @var array
105 */
106 protected $notifications = array();
107
108 /**
109 * List of error messages to be displayed on the front-end
110 *
111 * @var array
112 */
113 protected $errors = array();
114
115 /**
116 * List of container fields
117 *
118 * @see add_fields()
119 * @var array
120 */
121 protected $fields = array();
122
123 /**
124 * Array of custom CSS classes.
125 *
126 * @see set_classes()
127 * @see get_classes()
128 * @var array<string>
129 */
130 protected $classes = array();
131
132 /**
133 * Container datastores. Propagated to all container fields
134 *
135 * @see set_datastore()
136 * @see get_datastore()
137 * @var Datastore_Interface
138 */
139 protected $datastore;
140
141 /**
142 * Flag whether the datastore is the default one or replaced with a custom one
143 *
144 * @see set_datastore()
145 * @see get_datastore()
146 * @var boolean
147 */
148 protected $has_default_datastore = true;
149
150 /**
151 * Fulfillable_Collection to use when checking attachment/saving conditions
152 *
153 * @var Fulfillable_Collection
154 */
155 protected $condition_collection;
156
157 /**
158 * Translator to use when translating conditions to json
159 *
160 * @var \Carbon_Fields\Container\Fulfillable\Translator\Translator
161 */
162 protected $condition_translator;
163
164 /**
165 * Create a new container of type $type and name $name.
166 *
167 * @param string $raw_type
168 * @param string $id Unique id for the container. Optional
169 * @param string $name Human-readable name of the container
170 * @return Container $container
171 */
172 public static function factory( $raw_type, $id, $name = '' ) {
173 // no name provided - switch input around as the id is optionally generated based on the name
174 if ( $name === '' ) {
175 $name = $id;
176 $id = '';
177 }
178
179 $type = Helper::normalize_type( $raw_type );
180 $repository = Carbon_Fields::resolve( 'container_repository' );
181 $id = $repository->get_unique_container_id( ( $id !== '' ) ? $id : $name );
182
183 if ( ! Helper::is_valid_entity_id( $id ) ) {
184 Incorrect_Syntax_Exception::raise( 'Container IDs can only contain lowercase alphanumeric characters, dashes and underscores ("' . $id . '" passed).' );
185 return null;
186 }
187
188 if ( ! $repository->is_unique_container_id( $id ) ) {
189 Incorrect_Syntax_Exception::raise( 'The passed container id is already taken ("' . $id . '" passed).' );
190 return null;
191 }
192
193 $container = null;
194 if ( Carbon_Fields::has( $type, 'containers' ) ) {
195 $container = Carbon_Fields::resolve_with_arguments( $type, array(
196 'id' => $id,
197 'name' => $name,
198 'type' => $type,
199 ), 'containers' );
200 } else {
201 // Fallback to class name-based resolution
202 $class = Helper::type_to_class( $type, __NAMESPACE__, '_Container' );
203
204 if ( ! class_exists( $class ) ) {
205 Incorrect_Syntax_Exception::raise( 'Unknown container "' . $raw_type . '".' );
206 $class = __NAMESPACE__ . '\\Broken_Container';
207 }
208
209 $fulfillable_collection = Carbon_Fields::resolve( 'container_condition_fulfillable_collection' );
210 $condition_translator = Carbon_Fields::resolve( 'container_condition_translator_json' );
211 $container = new $class( $id, $name, $type, $fulfillable_collection, $condition_translator );
212 }
213
214 $repository->register_container( $container );
215
216 return $container;
217 }
218
219 /**
220 * An alias of factory().
221 *
222 * @see Container::factory()
223 * @return Container
224 */
225 public static function make() {
226 return call_user_func_array( array( get_class(), 'factory' ), func_get_args() );
227 }
228
229 /**
230 * Create a new container
231 *
232 * @param string $id Unique id of the container
233 * @param string $title Title of the container
234 * @param string $type Type of the container
235 * @param Fulfillable_Collection $condition_collection
236 * @param \Carbon_Fields\Container\Fulfillable\Translator\Translator $condition_translator
237 */
238 public function __construct( $id, $title, $type, $condition_collection, $condition_translator ) {
239 Carbon_Fields::verify_boot();
240
241 if ( empty( $title ) ) {
242 Incorrect_Syntax_Exception::raise( 'Empty container title is not supported' );
243 }
244
245 $this->id = $id;
246 $this->title = $title;
247 $this->type = $type;
248 $this->condition_collection = $condition_collection;
249 $this->condition_collection->set_condition_type_list(
250 array_merge( $this->get_condition_types( true ), $this->get_condition_types( false ) ),
251 true
252 );
253 $this->condition_translator = $condition_translator;
254 }
255
256 /**
257 * Return the container id
258 *
259 * @return string
260 */
261 public function get_id() {
262 return $this->id;
263 }
264
265 /**
266 * Get array of all static condition types
267 *
268 * @param boolean $static
269 * @return array<string>
270 */
271 protected function get_condition_types( $static ) {
272 $group = $static ? 'static' : 'dynamic';
273 $container_type = Helper::class_to_type( get_class( $this ), '_Container' );
274
275 $condition_types = array();
276 $condition_types = apply_filters( 'carbon_fields_' . $container_type . '_container_' . $group . '_condition_types', $condition_types, $container_type, $this );
277 $condition_types = apply_filters( 'carbon_fields_container_' . $group . '_condition_types', $condition_types, $container_type, $this );
278
279 return $condition_types;
280 }
281
282 /**
283 * Return whether the container is active
284 */
285 public function is_active() {
286 return $this->active;
287 }
288
289 /**
290 * Activate the container and trigger an action
291 */
292 protected function activate() {
293 $this->active = true;
294 $this->boot();
295 do_action( 'carbon_fields_container_activated', $this );
296
297 $fields = $this->get_fields();
298 foreach ( $fields as $field ) {
299 $field->activate();
300 }
301 }
302
303 /**
304 * Perform instance initialization
305 */
306 abstract public function init();
307
308 /**
309 * Boot the container once it's attached.
310 */
311 protected function boot() {
312
313 }
314
315 /**
316 * Load the value for each field in the container.
317 * Could be used internally during container rendering
318 */
319 public function load() {
320 foreach ( $this->fields as $field ) {
321 $field->load();
322 }
323 }
324
325 /**
326 * Called first as part of the container save procedure.
327 * Responsible for checking the request validity and
328 * calling the container-specific save() method
329 *
330 * @see save()
331 * @see is_valid_save()
332 */
333 public function _save() {
334 $param = func_get_args();
335 if ( call_user_func_array( array( $this, '_is_valid_save' ), $param ) ) {
336 call_user_func_array( array( $this, 'save' ), $param );
337 }
338 }
339
340 /**
341 * Load submitted data and save each field in the container
342 *
343 * @see is_valid_save()
344 */
345 public function save( $data = null ) {
346 foreach ( $this->fields as $field ) {
347 $field->set_value_from_input( Helper::input() );
348 $field->save();
349 }
350 }
351
352 /**
353 * Checks whether the current save request is valid
354 *
355 * @return bool
356 */
357 final protected function _is_valid_save() {
358 $params = func_get_args();
359 $is_valid_save = call_user_func_array( array( $this, 'is_valid_save' ), $params );
360 return apply_filters( 'carbon_fields_container_is_valid_save', $is_valid_save, $this );
361 }
362
363 /**
364 * Checks whether the current save request is valid
365 *
366 * @return bool
367 */
368 abstract protected function is_valid_save();
369
370 /**
371 * Called first as part of the container attachment procedure.
372 * Responsible for checking it's OK to attach the container
373 * and if it is, calling the container-specific attach() method
374 *
375 * @see attach()
376 * @see is_valid_attach()
377 */
378 public function _attach() {
379 if ( ! $this->is_valid_attach() ) {
380 return;
381 }
382
383 $param = func_get_args();
384 call_user_func_array( array( $this, 'attach' ), $param );
385
386 // Allow containers to initialize but not activate (useful in cases such as theme options)
387 if ( $this->should_activate() ) {
388 $this->activate();
389 }
390 }
391
392 /**
393 * Attach the container rendering and helping methods
394 * to concrete WordPress Action hooks
395 */
396 public function attach() {}
397
398 /**
399 * Perform checks whether the container should be attached during the current request
400 *
401 * @return bool True if the container is allowed to be attached
402 */
403 final public function is_valid_attach() {
404 $is_valid_attach = $this->is_valid_attach_for_request();
405 return apply_filters( 'carbon_fields_container_is_valid_attach', $is_valid_attach, $this );
406 }
407
408 /**
409 * Get environment array for page request (in admin)
410 *
411 * @return array
412 */
413 abstract protected function get_environment_for_request();
414
415 /**
416 * Check container attachment rules against current page request (in admin)
417 *
418 * @return bool
419 */
420 abstract protected function is_valid_attach_for_request();
421
422 /**
423 * Check if conditions pass for request
424 *
425 * @return bool
426 */
427 protected function static_conditions_pass() {
428 $environment = $this->get_environment_for_request();
429 $static_condition_collection = $this->condition_collection->evaluate(
430 $this->get_condition_types( false ),
431 true
432 );
433 return $static_condition_collection->is_fulfilled( $environment );
434 }
435
436 /**
437 * Get environment array for object id
438 *
439 * @param integer $object_id
440 * @return array
441 */
442 abstract protected function get_environment_for_object( $object_id );
443
444 /**
445 * Check container attachment rules against object id
446 *
447 * @param int $object_id
448 * @return bool
449 */
450 abstract public function is_valid_attach_for_object( $object_id );
451
452 /**
453 * Check if all conditions pass for object
454 *
455 * @param integer $object_id
456 * @return bool
457 */
458 protected function all_conditions_pass( $object_id ) {
459 $environment = $this->get_environment_for_object( $object_id );
460 return $this->condition_collection->is_fulfilled( $environment );
461 }
462
463 /**
464 * Whether this container is currently viewed.
465 */
466 public function should_activate() {
467 return true;
468 }
469
470 /**
471 * Perform a check whether the current container has fields
472 *
473 * @return bool
474 */
475 public function has_fields() {
476 return (bool) $this->fields;
477 }
478
479 /**
480 * Returns the private container array of fields.
481 * Use only if you are completely aware of what you are doing.
482 *
483 * @return Field[]
484 */
485 public function get_fields() {
486 return $this->fields;
487 }
488
489 /**
490 * Return root field from container with specified name
491 *
492 * @example crb_complex
493 *
494 * @param string $field_name
495 * @return Field
496 */
497 public function get_root_field_by_name( $field_name ) {
498 $fields = $this->get_fields();
499 foreach ( $fields as $field ) {
500 if ( $field->get_base_name() === $field_name ) {
501 return $field;
502 }
503 }
504 return null;
505 }
506
507 /**
508 * Get a regex to match field name patterns used to fetch specific fields
509 *
510 * @return string
511 */
512 protected function get_field_pattern_regex() {
513 $field_name_characters = Helper::get_field_name_characters_pattern();
514
515 // matches:
516 // field_name
517 // field_name[0]
518 // field_name[0]:group_name
519 // field_name:group_name
520 $regex = '/
521 \A
522 (?P<field_name>[' . $field_name_characters . ']+)
523 (?:\[(?P<group_index>\d+)\])?
524 (?:' . preg_quote( static::HIERARCHY_GROUP_SEPARATOR, '/' ). '(?P<group_name>[' . $field_name_characters . ']+))?
525 \z
526 /x';
527 return $regex;
528 }
529
530 /**
531 * Return field from container with specified name
532 *
533 * @example $field_name = 'crb_complex/text_field'
534 * @example $field_name = 'crb_complex/complex_2'
535 * @example $field_name = 'crb_complex/complex_2:text_group/text_field'
536 * @example $field_name = 'crb_complex[3]/complex_2[1]:text_group/text_field'
537 *
538 * @param string $field_name
539 * @return Field
540 */
541 public function get_field_by_name( $field_name ) {
542 $hierarchy = array_filter( explode( static::HIERARCHY_FIELD_SEPARATOR, $field_name ) );
543 $field = null;
544
545 $field_group = $this->get_fields();
546 $hierarchy_left = $hierarchy;
547 $field_pattern_regex = $this->get_field_pattern_regex();
548 $hierarchy_index = array();
549
550 while ( ! empty( $hierarchy_left ) ) {
551 $segment = array_shift( $hierarchy_left );
552 $segment_pieces = array();
553 if ( ! preg_match( $field_pattern_regex, $segment, $segment_pieces ) ) {
554 return null;
555 }
556
557 $segment_field_name = $segment_pieces['field_name'];
558 $segment_group_index = isset( $segment_pieces['group_index'] ) ? $segment_pieces['group_index'] : 0;
559 $segment_group_name = isset( $segment_pieces['group_name'] ) ? $segment_pieces['group_name'] : Group_Field::DEFAULT_GROUP_NAME;
560
561 foreach ( $field_group as $f ) {
562 if ( $f->get_base_name() !== $segment_field_name ) {
563 continue;
564 }
565
566 if ( empty( $hierarchy_left ) ) {
567 $field = clone $f;
568 $field->set_hierarchy_index( $hierarchy_index );
569 } else {
570 if ( ! ( $f instanceof \Carbon_Fields\Field\Complex_Field ) ) {
571 return null;
572 }
573
574 $group = $f->get_group_by_name( $segment_group_name );
575 if ( ! $group ) {
576 return null;
577 }
578 $field_group = $group->get_fields();
579 $hierarchy_index[] = $segment_group_index;
580 }
581 break;
582 }
583 }
584
585 return $field;
586 }
587
588 /**
589 * Perform checks whether there is a field registered with the name $name.
590 * If not, the field name is recorded.
591 *
592 * @param string $name
593 * @return boolean
594 */
595 protected function register_field_name( $name ) {
596 if ( in_array( $name, $this->registered_field_names ) ) {
597 Incorrect_Syntax_Exception::raise( 'Field name "' . $name . '" already registered' );
598 return false;
599 }
600
601 $this->registered_field_names[] = $name;
602 return true;
603 }
604
605 /**
606 * Return whether the datastore instance is the default one or has been overriden
607 *
608 * @return boolean
609 */
610 public function has_default_datastore() {
611 return $this->has_default_datastore;
612 }
613
614 /**
615 * Set datastore instance
616 *
617 * @param Datastore_Interface $datastore
618 * @param bool $set_as_default (optional)
619 * @return Container $this
620 */
621 public function set_datastore( Datastore_Interface $datastore, $set_as_default = false ) {
622 if ( $set_as_default && ! $this->has_default_datastore() ) {
623 return $this; // datastore has been overriden with a custom one - abort changing to a default one
624 }
625 $this->datastore = $datastore;
626 $this->has_default_datastore = $set_as_default;
627
628 foreach ( $this->fields as $field ) {
629 $field->set_datastore( $this->get_datastore(), true );
630 }
631 return $this;
632 }
633
634 /**
635 * Get the DataStore instance
636 *
637 * @return Datastore_Interface $datastore
638 */
639 public function get_datastore() {
640 return $this->datastore;
641 }
642
643 /**
644 * Return WordPress nonce name used to identify the current container instance
645 *
646 * @return string
647 */
648 protected function get_nonce_name() {
649 return $this->get_id() . '_nonce';
650 }
651
652 /**
653 * Return WordPress nonce name used to identify the current container instance
654 *
655 * @return string
656 */
657 protected function get_nonce_value() {
658 return wp_create_nonce( $this->get_nonce_name() );
659 }
660
661 /**
662 * Check if the nonce is present in the request and that it is verified
663 *
664 * @return bool
665 */
666 protected function verified_nonce_in_request() {
667 $input = Helper::input();
668 $nonce_name = $this->get_nonce_name();
669 $nonce_value = isset( $input[ $nonce_name ] ) ? $input[ $nonce_name ] : '';
670 return wp_verify_nonce( $nonce_value, $nonce_name );
671 }
672
673 /**
674 * Internal function that creates the tab and associates it with particular field set
675 *
676 * @param string $tab_name
677 * @param array $fields
678 * @param int $queue_end
679 * @return object $this
680 */
681 private function create_tab( $tab_name, $fields, $queue_end = self::TABS_TAIL ) {
682 if ( isset( $this->tabs[ $tab_name ] ) ) {
683 Incorrect_Syntax_Exception::raise( "Tab name duplication for $tab_name" );
684 }
685
686 if ( $queue_end === static::TABS_TAIL ) {
687 $this->tabs[ $tab_name ] = array();
688 } else if ( $queue_end === static::TABS_HEAD ) {
689 $this->tabs = array_merge(
690 array( $tab_name => array() ),
691 $this->tabs
692 );
693 }
694
695 foreach ( $fields as $field ) {
696 $field_name = $field->get_name();
697 $this->tabs[ $tab_name ][ $field_name ] = $field;
698 }
699
700 $this->settings['tabs'] = $this->get_tabs_json();
701 }
702
703 /**
704 * Whether the container is tabbed or not
705 *
706 * @return bool
707 */
708 public function is_tabbed() {
709 return (bool) $this->tabs;
710 }
711
712 /**
713 * Retrieve all fields that are not defined under a specific tab
714 *
715 * @return array
716 */
717 protected function get_untabbed_fields() {
718 $tabbed_fields_names = array();
719 foreach ( $this->tabs as $tab_fields ) {
720 $tabbed_fields_names = array_merge( $tabbed_fields_names, array_keys( $tab_fields ) );
721 }
722
723 $untabbed_fields = array_filter( $this->fields, function( $field ) use ( $tabbed_fields_names ) {
724 return ! in_array( $field->get_name(), $tabbed_fields_names );
725 } );
726
727 return $untabbed_fields;
728 }
729
730 /**
731 * Retrieve all tabs.
732 * Create a default tab if there are any untabbed fields.
733 *
734 * @return array
735 */
736 protected function get_tabs() {
737 $untabbed_fields = $this->get_untabbed_fields();
738
739 if ( ! empty( $untabbed_fields ) ) {
740 $this->create_tab(
741 apply_filters( 'carbon_fields_untabbed_fields_tab_title', __( 'General', 'carbon-fields' ), $this ),
742 $untabbed_fields,
743 static::TABS_HEAD
744 );
745 }
746
747 return $this->tabs;
748 }
749
750 /**
751 * Build the tabs JSON
752 *
753 * @return array
754 */
755 protected function get_tabs_json() {
756 $tabs_json = array();
757 $tabs = $this->get_tabs();
758
759 foreach ( $tabs as $tab_name => $fields ) {
760 foreach ( $fields as $field_name => $field ) {
761 $tabs_json[ $tab_name ][] = $field_name;
762 }
763 }
764
765 return $tabs_json;
766 }
767
768 /**
769 * Get custom CSS classes.
770 *
771 * @return array<string>
772 */
773 public function get_classes() {
774 return $this->classes;
775 }
776
777 /**
778 * Set CSS classes that the container should use.
779 *
780 * @param string|array<string> $classes
781 * @return Container $this
782 */
783 public function set_classes( $classes ) {
784 $this->classes = Helper::sanitize_classes( $classes );
785 return $this;
786 }
787
788 /**
789 * Returns an array that holds the container data, suitable for JSON representation.
790 *
791 * @param bool $load Should the value be loaded from the database or use the value from the current instance.
792 * @return array
793 */
794 public function to_json( $load ) {
795 $conditions = $this->condition_collection->evaluate( $this->get_condition_types( true ), $this->get_environment_for_request(), array( 'CUSTOM' ) );
796 $conditions = $this->condition_translator->fulfillable_to_foreign( $conditions );
797
798 $container_data = array(
799 'id' => $this->get_id(),
800 'type' => $this->type,
801 'title' => $this->title,
802 'layout' => $this->layout,
803 'classes' => $this->get_classes(),
804 'settings' => $this->settings,
805 'conditions' => $conditions,
806 'fields' => array(),
807 'nonce' => array(
808 'name' => $this->get_nonce_name(),
809 'value' => $this->get_nonce_value(),
810 ),
811 );
812
813 $fields = $this->get_fields();
814 foreach ( $fields as $field ) {
815 $field_data = $field->to_json( $load );
816 $container_data['fields'][] = $field_data;
817 }
818
819 return $container_data;
820 }
821
822 /**
823 * COMMON USAGE METHODS
824 */
825
826 /**
827 * Append array of fields to the current fields set. All items of the array
828 * must be instances of Field and their names should be unique for all
829 * Carbon containers.
830 * If a field does not have DataStore already, the container datastore is
831 * assigned to them instead.
832 *
833 * @param array $fields
834 * @return Container $this
835 */
836 public function add_fields( $fields ) {
837 foreach ( $fields as $field ) {
838 if ( ! ( $field instanceof Field ) ) {
839 Incorrect_Syntax_Exception::raise( 'Object must be of type Carbon_Fields\\Field\\Field' );
840 return $this;
841 }
842
843 $unique = $this->register_field_name( $field->get_name() );
844 if ( ! $unique ) {
845 return $this;
846 }
847
848 $field->set_context( $this->type );
849 if ( ! $field->get_datastore() ) {
850 $field->set_datastore( $this->get_datastore(), $this->has_default_datastore() );
851 }
852 }
853
854 $this->fields = array_merge( $this->fields, $fields );
855
856 return $this;
857 }
858
859 /**
860 * Configuration function for adding tab with fields
861 *
862 * @param string $tab_name
863 * @param array $fields
864 * @return Container $this
865 */
866 public function add_tab( $tab_name, $fields ) {
867 $this->add_fields( $fields );
868 $this->create_tab( $tab_name, $fields );
869 return $this;
870 }
871
872 /**
873 * Proxy function to set attachment conditions
874 *
875 * @see Fulfillable_Collection::where()
876 * @return Container $this
877 */
878 public function where() {
879 call_user_func_array( array( $this->condition_collection, 'where' ), func_get_args() );
880 return $this;
881 }
882
883 /**
884 * Proxy function to set attachment conditions
885 *
886 * @see Fulfillable_Collection::or_where()
887 * @return Container $this
888 */
889 public function or_where() {
890 call_user_func_array( array( $this->condition_collection, 'or_where' ), func_get_args() );
891 return $this;
892 }
893
894 /**
895 * Modify the layout of this field.
896 *
897 * @param string $layout
898 * @return self $this
899 */
900 public function set_layout( $layout ) {
901 $available_layouts = array(
902 static::LAYOUT_TABBED_HORIZONTAL,
903 static::LAYOUT_TABBED_VERTICAL,
904 );
905
906 if ( ! in_array( $layout, $available_layouts ) ) {
907 $error_message = 'Incorrect layout ``' . $layout . '" specified. ' .
908 'Available layouts: ' . implode( ', ', $available_layouts );
909
910 Incorrect_Syntax_Exception::raise( $error_message );
911 return $this;
912 }
913
914 $this->layout = $layout;
915
916 return $this;
917 }
918 }
919