{"id":41771,"date":"2024-11-29T20:44:49","date_gmt":"2024-11-29T18:44:49","guid":{"rendered":"https:\/\/coma.lv\/2024\/11\/29\/how-to-create-a-tinymce-plugin-for-wordpress\/"},"modified":"2024-11-29T20:44:49","modified_gmt":"2024-11-29T18:44:49","slug":"how-to-create-a-tinymce-plugin-for-wordpress","status":"publish","type":"post","link":"https:\/\/coma.lv\/en\/2024\/11\/29\/how-to-create-a-tinymce-plugin-for-wordpress\/","title":{"rendered":"How to Create a TinyMCE Plugin for WordPress"},"content":{"rendered":"\n<p style=\"text-align: left;\">If you are a WordPress developer, at some point you may need to extend or customize the visual editor. For example, you may want to add a button to the toolbar that lets your clients use certain features without having to resort to HTML code. In this article we will show you how to create a TinyMCE plugin in WordPress.<\/p>\n<p style=\"text-align: left;\"><strong>Requirements<\/strong><\/p>\n<p style=\"text-align: left;\">This article is intended for advanced users and you will need basic coding skills. Also keep in mind that experimenting on a live site is not a very good idea, since even the slightest mistake can make your site unavailable. But if you are still going to take the risk, at least make a WordPress backup first.<\/p>\n<h2 style=\"text-align: left;\">Creating Your First TinyMCE Plugin<\/h2>\n<p style=\"text-align: left;\">We will start by creating a custom toolbar button. When clicked, this button will let the user add a link with a custom CSS class. The full source code will be given at the end of this article, and before that let&#8217;s build our plugin step by step. First, create a directory in the wp-content\/plugins folder and name it tinymce-custom-link-class.<\/p>\n<h2 style=\"text-align: left;\">The Plugin Header<\/h2>\n<p style=\"text-align: left;\">Create a new file in the directory you just created and name it tinymce-custom-link-class.php. Add this code to the file and save it.<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n\/**\r\n * Plugin Name: TinyMCE Custom Link Class\r\n * Plugin URI: https:\/\/coma.lv\r\n * Version: 1.0\r\n * Author: Coma.lv\r\n * Author URI: https:\/\/coma.lv\r\n * Description: A simple TinyMCE Plugin to add a custom link class in the Visual Editor\r\n * License: GPL2\r\n *\/\r\n<\/pre>\n<p style=\"text-align: left;\">This is just a PHP comment that tells WordPress the plugin&#8217;s name, as well as its author and description. In the WordPress admin panel, activate the new plugin by going to the Plugins \u2013 Installed Plugins page and clicking the Activate link under TinyMCE Custom Link Class.<\/p>\n<p style=\"text-align: left;\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/coma.lv\/wp-content\/uploads\/2016\/11\/plugininstalled.jpg\" alt=\"WordPress\" title=\"\"><\/p>\n<h2 style=\"text-align: left;\">Setting Up Our Plugin Class<\/h2>\n<p style=\"text-align: left;\">If two plugins have functions with the same names, it can cause an error. We will avoid this problem by wrapping our functions in a class.<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\nclass TinyMCE_Custom_Link_Class {\r\n\t\r\n\t\/**\r\n\t* Constructor. Called when the plugin is initialised.\r\n\t*\/\r\n\tfunction __construct() {\r\n\t\t\r\n\t}\r\n\r\n}\r\n\r\n$tinymce_custom_link_class = new TinyMCE_Custom_Link_Class;\r\n<\/pre>\n<p style=\"text-align: left;\">This creates a PHP class together with a constructor that is called when we reach the line $tinymce_custom_link_class = new TinyMCE_Custom_Link_Class;<\/p>\n<p style=\"text-align: left;\">Any function added to this class should not conflict with other WordPress plugins.<\/p>\n<h2 style=\"text-align: left;\">Setting Up Our TinyMCE Plugin<\/h2>\n<p style=\"text-align: left;\">Next we need to tell TinyMCE that we want to add a custom button to the visual editor toolbar. To do this we can use WordPress actions. In this case, the action called init. Add the following code to your plugin&#8217;s __construct() function.<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\nif ( is_admin() ) {\r\n\tadd_action( &amp;#039;init&amp;#039;, array(  $this, &amp;#039;setup_tinymce_plugin&amp;#039; ) );\r\n}\r\n<\/pre>\n<p style=\"text-align: left;\">This function checks whether we are in the admin panel. If the answer is yes, the function asks for the setup_tinymce_plugin function inside our class to run once WordPress has finished loading. Then add the setup_tinymce_plugin function:<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n\/**\r\n* Check if the current user can edit Posts or Pages, and is using the Visual Editor\r\n* If so, add some filters so we can register our plugin\r\n*\/\r\nfunction setup_tinymce_plugin() {\r\n\r\n\/\/ Check if the logged in WordPress User can edit Posts or Pages\r\n\/\/ If not, don&amp;#039;t register our TinyMCE plugin\r\n\t\r\nif ( ! current_user_can( &amp;#039;edit_posts&amp;#039; ) &amp;amp;&amp;amp; ! current_user_can( &amp;#039;edit_pages&amp;#039; ) ) {\r\n\t        return;\r\n}\r\n\r\n\/\/ Check if the logged in WordPress User has the Visual Editor enabled\r\n\/\/ If not, don&amp;#039;t register our TinyMCE plugin\r\nif ( get_user_option( &amp;#039;rich_editing&amp;#039; ) !== &amp;#039;true&amp;#039; ) {\r\nreturn;\r\n}\r\n\r\n\/\/ Setup some filters\r\nadd_filter( &amp;#039;mce_external_plugins&amp;#039;, array( $this, &amp;#039;add_tinymce_plugin&amp;#039; ) );\r\nadd_filter( &amp;#039;mce_buttons&amp;#039;, array( $this, &amp;#039;add_tinymce_toolbar_button&amp;#039; ) );\r\n\t\t\r\n\t}\r\n<\/pre>\n<p style=\"text-align: left;\">This function first checks whether the logged-in user can edit posts or pages. If not, there is no point in registering our plugin for that user, since they will never see the visual editor. Then we check whether the user uses the visual editor, since some users turn it off in their profile. Again, if the user does not use the visual editor, we return (exit), since we do not need anything else. Finally, we add two WordPress filters, mce_external_plugins and mce_buttons, to call the functions that will load the necessary JavaScript file for TinyMCE and add the corresponding button to the toolbar.<\/p>\n<h2 style=\"text-align: left;\">Registering the JavaScript File and Button for the Visual Editor<\/h2>\n<p style=\"text-align: left;\">Let&#8217;s add the add_tinymce_plugin function:<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n\/**\r\n* Adds a TinyMCE plugin compatible JS file to the TinyMCE \/ Visual Editor instance\r\n*\r\n* @param array $plugin_array Array of registered TinyMCE Plugins\r\n* @return array Modified array of registered TinyMCE Plugins\r\n*\/\r\nfunction add_tinymce_plugin( $plugin_array ) {\r\n\r\n$plugin_array&#x5B;&amp;#039;custom_link_class&amp;#039;] = plugin_dir_url( __FILE__ ) . &amp;#039;tinymce-custom-link-class.js&amp;#039;;\r\nreturn $plugin_array;\r\n\r\n}\r\n <\/pre>\n<p style=\"text-align: left;\">This function tells TinyMCE that it needs to load the JavaScript files located in the $plugin_array cell. These files will tell TinyMCE what to do. We also need to add code to the add_tinymce_toolbar_button function to tell TinyMCE about the button we would like to add to the toolbar.<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n\/**\r\n* Adds a button to the TinyMCE \/ Visual Editor which the user can click\r\n* to insert a link with a custom CSS class.\r\n*\r\n* @param array $buttons Array of registered TinyMCE Buttons\r\n* @return array Modified array of registered TinyMCE Buttons\r\n*\/\r\nfunction add_tinymce_toolbar_button( $buttons ) {\r\n\r\narray_push( $buttons, &amp;#039;|&amp;#039;, &amp;#039;custom_link_class&amp;#039; );\r\nreturn $buttons;\r\n}\r\n<\/pre>\n<p style=\"text-align: left;\">This adds two items to the TinyMCE buttons cell: a separator (|) and the name of our button (custom_link_class). Save your plugin and edit a page or post to see the visual editor. Most likely, you will not see the toolbar.<\/p>\n<p style=\"text-align: left;\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/coma.lv\/wp-content\/uploads\/2016\/11\/wordpress-tinymce-plugin-missing-toolbar.jpg\" alt=\"WordPress\" title=\"\"><\/p>\n<p style=\"text-align: left;\">Don&#8217;t worry \u2013 if you look in the browser Inspector, you will see a 404 error generated by TinyMCE, telling us that it cannot find our JavaScript file.<\/p>\n<p style=\"text-align: left;\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/coma.lv\/wp-content\/uploads\/2016\/11\/wordpress-tinymce-plugin-js-404.jpg\" alt=\"WordPress\" title=\"\"><\/p>\n<p style=\"text-align: left;\">This is actually a good sign, as it means we have successfully registered a custom TinyMCE plugin and now we need to create the JavaScript file that tells TinyMCE what to do.<\/p>\n<h2 style=\"text-align: left;\">Creating the JavaScript Plugin<\/h2>\n<p style=\"text-align: left;\">Create a new file in your wp-content\/plugins\/tinymce-custom-link-class folder and name it tinymce-custom-link-class.js, and then add the following code to it:<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n(function() {\r\n\ttinymce.PluginManager.add( &amp;#039;custom_link_class&amp;#039;, function( editor, url ) {\r\n\t\t\r\n\t});\r\n})();\r\n<\/pre>\n<p style=\"text-align: left;\">This calls the TinyMCE Plugin Manager class, which we can use to run a number of plugin-related actions. In particular, we add our plugin to TinyMCE using the add function. It takes two items: the plugin name (custom_link_class) and an anonymous function. If you are familiar with the concept of functions in coding, an anonymous function is simply a function without a name. For example, function foobar() { &#8230; } is a function that we can call elsewhere in the code using foobar().<\/p>\n<p style=\"text-align: left;\">With an anonymous function we cannot call the function elsewhere in the code \u2013 only through the add() function. Save your JavaScript file and start editing a page or post to see the visual editor. If everything worked, you will see the toolbar:<\/p>\n<p style=\"text-align: left;\"><img decoding=\"async\" src=\"https:\/\/coma.lv\/wp-content\/uploads\/2016\/11\/wordpress-tinymce-plugin-visual-editor-toolbar.jpg\" alt=\"WordPress\" title=\"\"><\/p>\n<p style=\"text-align: left;\">At this point our button has not been added to the toolbar. That is because we have only told TinyMCE that we have created a custom plugin. Now we need to tell TinyMCE what to do, that is, add a button to the toolbar. Update your JavaScript file, replacing the existing code with the following:<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n(function() {\r\n    tinymce.PluginManager.add(&amp;#039;custom_link_class&amp;#039;, function(editor, url) {\r\n\r\n        \/\/ Detect if ui.registry exists (v5+)\r\n        if (editor.ui &amp;amp;&amp;amp; editor.ui.registry &amp;amp;&amp;amp; typeof editor.ui.registry.addButton === &amp;#039;function&amp;#039;) {\r\n            \/\/ Modern TinyMCE (v5+)\r\n            editor.ui.registry.addButton(&amp;#039;custom_link_class&amp;#039;, {\r\n                text: &amp;#039;Insert Button Link&amp;#039;,\r\n                tooltip: &amp;#039;Insert Button Link&amp;#039;,\r\n                onAction: function() {\r\n                    editor.execCommand(&amp;#039;custom_link_class&amp;#039;);\r\n                }\r\n            });\r\n        } else {\r\n            \/\/ Legacy TinyMCE (v4)\r\n            editor.addButton(&amp;#039;custom_link_class&amp;#039;, {\r\n                title: &amp;#039;Insert Button Link&amp;#039;,\r\n                cmd: &amp;#039;custom_link_class&amp;#039;\r\n            });\r\n        }\r\n\r\n    });\r\n})();\r\n<\/pre>\n<p style=\"text-align: left;\">Note that our anonymous function has two arguments. The first is editor, which is the TinyMCE visual editor. Just as we can call various functions in the PluginManager, we can also call various functions in editor. In this case we call the addButton function to add a button to the toolbar. Save your JavaScript file and go back to the visual editor. At first glance nothing has changed. However, if you hover the mouse cursor over the icon in the upper right, you will see a tooltip:<\/p>\n<p style=\"text-align: left;\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/coma.lv\/wp-content\/uploads\/2016\/11\/wordpress-tinymce-plugin-button-noicon.jpg\" alt=\"WordPress\" title=\"\"><\/p>\n<p style=\"text-align: left;\">We have successfully added a button to the toolbar, but it needs an image. Add the following parameter to the addButton function under title:<\/p>\n<p style=\"text-align: left;\"><em>image: url + &#8216;\/icon.png&#8217;,<\/em><\/p>\n<p style=\"text-align: left;\">url is the address of our plugin. This is convenient if we want to refer to an image file in the plugin folder. In this case we will need an image named icon.png in our plugin folder. Use the following icon:<\/p>\n<p style=\"text-align: left;\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/coma.lv\/wp-content\/uploads\/2016\/11\/icon.jpg\" alt=\"WordPress\" title=\"\"><\/p>\n<p style=\"text-align: left;\">Reload the visual editor and you will see your button with its icon:<\/p>\n<p style=\"text-align: left;\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/coma.lv\/wp-content\/uploads\/2016\/11\/wordpress-tinymce-plugin-button-icon.jpg\" alt=\"WordPress\" title=\"\"><\/p>\n<h2 style=\"text-align: left;\">Specifying the Command to Run<\/h2>\n<p style=\"text-align: left;\">At this point, if you click the button, nothing will happen. Let&#8217;s add a command that will tell TinyMCE what to do. Add the following code in our JavaScript file under the end of the editor.addButton section<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n\/\/ Add Command when Button Clicked\r\neditor.addCommand(&amp;#039;custom_link_class&amp;#039;, function() {\r\n\talert(&amp;#039;Button clicked!&amp;#039;);\r\n});\r\n<\/pre>\n<p style=\"text-align: left;\">Reload our visual editor, click the button and a notice will appear saying that you have just clicked the button:<\/p>\n<p style=\"text-align: left;\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/coma.lv\/wp-content\/uploads\/2016\/11\/wordpress-tinymce-plugin-alert-button-clicked.jpg\" alt=\"WordPress\" title=\"\"><\/p>\n<p style=\"text-align: left;\">Let&#8217;s replace the notice with a prompt asking the user for the link they want to wrap around the selected text in the visual editor.<\/p>\n<pre class=\"brush: php; title: ; notranslate\" title=\"\">\r\n\/\/ Add Command when Button Clicked\r\neditor.addCommand(&amp;#039;custom_link_class&amp;#039;, function() {\r\n\t\/\/ Check we have selected some text that we want to link\r\n\tvar text = editor.selection.getContent({\r\n\t\t&amp;#039;format&amp;#039;: &amp;#039;html&amp;#039;\r\n\t});\r\n\tif ( text.length === 0 ) {\r\n\t\talert( &amp;#039;Please select some text to link.&amp;#039; );\r\n\t\treturn;\r\n\t}\r\n\r\n\t\/\/ Ask the user to enter a URL\r\n\tvar result = prompt(&amp;#039;Enter the link&amp;#039;);\r\n\tif ( !result ) {\r\n\t\t\/\/ User cancelled - exit\r\n\t\treturn;\r\n\t}\r\n\tif (result.length === 0) {\r\n\t\t\/\/ User didn&amp;#039;t enter a URL - exit\r\n\t\treturn;\r\n\t}\r\n\r\n\t\/\/ Insert selected text back into editor, wrapping it in an anchor tag\r\n\teditor.execCommand(&amp;#039;mceReplaceContent&amp;#039;, false, &amp;#039;&amp;lt;a class=&amp;quot;button&amp;quot; href=&amp;quot;&amp;#039; + result + &amp;#039;&amp;quot;&amp;gt;&amp;#039; + text + &amp;#039;&amp;lt;\/a&amp;gt;&amp;#039;);\r\n});\r\n<\/pre>\n<p style=\"text-align: left;\">The code block does several things. First we check whether the user has selected any text to wrap in the visual editor. If not, they will see the following message.<\/p>\n<p style=\"text-align: left;\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/coma.lv\/wp-content\/uploads\/2016\/11\/wordpress-tinymce-plugin-alert-select-text.jpg\" alt=\"WordPress\" title=\"\"><\/p>\n<p style=\"text-align: left;\">Then we ask them to enter a link, again checking what they did. If they cancelled or entered nothing, we also do nothing.<\/p>\n<p style=\"text-align: left;\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/coma.lv\/wp-content\/uploads\/2016\/11\/wordpress-tinymce-plugin-prompt-url.jpg\" alt=\"WordPress\" title=\"\"><\/p>\n<p style=\"text-align: left;\">Finally, we run the execCommand function in the TinyMCE editor, triggering the mceReplaceContent action. This replaces the selected text with our HTML code, which includes an anchor link with class=\u00bbbutton\u201d, using the selected text. If everything worked, you will see the text you selected linked in the visual editor with the class associated with the button:<\/p>\n<p style=\"text-align: left;\"><img decoding=\"async\" class=\"aligncenter\" src=\"https:\/\/coma.lv\/wp-content\/uploads\/2016\/11\/wordpress-tinymce-plugin-link-visual.jpg\" alt=\"WordPress\" title=\"\"><\/p>\n<h2 style=\"text-align: left;\">Summary<\/h2>\n<p style=\"text-align: left;\">We have successfully created a WordPress plugin that adds a button to the TinyMCE visual editor in WordPress. This guide also covered some basics of the TinyMCE API and filter integration. We added code so that when a user clicks our custom button, they are prompted to select text in the visual editor that they can link to a URL of their choice. Finally, our plugin replaces the selected text with its linked version, which contains a custom CSS class called button.<\/p>\n<hr \/>\n<p style=\"text-align: left;\"><em>Our specialization is WordPress website development and maintenance. Contact us for a free consultation \u2014 <a href=\"mailto:vadim@coma.lv\">vadim@coma.lv<\/a>, <a href=\"tel:+37129394520\">+371 29394520<\/a><\/em><\/p>\n<hr \/>\n","protected":false},"excerpt":{"rendered":"<p>If you are a WordPress developer, at some point you may need to extend or customize the visual editor. For example, you may want to add a button to the toolbar that lets your clients use certain features without having to resort to HTML code. In this article we will show you how to create [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":38200,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1225,1409,1407],"tags":[],"class_list":["post-41771","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-wordpress","category-plugins","category-tutorials"],"_links":{"self":[{"href":"https:\/\/coma.lv\/en\/wp-json\/wp\/v2\/posts\/41771","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/coma.lv\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/coma.lv\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/coma.lv\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/coma.lv\/en\/wp-json\/wp\/v2\/comments?post=41771"}],"version-history":[{"count":0,"href":"https:\/\/coma.lv\/en\/wp-json\/wp\/v2\/posts\/41771\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/coma.lv\/en\/wp-json\/wp\/v2\/media\/38200"}],"wp:attachment":[{"href":"https:\/\/coma.lv\/en\/wp-json\/wp\/v2\/media?parent=41771"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/coma.lv\/en\/wp-json\/wp\/v2\/categories?post=41771"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/coma.lv\/en\/wp-json\/wp\/v2\/tags?post=41771"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}