1

I don't quite know how to explain what is going on, or how to title my post but I'm going to do my best.

I'm making my first plugin for WordPress, which is very simple.

  • Allow the user to select a file from the WordPress media picker.

  • Attach that selected file as a link to each page through a PHP Call href="<?php $image_id = get_option('foss_field_image_id'); echo wp_get_attachment_url($image_id);?>" in the the current WordPress theme.

Everything with regards to my plugin works, albeit with some stitched together parts I've found online. I've been attempting to expand upon my project, adding minor details as I go, and this is where I run into some issues.

I have an jQuery document which handles the Media Modal to pop up allowing the user to upload/select a file. Once the file is chosen, there's an Ajax Get/Post request which handles updating the thumbnail on the file selector, to showcase the newly selected image (and a Post request, which triggers WordPress to "update_options", and save the selected image to the DB.)

I'm attempting to have other information automatically refresh as well, when the image is selected. Primarily, the image ID and the image URL.

I've copied the existing code I have for updating the image, appending some new variables for the ID and URL. This seems to work just fine, however only once. When I load up the media selector, and choose an image, all 3 pieces of information will update, showing the newly selected image. However, if I then open up the medial selector again, and choose a different image, this time (and every time hence forth until a page reload), only the image will update, and the ID and URL remain from the previously selected image.

Here is an GIF, to showcase what I'm talking about. Hopefully this can help explain my issue.

https://i.imgur.com/FJkQivS.gif

Below are snippets of my code:

fcp.php (main script):

<?php
/*
Plugin Name: FOSS Field
Plugin URI: https://ultra64.ca
Description: Adds a custom field in the sidebar and allows the user to create a global file link.
Version: 0.1
Author: Jeff
Author URI: https://ultra64.ca
Text Domain: fcp
Domain Path: /lang
*/

add_action( 'admin_menu', 'createAdminMenusInSidebar', 0);
add_action( 'admin_enqueue_scripts', 'load_enqueued_scripts' );
add_action( 'wp_ajax_foss_field_get_image', 'foss_field_get_image');
add_action( 'wp_ajax_foss_field_save_image', 'foss_field_save_image');

function createAdminMenusInSidebar() {
    add_menu_page(
        "FOSS Field",                                                                       
        "FOSS Field",                                                                       
        "edit_posts",                                                                       
        "foss-field",                                                                       
        "foss_mainMenu",                                                                    
        "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgZmlsbD0ibm9uZSIga".
        "GVpZ2h0PSIyNCIgc3Ryb2tlLXdpZHRoPSIxLjUiIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0I".
        "iB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik00IDZIMjBDMjEuMTA0N".
        "iA2IDIyIDYuODk1NDMgMjIgOFYxNkMyMiAxNy4xMDQ2IDIxLjEwNDYgMTggMjAgMThINEMyLjg5NTQzI".
        "DE4IDIgMTcuMTA0NiAyIDE2VjhDMiA2Ljg5NTQzIDIuODk1NDMgNiA0IDZaIiBzdHJva2U9ImN1cnJlb".
        "nRDb2xvciIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIi8+PHBhd".
        "GggZD0iTTUgOC41SDYuNU04IDguNUg2LjVNNi41IDguNVYxNS41TTYuNSAxNS41SDVNNi41IDE1LjVIO".
        "CIgc3Ryb2tlPSJjdXJyZW50Q29sb3IiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb".
        "2luPSJyb3VuZCIvPjwvc3ZnPg==",                                                      
        50                                                                                  
    );
}

function foss_mainMenu() {
    include("includes/compare-downloads.php");
}

// Ajax action to refresh the image
function foss_field_get_image() {
    if(isset($_GET['id']) ){
        $image = wp_get_attachment_image( filter_input( INPUT_GET, 'id', FILTER_VALIDATE_INT ), 'medium', false, array( 'id' => 'foss_field-preview-image' ) );
        $image_is = $_GET['id'];
        $image_url = wp_get_attachment_url($_GET['id']);
        $data = array(
            'image'       => $image,
            'image_id'    => $image_id,
            'image_url'   => $image_url,
        );
        wp_send_json_success( $data );
    } else {
        wp_send_json_error();
    }
}

// Ajax action to save the image
function foss_field_save_image() {
    update_option('foss_field_image_id', $_POST['id']);
    echo $_POST['id'];              # prints out the ID of the file saved to jQuery console
}

// Enqueue and load related scripts for this plugin
function load_enqueued_scripts( $page ) {
    // change to the $page where you want to enqueue the script
    if( $page == 'toplevel_page_foss-field' || $page == 'foss-field_page_foss-field-settings' ) {
      // Enqueue WordPress media scripts
      wp_enqueue_media();
      // Enqueue custom script that will interact with wp.media
      wp_enqueue_script( 'foss_field_script', plugins_url( '/js/media.js' , __FILE__ ), array('jquery'), '1.5.4' );
      wp_enqueue_style( 'foss_css', plugins_url( '/css/foss-style.css' , __FILE__ ), false, '1.1.7', 'all');
    }
}

includes/compare-downloads.php:

<h1>FOSS Custom Field</h1>

<?php
    $image_id = get_option('foss_field_image_id');
?>

<div id="compare-download-selector">
    <div id="compare-download-information">
        <h2>Compare Download Link</h2>
        <strong>Current File ID:</strong><br>
        <span id="foss-current-id" class="foss-file-details">
            <?php echo $image_id; ?>
        </span><br>
        <strong>Current File Path:</strong><br>
        <span id="foss-current-url" class="foss-file-details">
            <?php echo wp_get_attachment_url($image_id); ?>
        </span>
    </div>



    <div id="foss_media_selector">
        <?php
            $image_id = get_option( 'foss_field_image_id' );

            if( intval( $image_id ) > 0 ) {
                // Change with the image size you want to use
                $image = wp_get_attachment_image( $image_id, 'thumbnail', false, array( 'id' => 'foss_field-preview-image' ) );
            } else {
                // Some default image   
                $image = '<img id="foss_field-preview-image" src="https://placehold.co/100x100?text=Select\na%20File" />';
            }

            echo $image;
        ?>

        <input type="hidden" name="foss_field_image_id" id="foss_field_image_id" value="<?php echo esc_attr( $image_id ); ?>" class="regular-text" />
        <input type='button' class="button-primary" value="<?php esc_attr_e( 'Select a File', 'mytextdomain' ); ?>" id="foss_field_media_manager"/>
    </div>
</div>

media.js:

jQuery(document).ready( function($) {
  if (window.console) console.log('[DEBUG] - Script loaded');
  jQuery('input#foss_field_media_manager').click(function(e) {
    if (window.console) console.log('[DEBUG] - Select a File clicked');
    e.preventDefault();
    var image_frame;
    if(image_frame){
      image_frame.open();
    }
    // Define image_frame as wp.media object
    image_frame = wp.media({
        title: 'Select or upload a file',
        button: {
          text: 'Use this file'
        },
        multiple : false,
    });

    image_frame.on('close',function() {
      if (window.console) console.log('[DEBUG] - Media Selected...');
      // On close, get selections and save to the hidden input
      // plus other AJAX stuff to refresh the image preview
      var selection =  image_frame.state().get('selection');
      var gallery_ids = new Array();
      var my_index = 0;
      selection.each(function(attachment) {
          gallery_ids[my_index] = attachment['id'];
          my_index++;
      });
      var ids = gallery_ids.join(",");
      if(ids.length === 0) return true; //if closed without selecting an image
      jQuery('input#foss_field_image_id').val(ids);
      Refresh_Image(ids);
    });

    image_frame.on('open',function() {
      // On open, get the id from the hidden input
      // and select the appropiate images in the media manager
      var selection =  image_frame.state().get('selection');
      var ids = jQuery('input#foss_field_image_id').val().split(',');
      ids.forEach(function(id) {
        var attachment = wp.media.attachment(id);
        attachment.fetch();
        selection.add( attachment ? [ attachment ] : [] );
      });

    });

    image_frame.open();
  });

});

// Ajax request to refresh the image preview and to save the image to the WP DB
function Refresh_Image(the_id){
      var data = {
          action: 'foss_field_get_image',
          id: the_id,
      };

      jQuery.get(ajaxurl, data, function(response) {

          if(response.success === true) {
              jQuery('#foss_field-preview-image').replaceWith( response.data.image );
              jQuery('#foss-current-id').replaceWith( response.data.image_id );
              jQuery('#foss-current-url').replaceWith( response.data.image_url );

              jQuery.post(
                ajaxurl,
                { action: "foss_field_save_image", id: the_id },
                function(data) {
                  console.log('[DEBUG] - Executing Save Function...');
                  console.log('[DEBUG] - ' + JSON.stringify(data));
                }
              );
          }
      });
}
4
  • Can you edit the quote explaining what you're trying to do to be more descriptive? Your entire question depends on it but I couldn't figure out what your goal is from that quote. What do you mean by " through the WordPress Template."? Your title says it doesn't update all information implying there is more than one thing being updated, but your AJAX handler and UI only store an image ID. Can you make things clearer?
    – Tom J Nowell
    Commented Feb 12 at 16:21
  • Sorry Tom, I think I meant to say the "Theme" not "Template". I updated the quote above. Essentially, the file that gets uploaded, the direct URL gets appended as an href into the theme, based on the value saved through update_options. I hope this clarifies things and makes a bit more sense.
    – level42
    Commented Feb 12 at 16:30
  • and there is a single image? Not multiple? If so would I be right that you can set the image but once it's set it can't be replaced/updated/changed? And you're asking how to fix that? I noticed that the refresh images funciton handles if(response.success === true) { but if it is not successful nothing happens and no debugging information is logged, can you add code to do something if it fails and test?
    – Tom J Nowell
    Commented Feb 13 at 12:38
  • I appreciate you taking the time to read through my response, and providing some "rubber duckying" to me, but I managed to find out what was going on and resolved the issue :D
    – level42
    Commented Feb 13 at 17:48

1 Answer 1

0

So, I figured out why this only worked once, and not every time afterward.

I have the ID and URL wrapped in a <span> with an ID and class tied to it. However when the if(response.success === true) { fired, and updated the ID and URL of the image, it overwrote the entire <span> with nothing more than the ID and URL. Thus, the next time it attempted to fire, the <span> was missing, as well as the ID, and class, which were used to target this item in the DOM in the first place.

Essentially...

  if(response.success === true) {
      jQuery('#foss_field-preview-image').replaceWith( response.data.image );
      jQuery('#foss-current-id').replaceWith( response.data.image_id );
      jQuery('#foss-current-url').replaceWith( response.data.image_url );

      jQuery.post(
        ajaxurl,
        { action: "foss_field_save_image", id: the_id },
        function(data) {
          console.log('[DEBUG] - Executing Save Function...');
          console.log('[DEBUG] - ' + JSON.stringify(data));
        }
      );
  }

Was replaced with:

      if(response.success === true) {
          jQuery('#foss_field-preview-image').replaceWith( response.data.image );
          jQuery('#foss-current-id').replaceWith( '<span id="foss-current-id" class="foss-current-file-details">' + response.data.image_id  + '</span>' );
          jQuery('#foss-current-url').replaceWith( '<span id="foss-current-url" class="foss-current-file-details">' + response.data.image_url   + '</span>' );

          jQuery.post(
            ajaxurl,
            { action: "foss_field_save_image", id: the_id },
            function(data) {
              console.log('[DEBUG] - Executing Save Function...');
              console.log('[DEBUG] - ' + JSON.stringify(data));
            }
          );
      }

This re-wrote the <span>, ID, and class information back to the object, along with the Image ID, allowing it to be target the second, third and so on time to be updated again and again.

Your Answer

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

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