Completed
Push — master ( 0af146...28843d )
by Ravinder
21:08
created

Give_CMB2_Settings_Loader::save()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 3
nc 1
nop 0
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 19 and the first side effect is on line 624.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * Give CMB2 settings backward compatibility.
4
 *
5
 * @package     Give
6
 * @subpackage  Classes/Give_CMB2_Settings_Loader
7
 * @copyright   Copyright (c) 2016, WordImpress
8
 * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
9
 * @since       1.8
10
 */
11
12
if ( ! class_exists( 'Give_CMB2_Settings_Loader' ) ) :
13
14
	/**
15
	 * This class loads the cmb2 settings.
16
	 *
17
	 * @since 1.8
18
	 */
19
	Class Give_CMB2_Settings_Loader {
20
21
		/**
22
		 * @since 1.8
23
		 * @var   Give_Plugin_Settings $prev_settings Previous setting class object.
24
		 */
25
		private $id;
26
27
		/**
28
		 * @since 1.8
29
		 * @var   Give_Plugin_Settings $prev_settings Previous setting class object.
30
		 */
31
		private $prev_settings;
32
33
		/**
34
		 * @since 1.8
35
		 * @var   string $current_tab Current setting section.
36
		 */
37
		protected $current_tab;
38
39
		/**
40
		 * @since 1.8
41
		 * @var   string $current_tab Current setting section.
42
		 */
43
		private $current_section;
44
45
46
		/**
47
		 * Give_CMB2_Settings_Loader constructor.
48
		 */
49
		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...
50
			// Get previous setting class object.
51
			$this->prev_settings = new Give_Plugin_Settings();
52
53
			// Get current tab.
54
			$this->current_tab     = give_get_current_setting_tab();
55
			$this->current_section = empty( $_REQUEST['section'] ) ? ( current( array_keys( $this->get_sections() ) ) ) : sanitize_title( $_REQUEST['section'] );
56
57
			// Tab ID.
58
			$this->id = $this->current_tab;
59
60
61
			// Add addon tabs.
62
			add_filter( 'give-settings_tabs_array', array( $this, 'add_addon_settings_page' ), 999999 );
63
64
			// Add save hook to addons.
65
			add_action( 'give-settings_get_settings_pages', array( $this, 'setup_addon_save_hook' ), 999999 );
66
67
			// Add backward compatibility filters plugin settings.
68
			$setting_tabs = array( 'general', 'gateways', 'display', 'emails', 'addons', 'licenses' );
69
70
			// Filter Payment Gateways settings.
71
			if ( in_array( $this->current_tab, $setting_tabs ) ) {
72
				add_filter( "give_get_settings_{$this->current_tab}", array(
73
					$this,
74
					'get_filtered_addon_settings'
75
				), 999999, 1 );
76
				add_filter( "give_get_sections_{$this->current_tab}", array(
77
					$this,
78
					'get_filtered_addon_sections'
79
				), 999999, 1 );
80
			}
81
		}
82
83
		/**
84
		 * Default setting tab.
85
		 *
86
		 * @since  1.8
87
		 *
88
		 * @param  $setting_tab
89
		 *
90
		 * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be integer|string|false?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
91
		 */
92
		function set_default_setting_tab( $setting_tab ) {
0 ignored issues
show
Unused Code introduced by
The parameter $setting_tab is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
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...
93
			$default_tab = '';
94
95
			// Set default tab to first setting tab.
96
			if ( $sections = array_keys( $this->get_sections() ) ) {
97
				$default_tab = current( $sections );
98
			}
99
100
			return $default_tab;
101
		}
102
103
		/**
104
		 * Add addon setting pages.
105
		 *
106
		 * @since  1.8
107
		 *
108
		 * @param  $pages
109
		 *
110
		 * @return mixed
111
		 */
112
		function add_addon_settings_page( $pages ) {
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...
113
			// Previous setting page.
114
			$previous_pages = $this->prev_settings->give_get_settings_tabs();
115
116
			// API and System Info setting tab merge to Tools setting tab, so remove them from tabs.
117
			unset( $previous_pages['api'] );
118
			unset( $previous_pages['system_info'] );
119
120
			// Tab is not register.
121
			$pages_diff = array_keys( array_diff( $previous_pages, $pages ) );
122
123
			// Merge old settings with new settings.
124
			$pages = array_merge( $pages, $previous_pages );
125
126
			if ( in_array( $this->current_tab, $pages_diff ) ) {
127
				// Filter & actions.
128
				add_filter( "give_default_setting_tab_section_{$this->current_tab}", array(
129
					$this,
130
					'set_default_setting_tab'
131
				), 10 );
132
				add_action( "give-settings_sections_{$this->current_tab}_page", array( $this, 'output_sections' ) );
133
				add_action( "give-settings_settings_{$this->current_tab}_page", array( $this, 'output' ), 10 );
134
				add_action( "give-settings_save_{$this->current_tab}", array( $this, 'save' ) );
135
			}
136
137
			return $pages;
138
		}
139
140
141
		/**
142
		 * Setup save addon data hook.
143
		 *
144
		 * @since  1.8
145
		 *
146
		 * @param  $pages
147
		 *
148
		 * @return mixed
149
		 */
150
		function setup_addon_save_hook( $pages ) {
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...
151
			$page_ids = array();
152
153
			foreach ( $pages as $page ) {
154
				$page_ids = $page->add_settings_page( $page_ids );
155
			}
156
157
			// Previous setting page.
158
			$previous_pages = $this->prev_settings->give_get_settings_tabs();
159
160
			// API and System Info setting tab merge to Tools setting tab, so remove them from tabs.
161
			unset( $previous_pages['api'] );
162
			unset( $previous_pages['system_info'] );
163
164
			// Tab is not register.
165
			$pages_diff = array_keys( array_diff( $previous_pages, $page_ids ) );
166
167
			// Merge old settings with new settings.
168
			$pages = array_merge( $page_ids, $previous_pages );
169
170
			if ( in_array( $this->current_tab, $pages_diff ) ) {
171
				// Filter & actions.
172
				add_action( "give-settings_save_{$this->current_tab}", array( $this, 'save' ) );
173
			}
174
175
			return $pages;
176
		}
177
178
		/**
179
		 * Get section name from section title
180
		 *
181
		 * @since  1.8
182
		 *
183
		 * @param  $field_name
184
		 *
185
		 * @return string
186
		 */
187
		function get_section_name( $field_name ) {
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...
188
			// Bailout.
189
			if ( empty( $field_name ) ) {
190
				return $field_name;
191
			}
192
193
			$section_name = explode( ' ', $field_name );
194
195
			// Output.
196
			return strip_tags( implode( ' ', $section_name ) );
197
		}
198
199
200
		/**
201
		 * Get addon sections.
202
		 *
203
		 * @since  1.8
204
		 *
205
		 * @param  array $sections Array of setting fields (Optional).
206
		 *
207
		 * @return mixed
208
		 */
209
		function get_filtered_addon_sections( $sections = array() ) {
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...
210
			// New sections.
211
			$new_sections = array();
212
			$sections_ID  = array_keys( $sections );
213
214
			if ( ( $setting_fields = $this->prev_settings->give_settings( $this->current_tab ) ) && ! empty( $setting_fields['fields'] ) ) {
215
216
				foreach ( $setting_fields['fields'] as $field ) {
217
					// Section name.
218
					$field['name'] = isset( $field['name'] ) ? $field['name'] : '';
219
					$section_name  = $this->get_section_name( $field['name'] );
220
221
					// Check if section name exit and section title array is not empty.
222
					if ( ! empty( $sections ) && ! empty( $field['name'] ) ) {
223
224
						// Bailout: Do not load section if it is already exist.
225
						if (
226
							in_array( sanitize_title( $field['name'] ), $sections_ID ) // Check section id.
227
							|| in_array( $section_name, $sections )                    // Check section name.
228
						) {
229
							continue;
230
						}
231
					}
232
233
					// Collect new sections from addons.
234
					if ( 'give_title' == $field['type'] ) {
235
						$new_sections[ sanitize_title( $field['name'] ) ] = $section_name;
236
					}
237
				}
238
			}
239
240
			// Add new section.
241
			$sections = array_merge( $sections, $new_sections );
242
243
			// Output.
244
			return $sections;
245
		}
246
247
248
		/**
249
		 * Get setting fields.
250
		 *
251
		 * @since  1.8
252
		 *
253
		 * @param  array $settings       List of settings.
254
		 * @param  array $setting_fields Main tab settings data.
255
		 *
256
		 * @return array
257
		 */
258
		function get_filtered_addon_settings( $settings, $setting_fields = array() ) {
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...
259
			global $wp_filter;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
260
261
			$new_setting_fields = array();
262
263
			if ( ! empty( $settings ) ) {
264
				// Bailout: If setting array contain first element of type title then it means it is already created with new setting api (skip this section ).
265
				if ( isset( $settings[0]['type'] ) && 'title' == $settings[0]['type'] ) {
266
					foreach ( $settings as $setting ) {
267
						$new_setting_fields[] = $setting;
268
269
						// We need setting only till first section end.
270
						if ( 'sectionend' === $setting['type'] ) {
271
							break;
272
						}
273
					}
274
275
					return $new_setting_fields;
276
				}
277
278
				// Store title field id.
279
				$prev_title_field_id = '';
280
281
				// Create new setting fields.
282
				foreach ( $settings as $index => $field ) {
283
284
					// Bailout: Must need field type to process.
285
					if ( ! isset( $field['type'] ) ) {
286
						continue;
287
					}
288
289
					// Set wrapper class if any.
290
					if ( ! empty( $field['row_classes'] ) ) {
291
						$field['wrapper_class'] = $field['row_classes'];
292
						unset( $field['row_classes'] );
293
					}
294
295
					$field['name'] = ! isset( $field['name'] ) ? '' : $field['name'];
296
					$field['desc'] = ! isset( $field['desc'] ) ? '' : $field['desc'];
297
298
					// Modify cmb2 setting fields.
299
					switch ( $field['type'] ) {
300
						case 'text' :
301
						case 'file' :
302
							$field['css'] = 'width:25em;';
303
							break;
304
305
						case 'text_small' :
306
							$field['type'] = 'text';
307
							break;
308
309
						case 'text_email' :
310
							$field['type'] = 'email';
311
							$field['css']  = 'width:25em;';
312
							break;
313
314
						case 'radio_inline' :
315
							$field['type']  = 'radio';
316
							$field['class'] = 'give-radio-inline';
317
							break;
318
319
						case 'give_title' :
320
							$field['type'] = 'title';
321
							break;
322
					}
323
324
					if ( 'title' === $field['type'] ) {
325
326
						// If we do not have first element as title then these field will be skip from frontend
327
						// because there are not belong to any section, so put all abandon fields under first section.
328
						if ( $index && empty( $prev_title_field_id ) ) {
329
							array_unshift(
330
								$new_setting_fields,
331
								array(
332
									'title' => $field['name'],
333
									'type'  => $field['type'],
334
									'desc'  => $field['desc'],
335
									'id'    => $field['id']
336
								)
337
							);
338
339
							$prev_title_field_id = $field['id'];
340
341
							continue;
342
						} elseif ( $index ) {
343
							// Section end.
344
							$new_setting_fields[] = array(
345
								'type' => 'sectionend',
346
								'id'   => $prev_title_field_id
347
							);
348
						}
349
350
						// Section start.
351
						$new_setting_fields[] = array(
352
							'title' => $field['name'],
353
							'type'  => $field['type'],
354
							'desc'  => $field['desc'],
355
							'id'    => $field['id']
356
						);
357
358
						$prev_title_field_id = $field['id'];
359
					} else {
360
361
						// setting fields
362
						$new_setting_fields[] = $field;
363
					}
364
				}
365
366
				// Section end.
367
				$new_setting_fields[] = array(
368
					'type' => 'sectionend',
369
					'id'   => $prev_title_field_id
370
				);
371
372
				// Check if setting page has title section or not.
373
				// If setting page does not have title section  then add title section to it and fix section end array id.
374
				if ( 'title' !== $new_setting_fields[0]['type'] ) {
375
					array_unshift(
376
						$new_setting_fields,
377
						array(
378
							'title' => ( isset( $settings['give_title'] ) ? $settings['give_title'] : '' ),
379
							'type'  => 'title',
380
							'desc'  => ! empty( $setting_fields['desc'] ) ? $setting_fields['desc'] : '',
381
							'id'    => ( isset( $settings['id'] ) ? $settings['id'] : '' )
382
						)
383
					);
384
385
					// Update id in section end array if does not contain.
386
					if ( empty( $new_setting_fields[ count( $new_setting_fields ) - 1 ]['id'] ) ) {
387
						$new_setting_fields[ count( $new_setting_fields ) - 1 ]['id'] = ( isset( $settings['id'] ) ? $settings['id'] : '' );
388
					}
389
				}
390
391
				// Return only section related settings.
392
				if ( $sections = $this->get_filtered_addon_sections() ) {
393
					$new_setting_fields = $this->get_section_settings( $new_setting_fields );
394
				}
395
396
				// Third party plugin backward compatibility.
397
				$wp_filter_keys = array_keys( $wp_filter );
398
				foreach ( $new_setting_fields as $index => $field ) {
399
400
					if ( in_array( $field['type'], array( 'title', 'sectionend' ) ) ) {
401
						continue;
402
					}
403
404
					$cmb2_filter_name = "cmb2_render_{$field['type']}";
405
406
					if ( in_array( $cmb2_filter_name, $wp_filter_keys ) ) {
407
408
						if( 0 >= version_compare( 4.7, get_bloginfo('version') ) &&  ! empty( $wp_filter[$cmb2_filter_name]->callbacks ) ) {
409
							$cmb2_filter_arr = current( $wp_filter[$cmb2_filter_name]->callbacks );
410
						} else {
411
							$cmb2_filter_arr = current( $wp_filter[ $cmb2_filter_name ] );
412
						}
413
414
						if ( ! empty( $cmb2_filter_arr ) ) {
415
							// Note: function can be called either globally or with class object, it depends on how developer invoke it.
416
							$new_setting_fields[ $index ]['func'] = current( $cmb2_filter_arr );
417
							add_action( "give_admin_field_{$field['type']}", array(
418
								$this,
419
								'addon_setting_field'
420
							), 10, 2 );
421
						}
422
					}
423
				}
424
425
				return $new_setting_fields;
426
			}
427
428
			return $settings;
429
		}
430
431
432
		/**
433
		 * Get section related setting.
434
		 *
435
		 * @since 1.8
436
		 *
437
		 * @param $tab_settings
438
		 *
439
		 * @return array
440
		 */
441
		function get_section_settings( $tab_settings ) {
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...
442
			$current_section = give_get_current_setting_section();
443
444
			// Note: If we are opening default tabe for addon setting then it is possible that we will get empty string as current section
445
			// because default section filter added after save hook fire, so we will always get problem to save first section [default] or if there are only on section
446
			// This is hack to fix this.
447
			if ( empty( $current_section ) ) {
448
				$current_section = $this->set_default_setting_tab( $current_section );
449
			}
450
451
			$section_start               = false;
452
			$section_end                 = false;
453
			$section_only_setting_fields = array();
454
455
			foreach ( $tab_settings as $field ) {
456
				if ( 'title' == $field['type'] && $current_section == sanitize_title( $field['title'] ) ) {
457
					$section_start = true;
458
				}
459
460
				if ( ! $section_start || $section_end ) {
461
					continue;
462
				}
463
464
				if ( $section_start && ! $section_end ) {
465
					if ( 'sectionend' == $field['type'] ) {
466
						$section_end = true;
467
					}
468
					$section_only_setting_fields[] = $field;
469
				}
470
			}
471
472
			// Remove title from setting, pevent it from render in setting tab.
473
			$section_only_setting_fields[0]['title'] = '';
474
475
			return apply_filters( "give_get_settings_{$this->current_tab}_{$current_section}", $section_only_setting_fields, $tab_settings );
476
		}
477
478
479
		/**
480
		 * CMB2 addon setting fields backward compatibility.
481
		 *
482
		 * @since  1.8
483
		 *
484
		 * @param  array $field
485
		 * @param  mixed $saved_value
486
		 *
487
		 * @return void
488
		 */
489
		function addon_setting_field( $field, $saved_value ) {
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...
490
			// Create object for cmb2  function callback backward compatibility.
491
			// Note: Do not call any cmb2 function on these objects
492
			$field_obj      = (object) array( 'args' => $field );
493
			$field_type_obj = (object) array( 'field' => $field_obj );
494
495
			switch ( $this->current_tab ) :
496
				case 'licenses':
497
					?>
498
					<div class="give-settings-wrap give-settings-wrap-<?php echo $this->current_tab; ?>">
499
						<?php $field['func']['function']( $field_obj, $saved_value, '', '', $field_type_obj ); ?>
500
					</div>
501
					<?php break;
502
503
				default :
504
					$colspan = "colspan=\"2\"";
505
					?>
506
					<tr valign="top">
507
						<?php if ( ! empty( $field['name'] ) && ! in_array( $field['name'], array( '&nbsp;' ) ) ) : ?>
508
							<th scope="row" class="titledesc">
509
								<label
510
									for="<?php echo esc_attr( $field['name'] ); ?>"><?php echo $field['title']; ?></label>
511
							</th>
512
							<?php $colspan = ''; ?>
513
						<?php endif; ?>
514
						<td class="give-forminp" <?php echo $colspan; ?>>
515
							<?php
516
							if ( is_array( $field['func']['function'] ) ) {
517
								$field['func']['function'][0]->$field['func']['function'][1]( $field_obj, $saved_value, '', '', $field_type_obj );
518
							} else {
519
								$field['func']['function']( $field_obj, $saved_value, '', '', $field_type_obj );
520
							}
521
							?>
522
						</td>
523
					</tr>
524
					<?php
525
			endswitch;
526
		}
527
528
		/**
529
		 * Get sections.
530
		 *
531
		 * @since  1.8
532
		 * @return array
533
		 */
534
		public function get_sections() {
535
			$sections = array();
536
537
			if ( ( $setting_fields = $this->prev_settings->give_settings( $this->current_tab ) ) && ! empty( $setting_fields['fields'] ) ) {
538
				foreach ( $setting_fields['fields'] as $field ) {
539
					if ( 'give_title' == $field['type'] ) {
540
						$sections[ sanitize_title( $field['name'] ) ] = $this->get_section_name( $field['name'] );
541
					}
542
				}
543
			}
544
545
			return $sections;
546
		}
547
548
549
		/**
550
		 * Get setting fields.
551
		 *
552
		 * @since  1.8
553
		 * @return array
554
		 */
555
		function get_settings() {
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...
556
			global $wp_filter;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
557
558
			$new_setting_fields = array();
559
560
			if ( $setting_fields = $this->prev_settings->give_settings( $this->current_tab ) ) {
561
				if ( isset( $setting_fields['fields'] ) ) {
562
563
					$tab_data = array(
564
						'id'         => $setting_fields['id'],
565
						'give_title' => $setting_fields['give_title'],
566
						'desc'       => ( isset( $setting_fields['desc'] ) ? $setting_fields['desc'] : '' )
567
					);
568
569
					$new_setting_fields = $this->get_filtered_addon_settings( $setting_fields['fields'], $tab_data );
570
				}
571
			}
572
573
			return $new_setting_fields;
574
		}
575
576
		/**
577
		 * Output sections.
578
		 *
579
		 * @since  1.8
580
		 * @return void
581
		 */
582
		public function output_sections() {
583
			$sections = $this->get_sections();
584
585
			if ( empty( $sections ) || 1 === sizeof( $sections ) ) {
586
				return;
587
			}
588
589
			echo '<ul class="subsubsub">';
590
591
			$array_keys = array_keys( $sections );
592
593
			foreach ( $sections as $id => $label ) {
594
				echo '<li><a href="' . admin_url( 'edit.php?post_type=give_forms&page=give-settings&tab=' . $this->current_tab . '&section=' . sanitize_title( $id ) ) . '" class="' . ( $this->current_section == $id ? 'current' : '' ) . '">' . strip_tags( $label ) . '</a> ' . ( end( $array_keys ) == $id ? '' : '|' ) . ' </li>';
595
			}
596
597
			echo '</ul><br class="clear" />';
598
		}
599
600
		/**
601
		 * Output the settings.
602
		 *
603
		 * @since  1.8
604
		 * @return void
605
		 */
606
		public function output() {
607
			$settings = $this->get_settings();
608
609
			Give_Admin_Settings::output_fields( $settings, 'give_settings' );
610
		}
611
612
		/**
613
		 * Save settings.
614
		 *
615
		 * @since  1.8
616
		 * @return void
617
		 */
618
		public function save() {
619
			$settings = $this->get_settings();
620
621
			Give_Admin_Settings::save_fields( $settings, 'give_settings' );
622
		}
623
	}
624
endif;
625
626
new Give_CMB2_Settings_Loader();