As an experienced WordPress developer, you'll often need to extend the Visual Editor with custom features, like adding a toolbar button for quick insertion of styled links or call-to-action buttons—no HTML coding required. In this comprehensive tutorial, drawn from years of plugin development at WPBeginner, we'll guide you through creating a TinyMCE plugin that adds a custom CSS class to links.

This guide is for intermediate to advanced users with basic PHP and JavaScript knowledge. Beginners should consider the TinyMCE Advanced plugin or our tips for using the default Visual Editor.
You'll need access to a WordPress site for testing. Never develop on a live site—a code error could break access. Use a staging environment or local setup, and always back up first.
We'll build a plugin that registers a custom toolbar button. Clicking it prompts for a URL and wraps selected text in a link with a 'button' CSS class. Full source code is at the end, but let's build it step by step.
Create a folder in wp-content/plugins named tinymce-custom-link-class.
In the new folder, create tinymce-custom-link-class.php and add this header:
/** * Plugin Name: TinyMCE Custom Link Class * Plugin URI: https://wpbeginner.com * Version: 1.0 * Author: WPBeginner * Author URI: https://www.wpbeginner.com * Description: A simple TinyMCE plugin to add a custom link class in the Visual Editor * License: GPL2 */
This PHP comment registers the plugin. In the WordPress admin, go to Plugins > Installed Plugins and activate "TinyMCE Custom Link Class".

To avoid function name conflicts, wrap code in a class:
class TinyMCE_Custom_Link_Class {
/**
* Constructor. Called when the plugin is initialized.
*/
function __construct() {
if ( is_admin() ) {
add_action( 'init', array( $this, 'setup_tinymce_plugin' ) );
}
}
}
$tinymce_custom_link_class = new TinyMCE_Custom_Link_Class();This ensures safe, isolated functionality.
Add this to the constructor to hook into TinyMCE only in admin:
if ( is_admin() ) {
add_action( 'init', array( $this, 'setup_tinymce_plugin' ) );
}Now define setup_tinymce_plugin():
/**
* Check if the user can edit posts/pages and uses Visual Editor, then register plugin.
*/
function setup_tinymce_plugin() {
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', array( $this, 'add_tinymce_plugin' ) );
add_filter( 'mce_buttons', array( $this, 'add_tinymce_toolbar_button' ) );
}This verifies permissions and editor usage before applying filters.
Add add_tinymce_plugin():
/**
* Adds the TinyMCE-compatible JS file to the editor instance.
*
* @param array $plugin_array Array of registered TinyMCE plugins.
* @return array Modified array.
*/
function add_tinymce_plugin( $plugin_array ) {
$plugin_array['custom_link_class'] = plugin_dir_url( __FILE__ ) . 'tinymce-custom-link-class.js';
return $plugin_array;
}And add_tinymce_toolbar_button():
/**
* Adds a button to the TinyMCE toolbar for custom links.
*
* @param array $buttons Array of registered TinyMCE buttons.
* @return array Modified array.
*/
function add_tinymce_toolbar_button( $buttons ) {
array_push( $buttons, '|', 'custom_link_class' );
return $buttons;
}Edit a post/page. Check browser console for a 404 on the JS file—that's expected; we've registered it successfully.


Create tinymce-custom-link-class.js in the plugin folder:
(function() {
tinymce.PluginManager.add( 'custom_link_class', function( editor, url ) {
});
})();Edit a post; toolbar appears but no button yet.

Add the button:
(function() {
tinymce.PluginManager.add( 'custom_link_class', function( editor, url ) {
editor.addButton( 'custom_link_class', {
title: 'Insert Button Link',
cmd: 'custom_link_class',
image: url + '/icon.png'
});
});
})();Download this icon as icon.png in the plugin folder:

Reload; button appears.

Add command after addButton:
// Add command for button click
editor.addCommand( 'custom_link_class', function() {
var text = editor.selection.getContent( {format: 'html'} );
if ( text.length === 0 ) {
alert( 'Please select some text to link.' );
return;
}
var result = prompt( 'Enter the link URL' );
if ( !result || result.length === 0 ) {
return;
}
editor.execCommand( 'mceReplaceContent', false, '<a href="' + result + '" class="button">' + text + '</a>' );
});This checks selection, prompts for URL, and inserts <a href="URL" class="button">text</a>.


Result in Visual and Text views:


We've built a WordPress plugin that enhances TinyMCE with a custom toolbar button for styled links. This covers key TinyMCE API and WordPress filter concepts.
Select text, click the button, enter a URL, and get an instant <a class="button"> link. For more, see our guide to site-specific plugins.
If this helped, subscribe to our YouTube channel for video tutorials. Follow us on Twitter and Facebook.