Dynamic Content in TinyMCE

Easily add dynamic content in TinyMCE popup.

Dynamic Content in TinyMCE

In one of the WordPress plugins I developed recently I had to add a list a button (which is a custom post type) in the TinyMCE popup. It was basically a select field where I needed to populate button ID and title as option fields.

Since I see a lot of people asking how to add dynamic content inside the TinyMCE popup so thought of sharing how I dealt with it.

Dynamic Content in TinyMCE
Dynamic Content in TinyMCE

In this tutorial, I will show you how to dynamically add post data as options inside TinyMCE popup select field. So without any ado let’s jump right into it.

Step 1. Create TinyMCE Button

First of all, create a TinyMCE button. Add the below code to your plugin file.

// Hooks your functions into the correct filters
function twd_mce_button() {
	// check user permissions
	if ( !current_user_can( 'edit_posts' ) && !current_user_can( 'edit_pages' ) ) {
	// check if WYSIWYG is enabled
	if ( 'true' == get_user_option( 'rich_editing' ) ) {
		add_filter( 'mce_external_plugins', 'twd_add_mce_plugin' );
		add_filter( 'mce_buttons', 'twd_register_mce_button' );
add_action( 'admin_head', 'twd_mce_button' );

// Script for our mce button
function twd_add_mce_plugin( $plugin_array ) {
	$plugin_array['twd_mce_button'] = plugin_dir_url( __FILE__ ) . 'mce.js';
	return $plugin_array;

// Register our button in the editor
function twd_register_mce_button( $buttons ) {
	array_push( $buttons, 'twd_mce_button' );
	return $buttons;

Here we are using basic WordPress TinyMCE filters to hook our MCE plugin into TinyMCE. You can read more about it on TinyMCE Custom Buttons page on WordPress.org.

Step 2. Fetch Post Titles

Now I will make use of the wpdb class to fetch the post titles and then return the data that I require (post id and title) as a JSON string in the format that TinyMCE select field expects.

 * Function to fetch cpt posts list
 * @return json
public function twd_posts( $post_type ) {

	global $wpdb;
   	$cpt_type = $post_type;
	$cpt_post_status = 'publish';
        $cpt = $wpdb->get_results( $wpdb->prepare(
        "SELECT ID, post_title
            FROM $wpdb->posts 
            WHERE $wpdb->posts.post_type = %s
            AND $wpdb->posts.post_status = %s
            ORDER BY ID DESC",
    ) );

    $list = array();

    foreach ( $cpt as $post ) {
		$selected = '';
		$post_id = $post->ID;
		$post_name = $post->post_title;
		$list[] = array(
			'text' =>	$post_name,
			'value'	=>	$post_id

	wp_send_json( $list );


Step 3. Store JSON Data with TinyMCE Editor Instance

You might ask why set data inside TinyMCE editor instance? This is because this way we will be able to easily access our data inside the TinyMCE popup. Here we just need to create a new property under TinyMCE Editor instance to store our data. I will use AJAX here to store the data from the previous step.

 * Function to fetch buttons
 * @since  1.6
 * @return string
public function twd_list_ajax() {
	// check for nonce
	check_ajax_referer( 'twd-nonce', 'security' );
	$posts = twd_posts( 'post' );
	return $posts;
add_action( 'wp_ajax_twd_cpt_list', 'twd_list_ajax' );

 * Function to output button list ajax script
 * @since  1.6
 * @return string
public function twd_cpt_list() {
	// create nonce
	global $pagenow;
	if( $pagenow != 'admin.php' ){
		$nonce = wp_create_nonce( 'twd-nonce' );
		?><script type="text/javascript">
			jQuery( document ).ready( function( $ ) {
				var data = {
					'action'	: 'twd_cpt_list', // wp ajax action
					'security'	: '<?php echo $nonce; ?>' // nonce value created earlier
				// fire ajax
			  	jQuery.post( ajaxurl, data, function( response ) {
			  		// if nonce fails then not authorized else settings saved
			  		if( response === '-1' ){
				  		// do nothing
			  		} else {
			  			if (typeof(tinyMCE) != 'undefined') {
			  				if (tinyMCE.DOM != null) {
								tinyMCE.DOM.cptPostsList = response;
add_action( 'admin_footer', 'twd_cpt_list' );


Step 4. Create TinyMCE Plugin

This is the last step where we need to create a TinyMCE plugin. The code below is basic JavaScript code to create a plugin. The only change here is that we are using TinyMCE editor instance property that we created earlier to add values to our select field. Submitting the form prints out a shortcode with id parameter containing the dynamic content.

(function() {
	tinymce.PluginManager.add('twd_mce_button', function( editor, url ) {
		editor.addButton('twd_mce_button', {
			text: '{ TWD CPT Posts }',
			icon: false,
			tooltip: 'CPT List',
			onclick: function() {
				editor.windowManager.open( {
					title: 'Insert List',
					width: 400,
					height: 100,
					body: [
							type: 'listbox',
							name: 'listboxName',
							label: 'TWD CPT Posts',
							'values': editor.settings.cptPostsList
					onsubmit: function( e ) {
						editor.insertContent( '[twd_post_title id="' + e.data.listboxName + '"]');

I hope through this tutorial you will be able to add dynamic content inside TinyMCE popup in WordPress. If something is unclear or if you have any suggestion to improve this code then please use the comment form below.

The full source code is available on Github.

Like this post?

Get more stuff on WordPress design, development & business before they get published.

5 Responses to “Dynamic Content in TinyMCE”

  • I cant seem to get this to work. I have the button in the tinymce then when i do the rest of the code it saying i am missing return statements. If i get rid of the comments with th @return i get now errors. But still no list in the dropdown. I also had to get rid of the public part of the public functions…so basically my code is exactly like yours but i cant get my custom post type titles in the dropdown.

  • Hey still need help with populating my listbox

    I have used some of you code but changed some to here is the php code

    	$args        = array(
    		'post_type'  => 'recipe_item',
    		'numberpost' => - 1
    	$recipeslist = get_posts( $args );
    	//$list        = array();
    	foreach ( $recipeslist as $singleRecipe ) {
    		//	$selected  = '';
    		$post_slug   = $singleRecipe->post_name;
    		$post_name = $singleRecipe->post_title;
    		$recipeArray[]    = array(
    			'text'  => $post_name,
    			'value' => $post_slug
    	$myJSON = json_encode($recipeArray);
    	file_put_contents( 'myfile.json', $myJSON );
    thats how i save my json
    then in my js file for my plugin
    jQuery(document).ready(function ($) {
        tinymce.PluginManager.add('twd_mce_button', function( ed, url ) {
            ed.addButton('twd_mce_button', {
                text: 'Recipe Cards',
                icon: false,
                tooltip: 'Recipe Cards',
                onclick: function(){
                    ed.windowManager.open( {
                        title: 'Insert List',
                        width: 400,
                        height: 100,
                        body: [{
                            type: 'listbox',
                            name: 'listboxName',
                            label: 'Recipe Cards',
                            'values': ed.settings.recipeList
                        onPostRender: getValues(),
                        onsubmit: function( e ) {
                            ed.insertContent( '[twd_post_title id="' + e.data.listboxName + '"]');
    function getValues() {
        jQuery.getJSON('http://liveinseason.com/myfile.json', function (result) {
        var recipeNames = result;
        //Set new values to myKeyValueList
        tinyMCE.activeEditor.settings.recipeList = recipeNames;
        return tinyMCE.activeEditor.settings.recipeList;

    but nothing get s populated into the listbox what am i missing?

  • Sorry i got it to work but it only populates if you click on it its empty then you close and reopen it and the list is populated so how to i get it to populate on first click

Start a Conversation