~canonical-sysadmins/wordpress/4.6

« back to all changes in this revision

Viewing changes to wp-includes/class-wp-widget.php

  • Committer: Manuel Seelaus
  • Date: 2015-12-09 17:47:18 UTC
  • mfrom: (1.1.11 upstream)
  • Revision ID: manuel.seelaus@canonical.com-20151209174718-coxethm2swbeqksy
Merge WP4.4 from upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
/**
 
3
 * Widget API: WP_Widget base class
 
4
 *
 
5
 * @package WordPress
 
6
 * @subpackage Widgets
 
7
 * @since 4.4.0
 
8
 */
 
9
 
 
10
/**
 
11
 * Core base class extended to register widgets.
 
12
 *
 
13
 * This class must be extended for each widget and WP_Widget::widget(), WP_Widget::update()
 
14
 * and WP_Widget::form() need to be overridden.
 
15
 *
 
16
 * @since 2.8.0
 
17
 * @since 4.4.0 Moved to its own file from wp-includes/widgets.php
 
18
 */
 
19
class WP_Widget {
 
20
 
 
21
        /**
 
22
         * Root ID for all widgets of this type.
 
23
         *
 
24
         * @since 2.8.0
 
25
         * @access public
 
26
         * @var mixed|string
 
27
         */
 
28
        public $id_base;
 
29
 
 
30
        /**
 
31
         * Name for this widget type.
 
32
         *
 
33
         * @since 2.8.0
 
34
         * @access public
 
35
         * @var string
 
36
         */
 
37
        public $name;
 
38
 
 
39
        /**
 
40
         * Option array passed to {@see wp_register_sidebar_widget()}.
 
41
         *
 
42
         * @since 2.8.0
 
43
         * @access public
 
44
         * @var array
 
45
         */
 
46
        public $widget_options;
 
47
 
 
48
        /**
 
49
         * Option array passed to {@see wp_register_widget_control()}.
 
50
         *
 
51
         * @since 2.8.0
 
52
         * @access public
 
53
         * @var array
 
54
         */
 
55
        public $control_options;
 
56
 
 
57
        /**
 
58
         * Unique ID number of the current instance.
 
59
         *
 
60
         * @since 2.8.0
 
61
         * @access public
 
62
         * @var bool|int
 
63
         */
 
64
        public $number = false;
 
65
 
 
66
        /**
 
67
         * Unique ID string of the current instance (id_base-number).
 
68
         *
 
69
         * @since 2.8.0
 
70
         * @access public
 
71
         * @var bool|string
 
72
         */
 
73
        public $id = false;
 
74
 
 
75
        /**
 
76
         * Whether the widget data has been updated.
 
77
         *
 
78
         * Set to true when the data is updated after a POST submit - ensures it does
 
79
         * not happen twice.
 
80
         *
 
81
         * @since 2.8.0
 
82
         * @access public
 
83
         * @var bool
 
84
         */
 
85
        public $updated = false;
 
86
 
 
87
        // Member functions that you must over-ride.
 
88
 
 
89
        /**
 
90
         * Echoes the widget content.
 
91
         *
 
92
         * Sub-classes should over-ride this function to generate their widget code.
 
93
         *
 
94
         * @since 2.8.0
 
95
         * @access public
 
96
         *
 
97
         * @param array $args     Display arguments including 'before_title', 'after_title',
 
98
         *                        'before_widget', and 'after_widget'.
 
99
         * @param array $instance The settings for the particular instance of the widget.
 
100
         */
 
101
        public function widget( $args, $instance ) {
 
102
                die('function WP_Widget::widget() must be over-ridden in a sub-class.');
 
103
        }
 
104
 
 
105
        /**
 
106
         * Updates a particular instance of a widget.
 
107
         *
 
108
         * This function should check that `$new_instance` is set correctly. The newly-calculated
 
109
         * value of `$instance` should be returned. If false is returned, the instance won't be
 
110
         * saved/updated.
 
111
         *
 
112
         * @since 2.8.0
 
113
         * @access public
 
114
         *
 
115
         * @param array $new_instance New settings for this instance as input by the user via
 
116
         *                            WP_Widget::form().
 
117
         * @param array $old_instance Old settings for this instance.
 
118
         * @return array Settings to save or bool false to cancel saving.
 
119
         */
 
120
        public function update( $new_instance, $old_instance ) {
 
121
                return $new_instance;
 
122
        }
 
123
 
 
124
        /**
 
125
         * Outputs the settings update form.
 
126
         *
 
127
         * @since 2.8.0
 
128
         * @access public
 
129
         *
 
130
         * @param array $instance Current settings.
 
131
         * @return string Default return is 'noform'.
 
132
         */
 
133
        public function form( $instance ) {
 
134
                echo '<p class="no-options-widget">' . __('There are no options for this widget.') . '</p>';
 
135
                return 'noform';
 
136
        }
 
137
 
 
138
        // Functions you'll need to call.
 
139
 
 
140
        /**
 
141
         * PHP5 constructor.
 
142
         *
 
143
         * @since 2.8.0
 
144
         * @access public
 
145
         *
 
146
         * @param string $id_base         Optional Base ID for the widget, lowercase and unique. If left empty,
 
147
         *                                a portion of the widget's class name will be used Has to be unique.
 
148
         * @param string $name            Name for the widget displayed on the configuration page.
 
149
         * @param array  $widget_options  Optional. Widget options. See wp_register_sidebar_widget() for information
 
150
         *                                on accepted arguments. Default empty array.
 
151
         * @param array  $control_options Optional. Widget control options. See wp_register_widget_control() for
 
152
         *                                information on accepted arguments. Default empty array.
 
153
         */
 
154
        public function __construct( $id_base, $name, $widget_options = array(), $control_options = array() ) {
 
155
                $this->id_base = empty($id_base) ? preg_replace( '/(wp_)?widget_/', '', strtolower(get_class($this)) ) : strtolower($id_base);
 
156
                $this->name = $name;
 
157
                $this->option_name = 'widget_' . $this->id_base;
 
158
                $this->widget_options = wp_parse_args( $widget_options, array('classname' => $this->option_name) );
 
159
                $this->control_options = wp_parse_args( $control_options, array('id_base' => $this->id_base) );
 
160
        }
 
161
 
 
162
        /**
 
163
         * PHP4 constructor.
 
164
         *
 
165
         * @param string $id_base
 
166
         * @param string $name
 
167
         * @param array  $widget_options
 
168
         * @param array  $control_options
 
169
         */
 
170
        public function WP_Widget( $id_base, $name, $widget_options = array(), $control_options = array() ) {
 
171
                _deprecated_constructor( 'WP_Widget', '4.3.0' );
 
172
                WP_Widget::__construct( $id_base, $name, $widget_options, $control_options );
 
173
        }
 
174
 
 
175
        /**
 
176
         * Constructs name attributes for use in form() fields
 
177
         *
 
178
         * This function should be used in form() methods to create name attributes for fields to be saved by update()
 
179
         *
 
180
         * @since 2.8.0
 
181
         * @since 4.4.0 Array format field names are now accepted.
 
182
         *
 
183
         * @param string $field_name Field name
 
184
         * @return string Name attribute for $field_name
 
185
         */
 
186
        public function get_field_name($field_name) {
 
187
                if ( false === $pos = strpos( $field_name, '[' ) ) {
 
188
                        return 'widget-' . $this->id_base . '[' . $this->number . '][' . $field_name . ']';
 
189
                } else {
 
190
                        return 'widget-' . $this->id_base . '[' . $this->number . '][' . substr_replace( $field_name, '][', $pos, strlen( '[' ) );
 
191
                }
 
192
        }
 
193
 
 
194
        /**
 
195
         * Constructs id attributes for use in {@see WP_Widget::form()} fields.
 
196
         *
 
197
         * This function should be used in form() methods to create id attributes
 
198
         * for fields to be saved by {@see WP_Widget::update()}.
 
199
         *
 
200
         * @since 2.8.0
 
201
         * @since 4.4.0 Array format field IDs are now accepted.
 
202
         * @access public
 
203
         *
 
204
         * @param string $field_name Field name.
 
205
         * @return string ID attribute for `$field_name`.
 
206
         */
 
207
        public function get_field_id( $field_name ) {
 
208
                return 'widget-' . $this->id_base . '-' . $this->number . '-' . trim( str_replace( array( '[]', '[', ']' ), array( '', '-', '' ), $field_name ), '-' );
 
209
        }
 
210
 
 
211
        /**
 
212
         * Register all widget instances of this widget class.
 
213
         *
 
214
         * @since 2.8.0
 
215
         * @access private
 
216
         */
 
217
        public function _register() {
 
218
                $settings = $this->get_settings();
 
219
                $empty = true;
 
220
 
 
221
                // When $settings is an array-like object, get an intrinsic array for use with array_keys().
 
222
                if ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) {
 
223
                        $settings = $settings->getArrayCopy();
 
224
                }
 
225
 
 
226
                if ( is_array( $settings ) ) {
 
227
                        foreach ( array_keys( $settings ) as $number ) {
 
228
                                if ( is_numeric( $number ) ) {
 
229
                                        $this->_set( $number );
 
230
                                        $this->_register_one( $number );
 
231
                                        $empty = false;
 
232
                                }
 
233
                        }
 
234
                }
 
235
 
 
236
                if ( $empty ) {
 
237
                        // If there are none, we register the widget's existence with a generic template.
 
238
                        $this->_set( 1 );
 
239
                        $this->_register_one();
 
240
                }
 
241
        }
 
242
 
 
243
        /**
 
244
         * Set the internal order number for the widget instance.
 
245
         *
 
246
         * @since 2.8.0
 
247
         * @access private
 
248
         *
 
249
         * @param int $number The unique order number of this widget instance compared to other
 
250
         *                    instances of the same class.
 
251
         */
 
252
        public function _set($number) {
 
253
                $this->number = $number;
 
254
                $this->id = $this->id_base . '-' . $number;
 
255
        }
 
256
 
 
257
        /**
 
258
         * @return callback
 
259
         */
 
260
        public function _get_display_callback() {
 
261
                return array($this, 'display_callback');
 
262
        }
 
263
        /**
 
264
         * @return callback
 
265
         */
 
266
        public function _get_update_callback() {
 
267
                return array($this, 'update_callback');
 
268
        }
 
269
        /**
 
270
         * @return callback
 
271
         */
 
272
        public function _get_form_callback() {
 
273
                return array($this, 'form_callback');
 
274
        }
 
275
 
 
276
        /**
 
277
         * Determine whether the current request is inside the Customizer preview.
 
278
         *
 
279
         * If true -- the current request is inside the Customizer preview, then
 
280
         * the object cache gets suspended and widgets should check this to decide
 
281
         * whether they should store anything persistently to the object cache,
 
282
         * to transients, or anywhere else.
 
283
         *
 
284
         * @since 3.9.0
 
285
         * @access public
 
286
         *
 
287
         * @global WP_Customize_Manager $wp_customize
 
288
         *
 
289
         * @return bool True if within the Customizer preview, false if not.
 
290
         */
 
291
        public function is_preview() {
 
292
                global $wp_customize;
 
293
                return ( isset( $wp_customize ) && $wp_customize->is_preview() ) ;
 
294
        }
 
295
 
 
296
        /**
 
297
         * Generate the actual widget content (Do NOT override).
 
298
         *
 
299
         * Finds the instance and calls {@see WP_Widget::widget()}.
 
300
         *
 
301
         * @since 2.8.0
 
302
         * @access public
 
303
         *
 
304
         * @param array     $args        Display arguments. See {@see WP_Widget::widget()} for information
 
305
         *                               on accepted arguments.
 
306
         * @param int|array $widget_args {
 
307
         *     Optional. Internal order number of the widget instance, or array of multi-widget arguments.
 
308
         *     Default 1.
 
309
         *
 
310
         *     @type int $number Number increment used for multiples of the same widget.
 
311
         * }
 
312
         */
 
313
        public function display_callback( $args, $widget_args = 1 ) {
 
314
                if ( is_numeric( $widget_args ) ) {
 
315
                        $widget_args = array( 'number' => $widget_args );
 
316
                }
 
317
 
 
318
                $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
 
319
                $this->_set( $widget_args['number'] );
 
320
                $instances = $this->get_settings();
 
321
 
 
322
                if ( array_key_exists( $this->number, $instances ) ) {
 
323
                        $instance = $instances[ $this->number ];
 
324
 
 
325
                        /**
 
326
                         * Filter the settings for a particular widget instance.
 
327
                         *
 
328
                         * Returning false will effectively short-circuit display of the widget.
 
329
                         *
 
330
                         * @since 2.8.0
 
331
                         *
 
332
                         * @param array     $instance The current widget instance's settings.
 
333
                         * @param WP_Widget $this     The current widget instance.
 
334
                         * @param array     $args     An array of default widget arguments.
 
335
                         */
 
336
                        $instance = apply_filters( 'widget_display_callback', $instance, $this, $args );
 
337
 
 
338
                        if ( false === $instance ) {
 
339
                                return;
 
340
                        }
 
341
 
 
342
                        $was_cache_addition_suspended = wp_suspend_cache_addition();
 
343
                        if ( $this->is_preview() && ! $was_cache_addition_suspended ) {
 
344
                                wp_suspend_cache_addition( true );
 
345
                        }
 
346
 
 
347
                        $this->widget( $args, $instance );
 
348
 
 
349
                        if ( $this->is_preview() ) {
 
350
                                wp_suspend_cache_addition( $was_cache_addition_suspended );
 
351
                        }
 
352
                }
 
353
        }
 
354
 
 
355
        /**
 
356
         * Deal with changed settings (Do NOT override).
 
357
         *
 
358
         * @since 2.8.0
 
359
         * @access public
 
360
         *
 
361
         * @global array $wp_registered_widgets
 
362
         *
 
363
         * @param int $deprecated Not used.
 
364
         */
 
365
        public function update_callback( $deprecated = 1 ) {
 
366
                global $wp_registered_widgets;
 
367
 
 
368
                $all_instances = $this->get_settings();
 
369
 
 
370
                // We need to update the data
 
371
                if ( $this->updated )
 
372
                        return;
 
373
 
 
374
                if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) {
 
375
                        // Delete the settings for this instance of the widget
 
376
                        if ( isset($_POST['the-widget-id']) )
 
377
                                $del_id = $_POST['the-widget-id'];
 
378
                        else
 
379
                                return;
 
380
 
 
381
                        if ( isset($wp_registered_widgets[$del_id]['params'][0]['number']) ) {
 
382
                                $number = $wp_registered_widgets[$del_id]['params'][0]['number'];
 
383
 
 
384
                                if ( $this->id_base . '-' . $number == $del_id )
 
385
                                        unset($all_instances[$number]);
 
386
                        }
 
387
                } else {
 
388
                        if ( isset($_POST['widget-' . $this->id_base]) && is_array($_POST['widget-' . $this->id_base]) ) {
 
389
                                $settings = $_POST['widget-' . $this->id_base];
 
390
                        } elseif ( isset($_POST['id_base']) && $_POST['id_base'] == $this->id_base ) {
 
391
                                $num = $_POST['multi_number'] ? (int) $_POST['multi_number'] : (int) $_POST['widget_number'];
 
392
                                $settings = array( $num => array() );
 
393
                        } else {
 
394
                                return;
 
395
                        }
 
396
 
 
397
                        foreach ( $settings as $number => $new_instance ) {
 
398
                                $new_instance = stripslashes_deep($new_instance);
 
399
                                $this->_set($number);
 
400
 
 
401
                                $old_instance = isset($all_instances[$number]) ? $all_instances[$number] : array();
 
402
 
 
403
                                $was_cache_addition_suspended = wp_suspend_cache_addition();
 
404
                                if ( $this->is_preview() && ! $was_cache_addition_suspended ) {
 
405
                                        wp_suspend_cache_addition( true );
 
406
                                }
 
407
 
 
408
                                $instance = $this->update( $new_instance, $old_instance );
 
409
 
 
410
                                if ( $this->is_preview() ) {
 
411
                                        wp_suspend_cache_addition( $was_cache_addition_suspended );
 
412
                                }
 
413
 
 
414
                                /**
 
415
                                 * Filter a widget's settings before saving.
 
416
                                 *
 
417
                                 * Returning false will effectively short-circuit the widget's ability
 
418
                                 * to update settings.
 
419
                                 *
 
420
                                 * @since 2.8.0
 
421
                                 *
 
422
                                 * @param array     $instance     The current widget instance's settings.
 
423
                                 * @param array     $new_instance Array of new widget settings.
 
424
                                 * @param array     $old_instance Array of old widget settings.
 
425
                                 * @param WP_Widget $this         The current widget instance.
 
426
                                 */
 
427
                                $instance = apply_filters( 'widget_update_callback', $instance, $new_instance, $old_instance, $this );
 
428
                                if ( false !== $instance ) {
 
429
                                        $all_instances[$number] = $instance;
 
430
                                }
 
431
 
 
432
                                break; // run only once
 
433
                        }
 
434
                }
 
435
 
 
436
                $this->save_settings($all_instances);
 
437
                $this->updated = true;
 
438
        }
 
439
 
 
440
        /**
 
441
         * Generate the widget control form (Do NOT override).
 
442
         *
 
443
         * @since 2.8.0
 
444
         * @access public
 
445
         *
 
446
         * @param int|array $widget_args Widget instance number or array of widget arguments.
 
447
         * @return string|null
 
448
         */
 
449
        public function form_callback( $widget_args = 1 ) {
 
450
                if ( is_numeric($widget_args) )
 
451
                        $widget_args = array( 'number' => $widget_args );
 
452
 
 
453
                $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
 
454
                $all_instances = $this->get_settings();
 
455
 
 
456
                if ( -1 == $widget_args['number'] ) {
 
457
                        // We echo out a form where 'number' can be set later
 
458
                        $this->_set('__i__');
 
459
                        $instance = array();
 
460
                } else {
 
461
                        $this->_set($widget_args['number']);
 
462
                        $instance = $all_instances[ $widget_args['number'] ];
 
463
                }
 
464
 
 
465
                /**
 
466
                 * Filter the widget instance's settings before displaying the control form.
 
467
                 *
 
468
                 * Returning false effectively short-circuits display of the control form.
 
469
                 *
 
470
                 * @since 2.8.0
 
471
                 *
 
472
                 * @param array     $instance The current widget instance's settings.
 
473
                 * @param WP_Widget $this     The current widget instance.
 
474
                 */
 
475
                $instance = apply_filters( 'widget_form_callback', $instance, $this );
 
476
 
 
477
                $return = null;
 
478
                if ( false !== $instance ) {
 
479
                        $return = $this->form($instance);
 
480
 
 
481
                        /**
 
482
                         * Fires at the end of the widget control form.
 
483
                         *
 
484
                         * Use this hook to add extra fields to the widget form. The hook
 
485
                         * is only fired if the value passed to the 'widget_form_callback'
 
486
                         * hook is not false.
 
487
                         *
 
488
                         * Note: If the widget has no form, the text echoed from the default
 
489
                         * form method can be hidden using CSS.
 
490
                         *
 
491
                         * @since 2.8.0
 
492
                         *
 
493
                         * @param WP_Widget $this     The widget instance, passed by reference.
 
494
                         * @param null      $return   Return null if new fields are added.
 
495
                         * @param array     $instance An array of the widget's settings.
 
496
                         */
 
497
                        do_action_ref_array( 'in_widget_form', array( &$this, &$return, $instance ) );
 
498
                }
 
499
                return $return;
 
500
        }
 
501
 
 
502
        /**
 
503
         * Register an instance of the widget class.
 
504
         *
 
505
         * @since 2.8.0
 
506
         * @access private
 
507
         *
 
508
         * @param integer $number Optional. The unique order number of this widget instance
 
509
         *                        compared to other instances of the same class. Default -1.
 
510
         */
 
511
        public function _register_one( $number = -1 ) {
 
512
                wp_register_sidebar_widget(     $this->id, $this->name, $this->_get_display_callback(), $this->widget_options, array( 'number' => $number ) );
 
513
                _register_widget_update_callback( $this->id_base, $this->_get_update_callback(), $this->control_options, array( 'number' => -1 ) );
 
514
                _register_widget_form_callback( $this->id, $this->name, $this->_get_form_callback(), $this->control_options, array( 'number' => $number ) );
 
515
        }
 
516
 
 
517
        /**
 
518
         * Save the settings for all instances of the widget class.
 
519
         *
 
520
         * @since 2.8.0
 
521
         * @access public
 
522
         *
 
523
         * @param array $settings Multi-dimensional array of widget instance settings.
 
524
         */
 
525
        public function save_settings( $settings ) {
 
526
                $settings['_multiwidget'] = 1;
 
527
                update_option( $this->option_name, $settings );
 
528
        }
 
529
 
 
530
        /**
 
531
         * Get the settings for all instances of the widget class.
 
532
         *
 
533
         * @since 2.8.0
 
534
         * @access public
 
535
         *
 
536
         * @return array Multi-dimensional array of widget instance settings.
 
537
         */
 
538
        public function get_settings() {
 
539
 
 
540
                $settings = get_option( $this->option_name );
 
541
 
 
542
                if ( false === $settings ) {
 
543
                        if ( isset( $this->alt_option_name ) ) {
 
544
                                $settings = get_option( $this->alt_option_name );
 
545
                        } else {
 
546
                                // Save an option so it can be autoloaded next time.
 
547
                                $this->save_settings( array() );
 
548
                        }
 
549
                }
 
550
 
 
551
                if ( ! is_array( $settings ) && ! ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) ) {
 
552
                        $settings = array();
 
553
                }
 
554
 
 
555
                if ( ! empty( $settings ) && ! isset( $settings['_multiwidget'] ) ) {
 
556
                        // Old format, convert if single widget.
 
557
                        $settings = wp_convert_widget_settings( $this->id_base, $this->option_name, $settings );
 
558
                }
 
559
 
 
560
                unset( $settings['_multiwidget'], $settings['__i__'] );
 
561
                return $settings;
 
562
        }
 
563
}