Adding shortcode button to TinyMCE editor

Continuing on the TinyMCE post I made earlier, I want to show you how to add a button on the TinyMCE editor for your custom shortcode. Idea for this came when I created a team member shortcode for a client. He needed a small and simple shortcode that will show image, title, some content and a link to a page or to some outside content. This is a trivial thing to do, but later on I had to explain to him how to use it, and I realized that adding shortcode via shortcode tags

[shortcode-name link="" bla=""]

is not the most user friendly way for a beginner to do. Or for non beginner for that matter. With the rise of the page builders like Visual Composer, Divi builder, The Creator and others, people got used to simple ‘just click’ way of doing things. I knew that I could add buttons to TinyMCE, and I remembered that I saw plugins adding their own buttons to the TinyMCE with modal windows, so I knew there’s got to be a way of achieving that.
 There indeed was a way, and you can google bunch of tutorials on how to add a button for shortcode. But I wanted to go a step further — add media from WordPress to your shortcode. You could even modify the code I’ll show you, to add links to pages (modifying the code from my first article here) and posts you made on WordPress. Endless possibilities indeed.

Paving the way

First thing we’ll do is add our button in functions.php, include the necessary JavaScript file where our control will be located and add a localization — which is important if you want to use this in a plugin and want it to be translatable. The whole code is as follows

add_action( 'after_setup_theme', 'mytheme_theme_setup' );

if ( ! function_exists( 'mytheme_theme_setup' ) ) {
function mytheme_theme_setup() {

add_action( 'init', 'mytheme_buttons' );

}
}

/********* TinyMCE Buttons ***********/
if ( ! function_exists( 'mytheme_buttons' ) ) {
function mytheme_buttons() {
if ( ! current_user_can( 'edit_posts' ) && ! current_user_can( 'edit_pages' ) ) {
return;
}

if ( get_user_option( 'rich_editing' ) !== 'true' ) {
return;
}

add_filter( 'mce_external_plugins', 'mytheme_add_buttons' );
add_filter( 'mce_buttons', 'mytheme_register_buttons' );
}
}

if ( ! function_exists( 'mytheme_add_buttons' ) ) {
function mytheme_add_buttons( $plugin_array ) {
$plugin_array['mybutton'] = get_template_directory_uri().'/js/tinymce_buttons.js';
return $plugin_array;
}
}

if ( ! function_exists( 'mytheme_register_buttons' ) ) {
function mytheme_register_buttons( $buttons ) {
array_push( $buttons, 'mybutton' );
return $buttons;
}
}

add_action ( 'after_wp_tiny_mce', 'mytheme_tinymce_extra_vars' );

if ( !function_exists( 'mytheme_tinymce_extra_vars' ) ) {
function mytheme_tinymce_extra_vars() { ?>
<script type="text/javascript">
var tinyMCE_object = <?php echo json_encode(
array(
'button_name' => esc_html__('My button name', 'mythemeslug'),
'button_title' => esc_html__('The title of the pop up box', 'mythemeslug'),
'image_title' => esc_html__('Image', 'mythemeslug'),
'image_button_title' => esc_html__('Upload image', 'mythemeslug'),
)
);
?>;
</script><?php
}
}

The first part is just adding our button (registering it with TinyMCE), the second part, with the function mytheme_tinymce_extra_vars(), is adding the object in which we’ll add our translatable strings that we can use in the tinymce_buttons.js file. Now you can skip this part out, but in that case you will have names of your button, labels etc. all fixed — not translatable. So I would go with this approach. We just created a php array, and encoded it to json, so that we can read it in our .js file later on.

Adding the button

Next thing we want to do is to add our button, that will open a modal window on click, with our options for our imaginary shortcode. On closing the modal the shortcode will be added to our content, so that we won’t have to type anything manually. Remember, when adding a button, we need to keep the previously defined name the same — in our case it’s ‘mybutton’. For every button you add, you add a separate code with that name. You can add image, like in the column button I showed you, but now we’ll just add a simple text with the button name. In tinymce_buttons.js file add

(function() {
tinymce.PluginManager.add('mybutton', function( editor, url ) {
editor.addButton( 'mybutton', {
text: tinyMCE_object.button_name,
icon: false,
onclick: function() {
editor.windowManager.open( {
title: tinyMCE_object.button_title,
body: [
{
type: 'textbox',
name: 'img',
label: tinyMCE_object.image_title,
value: '',
classes: 'my_input_image',
},
{
type: 'button',
name: 'my_upload_button',
label: '',
text: tinyMCE_object.image_button_title,
classes: 'my_upload_button',
},//new stuff!
{
type : 'listbox',
name : 'listbox',
label : 'listbox',
values : [
{ text: 'Test1', value: 'test1' },
{ text: 'Test2', value: 'test2' },
{ text: 'Test3', value: 'test3' }
],
value : 'test2' // Sets the default
},
{
type : 'combobox',
name : 'combobox',
label : 'combobox',
values : [
{ text: 'Test', value: 'test' },
{ text: 'Test2', value: 'test2' }
]
},
{
type : 'textbox',
name : 'textbox',
label : 'textbox',
tooltip: 'Some nice tooltip to use',
value : 'default value'
},
{
type : 'container',
name : 'container',
label : 'container',
html : '<h1>container<h1> is <i>ANY</i> html i guess...<br/><br/><pre>but needs some styling?!?</pre>'
},
{
type : 'tooltip',
name : 'tooltip',
label : 'tooltip ( you dont use it like this check textbox params )'
},
{
type : 'button',
name : 'button',
label : 'button ( i dont know the other params )',
text : 'My Button'
},
{
type : 'buttongroup',
name : 'buttongroup',
label : 'buttongroup ( i dont know the other params )',
items : [
{ text: 'Button 1', value: 'button1' },
{ text: 'Button 2', value: 'button2' }
]
},
{
type : 'checkbox',
name : 'checkbox',
label : 'checkbox ( it doesn`t seem to accept more than 1 )',
text : 'My Checkbox',
checked : true
},
{
type : 'colorbox',
name : 'colorbox',
label : 'colorbox ( i have no idea how it works )',
// text : '#fff',
values : [
{ text: 'White', value: '#fff' },
{ text: 'Black', value: '#000' }
]
},
{
type : 'colorpicker',
name : 'colorpicker',
label : 'colorpicker'
},
{
type : 'radio',
name : 'radio',
label : 'radio ( defaults to checkbox, or i`m missing something )',
text : 'My Radio Button'
}
],
onsubmit: function( e ) {
editor.insertContent( '[shortcode-name img="' + e.data.img + '" list="' + e.data.listbox + '" combo="' + e.data.combobox + '" text="' + e.data.textbox + '" check="' + e.data.checkbox + '" color="' + e.data.colorbox + '" color_2="' + e.data.colorpicker + '" radio="' + e.data.radio + '"]');
}
});
},
});
});

})();

I’ve put all the controls I could find that would be useful. We have textbox for writing simple text, or pasting image url, as I’ve intended here. Button or button groups for multiple buttons. Important thing to notice here is that you can add custom class to your field using classes property. This will add a class that you can use (you’ll see this just in a second). We also have colorpicker, combo box, radio buttons etc.

On submit you’ll notice that in the editor you’ll insert a shortcode tag, with your options inserted like

e.data.name

The name is the name of the field you’ve chosen.

The final step you’ll need to add after this code is a simple opening of the wp.media uploader on button click. Since our modal appears when we click the ‘My button name’ button, we need to add the on click event to our document object

jQuery(document).ready(function($){
$(document).on('click', '.mce-my_upload_button', upload_image_tinymce);

function upload_image_tinymce(e) {
e.preventDefault();
var $input_field = $('.mce-my_input_image');
var custom_uploader = wp.media.frames.file_frame = wp.media({
title: 'Add Image',
button: {
text: 'Add Image'
},
multiple: false
});
custom_uploader.on('select', function() {
var attachment = custom_uploader.state().get('selection').first().toJSON();
$input_field.val(attachment.url);
});
custom_uploader.open();
}
});

Here we used the fact that we added custom class to our button — this way we can attach to that specific class, and run our media chooser. The custom class that you add will get a ‘mce-’ prefix, be sure not to leave this out.

And that’s it. Once you’ve placed all this you’ll have something like the following

Add TinyMCE button for shortcode

Add TinyMCE button for shortcode, step by step

Hope this tutorial helped you guys. If you have any questions feel free to ask them in the comments below. Happy coding!


Originally published at Made by Denis.

Show your support

Clapping shows how much you appreciated Denis Žoljom’s story.