diff --git a/wp-admin/admin-ajax.php b/wp-admin/admin-ajax.php index ca7de560d8..817b70c515 100644 --- a/wp-admin/admin-ajax.php +++ b/wp-admin/admin-ajax.php @@ -1,9 +1,9 @@ 250 ) + li.animate( { marginLeft: 0 } ); + t.siblings('h4').children('a').text( editText ); + } else { + t.animate( { height: 'show' } ); + if ( width > 250 ) + li.animate( { marginLeft: ( width - 250 ) * -1 } ); + t.siblings('h4').children('a').text( cancText ); + } + } ).end(); + }; + + // onclick for edit links + var editClick = function() { + var q = wpAjax.unserialize( this.href ); + // if link is in available widgets list, make sure it points to the current sidebar + if ( ( q.sidebar && q.sidebar == $('#sidebar').val() ) || q.add ) { + var w = q.edit || q.add; + toggleWidget( $('#current-sidebar .widget-control-list input[@name^="widget-id"][@value=' + w + ']').parents('li:first') ).blur(); + return false; + } else if ( q.sidebar ) { // otherwise, redirect to correct page + return true; + } + + // If link is in current widgets list, just open the form + toggleWidget( $(this).parents('li:first') ).blur(); + return false; + }; + + // onclick for add links + var addClick = function() { + var oldLi = $(this).parents('li:first').find('ul.widget-control-info li'); + var newLi = oldLi.clone(); + + if ( newLi.html().match( /%i%/ ) ) { + // supplid form is a template, replace %i% by unique id + var i = $('#generated-time').val() + increment.toString(); + increment++; + newLi.html( newLi.html().replace( /%i%/g, i ) ); + } else { + $(this).text( editText ).unbind().click( editClick ); + // save form content in textarea so we don't have any conflicting HTML ids + oldLi.html( '' ); + } + + // add event handlers + addWidgetControls( newLi ); + + // add widget to sidebar sortable + widgetSortable.append( newLi ).SortableAddItem( newLi[0] ); + + // increment widget counter + var n = parseInt( $('#widget-count').text(), 10 ) + 1; + $('#widget-count').text( n.toString() ) + + return false; + }; + + // add event handlers to all links found in context + var addWidgetControls = function( context ) { + if ( !context ) + context = document; + + $('a.widget-control-edit', context).click( editClick ); + + // onclick for save links + $('a.widget-control-save', context).click( function() { + toggleWidget( $(this).parents('li:first') ).blur() + return false; + } ); + + // onclick for remove links + $('a.widget-control-remove', context).click( function() { + var w = $(this).parents('li:first').find('input[@name^="widget-id"]').val(); + $(this).parents('li:first').remove(); + var t = $('#widget-list ul#widget-control-info-' + w + ' textarea'); + t.parent().html( t.text() ).parents('li.widget-list-item:first').children( 'h4' ).children('a.widget-action') + .show().text( addText ).unbind().click( addClick ); + var n = parseInt( $('#widget-count').text(), 10 ) - 1; + $('#widget-count').text( n.toString() ) + return false; + } ); + } + + addWidgetControls(); + + $('a.widget-control-add').click( addClick ); + + // initialize sortable + var widgetSortable = $('#current-sidebar .widget-control-list').Sortable( { + accept: 'widget-sortable', + helperclass: 'sorthelper', + handle: 'h4.widget-title' + } ); + +}); diff --git a/wp-admin/widgets.php b/wp-admin/widgets.php index a33dc8463b..aa0364f16a 100644 --- a/wp-admin/widgets.php +++ b/wp-admin/widgets.php @@ -1,360 +1,272 @@ - - - $sidebar ) { - $cols[] = '\'' . $index . '\''; - } - $cols = implode( ', ', $cols ); - - $widgets = array(); - foreach ( $wp_registered_widgets as $name => $widget ) { - $widgets[] = '\'' . $widget['id'] . '\''; - } - $widgets = implode( ', ', $widgets ); -?> - -≡' - : ''; - - $output = '
  • %2$s
  • '; - - printf( $output, $sanitized_name, $wp_registered_widgets[$name]['name'] . $popper ); -} - $title = __( 'Widgets' ); $parent_file = 'themes.php'; -require_once 'admin-header.php'; - -if ( count( $wp_registered_sidebars ) < 1 ) { +// $sidebar = What sidebar are we editing? +if ( isset($_GET['sidebar']) && isset($wp_registered_sidebars[$_GET['sidebar']]) ) { + $sidebar = attribute_escape( $_GET['sidebar'] ); +} elseif ( is_array($wp_registered_sidebars) && !empty($wp_registered_sidebars) ) { + // By default we look at the first defined sidebar + $sidebar = array_shift( array_keys($wp_registered_sidebars) ); +} else { + // If no sidebars, die. + require_once( 'admin-header.php' ); ?> -
    -

    +
    +

    +
    + +

    follow these instructions.' ); /* TODO: article on codex */; ?>

    - $sidebar ) { - $postindex = $index . 'order'; + /* Hack #1 + * The widget_control is overloaded. It updates the widget's options AND echoes out the widget's HTML form. + * Since we want to update before sending out any headers, we have to catchi it with an output buffer + */ + ob_start(); + /* There can be multiple widgets of the same type, but the widget_control for that + * widget type needs only be called once. + */ + $already_done = array(); - parse_str( $_POST[$postindex], $order ); + foreach ( $wp_registered_widget_controls as $name => $control ) { + if ( in_array( $control['callback'], $already_done ) ) + continue; - $new_order = $order[$index]; - - if ( is_array( $new_order ) ) { - foreach ( $new_order as $sanitized_name ) { - foreach ( $wp_registered_widgets as $name => $widget ) { - if ( $sanitized_name == $widget['id'] ) { - $sidebars_widgets[$index][] = $name; - } - } - } - } - } - - wp_set_sidebars_widgets( $sidebars_widgets ); - break; - } -} - -ksort( $wp_registered_widgets ); - -$inactive_widgets = array(); - -foreach ( $wp_registered_widgets as $name => $widget ) { - $is_active = false; - - foreach ( $wp_registered_sidebars as $index => $sidebar ) { - if ( is_array( $sidebars_widgets[$index] ) && in_array( $name, $sidebars_widgets[$index] ) ) { - $is_active = true; - break; + if ( is_callable( $control['callback'] ) ) + call_user_func_array( $control['callback'], $control['params'] ); } + ob_end_clean(); + + // Prophylactic. Take out empty ids. + foreach ( (array) $_POST['widget-id'] as $key => $val ) + if ( !$val ) + unset($_POST['widget-id'][$key]); + + // Reset the key numbering and stare + $new_sidebar = array_values( $_POST['widget-id'] ); + $sidebars_widgets[$_POST['sidebar']] = $new_sidebar; + wp_set_sidebars_widgets( $sidebars_widgets ); + + // Re-register just in case + wp_widgets_init(); + + wp_redirect( add_query_arg( 'message', 'updated' ) ); + exit; +} + + + + +// What widget (if any) are we editing +$edit_widget = -1; + +$query_args = array('add', 'remove', 'key', 'edit', '_wpnonce', 'message' ); + +if ( isset($_GET['add']) && $_GET['add'] ) { + // Add to the end of the sidebar + if ( isset($wp_registered_widgets[$_GET['add']]) ) { + check_admin_referer( "add-widget_$_GET[add]" ); + $sidebars_widgets[$sidebar][] = $_GET['add']; + wp_set_sidebars_widgets( $sidebars_widgets ); } - - if ( !$is_active ) { - $inactive_widgets[] = $name; + wp_redirect( remove_query_arg( $query_args ) ); + exit; +} elseif ( isset($_GET['remove']) && $_GET['remove'] && isset($_GET['key']) && is_numeric($_GET['key']) ) { + // Remove from sidebar the widget of type $_GET['remove'] and in position $_GET['key'] + $key = (int) $_GET['key']; + if ( -1 < $key && ( $keys = array_keys($sidebars_widgets[$sidebar], $_GET['remove']) ) && in_array($key, $keys) ) { + check_admin_referer( "remove-widget_$_GET[remove]" ); + unset($sidebars_widgets[$sidebar][$key]); + $sidebars_widgets[$sidebar] = array_values($sidebars_widgets[$sidebar]); + wp_set_sidebars_widgets( $sidebars_widgets ); } + wp_redirect( remove_query_arg( $query_args ) ); + exit; +} elseif ( isset($_GET['edit']) && $_GET['edit'] && isset($_GET['key']) && is_numeric($_GET['key']) ) { + // Edit widget of type $_GET['edit'] and position $_GET['key'] + $key = (int) $_GET['key']; + if ( -1 < $key && ( $keys = array_keys($sidebars_widgets[$sidebar], $_GET['edit']) ) && in_array($key, $keys) ) + $edit_widget = $key; } -$containers = array( 'palette' ); +// Total number of registered sidebars +$sidebar_widget_count = count($sidebars_widgets[$sidebar]); -foreach ( $wp_registered_sidebars as $index => $sidebar ) { - $containers[] = $index; -} +// This is sort of lame since "widget" won't be converted to "widgets" in the JS +if ( 1 < $sidebars_count = count($wp_registered_sidebars) ) + $sidebar_info_text = __ngettext( 'You are using %1$s widget in the "%2$s" sidebar.', 'You are using %1$s widgets in the "%2$s" sidebar.', $sidebar_widget_count ); +else + $sidebar_info_text = __ngettext( 'You are using %1$s widget in the sidebar.', 'You are using %1$s widgets in the sidebar.', $sidebar_widget_count ); -$c_string = ''; -foreach ( $containers as $container ) { - $c_string .= '"' . $container . '",'; -} +$sidebar_info_text = sprintf( wp_specialchars( $sidebar_info_text ), "$sidebar_widget_count", $wp_registered_sidebars[$sidebar]['name'] ); -$c_string = substr( $c_string, 0, -1 ); +$page = isset($_GET['apage']) ? abs( (int) $_GET['apage'] ) : 1; -if ( isset( $_POST['action'] ) ) { -?> -
    -

    View site »' ), get_bloginfo( 'url' ) . '/' ); ?>

    +/* TODO: Paginate widgets list +$page_links = paginate_links( array( + 'base' => add_query_arg( 'apage', '%#%' ), + 'format' => '', + 'total' => ceil(($total = 105 )/ 10), + 'current' => $page +)); +*/ +$page_links = false; + +// Unsanitized! +$widget_search = isset($_GET['s']) ? $_GET['s'] : false; + +// Not entirely sure what all should be here +$show_values = array( + '' => $widget_search ? __( 'Show any widgets' ) : __( 'Show all widgets' ), + 'unused' => __( 'Show unused widgets' ), + 'used' => __( 'Show used widgets' ) +); + +$show = isset($_GET['show']) && isset($show_values[$_GET['show']]) ? attribute_escape( $_GET['show'] ) : false; + + +$messages = array( + 'updated' => __('Changes saved.') +); + +require_once( 'admin-header.php' ); + +if ( isset($_GET['message']) && isset($messages[$_GET['message']]) ) : ?> + +

    + + + +
    + +
    + +

    + + +
    +
    +

    ?' ); ?>

    +

    + + +

    + + +
    - -
    -

    - -

    - - -

    - -

    -
    - $sidebar ) { - ?> - - -
    -

    - -
    - -

    - -
    -
    - -
      - -
    -
    - - -
    - -
    -

    - -
      - -
    -
    - - - -

    - - - -

    - -
    - $widget ) { ?> - - -
    - - -
    -
    +
    +

    ?' ); ?>

    - + + +

    + + +

    + + + +
    + + + +
    + +
    + + + + + + + +
    +
    + +
    + +
    + + + +
    + +
    + + +
    + + + +
    +
    + +

    + + +

    + +
    + +
    + + + + - diff --git a/wp-includes/script-loader.php b/wp-includes/script-loader.php index 39651b4082..9970a26e36 100644 --- a/wp-includes/script-loader.php +++ b/wp-includes/script-loader.php @@ -79,7 +79,7 @@ class WP_Scripts { $this->add( 'jquery', '/wp-includes/js/jquery/jquery.js', false, '1.1.4'); $this->add( 'jquery-form', '/wp-includes/js/jquery/jquery.form.js', array('jquery'), '1.0.3'); - $this->add( 'interface', '/wp-includes/js/jquery/interface.js', array('jquery'), '1.2'); + $this->add( 'interface', '/wp-includes/js/jquery/interface.js', array('jquery'), '1.2' ); $this->add( 'dimensions', '/wp-includes/js/jquery/jquery.dimensions.min.js', array('jquery'), '1.1.2'); $this->add( 'suggest', '/wp-includes/js/jquery/suggest.js', array('dimensions'), '1.1'); $this->add( 'schedule', '/wp-includes/js/jquery/jquery.schedule.js', array('jquery'), '20'); @@ -143,6 +143,7 @@ class WP_Scripts { 'saveText' => attribute_escape(__('Save »')), 'confirmText' => __("Are you sure you want to delete the file '%title%'?\nClick ok to delete or cancel to go back.") ) ); + $this->add( 'admin-widgets', '/wp-admin/js/widgets.js', array( 'interface' ), mt_rand() ); } } diff --git a/wp-includes/widgets.php b/wp-includes/widgets.php index 124af81769..7e050e5069 100644 --- a/wp-includes/widgets.php +++ b/wp-includes/widgets.php @@ -2,13 +2,11 @@ /* Global Variables */ -global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_styles, $wp_registered_widget_defaults; +global $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls; $wp_registered_sidebars = array(); $wp_registered_widgets = array(); $wp_registered_widget_controls = array(); -$wp_registered_widget_styles = array(); -$wp_register_widget_defaults = false; /* Template tags & API functions */ @@ -95,8 +93,7 @@ function register_sidebar_widget($name, $output_callback, $classname = '') { } function wp_register_sidebar_widget($id, $name, $output_callback, $options = array()) { - - global $wp_registered_widgets, $wp_register_widget_defaults; + global $wp_registered_widgets; if ( empty($output_callback) ) { unset($wp_registered_widgets[$id]); @@ -113,10 +110,20 @@ function wp_register_sidebar_widget($id, $name, $output_callback, $options = arr ); $widget = array_merge($widget, $options); - if ( is_callable($output_callback) && ( !isset($wp_registered_widgets[$id]) || !$wp_register_widget_defaults) ) + if ( is_callable($output_callback) && ( !isset($wp_registered_widgets[$id]) || did_action( 'widgets_init' ) ) ) $wp_registered_widgets[$id] = $widget; } +function wp_widget_description( $id ) { + if ( !is_scalar($id) ) + return; + + global $wp_registered_widgets; + + if ( isset($wp_registered_widgets[$id]['description']) ) + return wp_specialchars( $wp_registered_widgets[$id]['description'] ); +} + function unregister_sidebar_widget($id) { return wp_unregister_sidebar_widget($id); } @@ -149,23 +156,27 @@ function register_widget_control($name, $control_callback, $width = '', $height call_user_func_array('wp_register_widget_control', $args); } +/* $options: height, width, id_base + * height: never used + * width: width of fully expanded control form. Try hard to use the default width. + * id_base: for widgets which allow multiple instances (such as the text widget), an id_base must be provided. + * the widget id will ennd up looking like {$id_base}-{$unique_number} + */ function wp_register_widget_control($id, $name, $control_callback, $options = array()) { - global $wp_registered_widget_controls, $wp_register_widget_defaults; + global $wp_registered_widget_controls; if ( empty($control_callback) ) { unset($wp_registered_widget_controls[$id]); return; } - if ( isset($wp_registered_widget_controls[$id]) && $wp_register_widget_defaults ) + if ( isset($wp_registered_widget_controls[$id]) && !did_action( 'widgets_init' ) ) return; - $defaults = array('width' => 300, 'height' => 200); + $defaults = array('width' => 250, 'height' => 200 ); // height is never used $options = wp_parse_args($options, $defaults); $options['width'] = (int) $options['width']; $options['height'] = (int) $options['height']; - $options['width'] = $options['width'] > 90 ? $options['width'] + 60 : 360; - $options['height'] = $options['height'] > 60 ? $options['height'] + 40 : 240; $widget = array( 'name' => $name, @@ -234,15 +245,17 @@ function dynamic_sidebar($index = 1) { return $did_one; } +/* @return mixed false if widget is not active or id of sidebar in which the widget is active + */ function is_active_widget($callback) { global $wp_registered_widgets; $sidebars_widgets = wp_get_sidebars_widgets(false); - if ( is_array($sidebars_widgets) ) foreach ( $sidebars_widgets as $widgets ) + if ( is_array($sidebars_widgets) ) foreach ( $sidebars_widgets as $sidebar => $widgets ) if ( is_array($widgets) ) foreach ( $widgets as $widget ) if ( $wp_registered_widgets[$widget]['callback'] == $callback ) - return true; + return $sidebar; return false; } @@ -387,16 +400,22 @@ function wp_widget_pages_control() { $title = attribute_escape($options['title']); $exclude = attribute_escape( $options['exclude'] ); ?> -

    -

    +

    +

    -


    -

    - + + +

    +

    + +
    + +

    + -

    -

    -

    +

    +

    + +
    + +

    -

    +

    -

    +

    $widget_args ); + $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); + extract( $widget_args, EXTR_SKIP ); + $options = get_option('widget_text'); + if ( !isset($options[$number]) ) + return; + $title = $options[$number]['title']; $text = apply_filters( 'widget_text', $options[$number]['text'] ); ?> @@ -545,80 +576,98 @@ function wp_widget_text($args, $number = 1) { - - - " name="text-submit-" value="1" /> - 9 ) $number = 9; - if ( $number < 1 ) $number = 1; - $newoptions['number'] = $number; - } - if ( $options != $newoptions ) { - $options = $newoptions; - update_option('widget_text', $options); - wp_widget_text_register($options['number']); - } -} + if ( is_numeric($widget_args) ) + $widget_args = array( 'number' => $widget_args ); + $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); + extract( $widget_args, EXTR_SKIP ); -function wp_widget_text_page() { $options = get_option('widget_text'); + if ( !is_array($options) ) + $options = array(); + + if ( !$updated && !empty($_POST['sidebar']) ) { + $sidebar = (string) $_POST['sidebar']; + + $sidebars_widgets = wp_get_sidebars_widgets(); + if ( isset($sidebars_widgets[$sidebar]) ) + $this_sidebar =& $sidebars_widgets[$sidebar]; + else + $this_sidebar = array(); + + foreach ( $this_sidebar as $_widget_id ) { + if ( 'wp_widget_text' == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) { + $widget_number = $wp_registered_widgets[$_widget_id]['params'][0]['number']; + unset($options[$widget_number]); + } + } + + foreach ( (array) $_POST['widget-text'] as $widget_number => $widget_text ) { + $title = strip_tags(stripslashes($widget_text['title'])); + if ( current_user_can('unfiltered_html') ) + $text = stripslashes( $widget_text['text'] ); + else + $text = stripslashes(wp_filter_post_kses( $widget_text['text'] )); + $options[$widget_number] = compact( 'title', 'text' ); + } + + update_option('widget_text', $options); + $updated = true; + } + + if ( -1 == $number ) { + $title = ''; + $text = ''; + $number = '%i%'; + } else { + $title = attribute_escape($options[$number]['title']); + $text = format_to_edit($options[$number]['text']); + } ?> -
    -
    -

    -

    - -

    -
    -
    +

    + + + +

    9 ) $number = 9; - $dims = array('width' => 460, 'height' => 350); - $class = array('classname' => 'widget_text'); - for ($i = 1; $i <= 9; $i++) { - $name = sprintf(__('Text %d'), $i); - $id = "text-$i"; // Never never never translate an id - wp_register_sidebar_widget($id, $name, $i <= $number ? 'wp_widget_text' : /* unregister */ '', $class, $i); - wp_register_widget_control($id, $name, $i <= $number ? 'wp_widget_text_control' : /* unregister */ '', $dims, $i); + $widget_ops = array('classname' => 'widget_text', 'description' => __('Arbitrary text or HTML')); + $control_ops = array('width' => 460, 'height' => 350, 'id_base' => 'text'); + $name = __('Text'); + + // If there are none, we register the widget's existance with a generic template + if ( !$options ) { + wp_register_sidebar_widget( 'text-1', $name, 'wp_widget_text', $widget_ops, array( 'number' => -1 ) ); + wp_register_widget_control( 'text-1', $name, 'wp_widget_text_control', $control_ops, array( 'number' => -1 ) ); + } + + foreach ( array_keys($options) as $o ) { + // Old widgets can have null values for some reason + if ( !isset($options[$o]['title']) || !isset($options[$o]['text']) ) + continue; + $id = "text-$o"; // Never never never translate an id + wp_register_sidebar_widget($id, $name, 'wp_widget_text', $widget_ops, array( 'number' => $o )); + wp_register_widget_control($id, $name, 'wp_widget_text_control', $control_ops, array( 'number' => $o )); } - add_action('sidebar_admin_setup', 'wp_widget_text_setup'); - add_action('sidebar_admin_page', 'wp_widget_text_page'); } -function wp_widget_categories($args, $number = 1) { - extract($args); +// See large comment section at end of this file +function wp_widget_categories($args, $widget_args = 1) { + extract($args, EXTR_SKIP); + if ( is_numeric($widget_args) ) + $widget_args = array( 'number' => $widget_args ); + $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); + extract($widget_args, EXTR_SKIP); + $options = get_option('widget_categories'); + if ( !isset($options[$number]) ) + return; $c = $options[$number]['count'] ? '1' : '0'; $h = $options[$number]['hierarchical'] ? '1' : '0'; @@ -635,7 +684,8 @@ function wp_widget_categories($args, $number = 1) { wp_dropdown_categories($cat_args . '&show_option_none= ' . __('Select Category')); ?> - +/* ]]> */ + $widget_args ); + $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); + extract($widget_args, EXTR_SKIP); - if ( $_POST['categories-submit-' . $number] ) { - $newoptions[$number]['count'] = isset($_POST['categories-count-' . $number]); - $newoptions[$number]['hierarchical'] = isset($_POST['categories-hierarchical-' . $number]); - $newoptions[$number]['dropdown'] = isset($_POST['categories-dropdown-' . $number]); - $newoptions[$number]['title'] = strip_tags(stripslashes($_POST['categories-title-' . $number])); - } + $options = get_option('widget_categories'); + + if ( !is_array( $options ) ) + $options = array(); + + if ( !$updated && !empty($_POST['sidebar']) ) { + $sidebar = (string) $_POST['sidebar']; + + $sidebars_widgets = wp_get_sidebars_widgets(); + if ( isset($sidebars_widgets[$sidebar]) ) + $this_sidebar =& $sidebars_widgets[$sidebar]; + else + $this_sidebar = array(); + + foreach ( $this_sidebar as $_widget_id ) { + if ( 'wp_widget_categories' == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) { + $widget_number = $wp_registered_widgets[$_widget_id]['params'][0]['number']; + unset($options[$widget_number]); + } + } + + foreach ( (array) $_POST['widget-categories'] as $widget_number => $widget_cat ) { + $title = trim(strip_tags(stripslashes($widget_cat['title']))); + $count = isset($widget_cat['count']); + $hierarchical = isset($widget_cat['hierarchical']); + $dropdown = isset($widget_cat['dropdown']); + $options[$widget_number] = compact( 'title', 'count', 'hierarchical', 'dropdown' ); + } - if ( $options != $newoptions ) { - $options = $newoptions; update_option('widget_categories', $options); + $updated = true; } - $title = attribute_escape( $options[$number]['title'] ); + if ( -1 == $number ) { + $title = ''; + $count = false; + $hierarchical = false; + $dropdown = false; + $number = '%i%'; + } else { + $title = attribute_escape( $options[$number]['title'] ); + $count = (bool) $options[$number]['count']; + $hierarchical = (bool) $options[$number]['hierarchical']; + $dropdown = (bool) $options[$number]['dropdown']; + } ?> -

    +

    + +

    -

    - -

    - -

    +

    + +
    + +
    + +

    9 ) { - $number = 9; - } elseif ( $number < 1 ) { - $number = 1; - } - - $newoptions['number'] = $number; - } - - if ( $newoptions != $options ) { - $options = $newoptions; - update_option( 'widget_categories', $options ); - wp_widget_categories_register( $options['number'] ); - } -} - -function wp_widget_categories_page() { +function wp_widget_categories_register() { $options = get_option( 'widget_categories' ); -?> -
    -
    -

    -

    - - - - -

    -
    -
    - 'widget_categories', 'description' => __( "A list or dropdown of categories" ) ); + + $name = __( 'Categories' ); + + // If there are none, we register the widget's existance with a generic template + if ( !$options ) { + wp_register_sidebar_widget( 'categories-1', $name, 'wp_widget_categories', $widget_ops, array( 'number' => -1 ) ); + wp_register_widget_control( 'categories-1', $name, 'wp_widget_categories_control', array( 'id_base' => 'categories' ), array( 'number' => -1 ) ); + } + + foreach ( array_keys($options) as $o ) { + // Old widgets can have null values for some reason + if ( !isset($options[$o]['title']) ) + continue; + $id = "categories-$o"; + wp_register_sidebar_widget( $id, $name, 'wp_widget_categories', $widget_ops, array( 'number' => $o ) ); + wp_register_widget_control( $id, $name, 'wp_widget_categories_control', array( 'id_base' => 'categories' ), array( 'number' => $o ) ); + } + } function wp_widget_categories_upgrade() { $options = get_option( 'widget_categories' ); - $newoptions = array( 'number' => 1, 1 => $options ); + if ( !isset( $options['title'] ) ) + return $options; + + $newoptions = array( 1 => $options ); update_option( 'widget_categories', $newoptions ); @@ -764,50 +841,9 @@ function wp_widget_categories_upgrade() { update_option( 'sidebars_widgets', $new_widgets ); } - if ( isset( $_POST['categories-submit'] ) ) { - $_POST['categories-submit-1'] = $_POST['categories-submit']; - $_POST['categories-count-1'] = $_POST['categories-count']; - $_POST['categories-hierarchical-1'] = $_POST['categories-hierarchical']; - $_POST['categories-dropdown-1'] = $_POST['categories-dropdown']; - $_POST['categories-title-1'] = $_POST['categories-title']; - foreach ( $_POST as $k => $v ) - if ( substr($k, -5) == 'order' ) - $_POST[$k] = str_replace('categories', 'categories-1', $v); - } - return $newoptions; } -function wp_widget_categories_register() { - $options = get_option( 'widget_categories' ); - if ( !isset($options['number']) ) - $options = wp_widget_categories_upgrade(); - $number = (int) $options['number']; - - if ( $number > 9 ) { - $number = 9; - } elseif ( $number < 1 ) { - $number = 1; - } - - $dims = array( 'width' => 350, 'height' => 170 ); - $class = array( 'classname' => 'widget_categories' ); - - for ( $i = 1; $i <= 9; $i++ ) { - $name = sprintf( __( 'Categories %d' ), $i ); - $id = 'categories-' . $i; - - $widget_callback = ( $i <= $number ) ? 'wp_widget_categories' : ''; - $control_callback = ( $i <= $number ) ? 'wp_widget_categories_control' : ''; - - wp_register_sidebar_widget( $id, $name, $widget_callback, $class, $i ); - wp_register_widget_control( $id, $name, $control_callback, $dims, $i ); - } - - add_action( 'sidebar_admin_setup', 'wp_widget_categories_setup' ); - add_action( 'sidebar_admin_page', 'wp_widget_categories_page' ); -} - function wp_widget_recent_entries($args) { if ( $output = wp_cache_get('widget_recent_entries') ) return print($output); @@ -861,8 +897,13 @@ function wp_widget_recent_entries_control() { if ( !$number = (int) $options['number'] ) $number = 5; ?> -

    -

    + +

    +

    + +
    + +

    -

    -

    +

    +

    + +
    + +

    320, 'height' => 90); - $class = array('classname' => 'widget_recent_comments'); - wp_register_sidebar_widget('recent-comments', __('Recent Comments'), 'wp_widget_recent_comments', $class); - wp_register_widget_control('recent-comments', __('Recent Comments'), 'wp_widget_recent_comments_control', $dims); + $widget_ops = array('classname' => 'widget_recent_comments', 'description' => __( 'The most recent comments' ) ); + wp_register_sidebar_widget('recent-comments', __('Recent Comments'), 'wp_widget_recent_comments', $widget_ops); + wp_register_widget_control('recent-comments', __('Recent Comments'), 'wp_widget_recent_comments_control'); if ( is_active_widget('wp_widget_recent_comments') ) add_action('wp_head', 'wp_widget_recent_comments_style'); } -function wp_widget_rss($args, $number = 1) { - require_once(ABSPATH . WPINC . '/rss.php'); - extract($args); +// See large comment section at end of this file +function wp_widget_rss($args, $widget_args = 1) { + extract($args, EXTR_SKIP); + if ( is_numeric($widget_args) ) + $widget_args = array( 'number' => $widegt_args ); + $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); + extract($widget_args, EXTR_SKIP); + $options = get_option('widget_rss'); - if ( isset($options['error']) && $options['error'] ) + + if ( !isset($options[$number]) ) return; + + if ( isset($options[$number]['error']) && $options[$number]['error'] ) + return; + $num_items = (int) $options[$number]['items']; $show_summary = $options[$number]['show_summary']; if ( empty($num_items) || $num_items < 1 || $num_items > 10 ) $num_items = 10; @@ -952,6 +1006,9 @@ function wp_widget_rss($args, $number = 1) { $url = substr($url, 1); if ( empty($url) ) return; + + require_once(ABSPATH . WPINC . '/rss.php'); + $rss = fetch_rss($url); $link = clean_url(strip_tags($rss->channel['link'])); while ( strstr($link, 'http') != $link ) @@ -1002,88 +1059,123 @@ function wp_widget_rss($args, $number = 1) { echo $after_widget; } -function wp_widget_rss_control($number) { - $options = $newoptions = get_option('widget_rss'); - if ( $_POST["rss-submit-$number"] ) { - $newoptions[$number]['items'] = (int) $_POST["rss-items-$number"]; - $url = sanitize_url(strip_tags(stripslashes($_POST["rss-url-$number"]))); - $newoptions[$number]['title'] = trim(strip_tags(stripslashes($_POST["rss-title-$number"]))); - if ( $url !== $options[$number]['url'] ) { - require_once(ABSPATH . WPINC . '/rss.php'); - $rss = fetch_rss($url); - if ( is_object($rss) ) { - $newoptions[$number]['url'] = $url; - $newoptions[$number]['error'] = false; - } else { - $newoptions[$number]['error'] = true; - $newoptions[$number]['url'] = wp_specialchars(__('Error: could not find an RSS or ATOM feed at that URL.'), 1); +function wp_widget_rss_control($widget_args) { + global $wp_registered_widgets; + static $updated = false; + + if ( is_numeric($widget_args) ) + $widget_args = array( 'number' => $widget_args ); + $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); + extract($widget_args, EXTR_SKIP); + + $options = get_option('widget_rss'); + if ( !is_array($options) ) + $options = array(); + + $urls = array(); + foreach ( $options as $option ) + if ( isset($option['url']) ) + $urls[$option['url']] = true; + + if ( !$updated && !empty($_POST['sidebar']) ) { + $sidebar = (string) $_POST['sidebar']; + + $sidebars_widgets = wp_get_sidebars_widgets(); + if ( isset($sidebars_widgets[$sidebar]) ) + $this_sidebar =& $sidebars_widgets[$sidebar]; + else + $this_sidebar = array(); + + foreach ( $this_sidebar as $_widget_id ) { + if ( 'wp_widget_rss' == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) { + $widget_number = $wp_registered_widgets[$_widget_id]['params'][0]['number']; + unset($options[$widget_number]); } } - } - if ( $options != $newoptions ) { - $options = $newoptions; - update_option('widget_rss', $options); - } - $url = attribute_escape($options[$number]['url']); - $items = (int) $options[$number]['items']; - $title = attribute_escape($options[$number]['title']); - if ( empty($items) || $items < 1 ) $items = 10; -?> -

    - " name="rss-url-" type="text" value="" /> -

    - " name="rss-title-" type="text" value="" /> -

    - " name="rss-submit-" value="1" /> - 9 ) $number = 9; - if ( $number < 1 ) $number = 1; - $newoptions['number'] = $number; - } - if ( $options != $newoptions ) { - $options = $newoptions; - update_option('widget_rss', $options); - wp_widget_rss_register($options['number']); - } -} + foreach( (array) $_POST['widget-rss'] as $widget_number => $widget_rss ) { + $items = (int) $widget_rss['items']; + if ( $items < 1 ) + $items = 10; + $url = sanitize_url(strip_tags(stripslashes($widget_rss['url']))); + $title = trim(strip_tags(stripslashes($widget_rss['title']))); + + if ( !isset($urls[$url]) ) { + require_once(ABSPATH . WPINC . '/rss.php'); + $rss = fetch_rss($url); + $error = false; + if ( !is_object($rss) ) { + $url = wp_specialchars(__('Error: could not find an RSS or ATOM feed at that URL.'), 1); + $error = sprintf(__('Error in RSS %1$d'), $widget_number ); + } + } + $options[$widget_number] = compact( 'title', 'url', 'items', 'error' ); + } + + update_option('widget_rss', $options); + $updated = true; + } + + if ( -1 == $number ) { + $title = ''; + $url = ''; + $items = 10; + $error = false; + $number = '%i%'; + } else { + $title = attribute_escape($options[$number]['title']); + $url = attribute_escape($options[$number]['url']); + $items = (int) $options[$number]['items']; + if ( $items < 1 ) + $items = 10; + $error = $options[$number]['error']; + } -function wp_widget_rss_page() { - $options = get_option('widget_rss'); ?> -
    -
    -

    -

    - -

    -
    -
    +

    + +

    +

    + +

    +

    + +

    + 9 ) $number = 9; - $dims = array('width' => 410, 'height' => 200); - $class = array('classname' => 'widget_rss'); - for ($i = 1; $i <= 9; $i++) { - $name = sprintf(__('RSS %d'), $i); - $id = "rss-$i"; // Never never never translate an id - wp_register_sidebar_widget($id, $name, $i <= $number ? 'wp_widget_rss' : /* unregister */ '', $class, $i); - wp_register_widget_control($id, $name, $i <= $number ? 'wp_widget_rss_control' : /* unregister */ '', $dims, $i); + $widget_ops = array('classname' => 'widget_rss', 'description' => __( 'Entries from any RSS or Atom feed' )); + $control_ops = array('width' => 410, 'height' => 200, 'id_base' => 'rss'); + $name = __('RSS'); + + // If there are none, we register the widget's existance with a generic template + if ( !$options ) { + wp_register_sidebar_widget( 'rss-1', $name, 'wp_widget_rss', $widget_ops, array( 'number' => -1 ) ); + wp_register_widget_control( 'rss-1', $name, 'wp_widget_rss_control', $control_ops, array( 'number' => -1 ) ); + } + + foreach ( array_keys($options) as $o ) { + // Old widgets can have null values for some reason + if ( !isset($options[$o]['url']) || !isset($options[$o]['title']) || !isset($options[$o]['items']) ) + contine; + $id = "rss-$o"; // Never never never translate an id + wp_register_sidebar_widget($id, $name, 'wp_widget_rss', $widget_ops, array( 'number' => $o )); + wp_register_widget_control($id, $name, 'wp_widget_rss_control', $control_ops, array( 'number' => $o )); } - add_action('sidebar_admin_setup', 'wp_widget_rss_setup'); - add_action('sidebar_admin_page', 'wp_widget_rss_page'); } function wp_widget_tag_cloud($args) { @@ -1112,7 +1204,7 @@ function wp_widget_tag_cloud_control() { $title = attribute_escape( $options['title'] ); ?>

    +

    'widget_pages', 'description' => __( "Your blog's WordPress Pages") ); + wp_register_sidebar_widget('pages', __('Pages'), 'wp_widget_pages', $widget_ops); + wp_register_widget_control('pages', __('Pages'), 'wp_widget_pages_control' ); - $dims90 = array( 'height' => 90, 'width' => 300 ); - $dims100 = array( 'height' => 100, 'width' => 300 ); - $dims150 = array( 'height' => 150, 'width' => 300 ); + $widget_ops = array('classname' => 'widget_calendar', 'description' => __( "A calendar of your blog's posts") ); + wp_register_sidebar_widget('calendar', __('Calendar'), 'wp_widget_calendar', $widget_ops); + wp_register_widget_control('calendar', __('Calendar'), 'wp_widget_calendar_control' ); - $class = array('classname' => 'widget_pages'); - wp_register_sidebar_widget('pages', __('Pages'), 'wp_widget_pages', $class); - wp_register_widget_control('pages', __('Pages'), 'wp_widget_pages_control', $dims150); + $widget_ops = array('classname' => 'widget_archive', 'description' => __( "A monthly archive of your blog's posts") ); + wp_register_sidebar_widget('archives', __('Archives'), 'wp_widget_archives', $widget_ops); + wp_register_widget_control('archives', __('Archives'), 'wp_widget_archives_control' ); - $class['classname'] = 'widget_calendar'; - wp_register_sidebar_widget('calendar', __('Calendar'), 'wp_widget_calendar', $class); - wp_register_widget_control('calendar', __('Calendar'), 'wp_widget_calendar_control', $dims90); + $widget_ops = array('classname' => 'widget_links', 'description' => __( "Your blogroll") ); + wp_register_sidebar_widget('links', __('Links'), 'wp_widget_links', $widget_ops); - $class['classname'] = 'widget_archives'; - wp_register_sidebar_widget('archives', __('Archives'), 'wp_widget_archives', $class); - wp_register_widget_control('archives', __('Archives'), 'wp_widget_archives_control', $dims100); + $widget_ops = array('classname' => 'widget_meta', 'description' => __( "Log in/out, admin, feed and WordPress links") ); + wp_register_sidebar_widget('meta', __('Meta'), 'wp_widget_meta', $widget_ops); + wp_register_widget_control('meta', __('Meta'), 'wp_widget_meta_control' ); - $class['classname'] = 'widget_links'; - wp_register_sidebar_widget('links', __('Links'), 'wp_widget_links', $class); + $widget_ops = array('classname' => 'widget_search', 'description' => __( "A search form for your blog") ); + wp_register_sidebar_widget('search', __('Search'), 'wp_widget_search', $widget_ops); - $class['classname'] = 'widget_meta'; - wp_register_sidebar_widget('meta', __('Meta'), 'wp_widget_meta', $class); - wp_register_widget_control('meta', __('Meta'), 'wp_widget_meta_control', $dims90); + $widget_ops = array('classname' => 'widget_recent_entries', 'description' => __( "The most recent posts on your blog") ); + wp_register_sidebar_widget('recent-posts', __('Recent Posts'), 'wp_widget_recent_entries', $widget_ops); + wp_register_widget_control('recent-posts', __('Recent Posts'), 'wp_widget_recent_entries_control' ); - $class['classname'] = 'widget_search'; - wp_register_sidebar_widget('search', __('Search'), 'wp_widget_search', $class); - - $class['classname'] = 'widget_recent_entries'; - wp_register_sidebar_widget('recent-posts', __('Recent Posts'), 'wp_widget_recent_entries', $class); - wp_register_widget_control('recent-posts', __('Recent Posts'), 'wp_widget_recent_entries_control', $dims90); - - $class['classname'] = 'widget_tag_cloud'; - wp_register_sidebar_widget('tag_cloud', __('Tag Cloud'), 'wp_widget_tag_cloud', $class); - wp_register_widget_control('tag_cloud', __('Tag Cloud'), 'wp_widget_tag_cloud_control', 'width=300&height=160'); + $widget_ops = array('classname' => 'widget_tag_cloud', 'description' => __( "Your most used tags in cloud format") ); + wp_register_sidebar_widget('tag_cloud', __('Tag Cloud'), 'wp_widget_tag_cloud', $widget_ops); + wp_register_widget_control('tag_cloud', __('Tag Cloud'), 'wp_widget_tag_cloud_control' ); wp_widget_categories_register(); wp_widget_text_register(); wp_widget_rss_register(); wp_widget_recent_comments_register(); - $GLOBALS['wp_register_widget_defaults'] = false; - do_action('widgets_init'); } add_action('init', 'wp_widgets_init', 1); +/* Pattern for widget which allows multiple instances (such as the text widget) + +// Displays widget on blag +// $widget_args: number +// number: which of the several widgets of this type do we mean +function widget_many( $args, $widget_args = 1 ) { + extract( $args, EXTR_SKIP ); + if ( is_numeric($widget_args) ) + $widget_args = array( 'number' => $widget_args ); + $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); + extract( $widget_args, EXTR_SKIP ); + + // Data should be stored as array: array( number => data for that instance of the widget, ... ) + $options = get_option('widget_many'); + if ( !isset($options[$number]) ) + return; + + echo $before_widget; + + // Do stuff for this widget, drawing data from $options[$number] + + echo $after_widget; +} + +// Displays form for a particular instance of the widget. Also updates the data after a POST submit +// $widget_args: number +// number: which of the several widgets of this type do we mean +function widget_many_control( $widget_args = 1 ) { + global $wp_registered_widgets; + static $updated = false; // Whether or not we have already updated the data after a POST submit + + if ( is_numeric($widget_args) ) + $widget_args = array( 'number' => $widget_args ); + $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) ); + extract( $widget_args, EXTR_SKIP ); + + // Data should be stored as array: array( number => data for that instance of the widget, ... ) + $options = get_option('widget_many'); + if ( !is_array($options) ) + $options = array(); + + // We need to update the data + if ( !$updated && !empty($_POST['sidebar']) ) { + // Tells us what sidebar to put the data in + $sidebar = (string) $_POST['sidebar']; + + $sidebars_widgets = wp_get_sidebars_widgets(); + if ( isset($sidebars_widgets[$sidebar]) ) + $this_sidebar =& $sidebars_widgets[$sidebar]; + else + $this_sidebar = array(); + + foreach ( $this_sidebar as $_widget_id ) { + // Remove all widgets of this type from the sidebar. We'll add the new data in a second. This makes sure we don't get any duplicate data + // since widget ids aren't necessarily persistent across multiple updates + if ( 'widget_many' == $wp_registered_widgets[$_widget_id]['callback'] && isset($wp_registered_widgets[$_widget_id]['params'][0]['number']) ) { + $widget_number = $wp_registered_widgets[$_widget_id]['params'][0]['number']; + unset($options[$widget_number]); + } + } + + foreach ( (array) $_POST['widget-many'] as $widget_number => $widget_many_instance ) { + // compile data from $widget_many_instance + $something = wp_specialchars( $widget_many_instance['something'] ); + $options[$widget_number] = array( 'something' => $something ); // Even simple widgets should store stuff in array, rather than in scalar + } + + update_option('widget_text', $options); + + $updated = true; // So that we don't go through this more than once + } + + + // Here we echo out the form + if ( -1 == $number ) { // We echo out a template for a form which can be converted to a specific form later via JS + $something = ''; + $number = '%i%'; + } else { + $something = attribute_escape($options[$number]['something']); + } + + // The form has inputs with names like widget-many[$number][something] so that all data for that instance of + // the widget are stored in one $_POST variable: $_POST['widget-many'][$number] +?> +

    + + +

    + 'widget_many', 'description' => __('Widget which allows multiple instances')); + $control_ops = array('width' => 400, 'height' => 350, 'id_base' => 'many'); + $name = __('Many'); + + // If there are none, we register the widget's existance with a generic template + if ( !$options ) { + wp_register_sidebar_widget( 'many-1', $name, 'widget_many', $widget_ops, array( 'number' => -1 ) ); + wp_register_widget_control( 'many-1', $name, 'widget_many_control', $control_ops, array( 'number' => -1 ) ); + } + + foreach ( array_keys($options) as $o ) { + // Old widgets can have null values for some reason + if ( !isset($options[$o]['something']) ) // we used 'something' above in our exampple. Replace with with whatever your real data are. + continue; + + // $id should look like {$id_base}-{$o} + $id = "many-$o"; // Never never never translate an id + wp_register_sidebar_widget( $id, $name, 'wp_widget_text', $widget_ops, array( 'number' => $o ) ); + wp_register_widget_control( $id, $name, 'wp_widget_text_control', $control_ops, array( 'number' => $o ) ); + } +} + +// This is important +add_action( 'widgets_init', 'widget_many_register' ) + +*/ + ?>