0

I'm trying to make simple about me widget with WordPress media uploader. When I click the button Upload it opens media uploader, but after I hit save, the button doesn't work anymore, the same behavior if I have one active widget and then I add another, media upload button doesn't work in second widget. No JS errors in console. Can someone point me, where I'm wrong?

PHP

class Inka_Profile_Widget extends WP_Widget {

  // setup the widget name, description etc.
  function __construct() {
    $widget_options = array(
      'classname'   => esc_attr( "inka_profile_widget", 'inka' ),
      'description'  => esc_html__( 'Custom Profile Widget', 'inka' ),
      'customize_selective_refresh' => true
    );
    parent::__construct( 'inka_profile', 'Inka Profile', $widget_options);
  }  


  // back-end display of widget
  function form( $instance ) {

    $title = ! empty( $instance['title'] ) ? $instance['title'] : esc_html__( 'About Me', 'inka' );
    $image = ! empty( $instance['image'] ) ? $instance['image'] : '';

    ?>

      <p>
        <label for="<?php echo esc_attr( $this->get_field_id('title') ); ?>"><?php esc_attr_e( 'Title', 'inka' ); ?></label>
        <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>">
      </p>
      <p>
        <img src="<?php echo esc_attr( $image ); ?>" alt="" class="deo-image-holder" style="width: 100%;">
      </p>      
      <p>
        <input type="hidden" class="deo-image-hidden-field" name="<?php echo $this->get_field_name( 'image' ); ?>" id="<?php echo $this->get_field_id( 'image' ); ?>" value="<?php echo esc_attr( $image ); ?>"/>
        <input type="button" class="deo-image-upload-button button button-primary" value="Upload">      
        <input type="button" class="deo-image-delete-button button" value="Remove Image">
      </p>

    <?php
  }

  // front-end display of widget
  function widget( $args, $instance ) {
    echo "Hey";
  }


  // update of the widget
  function update( $new_instance, $old_instance ) {
    $instance = $old_instance;
    $instance['title'] = ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
    $instance['image'] = ( ! empty( $new_instance['image'] ) ) ? strip_tags( $new_instance['image'] ) : '';
    return $instance;
  }

}


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

JS

(function($){

  /* WordPress Media Uploader
  -------------------------------------------------------*/
  var addButton = $('.deo-image-upload-button');
  var deleteButton = $('.deo-image-delete-button');
  var hiddenField = $('.deo-image-hidden-field');
  var imageHolder = $('.deo-image-holder');
  var mediaUploader;


  addButton.on('click', function(e) {
    e.preventDefault();
    if ( mediaUploader ) {
      mediaUploader.open();
      return;
    }

    mediaUploader = wp.media.frames.file_frame = wp.media({
      title: 'Select an Image',
      button: {
        text: 'Use This Image'
      },
      multiple: false
    });

    mediaUploader.on('select', function() {
      var attachment = mediaUploader.state().get('selection').first().toJSON();
      hiddenField.val(attachment.url);
      imageHolder.attr('src', attachment.url);
    });

    mediaUploader.open();

  });  


})(jQuery);

2 Answers 2

0

Ok, I finally found what causing the problem and want to share my solution here, in case if someone has the same experience. It's very sad though that this information is not highlighted anywhere ( codex, wp blogs, stackexchange etc. ).

The first problem is how to bind click event to the button. If you bind it directly on button selector, after saving the widget WordPress will refresh it and unbind click event from that button. So the solution here is to click on the body and then delegate it to the button selector:

$('body').on('click', '.deo-image-upload-button', function(e) {
    e.preventDefault();
    ...
}

The second problem was that after widget save, the hidden input is not populating with url of the selected image anymore. That was happening because of how I cached the input and image elements into the variables outside of mediaUploader select event. Simply placing this elements inside is solving this problem:

mediaUploader.on('select', function() {
    var attachment = mediaUploader.state().get('selection').first().toJSON();      
    $('.deo-hidden-input').val(attachment.url);
    $('.deo-media-image').attr('src', attachment.url);
});

So after all cleaning and optimizations, my code now looks like this:

/* WordPress Media Uploader
  -------------------------------------------------------*/
  var mediaUploader = wp.media.frames.file_frame = wp.media({
    title: 'Select an Image',
    button: {
      text: 'Use This Image'
    },
    multiple: false
  });

  $('body').on('click', '.deo-image-upload-button', function(e) {
    e.preventDefault();

    if ( mediaUploader ) {
      mediaUploader.open();
    }

    mediaUploader.on('select', function() {
      var attachment = mediaUploader.state().get('selection').first().toJSON();      
      $('.deo-hidden-input').val(attachment.url);
      $('.deo-media-image').attr('src', attachment.url);
    });

    mediaUploader.open();

  });

Hope this information will be helpful for you ;)

0

I tried this code and it works well

jQuery(document).ready(function ($) {

   $(document).on("click", ".fla_upload_image_button", function (e) {
      e.preventDefault();
      var $button = $(this);


      // Create the media frame.
      var file_frame = wp.media.frames.file_frame = wp.media({
         title: 'Select or upload image',
         library: { // remove these to show all
            type: 'image' // specific mime
         },
         button: {
            text: 'Select'
         },
         multiple: false  // Set to true to allow multiple files to be selected
      });

      // When an image is selected, run a callback.
      file_frame.on('select', function () {
         // We set multiple to false so only get one image from the uploader

         var attachment = file_frame.state().get('selection').first().toJSON();

         $button.siblings('input').val(attachment.url);

      });

      // Finally, open the modal
      file_frame.open();
   });
});

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.