Подсветка синтаксиса стала своего рода стандартным вопросом для обсуждения и написания практических руководств на целом ряде сайтов. Доступно множество способов для включения подсветки синтаксиса в зависимости от того, какие языки вы используете и как хотите отображать свой код.

Долгое время автор этого руководства использовал для данной цели Google Prettify, поскольку он прост в настройке. Единственный недостаток в его применении кроется в том, что он не всегда создает выделение цветом для всех используемых вами элементов кода. Попытки переработать его на свой лад не увенчались успехом, поскольку с данным инструментом не так-то просто разобраться самостоятельно в плане внесения авторских правок в исходный его код.

Скачать исходники | Демонстрация

К счастью, не так давно был найден другой инструмент для подсветки синтаксиса под названием Prism.js, позволяющий расширять возможности подсветки синтаксиса и выделения блоков разметки кода в HTML и CSS силами достаточно простого плагина.

Взяв за основу данный инструмент и добавив в него поддержку нумерации строк и подсветку кода PHP, а также изменив несколько паттернов по работе с различными элементами разных языков, автор смог получить плагин, речь о создании и использовании которого и пойдет в этой статье.

Собираем плагин

Нам надо всего лишь добавить функцию и шорт-код в WordPress, чтобы мы могли легко включать подсветку кода в своих сниппетах, используя для этой цели слегка модифицированный скрипт Prism.js. Самый простой способ решить все задачи — это сделать отдельный плагин. В итоговом виде выглядеть это будет как-то вот так:

Начнем писать наш плагин с обязательных полей:

/*
Plugin Name: Syntax Highlighter
Plugin URI: http://wp.tutsplus.com/tutorials/plugins/adding-a-syntax-highlighter-shortcode-using-prism-js
Description: Highlight your code snippets with an easy to use shortcode based on Lea Verou's Prism.js.
Version: 1.0.0
Author: c.bavota
Author URI: http://bavotasan.com
*/

Далее добавим наш шорт-код и обработаем этот код, чтобы быть уверенными в том, что он сработает в точно нужное нам время:

add_filter( 'the_content', 'sh_pre_process_shortcode', 7 );
/**
 * Functionality to set up highlighter shortcode correctly.
 *
 * This function is attached to the 'the_content' filter hook.
 *
 * @since 1.0.0
 */
function sh_pre_process_shortcode( $content ) {
    global $shortcode_tags;
    $orig_shortcode_tags = $shortcode_tags;
    $shortcode_tags = array();
    // New shortcodes
    add_shortcode( 'code', 'sh_syntax_highlighter' );
    $content = do_shortcode( $content );
    $shortcode_tags = $orig_shortcode_tags;
    return $content;
}
/**
 * Code shortcode function
 *
 * This function is attached to the 'code' shortcode hook.
 *
 * @since 1.0.0
 */
function sh_syntax_highlighter( $atts, $content = null ) {
    extract( shortcode_atts( array(
        'type' => 'markup',
        'title' => '',
        'linenums' => '',
    ), $atts ) );
    $title = ( $title ) ? ' rel="' . $title . '"' : '';
    $linenums = ( $linenums ) ? ' data-linenums="' . $linenums . '"' : '';
    $find_array = array( '[', ']' );
    $replace_array = array( '[', ']' );
    return '</pre>
<div class="syntax-highlighter" title="">
<pre><code class="language-' . $type . '">' . preg_replace_callback( '|(.*)|isU', 'sh_pre_entities', trim( str_replace( $find_array, $replace_array, $content ) ) ) . '</code></pre>
</div>
<pre>
';
}
/**
 * Helper function for 'sh_syntax_highlighter'
 *
 * @since 1.0.0
 */
function sh_pre_entities( $matches ) {
    return str_replace( $matches[1], htmlentities( $matches[1]), $matches[0] );
}

Функция sh_pre_process_shortcode() нужная для того, чтобы синтаксис нашего шорт-кода был обработан до того, как все фильтры контента уберут текст, предложенный в WordPress по умолчанию. Вспомогательная функция отфильтрует наш код и заменит значения HTML-кода нашими соответственными значениями и параметрами.

Делаем запросы к скриптам и стилям

Чтобы наш плагин работал как следует, нам надо добавить парочку функций в наши файлы CSS и JS:

add_action( 'wp_enqueue_scripts', 'sh_add_js' );
/**
 * Load all JavaScript to header
 *
 * This function is attached to the 'wp_enqueue_scripts' action hook.
 *
 * @uses    is_admin()
 * @uses    is_singular()
 * @uses    wp_enqueue_script()
 * @uses    plugins_url()
 *
 * @since 1.0.0
 */
function sh_add_js() {
    if ( sh_has_shortcode( 'code' ) ) {
        wp_enqueue_script( 'sh_js', plugins_url( 'js/sh.js', __FILE__ ), '', '', true );
        wp_enqueue_style( 'sh_css', plugins_url( 'css/sh.css', __FILE__ ) );
    }
}
/**
 * Check posts to see if shortcode has been used
 *
 * @since 1.0.0
 */function sh_has_shortcode( $shortcode = '' ) {
    global $wp_query;
    foreach( $wp_query->posts as $post ) {
        if ( ! empty( $shortcode ) && stripos($post->post_content, '[' . $shortcode) !== false ) {
            return true;
        }
    }
    return false;
}

К ним также надо сделать запросы, но только в том случае, если наш шорт-код используется в структуре контента конкретного поста. Поэтому нам надо ввести дополнительную функцию, которая будет проверять, есть ли в посте требуемый шорт-код.

Быстрая разметка тегами

Добавляем быстрый тег к нашему шорт-коду, это достаточно просто:

add_action( 'admin_enqueue_scripts', 'sh_add_quicktags' );
/**
 * Adds a syntax highlighter quicktag to the post editor
 *
 * This function is attached to the 'admin_print_footer_scripts' action hook.
 *
 * @since 1.0.0
 */
function sh_add_quicktags( $hook ) {
    if( 'post.php' == $hook ||  'post-new.php' == $hook )
        wp_enqueue_script( 'sh_quicktag_js', plugins_url( 'js/quicktag.js', __FILE__ ), array( 'quicktags' ), '', true );
}

Вот что нам понадобится в файле quicktag.js:

QTags.SyntaxButton = function() {
    QTags.TagButton.call( this, 'syntax_highlighter', 'syntax highlighter', '', '[/code]' );
};
QTags.SyntaxButton.prototype = new QTags.TagButton();
QTags.SyntaxButton.prototype.callback = function( e, c, ed ) {
    var type, linenums, title, t = this;
    if ( t.isOpen( ed ) === false ) {
        type = prompt( 'Type (markup, php, css, javascript)', 'markup' ),
        title = prompt( 'Title (optional)' ),
        linenums = prompt( 'Line number (optional)' );
        type = ( type ) ? ' type="' + type + '"' : '';
        title = ( title ) ? ' title="' + title + '"' : '';
        linenums = ( linenums ) ? ' linenums="' + linenums + '"' : '';
        if ( type ) {
            t.tagStart = '1';
            QTags.TagButton.prototype.callback.call( t, e, c, ed );
        }
    } else {
        QTags.TagButton.prototype.callback.call( t, e, c, ed );
    }
};
edButtons[150] = new QTags.SyntaxButton();

Оформление CSS

Для выделения синтаксиса я предпочитаю темную тему, поэтому использую следующие параметры для CSS:

code[class*="language-"],
pre[class*="language-"] {
    color: #fff;
    text-shadow: 0 1px 1px #000;
    font-family: Menlo, Monaco, "Courier New", monospace;
    direction: ltr;
    text-align: left;
    word-spacing: normal;
    white-space: pre;
    word-wrap: normal;
    line-height: 1.4;
    background: none;
    border: 0;
    -moz-tab-size: 4;
    -o-tab-size: 4;
    tab-size: 4;
    -webkit-hyphens: none;
    -moz-hyphens: none;
    -ms-hyphens: none;
    hyphens: none;
    }
    pre[class*="language-"] code {
        float: left;
        padding: 0 15px 0 0;
        }
pre[class*="language-"],
:not(pre) > code[class*="language-"] {
    background: #222;
    }
.syntax-highlighter[rel] {
    position: relative;
    }
    .syntax-highlighter[rel] pre[class*="language-"] {
        padding-top: 44px;
        }
    .syntax-highlighter[rel]:before {
        content: attr(rel);
        text-align: center;
        text-shadow: 1px 1px 2px rgba(0,0,0,0.6);
        position: absolute;
        top: -1px;
        background: #3A87AD;
        padding: 5px 10px;
        left: 0;
        right: 0;
        font: bold 16px/20px "myriad-pro-1","myriad-pro-2","Lucida Grande",Sans-Serif;
        color: #fff;
        -moz-border-radius: 7px 7px 0 0;
        -webkit-border-radius: 7px 7px 0 0;
        border-radius: 7px 7px 0 0;
        }
/* Code blocks */
pre[class*="language-"] {
    padding: 15px;
    margin: 1em 0;
    overflow: auto;
    -moz-border-radius: 8px;
    -webkit-border-radius: 8px;
    border-radius: 8px;
    }
/* Inline code */
:not(pre) > code[class*="language-"] {
    padding: 5px 10px;
    line-height: 1;
    -moz-border-radius: 3px;
    -webkit-border-radius: 3px;
    border-radius: 3px;
    }
.token.comment,
.token.line-comment,
.token.prolog,
.token.doctype,
.token.cdata {
    color: #797979;
    }
.token.selector,
.token.operator,
.token.punctuation {
    color: #fff;
    }
.namespace {
    opacity: .7;
    }
.token.tag,
.token.boolean {
    color: #ffd893;
    }
.token.atrule,
.token.attr-value,
.token.hex,
.token.string {
    color: #B0C975;
    }
.token.property,
.token.entity,
.token.url,
.token.attr-name,
.token.keyword {
    color: #c27628;
    }
.token.regex {
    color: #9B71C6;
    }
.token.entity {
    cursor: help;
    }
.token.function,
.token.constant {
    color: #e5a638;
    }
.token.variable {
    color: #fdfba8;
    }
.token.number {
    color: #8799B0;
    }
.token.important,
.token.deliminator {
    color: #E45734;
    }
pre[data-line] {
    position: relative;
    padding: 1em 0 1em 3em;
    }
.line-highlight {
    position: absolute;
    left: 0;
    right: 0;
    padding: inherit 0;
    margin-top: 1em; /* Same as .prism’s padding-top */
    background: rgba(255,255,255,.2);
    pointer-events: none;
    line-height: inherit;
    white-space: pre;
    }
    .line-highlight:before,
    .line-highlight[data-end]:after {
        content: attr(data-start);
        position: absolute;
        top: .3em;
        left: .6em;
        min-width: 1em;
        padding: 0 .5em;
        background-color: rgba(255,255,255,.3);
        color: #fff;
        font: bold 65%/1.5 sans-serif;
        text-align: center;
        -moz-border-radius: 8px;
        -webkit-border-radius: 8px;
        border-radius: 8px;
        text-shadow: none;
        }
    .line-highlight[data-end]:after {
        content: attr(data-end);
        top: auto;
        bottom: .4em;
        }
/* for line numbers */
ol.linenums {
    margin: 0;
    padding: 0 0 0 35px;
    }
    .linenums li {
        padding-left: 10px;
        border-left: 3px #d9d336 solid;
        }

Использование шорт-кода

Код нашего "разметчика" содержит три атрибута: type, title и linenums. Расшифруем, что же они означают:

  • type: 4 типа языка, которые работают с нашим "разметчиком": markup, css, php, javascript.
  • title: необязательный заголовок, который можно включить при запуске подсветки синтаксиса.
  • linenums: добавляет номера строк к вашему коду, начиная с любого заданного вами числа (тоже необязательно).

Единственный обязательный атрибут — это "type", по умолчанию его значение выставлено как "markup".

Заключение

Сборка плагина для визуальной "подсветки" кода — дело всего нескольких кликов и последовательных шагов; но благодаря этому у вас появится плагин, который всегда можно скачать и установить на новый сайт без необходимости разбираться, как он работает, и как все это было собрано воедино. Хотя порой довольно занимательно разбираться в том, как все устроено в работе WordPress и как изменить те или иные настройки. Если темная тема оформления и выделения вам не по вкусу, то можете внести собственные настройки в CSS для внедрения новых стилей "подсветки", которая больше подойдет дизайну вашего сайта.

Источник: WP.tutsplus.com

Вам понравился материал?

Добавить комментарий

Такой e-mail уже зарегистрирован. Воспользуйтесь формой входа или введите другой.

Вы ввели некорректные логин или пароль

Извините, для комментирования необходимо войти.

2 комментария

сначала новые
по рейтингу сначала новые по хронологии

А почему сей плагин не поддерживает кирилицу, он ее кракозябрами выводит

Наверное потому, что этот плагин не рассчитан на поддержку кириллицы. Попробуйте Syntax Highlighter.