টেনে আনুন এবং ছাড়ার পরে উইজেট ফর্মটি আপডেট করুন (ডাব্লুপি সেভ বাগ)


15

আমি কয়েক মাস আগে এটি সম্পর্কে একটি বাগ-প্রতিবেদন পোস্ট করেছি ( ওয়ার্ডপ্রেস ট্র্যাকে (উইজেট ইনস্ট্যান্স ফর্ম আপডেট বাগ) ) এবং আমি ভেবেছিলাম যে আমি এটি সম্পর্কে এখানে লেখার চেষ্টা করব। আমার চেয়ে কারও কাছে এই ইস্যুটির আরও ভাল সমাধান হতে পারে।

মূলত সমস্যাটি হ'ল যদি আপনি কোনও উইজেটকে একটি সাইডবারে ফেলে দেন তবে আপনি নিজে নিজে সেভ টিপুন (বা পৃষ্ঠাটি পুনরায় লোড করুন) অবধি উইজেট ফর্মটি আপডেট হবে না।

এটি form()ফাংশন থেকে সমস্ত কোড অকেজো করে তোলে যা কিছু করার জন্য উইজেট উদাহরণ আইডির উপর নির্ভর করে (যতক্ষণ না আপনি সেভ বোতাম টিপেন)। এজাক্স অনুরোধগুলির মতো যে কোনও স্টাফ, রঙিন পিকারগুলির মতো 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>

এই সমাধানটির একটি অসুবিধা হ'ল যদি আপনার প্রচুর উইজেটগুলি নিবন্ধিত হয় তবে ব্রাউজারটি প্রচুর সিপিইউ খায়, কারণ ডমসের জন্য লাইভক্যারি চেক প্রতি সেকেন্ডে পরিবর্তিত হয় (আমি এটি নির্দিষ্টভাবে পরীক্ষা করিনি, এটি কেবল আমার অনুমান :)

বাগ ঠিক করার আরও ভাল উপায়ের জন্য কোনও পরামর্শ?


একটি পূর্ণ সেভ জমাটি ট্রিগার করার পরিবর্তে, প্রয়োজনীয় আইডি সরবরাহের জন্য সেভ বোতামটি চাপলে কী কোডটি পৃথক করে তার পরিবর্তে ড্রপিং অপারেশন শেষে কল করবে এটি ভিতরে কী কী তা বোঝা যাবে না?
hakre

উত্তর:


5

আমি সম্প্রতি একই পরিস্থিতি নিয়ে যুদ্ধ করেছি। উইজেটে অ্যাজাক্স কোনও রসিকতা নয়! দৃষ্টান্তগুলি জুড়ে কাজ করার জন্য কিছু সুন্দর ক্রেজি কোড লিখতে হবে। আমি লাইভ ক্যোয়ারির সাথে পরিচিত নই, তবে আপনি যদি বলেন যে এটি প্রতি সেকেন্ডে ডোমটি পরীক্ষা করে, তবে আপনার কাছে আমার কম তীব্র সমাধান হতে পারে:

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 অবজেক্টটি পাস করতে পারেন এবং এটি বর্তমান দৃষ্টান্তের আইডেন্সটি ফিরিয়ে দেবে। আমি এই সমস্যাটি ছাড়া অন্য কোনও উপায় খুঁজে পাইনি could শুনে আমি খুব খুশি যে আমি একাই নই :)


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);

  }

});

এটি উইজেট-সেভ এজ্যাক্স অনুরোধটি সরিয়ে দেবে, উইজেট-সংরক্ষণের অনুরোধটি সম্পন্ন হওয়ার ঠিক পরে (যদি এইচটিএমএল ফর্মটির সাথে কোনও প্রতিক্রিয়া না থাকে)।

এটি jQuery(document).ready()ফাংশনে যুক্ত করা দরকার।

এখন, আপনি যদি নিজের জাভাস্ক্রিপ্ট ফাংশনগুলি সহজেই উইজেট ফর্ম ফাংশন দ্বারা যুক্ত নতুন DOM উপাদানের সাথে পুনরায় সংযুক্ত করতে চান তবে কেবল তাদের "সেভড উইজেট" ইভেন্টে আবদ্ধ করুন:

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

3
নোট করুন যে jQuery 1.8 হিসাবে, .ajaxComplete () পদ্ধতিটি কেবলমাত্র নথির সাথে সংযুক্ত থাকতে হবে। - api.jquery.com/ajaxComplete এইভাবে আপনার স্নিপেটের প্রথম লাইনটি পড়তে হবে: $ (ডকুমেন্ট) .জ্যাক্স কমপ্লিট (ফাংশন (ইভেন্ট, এক্সএমএলএইচটিপিআরকেস্ট, অজ্যাক্সঅ্যাপশনস) W কমপক্ষে ডাব্লুপি 3.6+ এর জন্য
ডেভিড লইং

3

এটি সম্প্রতি এটিকে ছড়িয়ে পড়েছে এবং মনে হয় যে traditionalতিহ্যবাহী "উইজেটস.এফপি" ইন্টারফেসে কোনও জাভাস্ক্রিপ্ট সূচনাটি সরাসরি বিদ্যমান উইজেটগুলির জন্য (ডিভের মধ্যে যারা #widgets-right) সরাসরি চালানো উচিত এবং অপ্রত্যক্ষভাবে widget-addedনতুনভাবে যুক্ত উইজেটগুলির জন্য ইভেন্টের মাধ্যমে চালানো উচিত ; যদিও কাস্টমাইজার "কাস্টমাইজ.এফপি" ইন্টারফেসে সমস্ত উইজেট - বিদ্যমান এবং নতুন - 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

আমি মনে করি ওয়ার্ডপ্রেস 3.9 এ এমন কিছু বিদ্যমান রয়েছে যা আপনাকে সাহায্য করতে পারে। এটি উইজেট আপডেটেড কলব্যাক। এটি এর মতো ব্যবহার করুন (কফিসিপি):

$(document).on 'widget-updated', (event, widget) ->
    doWhatINeed() if widget[0].id.match(/my_widget_name/)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.