Call PHP function inside TinyMCE modal window on the WordPress backend

I am using a static .js file that is registered for a TinyMCE plugin. You click on the new button and it opens up the modal window, with a form in it, that I use to generate a Shortcode. The problem is that I need some of my form fields to be populated from PHP functions. I’ve been looking at articles on this for hours and haven’t found a workable solution. Right now my php function is a Shortcode, so I need to adapt it to be a regular old function. But the big challenge is figuring out how to arrange this so that the .js file can take the function in the form. Here’s the basic stuff. First, some chunks of the .js file:

(function(){
    // creates the plugin
    tinymce.create('tinymce.plugins.myshortcode', {
        // creates control instances based on the control's id.
        createControl : function(id, controlManager) {
            if (id == 'myshortcode') {
                // creates the button
                var button = controlManager.createButton('myshortcode', {
                    title : 'My Shortcode', // title of the button
                    image : '../wp-content/plugins/my-shortcode/js/images/myshortcode.png',  // path to the button's image
                    onclick : function() {
                        // triggers the thickbox
                        var width = jQuery(window).width(), H = jQuery(window).height(), W = ( 720 < width ) ? 720 : width;
                        W = W - 80;
                        H = H - 80;
                        tb_show( 'My Shortcode', '#TB_inline?width=' + W + '&height=' + H + '&inlineId=myshortcode-form' );
                    }
                });
                return button;
            }
            return null;
        }
    });
    // registers the plugin.
    tinymce.PluginManager.add('myshortcode', tinymce.plugins.myshortcode);
    jQuery(function(){
        var form = jQuery(' 

The HTML Web Form all goes in here.

 ');
var table = form.find('table');
        form.appendTo('body').hide();
        form.find('#myshortcode-submit').click(function(){
            var options = { 
                'att1'  : '',
                'att2'   : '',
                'att3'   : '',
                'att4'   : '',
                };
            var shortcode = '[myshortcode';
            
                for( var index in options) {
                var value = table.find('#myshortcode-' + index).val();
                
                if ( value !== options[index] && value != null )
                    shortcode += ' ' + index + '="' + value + '"';
            }
            
            shortcode += '] content here. [/myshortcode]';
            
            tinyMCE.activeEditor.execCommand('mceInsertContent', 0, shortcode);
            
            tb_remove();
        });
    });
})()

But in that spot where it says, “The HTML Web Form goes in here,” I need to have a couple of fields that are generated based on PHP functions. I’ve only written one of the two so far, and as I said, it’s currently written as a Shortcode, so I need to change it (not sure the best way to do that given the other big questions here). But here it is:

Read More
add_shortcode('rolescapsdropdown', 'sc_rolescapsdropdown');
function sc_rolescapsdropdown($attr) {
    global $wp_roles;
    $all_roles = $wp_roles->roles; 
    $editable_roles = apply_filters('editable_roles', $all_roles); 
    $user = new WP_User( 1 );
    $capslist = $user->allcaps;
    $dropdown = '<select multiple>';
    foreach($editable_roles as $role=>$theroles){
        $dropdown .= '<option value="'.$role.'">'.$role.'</option>';
    }
    foreach($capslist as $cap=>$caps){
        if($cap !== 'administrator' && $cap !== 'level_0' && $cap !== 'level_1' && $cap !== 'level_2' && $cap !== 'level_3' && $cap !== 'level_4' && $cap !== 'level_5' && $cap !== 'level_6' && $cap !== 'level_7' && $cap !== 'level_8' && $cap !== 'level_9' && $cap !== 'level_10'){ 
            $dropdown .= '<option value="'.$cap.'">'.$cap.'</option>';
        }
    }
    $dropdown .= '</select>';
    return $dropdown;
}

I’m hoping to avoid having to learn Ajax here. But I tried making the .js file a .php file and just wrapping the JavaScript in <script> tags, but then all the TinyMCE buttons disappeared, so apparently it won’t let me use a .php file to register the plugin.

Update 1

One idea I have is to try to move the web form to a php file, and just have the .js file that registers the TMCE plugin call it up, but I wouldn’t know if that would work, nor how to get the .js file to recognize the existence of the form in an external php file.

Update 2

Based on ScottA’s help, here’s how I’m trying to work this:

I’ve added this to my static .js file that has the form:

$.get( "ajax/test.php", function( data ) {
  var options = data.options;
  for(row in options) {
     $("#option-list").append("<option value=" + options[row].value + ">" + options[row].name + "</option>");
     // debug for unexpected results
     console.log(data.options);
  }
}, "json" );

I’ve created this test.php file in a subdirectory called “ajax”:

function rolescapsdropdown() {
    global $wp_roles;
    $all_roles = $wp_roles->roles; 
    $editable_roles = apply_filters('editable_roles', $all_roles); 
    $user = new WP_User( 1 );
    $capslist = $user->allcaps;
    $all_options = $editable_roles . $capslist;
    $all_options[]['value'] = $value;
    $all_options[]['name'] = $name;
    echo json_encode( array('options' => $all_options) );
}

And I added this HTML to the form in the static .js file:

<select id="option-list"></select>

What I’m getting is a blank modal window. None of the HTML is showing up at all when I include the $.get function.

Update 3

Still getting a blank modal window. I converted it back to a shortcode to see what it outputs. This…

add_shortcode('rolesdropdown', 'sc_rolesdropdown');
function sc_rolesdropdown() {
    global $wp_roles;
    $all_roles = $wp_roles->roles; 
    $editable_roles = apply_filters('editable_roles', $all_roles); 
    $user = new WP_User( 1 );
    $capslist = $user->allcaps;
    foreach ($editable_roles as $role=>$theroles){
        $all_options = $role;
    }
    foreach ($capslist as $cap=>$caps){
        $all_options .= $cap;
    }
    echo json_encode( array('options' => $all_options) );
}

outputs this on the page:

{“options”:”trollswitch_themesedit_themesactivate_pluginsedit_pluginsedit_usersedit_filesmanage_optionsmoderate_commentsmanage_categoriesmanage_linksupload_filesimportunfiltered_htmledit_postsedit_others_postsedit_published_postspublish_postsedit_pagesreadlevel_10level_9level_8level_7level_6level_5level_4level_3level_2level_1level_0edit_others_pagesedit_published_pagespublish_pagesdelete_pagesdelete_others_pagesdelete_published_pagesdelete_postsdelete_others_postsdelete_published_postsdelete_private_postsedit_private_postsread_private_postsdelete_private_pagesedit_private_pagesread_private_pagesdelete_userscreate_usersunfiltered_uploadedit_dashboardupdate_pluginsdelete_pluginsinstall_pluginsupdate_themesinstall_themesupdate_corelist_usersremove_usersadd_userspromote_usersedit_theme_optionsdelete_themesexportbe_trollexec_phpedit_others_phpadministrator”}

But when in the modal window on the backend, the window is just blank when the $.get is calling the file with that function in it.

Related posts

Leave a Reply

2 comments

  1. You say you don’t want to learn AJAX, but you should not be afraid. jQuery’s $.get() function makes it very easy to get and process data from an external file. If your PHP functions reside in a separate file, you could make the $.get() call to that file and populate the form in the same jQuery function.

    Your jQuery could be as simple as:

    $.get( "ajax/test.php", function( data ) {
      $( ".result" ).html( data );
    });
    

    Say your file, test.php returned a JSON array, or even plain text based off parameters you pass in the URL (ie: “ajax/test.php?userid=1&get=name”) you could use jQuery to populate the form.

    Your jQuery:

    $.get( "ajax/test.php?userid=1&get=name", function( data ) {
      $( "#myform input.firstname").val( data.firstname );
      $( "#myform input.lastname").val( data.lastname );
    }, "json" );
    

    test.php could look like:

    <?php
    
    // your function to retrieve the data from the database, a file, etc.
    
    echo json_encode(array(
      "firstname" => "Burt",
      "lastname" => "Bartigan"
    ));
    
    ?>
    

    You say you don’t want to use AJAX, but that’s the easiest way you will solve this problem.

    More information on $.get();

    More information on PHP json functions

    — EDIT —

    To answer your comment below:

    your php:

    $all_options[]['value'] = $value;
    $all_options[]['name'] = $name;
    // or however you can best get it
    // from the database into an array
    
    echo json_encode( array('options' => $all_optoins) );
    

    your jQuery:

    $.get( "ajax/test.php", function( data ) {
      var options = data.options;
      for(row in options) {
         // append will place this inside the <select> HTML element
         $("#option-list").append("<option value=" + options[row].value + ">" + options[row].name + "</option>");
         // debug for unexpected results?
         console.log(data.options);
      }
    }, "json" );
    

    your HTML:

    <select id="option-list"></select>
    
  2. I just had the same issue and this is how I solved it. First, we need to pass some PHP values to the JavaScript file. As wp_localize_script cannot be used (we’re not enqueueing the script), we’ll print it directly in admin_head:

    foreach( array('post.php','post-new.php') as $hook )
        add_action( "admin_head-$hook", 'admin_head_js_vars' );
    
    /**
     * Localize Script
     */
    function admin_head_js_vars() 
    {
            $img = plugins_url( '/js/images/myshortcode.png', __FILE__ );
            ?>
    <!-- TinyMCE Shortcode Plugin -->
    <script type='text/javascript'>
        var b5f_mce_config = {
            'tb_title': '<?php _e('Roles Shortcode'); ?>',
            'button_img': '<?php echo $img; ?>',
            'ajax_url': '<?php echo admin_url( 'admin-ajax.php')?>',
            'ajax_nonce': '<?php echo wp_create_nonce( '_nonce_tinymce_shortcode' ); ?>' 
        };
    </script>
    <!-- TinyMCE Shortcode Plugin -->
            <?php
    }
    

    With this, the button creation looks like:

    title: b5f_mce_config.tb_title, // title of the button
    image: b5f_mce_config.button_img, // path to the button's image
    

    Now, we’ll add an Ajax action:

    add_action( 'wp_ajax_b5f_tinymce_shortcode', 'b5f_tinymce_shortcode' );
    
    function b5f_tinymce_shortcode()
    {
        $do_check = check_ajax_referer( '_nonce_tinymce_shortcode', 'security', false ); 
    
        if( !$do_check )
            echo 'error';
        else
            include_once 'my-form.php';
        exit();
    }
    

    Back to JS (noting that my example is based on this):

    jQuery(function($)
    {
        /* Used in Ajax and Callback */
        var table;
    
        /**
         * Get the ThickBox contents wit Ajax
         */
        var data_alt = {
            action: 'b5f_tinymce_shortcode',
            security: b5f_mce_config.ajax_nonce
        };
        $.post( 
            b5f_mce_config.ajax_url, 
            data_alt,                   
            function( response )
            {
                if( 'error' == response  )
                {
                    $('<div id="mygallery-form"><h1 style="color:#c00;padding:100px 0;width:100%;text-align:center">Ajax error</h1></div>')
                        .appendTo('body').hide();
                }
                else
                {
                    form = $(response);
                    table = form.find('table');
                    form.appendTo('body').hide();
                    form.find('#mygallery-submit').click(b5f_submit_gallery);
                }
            }
        ); 
    
        /**
         * Callback for submit click
         */
        function b5f_submit_gallery()
        {
            // Options defined in admin_head
            var shortcode = '[my_shortcode]';
    
            // inserts the shortcode into the active editor
            tinyMCE.activeEditor.execCommand('mceInsertContent', 0, shortcode);
    
            // closes Thickbox
            tb_remove();
        }
    });
    

    Finally, the file myform.php, included with Ajax, can contain any WordPress functions:

    <?php
    /**
     * Used by Ajax
     */
    ?>
    <div id="mygallery-form">
    <?php echo site_url(); ?>
    </div>