ड्रैग-एंड-ड्रॉप (WP सेव बग) के बाद विजेट फॉर्म अपडेट करें


15

मैंने इस बारे में कुछ महीने पहले (बग के बारे में एक रिपोर्ट पोस्ट किया है। वर्डप्रेस ट्रैक (विजेट इंस्टेंस फॉर्म अपडेट बग) पर ) और मैंने सोचा कि मैं इसके बारे में भी यहां लिखने की कोशिश करूंगा। हो सकता है कि किसी के पास इस मुद्दे का मुझसे बेहतर समाधान हो।

मूल रूप से समस्या यह है कि यदि आप किसी विजेट को साइडबार में छोड़ते हैं, तो विजेट फॉर्म तब तक अपडेट नहीं होता है जब तक आप मैन्युअल रूप से सेव (या पेज को पुनः लोड नहीं करते) दबाते हैं।

यह form()फंक्शन से सभी कोड को बेकार कर देता है जो विजेट इंस्टेंस आईडी पर निर्भर करता है कि आप कुछ कर सकते हैं (जब तक आप सेव बटन दबाते हैं)। Ajax रिक्वेस्ट जैसे कोई भी सामान, colorpickers जैसी jQuery की चीजें वगैरह एकदम से काम नहीं करेंगी, क्योंकि उस फंक्शन से ऐसा लगेगा कि विजेट इंस्टेंस अभी इनिशियलाइज़ नहीं हुआ है।

गंदे फिक्स को लाइव बटन की तरह उपयोग करके स्वचालित रूप से सेव बटन को ट्रिगर करना होगा :

$("#widgets-right .needfix").livequery(function(){
  var widget = $(this).closest('div.widget');
  wpWidgets.save(widget, 0, 1, 0);
  return false;
});

और यदि विजेट उदाहरण इनिशियलाइज़ नहीं दिखता है तो .needfixक्लास जोड़ें form():

 <div <?php if(!is_numeric($this->number)): ?>class="needfix"<?php endif; ?>
   ...
 </div>

इस समाधान का एक दोष यह है कि यदि आपके पास बहुत सारे विगेट्स पंजीकृत हैं, तो ब्राउज़र बहुत सारे सीपीयू खाएगा, क्योंकि डोम के लिए लाइवक्वेरी चेक हर सेकंड बदलता है (यद्यपि मैंने विशेष रूप से इसका परीक्षण नहीं किया था, यह सिर्फ मेरी धारणा है :)

बग को ठीक करने के बेहतर तरीके के लिए कोई सुझाव?


एक पूर्ण सहेजें सबमिट को ट्रिगर करने के बजाय, क्या यह देखने के लिए अधिक समझ में नहीं आएगा कि आवश्यक आईडी प्रदान करने के लिए सहेजें बटन दबाने से क्या होता है, उस कोड को अलग करें और इसके बजाय ड्रॉपिंग ऑपरेशन के अंत में कॉल करें?
हकर्रे

जवाबों:


5

मैंने हाल ही में इसी तरह की स्थिति के साथ लड़ाई की थी। विगेट्स में अजाक्स कोई मजाक नहीं है! उदाहरणों में काम करने के लिए कुछ सुंदर पागल कोड लिखने की आवश्यकता है। मैं लाइव क्वेरी से परिचित नहीं हूं, लेकिन यदि आप कहते हैं कि यह हर सेकंड DOM की जांच करता है, तो मेरे पास आपके लिए कम गहन समाधान हो सकता है:

var get_widget_id = function ( selector ) {
    var selector, widget_id = false;
    var id_attr = $( selector ).closest( 'form' ).find( 'input[name="widget-id"]' ).val();
    if ( typeof( id_attr ) != 'undefined' ) {
        var parts = id_attr.split( '-' );
        widget_id = parts[parts.length-1];
    }
    return parseInt( widget_id );
};

आप इस फ़ंक्शन को एक चयनकर्ता या jQuery ऑब्जेक्ट पास कर सकते हैं और यह वर्तमान उदाहरण की इंस्टेंस आईडी वापस कर देगा। मैं इस मुद्दे के आसपास कोई अन्य रास्ता नहीं खोज सका। सुनकर खुशी हुई कि मैं अकेला नहीं हूं :)


7

मुझे अपने स्वयं के प्रश्न का उत्तर देना पसंद नहीं है, लेकिन मुझे लगता है कि यह अब तक का सबसे अच्छा समाधान है:

$('#widgets-right').ajaxComplete(function(event, XMLHttpRequest, ajaxOptions){

  // determine which ajax request is this (we're after "save-widget")
  var request = {}, pairs = ajaxOptions.data.split('&'), i, split, widget;

  for(i in pairs){
    split = pairs[i].split('=');
    request[decodeURIComponent(split[0])] = decodeURIComponent(split[1]);
  }

  // only proceed if this was a widget-save request
  if(request.action && (request.action === 'save-widget')){

    // locate the widget block
    widget = $('input.widget-id[value="' + request['widget-id'] + '"]').parents('.widget');

    // trigger manual save, if this was the save request 
    // and if we didn't get the form html response (the wp bug)
    if(!XMLHttpRequest.responseText)
      wpWidgets.save(widget, 0, 1, 0);

    // we got an response, this could be either our request above,
    // or a correct widget-save call, so fire an event on which we can hook our js
    else
      $(document).trigger('saved_widget', widget);

  }

});

यह विजेट-सेव अजाक्स अनुरोध को आग देगा, बस एक विजेट-बचाने के अनुरोध के पूरा होने के बाद (यदि फॉर्म html के साथ कोई प्रतिक्रिया नहीं थी)।

इसे jQuery(document).ready()फंक्शन में शामिल करने की आवश्यकता है ।

अब, यदि आप आसानी से अपने जावास्क्रिप्ट फ़ंक्शंस को नए डोम तत्वों से जोड़ना चाहते हैं, जिसे विजेट फॉर्म फ़ंक्शन द्वारा जोड़ा गया है, तो उन्हें "save_widget" ईवेंट में बाँध दें:

$(document).bind('saved_widget', function(event, widget){
  // For example: $(widget).colorpicker() ....
});

3
ध्यान दें कि jQuery 1.8 के रूप में, .ajaxComplete () विधि केवल दस्तावेज़ से जुड़ी होनी चाहिए। - api.jquery.com/ajaxComplete इस प्रकार आपके स्निपेट की पहली पंक्ति को पढ़ना चाहिए: $ (दस्तावेज़) ।ajaxComplete (फ़ंक्शन (घटना, XMLHttpRequest, ajaxOptions)) WP 3.6+ के लिए कम से कम
डेविड लॉंग

3

हाल ही में भाग गया और ऐसा लगता है कि पारंपरिक "widgets.php" इंटरफ़ेस में किसी भी जावास्क्रिप्ट इनिशियलाइज़ेशन को मौजूदा विगेट्स (उन #widgets-rightडिव में) के लिए सीधे चलाया जाना चाहिए , और अप्रत्यक्ष रूप से widget-addedनए जोड़े गए विगेट्स के लिए इवेंट के माध्यम से ; हालांकि कस्टमाइज़र "custom.php" इंटरफ़ेस में सभी विजेट - मौजूदा और नए - को widget-addedघटना को भेजा जाता है, इसलिए वहां केवल आरंभ किया जा सकता है। इसके आधार पर निम्न WP_Widgetवर्ग का एक विस्तार है जो एक फ़ंक्शन को ओवरराइड करके विजेट के रूप में जावास्क्रिप्ट आरंभ को जोड़ना आसान बनाता है form_javascript_init():

class WPSE_JS_Widget extends WP_Widget { // For widgets using javascript in form().
    var $js_ns = 'wpse'; // Javscript namespace.
    var $js_init_func = ''; // Name of javascript init function to call. Initialized in constructor.
    var $is_customizer = false; // Whether in customizer or not. Set on 'load-customize.php' action (if any).

    public function __construct( $id_base, $name, $widget_options = array(), $control_options = array(), $js_ns = '' ) {
        parent::__construct( $id_base, $name, $widget_options, $control_options );
        if ( $js_ns ) {
            $this->js_ns = $js_ns;
        }
        $this->js_init_func = $this->js_ns . '.' . $this->id_base . '_init';
        add_action( 'load-widgets.php', array( $this, 'load_widgets_php' ) );
        add_action( 'load-customize.php', array( $this, 'load_customize_php' ) );
    }

    // Called on 'load-widgets.php' action added in constructor.
    public function load_widgets_php() {
        add_action( 'in_widget_form', array( $this, 'form_maybe_call_javascript_init' ) );
        add_action( 'admin_print_scripts', array( $this, 'admin_print_scripts' ), PHP_INT_MAX );
    }

    // Called on 'load-customize.php' action added in constructor.
    public function load_customize_php() {
        $this->is_customizer = true;
        // Don't add 'in_widget_form' action as customizer sends 'widget-added' event to existing widgets too.
        add_action( 'admin_print_scripts', array( $this, 'admin_print_scripts' ), PHP_INT_MAX );
    }

    // Form javascript initialization code here. "widget" and "widget_id" available.
    public function form_javascript_init() {
    }

    // Called on 'in_widget_form' action (ie directly after form()) when in traditional widgets interface.
    // Run init directly unless we're newly added.
    public function form_maybe_call_javascript_init( $callee_this ) {
        if ( $this === $callee_this && '__i__' !== $this->number ) {
            ?>
            <script type="text/javascript">
            jQuery(function ($) {
                <?php echo $this->js_init_func; ?>(null, $('#widgets-right [id$="<?php echo $this->id; ?>"]'));
            });
            </script>
            <?php
        }
    }

    // Called on 'admin_print_scripts' action added in constructor.
    public function admin_print_scripts() {
        ?>
        <script type="text/javascript">
        var <?php echo $this->js_ns; ?> = <?php echo $this->js_ns; ?> || {}; // Our namespace.
        jQuery(function ($) {
            <?php echo $this->js_init_func; ?> = function (e, widget) {
                var widget_id = widget.attr('id');
                if (widget_id.search(/^widget-[0-9]+_<?php echo $this->id_base; ?>-[0-9]+$/) === -1) { // Check it's our widget.
                    return;
                }
                <?php $this->form_javascript_init(); ?>
            };
            $(document).on('widget-added', <?php echo $this->js_init_func; ?>); // Call init on widget add.
        });
        </script>
        <?php
    }
}

इसका उपयोग करके एक उदाहरण परीक्षण विजेट:

class WPSE_Test_Widget extends WPSE_JS_Widget {
    var $defaults; // Form defaults. Initialized in constructor.

    function __construct() {
        parent::__construct( 'wpse_test_widget', __( 'WPSE: Test Widget' ), array( 'description' => __( 'Test init of javascript.' ) ) );
        $this->defaults = array(
            'one' => false,
            'two' => false,
            'color' => '#123456',
        );
        add_action( 'admin_enqueue_scripts', function ( $hook_suffix ) {
            if ( ! in_array( $hook_suffix, array( 'widgets.php', 'customize.php' ) ) ) return;
            wp_enqueue_script( 'wp-color-picker' ); wp_enqueue_style( 'wp-color-picker' );
        } );
    }

    function widget( $args, $instance ) {
        extract( $args );
        extract( wp_parse_args( $instance, $this->defaults ) );

        echo $before_widget, '<p style="color:', $color, ';">', $two ? 'Two' : ( $one ? 'One' : 'None' ), '</p>', $after_widget;
    }

    function update( $new_instance, $old_instance ) {
        $new_instance['one'] = isset( $new_instance['one'] ) ? 1 : 0;
        $new_instance['two'] = isset( $new_instance['two'] ) ? 1 : 0;
        return $new_instance;
    }

    function form( $instance ) {
        extract( wp_parse_args( $instance, $this->defaults ) );
        ?>
        <div class="wpse_test">
            <p class="one">
                <input class="checkbox" type="checkbox" <?php checked( $one ); disabled( $two ); ?> id="<?php echo $this->get_field_id( 'one' ); ?>" name="<?php echo $this->get_field_name( 'one' ); ?>" />
                <label for="<?php echo $this->get_field_id( 'one' ); ?>"><?php _e( 'One?' ); ?></label>
            </p>
            <p class="two">
                <input class="checkbox" type="checkbox" <?php checked( $two ); disabled( $one ); ?> id="<?php echo $this->get_field_id( 'two' ); ?>" name="<?php echo $this->get_field_name( 'two' ); ?>" />
                <label for="<?php echo $this->get_field_id( 'two' ); ?>"><?php _e( 'Two?' ); ?></label>
            </p>
            <p class="color">
                <input type="text" value="<?php echo htmlspecialchars( $color ); ?>" id="<?php echo $this->get_field_id( 'color' ); ?>" name="<?php echo $this->get_field_name( 'color' ); ?>" />
            </p>
        </div>
        <?php
    }

    // Form javascript initialization code here. "widget" and "widget_id" available.
    function form_javascript_init() {
        ?>
            $('.one input', widget).change(function (event) { $('.two input', widget).prop('disabled', this.checked); });
            $('.two input', widget).change(function (event) { $('.one input', widget).prop('disabled', this.checked); });
            $('.color input', widget).wpColorPicker({
                <?php if ( $this->is_customizer ) ?> change: _.throttle( function () { $(this).trigger('change'); }, 1000, {leading: false} )
            });
        <?php
    }
}

add_action( 'widgets_init', function () {
    register_widget( 'WPSE_Test_Widget' );
} );

2

मुझे लगता है कि Wordpress 3.9 में कुछ मौजूद है जो आपकी मदद कर सकता है। यह विजेट-अपडेटेड कॉलबैक है। इसे इस तरह से उपयोग करें (कॉफ़ीस्क्रिप्ट):

$(document).on 'widget-updated', (event, widget) ->
    doWhatINeed() if widget[0].id.match(/my_widget_name/)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.