Hook for image edit popup

Is there a hook for the popup window which shows up when you click on the edit button on an image in a post?

Related posts

Leave a Reply

2 comments

  1. The answer is there is no damn hook for the edit button.

    It’s just a bunch of JS contained within wp-includes/js/tinymce/plugins/wpeditimage/plugin.js.

    I’ve included the barebones of what you need below. Key points:

    a. Clicking an element with a data-wp-imgselect attribute will open the image edit dialogue. You need to change that to something else if you don’t want that to happen (data-wp-chartselect in my example).

    b. A good way of preventing wpeditimage from conflicting is to give whatever element you’re editing a mceItem class. This will make WordPress think it’s a placeholder and thus not select it.

    c. The bit you can’t see is my Angular app loaded from the datacharts.cb_url global. I have a button in that which does the following when clicked:

    parent.tinymce.activeEditor.insertContent('<div class="mceNonEditable"><img src="' + angular.element('.savePNG').attr('href') + '" data-llama='' + window.btoa(angular.toJson(scope.config)) + '' class="mceItem" /></div><br />');
    
    parent.tinymce.activeEditor.windowManager.close();
    

    The key thing here is that it creates an image with a data attribute (data-llama) containing a Base64-encoded representation of my chart configuration. This is decoded and deserialised when it gets passed back to my Angular app via TinyMCE, which is then used to populate the chart. I’m open-sourcing my entire codebase and will link to it here once I’ve done so, in case you want to see a complete implementation.

    Without any further ado, here’s my TinyMCE plugin:

    /**
     *  datacharts TinyMCE plugin
     */
    
    tinymce.PluginManager.add('datacharts', function(editor, url) {
      var toolbarActive = false;
    
      // Add a button that opens a window. This is just the toolbar.
      editor.addButton('datacharts', {
        text: false,
        icon: 'icon dashicons-chart-area',
        onclick: function() {
          // Open window
          editor.windowManager.open({
            title: 'datacharts',
            width: jQuery(window).width() - 100,
            height: jQuery(window).height() - 100,
            url: datacharts.cb_url,
            buttons: [
              {
                text: 'Cancel',
                onclick: 'close'
              }
            ]
          });
        }
      });
    
      function editImage( img ) {
        // Open window
        editor.windowManager.open({
          title: 'datacharts',
          width: jQuery(window).width() - 100,
          height: jQuery(window).height() - 100,
          url: datacharts.cb_url,
          buttons:
            [
              {
                text: 'Cancel',
                onclick: 'close'
              }
            ]
          },
          { // This object is passed to the receiving URL via parent.tinymce.activeEditor.windowManager.getParams()
            llama: img.dataset.llama
          }
        );
      }
    
      // Remove the element if the "delete" button is clicked.
      function removeImage( node ) {
        var wrap;
    
        if ( node.nodeName === 'DIV' && editor.dom.hasClass( node, 'mceTemp' ) ) {
          wrap = node;
        } else if ( node.nodeName === 'IMG' || node.nodeName === 'DT' || node.nodeName === 'A' ) {
          wrap = editor.dom.getParent( node, 'div.mceTemp' );
        }
    
        if ( wrap ) {
          if ( wrap.nextSibling ) {
            editor.selection.select( wrap.nextSibling );
          } else if ( wrap.previousSibling ) {
            editor.selection.select( wrap.previousSibling );
          } else {
            editor.selection.select( wrap.parentNode );
          }
    
          editor.selection.collapse( true );
          editor.nodeChanged();
          editor.dom.remove( wrap );
        } else {
          editor.dom.remove( node );
        }
        removeToolbar();
      }
    
      // This adds the "edit" and "delete" buttons.
      function addToolbar( node ) {
        var rectangle, toolbarHtml, toolbar, left,
          dom = editor.dom;
    
        removeToolbar();
    
        // Don't add to placeholders
        if ( ! node || node.nodeName !== 'IMG' || isPlaceholder( node ) ) {
          return;
        }
    
        dom.setAttrib( node, 'data-wp-chartselect', 1 );
        rectangle = dom.getRect( node );
    
        toolbarHtml = '<div class="dashicons dashicons-edit edit" data-mce-bogus="1"></div>' +
          '<div class="dashicons dashicons-no-alt remove" data-mce-bogus="1"></div>';
    
        toolbar = dom.create( 'div', {
          'id': 'wp-image-toolbar',
          'data-mce-bogus': '1',
          'contenteditable': false
        }, toolbarHtml );
    
        if ( editor.rtl ) {
          left = rectangle.x + rectangle.w - 82;
        } else {
          left = rectangle.x;
        }
    
        editor.getBody().appendChild( toolbar );
        dom.setStyles( toolbar, {
          top: rectangle.y,
          left: left
        });
    
        toolbarActive = true;
      }
    
      // This removes the edit and delete buttons.
      function removeToolbar() {
        var toolbar = editor.dom.get( 'wp-image-toolbar' );
    
        if ( toolbar ) {
          editor.dom.remove( toolbar );
        }
    
        editor.dom.setAttrib( editor.dom.select( 'img[data-wp-chartselect]' ), 'data-wp-chartselect', null );
    
        toolbarActive = false;
      }
    
      function isPlaceholder( node ) {
        var dom = editor.dom;
    
        if ( /*dom.hasClass( node, 'mceItem' ) ||*/ dom.getAttrib( node, 'data-mce-placeholder' ) ||
          dom.getAttrib( node, 'data-mce-object' ) ) {
    
          return true;
        }
    
        return false;
      }
    
      editor.on( 'mousedown', function( event ) {
        if ( editor.dom.getParent( event.target, '#wp-image-toolbar' ) ) {
          if ( tinymce.Env.ie ) {
            // Stop IE > 8 from making the wrapper resizable on mousedown
            event.preventDefault();
          }
        } else if ( event.target.nodeName !== 'IMG' ) {
          removeToolbar();
        }
      });
    
      editor.on( 'mouseup', function( event ) {
        var image,
          node = event.target,
          dom = editor.dom;
    
        // Don't trigger on right-click
        if ( event.button && event.button > 1 ) {
          return;
        }
    
        if ( node.nodeName === 'DIV' && dom.getParent( node, '#wp-image-toolbar' ) ) {
          image = dom.select( 'img[data-wp-chartselect]' )[0];
    
          if ( image ) {
            editor.selection.select( image );
            if ( dom.hasClass( node, 'remove' ) ) {
              removeImage( image );
            } else if ( dom.hasClass( node, 'edit' ) ) {
              editImage( image );
            }
          }
        } else if ( node.nodeName === 'IMG' && ! editor.dom.getAttrib( node, 'data-wp-chartselect' ) && ! isPlaceholder( node ) ) {
          addToolbar( node );
        } else if ( node.nodeName !== 'IMG' ) {
          removeToolbar();
        }
      });
    
      editor.on( 'cut', function() {
        removeToolbar();
      });
    
    
      // This might not be needed, not sure what it does.
      editor.on( 'PostProcess', function( event ) {
        if ( event.get ) {
          event.content = event.content.replace( / data-wp-chartselect="1"/g, '' );
        }
      });
    
    });
    
  2. add_filter( 'attachment_fields_to_edit', 'attachment_fields_to_edit', null, 2 );
    add_filter( 'attachment_fields_to_save', 'attachment_fields_to_save', null, 2 );
    
    function attachment_fields_to_edit( $form_fields, $post ) {
        $form_fields['my_attachment_field'] = array(
            'label' => 'My Label',
            'input' => 'text',
            'value' => get_post_meta( $post->ID, '_my_attachment_field', true )
        );
    
        return $form_fields;
    }
    
    function attachment_fields_to_save( $post, $attachment ) {
        if ( ! empty( $attachment['my_attachment_field'] ) )
            update_post_meta( $post['ID'], '_my_attachment_field', $attachment['my_attachment_field'] );
        else
            delete_post_meta( $post['ID'], '_my_attachment_field' );
    
        return $post;
    }