Programming » Wordpress

Add Ace Editor to Theme Options Textarea

I tried to create a simple Theme Options page which allowed to add custom CSS style to the site.
WordPress saved the content of the field to the database and then the theme script retrieved the saved value and included it as inline style.

Ace editor raw textarea [sm]

It worked well but I wanted to highlight and indent the code. So I found this tutorial on Tuts+.
I guess the tutorial used Ace editor of version 1.0.0 of something near. So I worked with more modern version 1.1.8.
And had to change some adjustments so that the editor works.

Here are my own steps I used to implement the editor feature.

1. Download Ace editor from GitHub.

2. Get these files and copy them to js/ace/ folder in the theme

ace.js
mode-css.js
worker-css.js

3. Create file custom.js in the same folder

( function( global, $ ) {
  var editor,
  syncCSS = function() {
    $('#custom_css_textarea').val( editor.getSession().getValue() );
  },
  loadAce = function() {
    editor = ace.edit( 'custom_css_div' );

    global.safecss_editor = editor;
    editor.getSession().setUseWrapMode( true );
    editor.getSession().setValue( $( '#custom_css_textarea' ).val() );
    editor.getSession().setMode("ace/mode/css");

    $( '#options_form' ).submit( syncCSS );
    editor.focus();
  };

  $( global ).load( loadAce );
  global.aceSyncCSS = syncCSS;
  
} )( this, jQuery );

Here it is necessary to change some text:

custom_css_textarea - textarea id
custom_css_div - id of inner <div> which will be the editor itself
options_form - options form id

editor.getSession().setValue() – gets data from the textarea and puts it to the editor.
$('#custom_css_textarea').val() – copies the text to the textarea so it can be saved to the database on form submit.

4. Add scripts to admin page: functions.php

function custom_css_scripts( $hook ) {
  if ( 'appearance_page_theme_options' == $hook ) {
    wp_enqueue_style( 'admin-custom-style' , get_template_directory_uri() . '/css/admin-theme-options.css' );
    
    wp_enqueue_script( 'ace_js', get_template_directory_uri() . 'js/ace/ace.js', '', '1.0.0', true );
    wp_enqueue_script( 'ace_mode_js', get_template_directory_uri() . 'js/ace/mode-css.js', array( 'ace_js' ), '1.0.0', true );
    wp_enqueue_script( 'custom_js', get_template_directory_uri() . 'js/ace/custom-css.js', array( 'jquery', 'ace_js' ), '1.0.0', true );
  }
}
add_action( 'admin_enqueue_scripts', 'custom_css_scripts' );

The if part filters the admin pages so these scripts only load when the Theme Options page is loaded.
And this function is for my theme options so the link is situated in the Appearance menu and the textarea with the CSS code is on this page (no subpages for this simple example).

The admin-theme-options.css file is explained later.

5. Add the necessary markup for the options page

<div id="custom_css_container">
  <div name="custom_css_div" id="custom_css_div"></div>
</div>

<textarea name="theme_general_options[custom_css]" id="custom_css_textarea" cols="60" rows="20"><?php echo esc_textarea( $options['custom_css'] ) ?></textarea>

The “custom_css_div” will contain the editor markup after script is executed. And textarea will get text from the editor which will be then saved to the database:

table: wp_options
option_name: theme_general_options
option_value: custom_css:[css]

The option_value part will be in JSON format because it will contain other options for each field in the options form.

6. Edit the style

Create file admin-theme-options.css and put it to the css folder in the theme. Add this to the file:

#custom_css_div{
  position: relative;
  width: 100%; 
  height: 400px; 
  font-size:15px;
  border: 1px solid #DFDFDF; 
  border-radius: 3px; 
}
#custom_css_textarea{
  display: none;
}

This will hide the textarea and set the size of the editor. For the debug purpose you may comment the textarea style and check if the data is showing in the same way in both textarea and editor.

7. Watch the Editor

Now the editor should appear on the theme options page. Check the saving and database theme_general_options field content.

Ace editor [sm]

8. Check the style on the front end.

Add the code to the functions.php

function display_custom_style() {
  $opt = get_option( 'theme_general_options' );
  if($opt){
    $css=$opt['custom_css'];
    if($css){
    ?>
      <style id="custom-style">
        <?php echo $css ?>
      </style>
<?php
    }
  }
}
add_action( 'wp_head', 'display_custom_style' );

9. What editor gives

  • Code folding

    Ace editor folding [sm]

  • Highlight matching braces
  • Syntax checking
  • Multicursor to edit multiple regions at the same time.

    Ace editor multicursor [sm]

  • Keyboard Shortcuts.

10. Extend the editor.

It is possible to use some additional features in the editor:

  • Set custom options
  • Enable autocompletion
  • Include Emmet snippets
  • Add search box
  • Add custom keyboard shortcuts
  • Change theme

Demos for these features can be seen here or in the ace-builds/demo folder of the downloaded repository.

a. Custom options

1. Options general overview may be seen on the GitHub pages here and here.

2. I used this code to set options (insert it in the loadAce() function)

editor.setOptions({
  fontSize:15,
  tabSize:2,
  displayIndentGuides:true,
  useSoftTabs:true,
  showPrintMargin:false,
});

b. Autocompletion

1. Allows to autocomplete language keywords, snippets and local words from the text

2. To add this tool check the autocompletion.html file source in the demo folder.

3. The steps are following:

  1. Copy additional files to the js/ace/ folder of the theme
    src/ext-language_tools.js
    src/snippets/css.js
  2. Add the code to the custom.js
    ace.require("ace/ext/language_tools");
    editor.setOptions({
      enableBasicAutocompletion: true,
      enableLiveAutocompletion: true,
      enableSnippets: true,
    });
  3. Add the code to the functions.php custom_css_scripts() function

    wp_enqueue_script( 'ace_language_tools_js', get_template_directory_uri() . '/js/ace/ext-language_tools.js', array( 'ace_js' ), '1.0.0', true );
  4. Check the feature
    If enableLiveAutocompletion is set the popup window should appear after typing first letters of a keyword. Otherwise the Ctrl+Space key will open it.
    The snippets are triggered after typing the snippet key and pressing Tab.

    For example, typing

    bxsh+
    

    with Tab will output the

    box-shadow: ${1:0} ${2:0} ${3:0} #${4:000}
    

    code which allows to set each parameter and switch between them with Tab again.

    The snippets list can be retrieved from the snippets/css.js file in the theme or from the source css.snippet file. For this download the source package from another repository. It contains source files which are built in the final release with the Node.js. So for snippets go to the lib/ace/snippets and view the css.snippets file. It has the following structure:

    snippet [key]
    [snippet]

    [key] is typed in the editor and the [snippet] is printed after the Tab key.

Ace editor autocompletion

c. Emmet snippets

1. Emmet is a web-toolkit which primarily used for easier HTML typing. But it also has a lot os CSS abbreviations. The full list can be found here.

2. It may be more useful to disable default snippets and include Emmet. Because both features enabled can produce some autocompletion conflicts.

3. To add Emmet functionality to the editor use these steps:

  1. Copy file to the js/ace/ folder:
    src/ext-emmet.js
  2. Download the Emmet For Ace repository which contains packaged Emmet script and snippets for Ace editor. Then copy emmet.js file to js/ace/ folder.
  3. Add the code to the custom.js
    editor.setOptions({
      enableEmmet: true,
    });
  4. Add the code to the functions.php custom_css_scripts() function
    wp_enqueue_script( 'emmet_js', get_template_directory_uri() . '/js/ace/emmet.js', array('underscore'), '1.0.0', true );
    wp_enqueue_script( 'ace_emmet_js', get_template_directory_uri() . '/js/ace/ext-emmet.js', array( 'ace_js' ), '1.0.0', true );
  5. Reload the options page and check some snippets
    bd+ -> border: 1px solid #000;
    fwb -> font-weight: bold;
    bg#a -> background: #aaa;

Ace editor emmet before [sm]

Ace editor emmet after [sm]

d. Search box    

1. Allows general searching through the text, replacing, using Regex and whole word searching.

2. To add the search box follow the steps:

  1. Copy file to the js/ace/ folder:
    src/ext-searchbox.js
    
  2. Add the code to the custom.js
    ace.require("ace/ext/searchbox");
  3. Add the code to the functions.php custom_css_scripts() function
    wp_enqueue_script( 'ace_search_js', get_template_directory_uri() . '/js/ace/ext-searchbox.js', array( 'ace_js' ), '1.0.0', true );
  4. Check the search. Press Ctrl+F and try its functions.

Ace editor search [sm]

Ace editor replace [sm]

e. Custom keyboard shortcuts

1. In addition to default shortcuts it’s possible to add custom commands.

2. I’ve taken an example code from the demo/scrollable-page.html file in the build package. It adds the F11 key for the fullScreen command.

3. To implement the full screen feature I used these steps:

  1. Add the code to the custom.js

    var dom = require("ace/lib/dom");
      
    editor.commands.addCommands([{
      name: "toggleFullscreen",
      bindKey: {win: "F11", mac: "F11"},
      exec: function(editor) {
        var fullScreen = dom.toggleCssClass(document.body, "fullScreen")
        dom.setCssClass(editor.container, "fullScreen", fullScreen)
        
        var leftMenu,topMenu,left,top,width,height
        
        if(fullScreen){
          leftMenu=$("#adminmenuwrap")
          topMenu=$("#wpadminbar")
          
          left=leftMenu.width()
          top=topMenu.height()
          width=$(window).width()-left
          height=$(window).height()-top
        }else{
          left=0
          top=0
          width="100%"
          height="400px"
        }
        
        var container=$(editor.container)
        container.css({
          "width":width,
          "height":height,
          "left":left,
          "top":top
        })
        
        editor.setAutoScrollEditorIntoView(!fullScreen)
        editor.resize()
      },
      readOnly: true
    }]);

    The addCommands() function has 3 parts:

    name - command name
    bindKey - shortcut key
    exec - function to execute when the shortcut is pressed

    To use a key combination add plus (+) between keys (Ctrl+Q)

    The function first toggles the body class to “fullScreen”. Then it adds or removes the “fullScreen” class from the editor container (div element) depending on the toggling result for the body. Then the styles for the editor are set. If editor is going to go to the full screen it is necessary to calculate its coordinates and dimensions. Unlike in the demo page example I didn’t use the 100% width and height but used relative values which depend on admin top and left menu dimensions. If F11 moves the editor to the normal size then the default dimensions are set. So after these calculations the editor resizes and is shown in full screen or normal mode.

    If you want to have the absolutely full screen change the code this way:

    if(fullScreen){
      left=0
      top=0
      width="100%"
      height="100%"
    
      var container=$(editor.container)
      container.css({
        "width":width,
        "height":height,
        "left":left,
        "top":top,
        "z-index":100000
      })
    }

    The z-index part will overlap the admin menus.

  2. Check the function. Press F11 in the editor – it goes to the full screen mode. Press again – it restores the normal size.

    Ace editor full screen [sm]

  3. Now it would be better to create a new function to set the default style of the editor, because it’s used on the load and when the editor returns from the full screen mode. So in the else branch of this part
    if(fullScreen){

    add this code

    else{
      setInitialStyle()
    }

    and in the end of the script, before the }) brackets add the function

    function setInitialStyle(){
      var container=$(editor.container)
      container.css({
        "width":"100%",
        "height":"400px",
        "left":"0",
        "top":"0",
      })
    }

    also add these lines after the setOptions() function

    setInitialStyle()
    editor.resize()

    This will allow to change size in one place.

f. Change theme

1. There is a lot of default themes in the src folder of the Ace package. They have names in the theme-[name].js format.

2. If you need another theme copy on of the “theme-“ files to the js/ace/ folder and add this code to the custom.js

editor.setTheme("ace/theme/tomorrow_night");

or other name instead of “tomorrow_night”.

Ace editor replace theme [sm]

3. If you need to customize some styles of the theme you can create own theme following these steps:

  1. Copy the theme file and rename it as “theme-[name].js”.

  2. Open it and change styles for different syntax parts.

    You can find the right class names to change with the tools like Firebug or default Inspectors in Firefox and Chrome browsers. Start with “Inspect element” command on the editor and go down the DOM tree finding these classes:

    ace_scroller -> ace_content -> ace_layer ace_text-layer

    Each line of the editor is represented by a div’s with classes ace_line_group -> ace_line. And each ace_line has its parts corresponding to syntax parts of CSS (keywords, numbers, constants, strings).

  3. Set theme using this code in the custom.js

    editor.setTheme("ace/theme/[name]");
  4. Add code to the functions.php custom_css_scripts() function

    wp_enqueue_script( 'ace_theme_js', get_template_directory_uri() . '/js/ace/theme-[name].js', array( 'ace_js' ), '1.0.0', true );
  5. Reload the page.

Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>