返回

WordPress 3.9 TinyMCE 4 自定义短代码失效修复

javascript

WordPress 3.9 TinyMCE 4 可视化编辑器中自定义短代码失效的解决办法

升级到 WordPress 3.9 后,以前在 TinyMCE 编辑器中用来显示自定义短代码的下拉列表不见了。原来 functions 文件里的代码,还有 Javascript 文件里的代码都需要改。

问题原因

WordPress 3.9 版本对 TinyMCE 编辑器进行了重大升级,升级到了 TinyMCE 4。这次升级改变了编辑器 API 的调用方式,导致原先用于创建自定义下拉菜单的代码不再有效。 主要原因是 TinyMCE 4 不再支持 createListBox 方法。

解决方案

要让自定义短代码下拉菜单重新工作,我们需要对代码做一些修改,主要是替换旧的 TinyMCE API 并适配新的API:

方案一: 使用 addCommandaddMenuItem (推荐)

这种方法更符合 TinyMCE 4 的 API 设计,也更简洁。

  1. 修改 functions.php (可选) :

    原来的 functions.php 文件中的代码基本不需要改变,能继续使用。为让代码更加规范,可以将函数名改成更具有性的名称。例如:

    function register_kleen_shortcodes_dropdown( $buttons ) {
       array_push( $buttons, "kleen_shortcodes" ); // 使用更具性的按钮 ID
       return $buttons;
    }
    
    function add_kleen_shortcodes_dropdown( $plugin_array ) {
       $plugin_array['kleen_shortcodes'] = get_template_directory_uri() . '/js/mybuttons.js';  // 使用更具描述性的插件 ID
       return $plugin_array;
    }
    
    function kleen_shortcodes_dropdown() {
    
       if ( ! current_user_can('edit_posts') && ! current_user_can('edit_pages') ) {
          return;
       }
    
       if ( get_user_option('rich_editing') == 'true' ) {
          add_filter( 'mce_external_plugins', 'add_kleen_shortcodes_dropdown' );
          add_filter( 'mce_buttons', 'register_kleen_shortcodes_dropdown' );
       }
    
    }
    
    add_action('init', 'kleen_shortcodes_dropdown');
    
    
  2. 修改 mybuttons.js :

    这是主要需要修改的地方。我们需要使用 addCommand 来插入短代码,使用 addMenuItem 来创建下拉菜单项。

    (function() {
        tinymce.PluginManager.add('kleen_shortcodes', function( editor, url ) { // 与 functions.php 中的插件 ID 对应
            var shortcodes = {
                'Tabs Wrapper': '[tabs_wrap][/tabs_wrap]',
                'Tab Content': '[tab_content title=""][/tab_content]',
                'Accordion Wrapper': '[accordion_wrap][/accordion_wrap]',
                'Accordion Content': '[accordion_content title=""][/accordion_content]',
                'Button Link': '[button_link][/button_link]',
                'Column 1/2': '[one_half][/one_half]',
                'Column 1/2 Last': '[one_half_last][/one_half_last]',
                'Column 1/3': '[one_third][/one_third]',
                'Column 1/3 Last': '[one_third_last][/one_third_last]',
                'Column 1/4': '[one_fourth][/one_fourth]',
                'Column 1/4 Last': '[one_fourth_last][/one_fourth_last]',
                'Column 1/2 Center': '[one_half_center][/one_half_center]',
                'Column 1/2 Center Last': '[one_half_center_last][/one_half_center_last]',
                'Column 1/3 Center': '[one_third_center][/one_third_center]',
                'Column 1/3 Center Last': '[one_third_center_last][/one_third_center_last]',
                'Column 1/4 Center': '[one_fourth_center][/one_fourth_center]',
                'Column 1/4 Center Last': '[one_fourth_center_last][/one_fourth_center_last]',
                'Column 3/4': '[three_fourth][/three_fourth]',
                'Column 3/4 Last': '[three_fourth_last][/three_fourth_last]',
                'Column 2/3': '[two_third][/two_third]',
                'Column 2/3 Last': '[two_third_last][/two_third_last]',
                'Highlight Text': '[highlight][/highlight]',
                'Blockquote': '[blockquote][/blockquote]',
                'Recent Post': '[post_recent posts="2"]',
                'Recent Sermons': '[recent_sermons posts="2"]',
                'Staff List': '[staff_category posts="4" staff_category=""]',
                'Check List': '[check_list][/check_list]',
                'Times List': '[times_list][/times_list]',
                'Arrow List': '[arrow_list][/arrow_list]',
                'Horizontal Rule Center': '[horizontal_rule_center][/horizontal_rule_center]'
            };
    
             // 添加菜单按钮
             editor.addButton( 'kleen_shortcodes', { //和 mce_buttons 数组内的按钮 id 对应
                type: 'menubutton', // 改成 menubutton
                text: 'Kleen Shortcodes',  // 菜单显示的文字
                icon: false,           // 可以设置一个图标,也可以不设置
                menu: Object.keys(shortcodes).map(function(key) { // 遍历生成菜单项
                    return {
                        text: key, //每个下拉的文本
                        onclick: function() {
                             var content =  shortcodes[key];
                             // 使用更简洁的 insertContent 插入短代码
                             editor.insertContent(content);
                        }
                    };
                })
             });
        });
    })();
    
    
    • tinymce.PluginManager.add: 第一个参数 'kleen_shortcodes' 应该与 functions.phpadd_kleen_shortcodes_dropdown 函数里设置的插件 ID 一致。
    • editor.addButton: 创建一个菜单按钮(menubutton)。
    • menu: 这个属性定义了下拉菜单中的项目。 使用Object.keys(shortcodes).map 循环生成菜单项。
    • onclick: 直接使用editor.insertContent(content)插入对应短代码, 代码简洁了不少。

方案二: 使用 addButtontype: 'listbox' (不推荐, 但可以作为旧代码升级参考)

如果想尽可能保留原来的 JavaScript 代码结构, 那么这种方案修改幅度最小。 但需要注意的是, 官方文档不再建议使用listbox

  1. functions.php : 与方案一相同, 可以选择性修改。

  2. mybuttons.js :

    (function() {
        tinymce.PluginManager.add('kleen_shortcodes', function( editor, url ) {
    
            var shortcodes = {
                'Tabs Wrapper': '[tabs_wrap][/tabs_wrap]',
                'Tab Content': '[tab_content title=""][/tab_content]',
                'Accordion Wrapper': '[accordion_wrap][/accordion_wrap]',
                'Accordion Content': '[accordion_content title=""][/accordion_content]',
                'Button Link': '[button_link][/button_link]',
                'Column 1/2': '[one_half][/one_half]',
                'Column 1/2 Last': '[one_half_last][/one_half_last]',
                'Column 1/3': '[one_third][/one_third]',
                'Column 1/3 Last': '[one_third_last][/one_third_last]',
                'Column 1/4': '[one_fourth][/one_fourth]',
                'Column 1/4 Last': '[one_fourth_last][/one_fourth_last]',
                'Column 1/2 Center': '[one_half_center][/one_half_center]',
                'Column 1/2 Center Last': '[one_half_center_last][/one_half_center_last]',
                'Column 1/3 Center': '[one_third_center][/one_third_center]',
                'Column 1/3 Center Last': '[one_third_center_last][/one_third_center_last]',
                'Column 1/4 Center': '[one_fourth_center][/one_fourth_center]',
                'Column 1/4 Center Last': '[one_fourth_center_last][/one_fourth_center_last]',
                'Column 3/4': '[three_fourth][/three_fourth]',
                'Column 3/4 Last': '[three_fourth_last][/three_fourth_last]',
                'Column 2/3': '[two_third][/two_third]',
                'Column 2/3 Last': '[two_third_last][/two_third_last]',
                'Highlight Text': '[highlight][/highlight]',
                'Blockquote': '[blockquote][/blockquote]',
                'Recent Post': '[post_recent posts="2"]',
                'Recent Sermons': '[recent_sermons posts="2"]',
                'Staff List': '[staff_category posts="4" staff_category=""]',
                'Check List': '[check_list][/check_list]',
                'Times List': '[times_list][/times_list]',
                'Arrow List': '[arrow_list][/arrow_list]',
                'Horizontal Rule Center': '[horizontal_rule_center][/horizontal_rule_center]'
            };
    
            editor.addButton('kleen_shortcodes', {
                type: 'listbox', // 虽然不推荐,但为了兼容,这里保留
                text: 'Kleen Shortcodes',
                icon: false,
                fixedWidth: true, // 让宽度固定
                onselect: function(e) { // 当选择某个选项
                   var selectedValue = this.value();
                   if (selectedValue) { //值存在
                        var content = shortcodes[selectedValue];
                        editor.insertContent(content); //使用 insertContent 插入
                   }
    
                },
                values: Object.keys(shortcodes).map(function(key) { //生成选项
                   return {text: key, value: key};
                })
            });
        });
    })();
    
  • 删除了 createControl
  • 修改tinymce.createtinymce.PluginManager.add,参数和上面一致。
  • 使用 editor.addButton 注册按钮, 使用 type: 'listbox' 来创建一个列表框.
  • 通过 values 属性配置下拉列表的选项,把文本和值设置成一致.
  • 使用 onselect 事件来插入短代码, this.value() 可以获取选中的值.

安全建议

无论采用哪种方案,都建议:

  • 备份: 在修改任何代码之前,请务必备份你的 functions.phpmybuttons.js 文件。
  • 测试: 修改完成后,请彻底测试所有短代码,确保它们在 WordPress 编辑器中能正常工作。

进阶使用技巧

  1. 增加图标
    可以在addButton中设置 icon 属性, 从而为按钮增加图标。 首先在主题文件夹的images这类目录下放入一个你希望的 icon, 命名为 shortcode-icon.png (或者其他你希望的文件名),然后在 addButton设置,例如:
    editor.addButton( 'kleen_shortcodes', { //和 mce_buttons 数组内的按钮 id 对应
              type: 'menubutton',
              text: 'Kleen Shortcodes',
              icon: 'shortcode-icon', //引入图标,不需要写完整路径和文件后缀名
               image: url + '/../images/shortcode-icon.png',  //  使用绝对路径,确保图标能找到,  url 指向 js 文件的路径,所以这里需要用 ../images/ 找到图片
              menu: // 保持不变
...

icon 使用的是 TinyMCE 内置的图标名称。如果想使用自定义的图标,则设置image参数即可.
2. 分组菜单

如果短代码非常多,可以给他们进行分组,让菜单更整洁。 例如:
     editor.addButton( 'kleen_shortcodes', {
        type: 'menubutton',
        text: 'Kleen Shortcodes',
        icon: false,
        menu: [
            {
                text: '布局', // 一级菜单
                menu: [  //二级菜单
                    {text: 'Column 1/2', onclick: function() { editor.insertContent('[one_half][/one_half]'); }},
                    {text: 'Column 1/2 Last', onclick: function() { editor.insertContent('[one_half_last][/one_half_last]'); }},
                    // 其他布局短代码...
                ]
            },
            {
                text: '内容',
                menu: [
                    {text: 'Tabs Wrapper', onclick: function() { editor.insertContent('[tabs_wrap][/tabs_wrap]'); }},
                    {text: 'Tab Content', onclick: function() { editor.insertContent('[tab_content title=""][/tab_content]'); }},
                    // 其他内容短代码
                ]
            },
             //其他分组
        ]
     });

通过以上步骤,就能完美解决 WordPress 3.9 版本 TinyMCE 编辑器中自定义短代码下拉菜单失效的问题, 使短代码功能重新工作。