' . __('There are no options for this widget.') . '
'; return 'noform'; } // Functions you'll need to call. /** * PHP5 constructor. * * @since 2.8.0 * @access public * * @param string $id_base Optional Base ID for the widget, lowercase and unique. If left empty, * a portion of the widget's class name will be used Has to be unique. * @param string $name Name for the widget displayed on the configuration page. * @param array $widget_options Optional. Widget options. See {@see wp_register_sidebar_widget()} for * information on accepted arguments. Default empty array. * @param array $control_options Optional. Widget control options. See {@see wp_register_widget_control()} * for information on accepted arguments. Default empty array. */ public function __construct( $id_base, $name, $widget_options = array(), $control_options = array() ) { $this->id_base = empty($id_base) ? preg_replace( '/(wp_)?widget_/', '', strtolower(get_class($this)) ) : strtolower($id_base); $this->name = $name; $this->option_name = 'widget_' . $this->id_base; $this->widget_options = wp_parse_args( $widget_options, array('classname' => $this->option_name) ); $this->control_options = wp_parse_args( $control_options, array('id_base' => $this->id_base) ); } /** * PHP4 constructor * * @param string $id_base * @param string $name * @param array $widget_options * @param array $control_options */ public function WP_Widget( $id_base, $name, $widget_options = array(), $control_options = array() ) { WP_Widget::__construct( $id_base, $name, $widget_options, $control_options ); } /** * Constructs name attributes for use in form() fields * * This function should be used in form() methods to create name attributes for fields to be saved by update() * * @param string $field_name Field name * @return string Name attribute for $field_name */ public function get_field_name($field_name) { return 'widget-' . $this->id_base . '[' . $this->number . '][' . $field_name . ']'; } /** * Constructs id attributes for use in {@see WP_Widget::form()} fields. * * This function should be used in form() methods to create id attributes * for fields to be saved by {@see WP_Widget::update()}. * * @since 2.8.0 * @access public * * @param string $field_name Field name. * @return string ID attribute for `$field_name`. */ public function get_field_id( $field_name ) { return 'widget-' . $this->id_base . '-' . $this->number . '-' . $field_name; } /** * Register all widget instances of this widget class. * * @since 2.8.0 * @access private */ public function _register() { $settings = $this->get_settings(); $empty = true; if ( is_array($settings) ) { foreach ( array_keys($settings) as $number ) { if ( is_numeric($number) ) { $this->_set($number); $this->_register_one($number); $empty = false; } } } if ( $empty ) { // If there are none, we register the widget's existence with a // generic template $this->_set(1); $this->_register_one(); } } /** * Set the internal order number for the widget instance. * * @since 2.8.0 * @access private * * @param int $number The unique order number of this widget instance compared to other * instances of the same class. */ public function _set($number) { $this->number = $number; $this->id = $this->id_base . '-' . $number; } public function _get_display_callback() { return array($this, 'display_callback'); } public function _get_update_callback() { return array($this, 'update_callback'); } public function _get_form_callback() { return array($this, 'form_callback'); } /** * Determine whether the current request is inside the Customizer preview. * * If true -- the current request is inside the Customizer preview, then * the object cache gets suspended and widgets should check this to decide * whether they should store anything persistently to the object cache, * to transients, or anywhere else. * * @since 3.9.0 * @access public * * @return bool True if within the Customizer preview, false if not. */ public function is_preview() { global $wp_customize; return ( isset( $wp_customize ) && $wp_customize->is_preview() ) ; } /** * Generate the actual widget content (Do NOT override). * * Finds the instance and calls {@see WP_Widget::widget()}. * * @since 2.8.0 * @access public * * @param array $args Display arguments. See {@see WP_Widget::widget()} for information * on accepted arguments. * @param int|array $widget_args { * Optional. Internal order number of the widget instance, or array of multi-widget arguments. * Default 1. * * @type int $number Number increment used for multiples of the same widget. * } */ public function display_callback( $args, $widget_args = 1 ) { if ( is_numeric($widget_args) ) $widget_args = array( 'number' => $widget_args ); $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); $this->_set( $widget_args['number'] ); $instance = $this->get_settings(); if ( array_key_exists( $this->number, $instance ) ) { $instance = $instance[$this->number]; /** * Filter the settings for a particular widget instance. * * Returning false will effectively short-circuit display of the widget. * * @since 2.8.0 * * @param array $instance The current widget instance's settings. * @param WP_Widget $this The current widget instance. * @param array $args An array of default widget arguments. */ $instance = apply_filters( 'widget_display_callback', $instance, $this, $args ); if ( false === $instance ) { return; } $was_cache_addition_suspended = wp_suspend_cache_addition(); if ( $this->is_preview() && ! $was_cache_addition_suspended ) { wp_suspend_cache_addition( true ); } $this->widget( $args, $instance ); if ( $this->is_preview() ) { wp_suspend_cache_addition( $was_cache_addition_suspended ); } } } /** * Deal with changed settings (Do NOT override). * * @since 2.8.0 * @access public * * @param int $deprecated Not used. */ public function update_callback( $deprecated = 1 ) { global $wp_registered_widgets; $all_instances = $this->get_settings(); // We need to update the data if ( $this->updated ) return; if ( isset($_POST['delete_widget']) && $_POST['delete_widget'] ) { // Delete the settings for this instance of the widget if ( isset($_POST['the-widget-id']) ) $del_id = $_POST['the-widget-id']; else return; if ( isset($wp_registered_widgets[$del_id]['params'][0]['number']) ) { $number = $wp_registered_widgets[$del_id]['params'][0]['number']; if ( $this->id_base . '-' . $number == $del_id ) unset($all_instances[$number]); } } else { if ( isset($_POST['widget-' . $this->id_base]) && is_array($_POST['widget-' . $this->id_base]) ) { $settings = $_POST['widget-' . $this->id_base]; } elseif ( isset($_POST['id_base']) && $_POST['id_base'] == $this->id_base ) { $num = $_POST['multi_number'] ? (int) $_POST['multi_number'] : (int) $_POST['widget_number']; $settings = array( $num => array() ); } else { return; } foreach ( $settings as $number => $new_instance ) { $new_instance = stripslashes_deep($new_instance); $this->_set($number); $old_instance = isset($all_instances[$number]) ? $all_instances[$number] : array(); $was_cache_addition_suspended = wp_suspend_cache_addition(); if ( $this->is_preview() && ! $was_cache_addition_suspended ) { wp_suspend_cache_addition( true ); } $instance = $this->update( $new_instance, $old_instance ); if ( $this->is_preview() ) { wp_suspend_cache_addition( $was_cache_addition_suspended ); } /** * Filter a widget's settings before saving. * * Returning false will effectively short-circuit the widget's ability * to update settings. * * @since 2.8.0 * * @param array $instance The current widget instance's settings. * @param array $new_instance Array of new widget settings. * @param array $old_instance Array of old widget settings. * @param WP_Widget $this The current widget instance. */ $instance = apply_filters( 'widget_update_callback', $instance, $new_instance, $old_instance, $this ); if ( false !== $instance ) { $all_instances[$number] = $instance; } break; // run only once } } $this->save_settings($all_instances); $this->updated = true; } /** * Generate the widget control form (Do NOT override). * * @since 2.8.0 * @access public * * @param int|array $widget_args Widget instance number or array of widget arguments. */ public function form_callback( $widget_args = 1 ) { if ( is_numeric($widget_args) ) $widget_args = array( 'number' => $widget_args ); $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); $all_instances = $this->get_settings(); if ( -1 == $widget_args['number'] ) { // We echo out a form where 'number' can be set later $this->_set('__i__'); $instance = array(); } else { $this->_set($widget_args['number']); $instance = $all_instances[ $widget_args['number'] ]; } /** * Filter the widget instance's settings before displaying the control form. * * Returning false effectively short-circuits display of the control form. * * @since 2.8.0 * * @param array $instance The current widget instance's settings. * @param WP_Widget $this The current widget instance. */ $instance = apply_filters( 'widget_form_callback', $instance, $this ); $return = null; if ( false !== $instance ) { $return = $this->form($instance); /** * Fires at the end of the widget control form. * * Use this hook to add extra fields to the widget form. The hook * is only fired if the value passed to the 'widget_form_callback' * hook is not false. * * Note: If the widget has no form, the text echoed from the default * form method can be hidden using CSS. * * @since 2.8.0 * * @param WP_Widget $this The widget instance, passed by reference. * @param null $return Return null if new fields are added. * @param array $instance An array of the widget's settings. */ do_action_ref_array( 'in_widget_form', array( &$this, &$return, $instance ) ); } return $return; } /** * Register an instance of the widget class. * * @since 2.8.0 * @access private * * @param integer $number Optional. The unique order number of this widget instance * compared to other instances of the same class. Default -1. */ public function _register_one( $number = -1 ) { wp_register_sidebar_widget( $this->id, $this->name, $this->_get_display_callback(), $this->widget_options, array( 'number' => $number ) ); _register_widget_update_callback( $this->id_base, $this->_get_update_callback(), $this->control_options, array( 'number' => -1 ) ); _register_widget_form_callback( $this->id, $this->name, $this->_get_form_callback(), $this->control_options, array( 'number' => $number ) ); } /** * Save the settings for all instances of the widget class. * * @since 2.8.0 * @access public * * @param array $settings Multi-dimensional array of widget instance settings. */ public function save_settings( $settings ) { $settings['_multiwidget'] = 1; update_option( $this->option_name, $settings ); } /** * Get the settings for all instances of the widget class. * * @since 2.8.0 * @access public * * @return array Multi-dimensional array of widget instance settings. */ public function get_settings() { $settings = get_option($this->option_name); if ( false === $settings && isset($this->alt_option_name) ) $settings = get_option($this->alt_option_name); if ( !is_array($settings) ) $settings = array(); if ( !empty($settings) && !array_key_exists('_multiwidget', $settings) ) { // old format, convert if single widget $settings = wp_convert_widget_settings($this->id_base, $this->option_name, $settings); } unset($settings['_multiwidget'], $settings['__i__']); return $settings; } } /** * Singleton that registers and instantiates WP_Widget classes. * * @package WordPress * @subpackage Widgets * @since 2.8.0 */ class WP_Widget_Factory { public $widgets = array(); public function WP_Widget_Factory() { add_action( 'widgets_init', array( $this, '_register_widgets' ), 100 ); } /** * Register a widget subclass. * * @since 2.8.0 * @access public * * @param string $widget_class The name of a {@see WP_Widget} subclass. */ public function register( $widget_class ) { $this->widgets[$widget_class] = new $widget_class(); } /** * Un-register a widget subclass. * * @since 2.8.0 * @access public * * @param string $widget_class The name of a {@see WP_Widget} subclass. */ public function unregister( $widget_class ) { if ( isset($this->widgets[$widget_class]) ) unset($this->widgets[$widget_class]); } /** * Utility method for adding widgets to the registered widgets global. * * @since 2.8.0 * @access public */ public function _register_widgets() { global $wp_registered_widgets; $keys = array_keys($this->widgets); $registered = array_keys($wp_registered_widgets); $registered = array_map('_get_widget_id_base', $registered); foreach ( $keys as $key ) { // don't register new widget if old widget with the same id is already registered if ( in_array($this->widgets[$key]->id_base, $registered, true) ) { unset($this->widgets[$key]); continue; } $this->widgets[$key]->_register(); } } } /* Global Variables */ /** @ignore */ global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates; /** * Stores the sidebars, since many themes can have more than one. * * @global array $wp_registered_sidebars * @since 2.2.0 */ $wp_registered_sidebars = array(); /** * Stores the registered widgets. * * @global array $wp_registered_widgets * @since 2.2.0 */ $wp_registered_widgets = array(); /** * Stores the registered widget control (options). * * @global array $wp_registered_widget_controls * @since 2.2.0 */ $wp_registered_widget_controls = array(); $wp_registered_widget_updates = array(); /** * Private */ $_wp_sidebars_widgets = array(); /** * Private */ $GLOBALS['_wp_deprecated_widgets_callbacks'] = array( 'wp_widget_pages', 'wp_widget_pages_control', 'wp_widget_calendar', 'wp_widget_calendar_control', 'wp_widget_archives', 'wp_widget_archives_control', 'wp_widget_links', 'wp_widget_meta', 'wp_widget_meta_control', 'wp_widget_search', 'wp_widget_recent_entries', 'wp_widget_recent_entries_control', 'wp_widget_tag_cloud', 'wp_widget_tag_cloud_control', 'wp_widget_categories', 'wp_widget_categories_control', 'wp_widget_text', 'wp_widget_text_control', 'wp_widget_rss', 'wp_widget_rss_control', 'wp_widget_recent_comments', 'wp_widget_recent_comments_control' ); /* Template tags & API functions */ /** * Register a widget * * Registers a WP_Widget widget * * @since 2.8.0 * * @see WP_Widget * @see WP_Widget_Factory * @uses WP_Widget_Factory * * @param string $widget_class The name of a class that extends WP_Widget */ function register_widget($widget_class) { global $wp_widget_factory; $wp_widget_factory->register($widget_class); } /** * Unregister a widget * * Unregisters a WP_Widget widget. Useful for unregistering default widgets. * Run within a function hooked to the widgets_init action. * * @since 2.8.0 * * @see WP_Widget * @see WP_Widget_Factory * @uses WP_Widget_Factory * * @param string $widget_class The name of a class that extends WP_Widget */ function unregister_widget($widget_class) { global $wp_widget_factory; $wp_widget_factory->unregister($widget_class); } /** * Creates multiple sidebars. * * If you wanted to quickly create multiple sidebars for a theme or internally. * This function will allow you to do so. If you don't pass the 'name' and/or * 'id' in `$args`, then they will be built for you. * * @since 2.2.0 * * @see register_sidebar() The second parameter is documented by register_sidebar() and is the same here. * * @param int $number Optional. Number of sidebars to create. Default 1. * @param array|string $args { * Optional. Array or string of arguments for building a sidebar. * * @type string $id The base string of the unique identifier for each sidebar. If provided, and multiple * sidebars are being defined, the id will have "-2" appended, and so on. * Default 'sidebar-' followed by the number the sidebar creation is currently at. * @type string $name The name or title for the sidebars displayed in the admin dashboard. If registering * more than one sidebar, include '%d' in the string as a placeholder for the uniquely * assigned number for each sidebar. * Default 'Sidebar' for the first sidebar, otherwise 'Sidebar %d'. * } */ function register_sidebars( $number = 1, $args = array() ) { global $wp_registered_sidebars; $number = (int) $number; if ( is_string($args) ) parse_str($args, $args); for ( $i = 1; $i <= $number; $i++ ) { $_args = $args; if ( $number > 1 ) $_args['name'] = isset($args['name']) ? sprintf($args['name'], $i) : sprintf(__('Sidebar %d'), $i); else $_args['name'] = isset($args['name']) ? $args['name'] : __('Sidebar'); // Custom specified ID's are suffixed if they exist already. // Automatically generated sidebar names need to be suffixed regardless starting at -0 if ( isset($args['id']) ) { $_args['id'] = $args['id']; $n = 2; // Start at -2 for conflicting custom ID's while ( isset($wp_registered_sidebars[$_args['id']]) ) $_args['id'] = $args['id'] . '-' . $n++; } else { $n = count($wp_registered_sidebars); do { $_args['id'] = 'sidebar-' . ++$n; } while ( isset($wp_registered_sidebars[$_args['id']]) ); } register_sidebar($_args); } } /** * Builds the definition for a single sidebar and returns the ID. * * Accepts either a string or an array and then parses that against a set * of default arguments for the new sidebar. WordPress will automatically * generate a sidebar ID and name based on the current number of registered * sidebars if those arguments are not included. * * When allowing for automatic generation of the name and ID parameters, keep * in mind that the incrementor for your sidebar can change over time depending * on what other plugins and themes are installed. * * If theme support for 'widgets' has not yet been added when this function is * called, it will be automatically enabled through the use of add_theme_support() * * @since 2.2.0 * * @global array $wp_registered_sidebars Stores the new sidebar in this array by sidebar ID. * * @param array|string $args { * Optional. Array or string of arguments for the sidebar being registered. * * @type string $name The name or title of the sidebar displayed in the Widgets * interface. Default 'Sidebar $instance'. * @type string $id The unique identifier by which the sidebar will be called. * Default 'sidebar-$instance'. * @type string $description Description of the sidebar, displayed in the Widgets interface. * Default empty string. * @type string $class Extra CSS class to assign to the sidebar in the Widgets interface. * Default empty. * @type string $before_widget HTML content to prepend to each widget's HTML output when * assigned to this sidebar. Default is an opening list item element. * @type string $after_widget HTML content to append to each widget's HTML output when * assigned to this sidebar. Default is a closing list item element. * @type string $before_title HTML content to prepend to the sidebar title when displayed. * Default is an opening h2 element. * @type string $after_title HTML content to append to the sidebar title when displayed. * Default is a closing h2 element. * } * @return string Sidebar ID added to $wp_registered_sidebars global. */ function register_sidebar($args = array()) { global $wp_registered_sidebars; $i = count($wp_registered_sidebars) + 1; $defaults = array( 'name' => sprintf(__('Sidebar %d'), $i ), 'id' => "sidebar-$i", 'description' => '', 'class' => '', 'before_widget' => '