PluginProbe
GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI / 8.0.3
GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI v8.0.3
8.0.4 8.0.3 8.0.1 8.0.2 8.0.0 7.9.9.7 7.9.9.6 7.9.9.5 7.9.9.4 7.9.9.3 7.9.9.2 7.9.9.1 7.9.9 7.9.8 7.9.7 7.9.6 7.9.5 7.9.4 7.9.3 7.9.2 7.9.1 7.9.0 7.8.9 7.8.8 7.8.7 All 46 releases
gamipress / libraries / cmb2 / includes / CMB2_Options_Hookup.php

CMB2_Options_Hookup.php in GamiPress – Gamification plugin to reward points, badges & ranks in WordPress, now with AI 8.0.3, at libraries/cmb2/includes/CMB2_Options_Hookup.php

393 lines 12.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles hooking CMB2 forms/metaboxes into the post/attachement/user screens
4 * and handles hooking in and saving those fields.
5 *
6 * @since 2.0.0
7 *
8 * @category WordPress_Plugin
9 * @package CMB2
10 * @author CMB2 team
11 * @license GPL-2.0+
12 * @link https://cmb2.io
13 */
14 class CMB2_Options_Hookup extends CMB2_Hookup {
15
16 /**
17 * The object type we are performing the hookup for
18 *
19 * @var string
20 * @since 2.0.9
21 */
22 protected $object_type = 'options-page';
23
24 /**
25 * Options page key.
26 *
27 * @var string
28 * @since 2.2.5
29 */
30 protected $option_key = '';
31
32 /**
33 * Constructor
34 *
35 * @since 2.0.0
36 * @param CMB2 $cmb The CMB2 object to hookup.
37 * @param string $option_key Option key to use.
38 */
39 public function __construct( CMB2 $cmb, $option_key ) {
40 $this->cmb = $cmb;
41 $this->option_key = $option_key;
42 }
43
44 public function hooks() {
45 if ( empty( $this->option_key ) ) {
46 return;
47 }
48
49 if ( ! $this->cmb->prop( 'autoload', true ) ) {
50 // Disable option autoload if requested.
51 add_filter( "cmb2_should_autoload_{$this->option_key}", '__return_false' );
52 }
53
54 /**
55 * For WP < 4.7. Ensure the register_setting function exists.
56 */
57 if ( ! CMB2_Utils::wp_at_least( '4.7' ) && ! function_exists( 'register_setting' ) ) {
58 require_once ABSPATH . 'wp-admin/includes/plugin.php';
59 }
60
61 // Register setting to cmb2 group.
62 register_setting( 'cmb2', $this->option_key, array(
63 'type' => 'array',
64 'sanitize_callback' => 'cmb2_settings_sanitization_cb',
65 ) );
66
67 // Handle saving the data.
68 add_action( 'admin_post_' . $this->option_key, array( $this, 'save_options' ) );
69
70 // Optionally network_admin_menu.
71 $hook = $this->cmb->prop( 'admin_menu_hook' );
72
73 // Hook in to add our menu.
74 add_action( $hook, array( $this, 'options_page_menu_hooks' ), $this->get_priority() );
75
76 // If in the network admin, need to use get/update_site_option.
77 if ( 'network_admin_menu' === $hook ) {
78 // Override CMB's getter.
79 add_filter( "cmb2_override_option_get_{$this->option_key}", array( $this, 'network_get_override' ), 10, 2 );
80 // Override CMB's setter.
81 add_filter( "cmb2_override_option_save_{$this->option_key}", array( $this, 'network_update_override' ), 10, 2 );
82 }
83 }
84
85 /**
86 * Hook up our admin menu item and admin page.
87 *
88 * @since 2.2.5
89 *
90 * @return void
91 */
92 public function options_page_menu_hooks() {
93 $parent_slug = $this->cmb->prop( 'parent_slug' );
94 $title = $this->cmb->prop( 'title' );
95 $menu_title = $this->cmb->prop( 'menu_title', $title );
96 $capability = $this->cmb->prop( 'capability' );
97 $callback = array( $this, 'options_page_output' );
98
99 if ( $parent_slug ) {
100 $page_hook = add_submenu_page(
101 $parent_slug,
102 $title,
103 $menu_title,
104 $capability,
105 $this->option_key,
106 $callback
107 );
108 } else {
109 $page_hook = add_menu_page(
110 $title,
111 $menu_title,
112 $capability,
113 $this->option_key,
114 $callback,
115 $this->cmb->prop( 'icon_url' ),
116 $this->cmb->prop( 'position' )
117 );
118 }
119
120 if ( $this->cmb->prop( 'cmb_styles' ) ) {
121 // Include CMB CSS in the head to avoid FOUC.
122 add_action( "admin_print_styles-{$page_hook}", array( 'CMB2_Hookup', 'enqueue_cmb_css' ) );
123 }
124
125 $this->maybe_register_message();
126 }
127
128 /**
129 * If there is a message callback, let it determine how to register the message,
130 * else add a settings message if on this settings page.
131 *
132 * @since 2.2.6
133 *
134 * @return void
135 */
136 public function maybe_register_message() {
137 $is_options_page = self::is_page( $this->option_key );
138 $should_notify = ! $this->cmb->prop( 'disable_settings_errors' ) && isset( $_GET['settings-updated'] ) && $is_options_page;
139 $is_updated = $should_notify && 'true' === $_GET['settings-updated'];
140 $setting = "{$this->option_key}-notices";
141 $code = '';
142 $message = __( 'Nothing to update.', 'cmb2' );
143 $type = 'notice-warning';
144
145 if ( $is_updated ) {
146 $message = __( 'Settings updated.', 'cmb2' );
147 $type = 'updated';
148 }
149
150 // Check if parameter has registered a callback.
151 if ( $cb = $this->cmb->maybe_callback( 'message_cb' ) ) {
152
153 /**
154 * The 'message_cb' callback will receive the following parameters.
155 * Unless there are other reasons for notifications, the callback should only
156 * `add_settings_error()` if `$args['should_notify']` is truthy.
157 *
158 * @param CMB2 $cmb The CMB2 object.
159 * @param array $args {
160 * An array of message arguments
161 *
162 * @type bool $is_options_page Whether current page is this options page.
163 * @type bool $should_notify Whether options were saved and we should be notified.
164 * @type bool $is_updated Whether options were updated with save (or stayed the same).
165 * @type string $setting For add_settings_error(), Slug title of the setting to which
166 * this error applies.
167 * @type string $code For add_settings_error(), Slug-name to identify the error.
168 * Used as part of 'id' attribute in HTML output.
169 * @type string $message For add_settings_error(), The formatted message text to display
170 * to the user (will be shown inside styled `<div>` and `<p>` tags).
171 * Will be 'Settings updated.' if $is_updated is true, else 'Nothing to update.'
172 * @type string $type For add_settings_error(), Message type, controls HTML class.
173 * Accepts 'error', 'updated', '', 'notice-warning', etc.
174 * Will be 'updated' if $is_updated is true, else 'notice-warning'.
175 * }
176 */
177 $args = compact( 'is_options_page', 'should_notify', 'is_updated', 'setting', 'code', 'message', 'type' );
178
179 $this->cmb->do_callback( $cb, $args );
180
181 } elseif ( $should_notify ) {
182
183 add_settings_error( $setting, $code, $message, $type );
184 }
185 }
186
187 /**
188 * Display options-page output. To override, set 'display_cb' box property.
189 *
190 * @since 2.2.5
191 */
192 public function options_page_output() {
193 $this->maybe_output_settings_notices();
194
195 $callback = $this->cmb->prop( 'display_cb' );
196 if ( is_callable( $callback ) ) {
197 return call_user_func( $callback, $this );
198 }
199
200 ?>
201 <div class="wrap cmb2-options-page option-<?php echo esc_attr( sanitize_html_class( $this->option_key ) ); ?>">
202 <?php if ( $this->cmb->prop( 'title' ) ) : ?>
203 <h2><?php echo wp_kses_post( $this->cmb->prop( 'title' ) ); ?></h2>
204 <?php endif; ?>
205 <?php $this->options_page_tab_nav_output(); ?>
206 <form class="cmb-form" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="POST" id="<?php echo $this->cmb->cmb_id; ?>" enctype="multipart/form-data" encoding="multipart/form-data">
207 <input type="hidden" name="action" value="<?php echo esc_attr( $this->option_key ); ?>">
208 <?php $this->options_page_metabox(); ?>
209 <?php submit_button( esc_attr( $this->cmb->prop( 'save_button' ) ), 'primary', 'submit-cmb' ); ?>
210 </form>
211 </div>
212 <?php
213 }
214
215 /**
216 * Display options-page Tab Navigation output.
217 *
218 * @since 2.9.0
219 */
220 public function options_page_tab_nav_output() {
221 $tabs = $this->get_tab_group_tabs();
222 if ( empty( $tabs ) ) {
223 return;
224 }
225 ?>
226 <h2 class="nav-tab-wrapper">
227 <?php foreach ( $tabs as $option_key => $tab_title ) : ?>
228 <?php // phpcs:ignore Squiz.ControlStructures.ControlSignature.NewlineAfterOpenBrace -- Inline alternative-syntax conditional in template markup; keep on one line. ?>
229 <a class="nav-tab<?php if ( self::is_page( $option_key ) ) : ?> nav-tab-active<?php endif; ?>" href="<?php menu_page_url( $option_key ); ?>"><?php echo wp_kses_post( $tab_title ); ?></a>
230 <?php endforeach; ?>
231 </h2>
232 <?php
233 }
234
235 /**
236 * Outputs the settings notices if a) not a sub-page of 'options-general.php'
237 * (because settings_errors() already called in wp-admin/options-head.php),
238 * and b) the 'disable_settings_errors' prop is not set or truthy.
239 *
240 * @since 2.2.5
241 * @return void
242 */
243 public function maybe_output_settings_notices() {
244 global $parent_file;
245
246 // The settings sub-pages will already have settings_errors() called in wp-admin/options-head.php.
247 if ( 'options-general.php' !== $parent_file ) {
248 settings_errors( "{$this->option_key}-notices" );
249 }
250 }
251
252 /**
253 * Gets navigation tabs array for CMB2 options pages which share the
254 * same tab_group property.
255 *
256 * @since 2.4.0
257 * @return array Array of tab information ($option_key => $tab_title)
258 */
259 public function get_tab_group_tabs() {
260 $tab_group = $this->cmb->prop( 'tab_group' );
261 $tabs = array();
262
263 if ( $tab_group ) {
264 $boxes = CMB2_Boxes::get_by( 'tab_group', $tab_group );
265
266 foreach ( $boxes as $cmb ) {
267 $option_key = $cmb->options_page_keys();
268
269 // Must have an option key, must be an options page box.
270 if ( ! isset( $option_key[0] ) || 'options-page' !== $cmb->mb_object_type() ) {
271 continue;
272 }
273
274 $tabs[ $option_key[0] ] = $cmb->prop( 'tab_title', $cmb->prop( 'title' ) );
275 }
276 }
277
278 return apply_filters( 'cmb2_tab_group_tabs', $tabs, $tab_group );
279 }
280
281 /**
282 * Display metaboxes for an options-page object.
283 *
284 * @since 2.2.5
285 */
286 public function options_page_metabox() {
287 $this->show_form_for_type( 'options-page' );
288 }
289
290 /**
291 * Save data from options page, then redirects back.
292 *
293 * @since 2.2.5
294 * @return void
295 */
296 public function save_options() {
297 $url = wp_get_referer();
298 if ( ! $url ) {
299 $url = admin_url();
300 }
301
302 if (
303 $this->can_save( 'options-page' )
304 // check params.
305 && isset( $_POST['submit-cmb'], $_POST['action'] )
306 && $this->option_key === $_POST['action']
307 ) {
308
309 $updated = $this->cmb
310 ->save_fields( $this->option_key, $this->cmb->object_type(), $_POST )
311 ->was_updated(); // Will be false if no values were changed/updated.
312
313 $url = add_query_arg( 'settings-updated', $updated ? 'true' : 'false', $url );
314 }
315
316 wp_safe_redirect( esc_url_raw( $url ), 303 /* WP_Http::SEE_OTHER */ );
317 exit;
318 }
319
320 /**
321 * Replaces get_option with get_site_option.
322 *
323 * @since 2.2.5
324 *
325 * @param mixed $test Not used.
326 * @param mixed $default Default value to use.
327 * @return mixed Value set for the network option.
328 */
329 public function network_get_override( $test, $default = false ) {
330 return get_site_option( $this->option_key, $default );
331 }
332
333 /**
334 * Replaces update_option with update_site_option.
335 *
336 * @since 2.2.5
337 *
338 * @param mixed $test Not used.
339 * @param mixed $option_value Value to use.
340 * @return bool Success/Failure
341 */
342 public function network_update_override( $test, $option_value ) {
343 return update_site_option( $this->option_key, $option_value );
344 }
345
346 /**
347 * Determines if given page slug matches the 'page' GET query variable.
348 *
349 * @since 2.4.0
350 *
351 * @param string $page Page slug.
352 * @return boolean
353 */
354 public static function is_page( $page ) {
355 return isset( $_GET['page'] ) && $page === $_GET['page'];
356 }
357
358 /**
359 * Magic getter for our object.
360 *
361 * @param string $field Property to retrieve.
362 *
363 * @throws Exception Throws an exception if the field is invalid.
364 * @return mixed
365 */
366 public function __get( $field ) {
367 switch ( $field ) {
368 case 'object_type':
369 case 'option_key':
370 case 'cmb':
371 return $this->{$field};
372 default:
373 // translators: 1: class name, 2: property name.
374 throw new Exception( sprintf( esc_html__( 'Invalid %1$s property: %2$s', 'cmb2' ), __CLASS__, $field ) );
375 }
376 }
377 }
378
379 if( ! function_exists( 'cmb2_settings_sanitization_cb' ) ) {
380 function cmb2_settings_sanitization_cb( $settings ) {
381 global $cmb2_settings_sanitizated;
382
383 if( $cmb2_settings_sanitizated === true ) {
384 return $settings;
385 }
386
387 $cmb2_settings_sanitizated = true;
388
389 return map_deep( $settings, 'sanitize_text_field' );
390 }
391
392 }
393