WordPress как на ладони
wordpress jino

wp_enqueue_code_editor() WP 4.9.0

Подключает все необходимое (скрипты, стили, настройки, языки) для использования встроенного в WordPress редактора кода.

Для редактирования кода в поле textarea, используется библиотека CodeMirror, с версии WP 4.9.

Что делает функция?

Функция ставит в очередь на подключение следующие базовые скрипты и стили WP:

wp_enqueue_script( 'code-editor' );
wp_enqueue_style( 'code-editor' );

Далее, на основе указанного или определившегося типа кода, который будет использоваться в textarea, может подключить дополнительные lint/hint скрипты, нужные CodeMirror. Например, при типе HTML эти дополнения будут авто-закрывать теги, выводить подсказки и т.д.

wp_enqueue_script( 'htmlhint' );
wp_enqueue_script( 'csslint' );
wp_enqueue_script( 'jshint' );

Далее, на основе переданных функции параметров, собирает параметры для CodeMirror и заменяет/дополняет дефолтные параметры: wp.codeEditor.defaultSettings.

Фильтр wp_code_editor_settings

Плагины могут отфильтровать параметры CodeMirror, перед тем, как они будут объедененны с дефолтными, через фильтр wp_code_editor_settings.

Если фильтр вернет false, то функция не подключит никаких скриптов.

Отключение подсветки

Если в опциях текущего юзера подсветка синтаксиса отключена, то функция ничего не будет делать и прервет свою работу в самом начале:

Глобальная переменная wp.codeEditor

При подключении скрипта CodeMirror, в JS не регистрируется глобальная переменная, чтобы не было конфликта, если какой-то плагин использует свою версию этой библиотеки. Экземпляр объекта CodeMirror находится в переменной wp.codeEditor. Т.е. можно написать так: window.CodeMirror = wp.CodeMirror.

Метод initialize() - wp.codeEditor.initialize( id, options ) - это аналог CodeMirror.fromTextArea(). Первым аргументом он принимает id или объект элемента textarea, а вторым опции для CodeMirror. Такие опции возвращает эта функция, только в виде PHP массива.

Также, в опциях для метода initialize() можно указать дополнительные callback функции: onChangeLintingErrors, onUpdateErrorNotice, onTabPrevious, onTabNext. Эти коллбэки позволяют управлять отображением блоков с lint ошибками и навигацией с клавиатуры (для подсказок).

Работает на основе: wp_enqueue_script(), wp_enqueue_style()
Хуки из функции:
Возвращает

Массив настроек для CodeMirror в PHP формате.

Использование

$settings = wp_enqueue_code_editor( $args );
$args(массив) (обязательный)

Параметры.

  • type (строка)
    MIME тип файла, который собираемся редактировать. Например: text/html, говорит о том, что в поле редактирования будет писаться HTML код. Возможные типы:

    type язык
    text/html html
    xml xml
    application/javascript javascript
    json json
    application/x-httpd-php php
    text/x-sql sql
    text/css css
    text/x-scss scss
    text/x-less less
    text/x-sass sass
    text/nginx nginx
    text/x-markdown markdown
    text/x-gfm gfm
    jsx jsx
    text/x-diff diff
  • file (строка)
    Альтернатива параметру $type. Название файла, например file.php. Используется, чтобы определить тип ($type) по расширению файла.

  • codemirror (массив)
    Позволяет напрямую указать параметры для CodeMirror. Перепишет текущие. Массив имеет такую же структуру, как если бы мы передавали параметры CodeMirror в JS. См. документацию.

  • csslint (массив)
    Позволяет напрямую указать параметры для CSSLint. Перепишет текущие.

  • jshint (массив)
    Позволяет напрямую указать параметры для JSHint. Перепишет текущие.

  • htmlhint (массив)
    Позволяет напрямую указать параметры для HTMLHint. Перепишет текущие.

  • theme (WP_Theme)
    Тема которая редактируется. Для страницы редактирования файлов темы.

  • plugin (строка)
    Плагин который редактируется. Для страницы редактирования файлов плагина.

Примеры

#1 Пример создания редактора кода для textarea

Для этого, давайте превратим поле Биография на странице редактирования профиля в редактор HTML кода.

Чтобы лучше понимать что делает код, посмотрим на HTML код textarea, который в итоге превратиться в редактор кода:

<textarea id="description" name="description" rows="5" cols="30"></textarea>
add_action( 'admin_enqueue_scripts', function() {
	if ( 'profile' !== get_current_screen()->id ) {
		return;
	}

	// подключаем редактор кода для HTML.
	$settings = wp_enqueue_code_editor( array( 'type' => 'text/html' ) );

	// ничего не делаем если CodeMirror отключен.
	if ( false === $settings ) {
		return;
	}

	// инициализация
	wp_add_inline_script( 
		'code-editor',
		sprintf( 'jQuery( function() { wp.codeEditor.initialize( "description", %s ); } );', wp_json_encode( $settings ) )  
	);

} );

В результате получим:

Переменная $settings содержит такой массив:

Array
(
	[codemirror] => Array
		(
			[indentUnit] => 4
			[indentWithTabs] => 1
			[inputStyle] => contenteditable
			[lineNumbers] => 1
			[lineWrapping] => 1
			[styleActiveLine] => 1
			[continueComments] => 1
			[extraKeys] => Array
				(
					[Ctrl-Space] => autocomplete
					[Ctrl-/] => toggleComment
					[Cmd-/] => toggleComment
					[Alt-F] => findPersistent
					[Ctrl-F] => findPersistent
					[Cmd-F] => findPersistent
				)

			[direction] => ltr
			[gutters] => Array
				(
					[0] => CodeMirror-lint-markers
				)

			[mode] => css
			[lint] => 1
			[autoCloseBrackets] => 1
			[matchBrackets] => 1
		)

	[csslint] => Array
		(
			[errors] => 1
			[box-model] => 1
			[display-property-grouping] => 1
			[duplicate-properties] => 1
			[known-properties] => 1
			[outline-none] => 1
		)

	[jshint] => Array
		(
			[boss] => 1
			[curly] => 1
			[eqeqeq] => 1
			[eqnull] => 1
			[es3] => 1
			[expr] => 1
			[immed] => 1
			[noarg] => 1
			[nonbsp] => 1
			[onevar] => 1
			[quotmark] => single
			[trailing] => 1
			[undef] => 1
			[unused] => 1
			[browser] => 1
			[globals] => Array
				(
					[_] => 
					[Backbone] => 
					[jQuery] => 
					[JSON] => 
					[wp] => 
				)

		)

	[htmlhint] => Array
		(
			[tagname-lowercase] => 1
			[attr-lowercase] => 1
			[attr-value-double-quotes] => 
			[doctype-first] => 
			[tag-pair] => 1
			[spec-char-escape] => 1
			[id-unique] => 1
			[src-not-empty] => 1
			[attr-no-duplication] => 1
			[alt-require] => 1
			[space-tab-mixed-disabled] => tab
			[attr-unsafe-chars] => 1
		)

)

JS функция wp.codeEditor.initialize(textarea, settings)

Находится в файле wp-admin/js/code-editor.js

Параметры:

textarea(string|jQuery|Element) (обязательный)
Атрибут id элемента в виде строки, jquery элемент или DOM элемент поля textarea, для которого будет использован редактор.
settings(объект) (обязательный)

JS объект настроек для codeMirror. Его в виде PHP массива возвращает эта функция: wp_enqueue_code_editor().

Что можно указать в объекте:

  • settings.onChangeLintingErrors (Function) - Обратный вызов при изменении ошибок компоновки.
  • settings.onUpdateErrorNotice (Function) - Обратный вызов для того, когда уведомление об ошибке должно быть отображено.
  • settings.onTabPrevious (Function) - Обратный вызов для обработки нажатия на TAB к предыдущему элементу.
  • settings.onTabNext (Function) - Обратный вызов для обработки нажатия на TAB к следующему элементу.
  • settings.codemirror (object) - Опции CodeMirror.
  • settings.csslint (object) - Правила CSSLint.
  • settings.htmlhint (object) - Правила HTMLHint.
  • settings.jshint (object) - Правила JSHint.

Выглядит так:

{
	"codemirror": {
		"indentUnit"      : 4,
		"indentWithTabs"  : true,
		"inputStyle"      : "contenteditable",
		"lineNumbers"     : true,
		"lineWrapping"    : true,
		"styleActiveLine" : true,
		"continueComments": true,
		"extraKeys": {
			"Ctrl-Space" : "autocomplete",
			"Ctrl-/"     : "toggleComment",
			"Cmd-/"      : "toggleComment",
			"Alt-F"      : "findPersistent",
			"Ctrl-F"     : "findPersistent",
			"Cmd-F"      : "findPersistent"
		},
		"direction": "ltr",
		"gutters": [
			"CodeMirror-lint-markers"
		],
		"mode"              : "css",
		"lint"              : true,
		"autoCloseBrackets" : true,
		"matchBrackets"     : true
	},
	"csslint": {
		"errors"                    : true,
		"box-model"                 : true,
		"display-property-grouping" : true,
		"duplicate-properties"      : true,
		"known-properties"          : true,
		"outline-none"              : true
	},
	"jshint": {
		"boss"    : true,
		"curly"   : true,
		"eqeqeq"  : true,
		"eqnull"  : true,
		"es3"     : true,
		"expr"    : true,
		"immed"   : true,
		"noarg"   : true,
		"nonbsp"  : true,
		"onevar"  : true,
		"quotmark": "single",
		"trailing": true,
		"undef"   : true,
		"unused"  : true,
		"browser" : true,
		"globals": {
			"_"        : false,
			"Backbone" : false,
			"jQuery"   : false,
			"JSON"     : false,
			"wp"       : false
		}
	},
	"htmlhint": {
		"tagname-lowercase"       : true,
		"attr-lowercase"          : true,
		"attr-value-double-quotes": false,
		"doctype-first"           : false,
		"tag-pair"                : true,
		"spec-char-escape"        : true,
		"id-unique"               : true,
		"src-not-empty"           : true,
		"attr-no-duplication"     : true,
		"alt-require"             : true,
		"space-tab-mixed-disabled": "tab",
		"attr-unsafe-chars"       : true
	}
}

Код wp_enqueue_code_editor: wp-includes/general-template.php VER 4.9.8

<?php
function wp_enqueue_code_editor( $args ) {
	if ( is_user_logged_in() && 'false' === wp_get_current_user()->syntax_highlighting ) {
		return false;
	}

	$settings = array(
		'codemirror' => array(
			'indentUnit' => 4,
			'indentWithTabs' => true,
			'inputStyle' => 'contenteditable',
			'lineNumbers' => true,
			'lineWrapping' => true,
			'styleActiveLine' => true,
			'continueComments' => true,
			'extraKeys' => array(
				'Ctrl-Space' => 'autocomplete',
				'Ctrl-/' => 'toggleComment',
				'Cmd-/' => 'toggleComment',
				'Alt-F' => 'findPersistent',
				'Ctrl-F'     => 'findPersistent',
				'Cmd-F'      => 'findPersistent',
			),
			'direction' => 'ltr', // Code is shown in LTR even in RTL languages.
			'gutters' => array(),
		),
		'csslint' => array(
			'errors' => true, // Parsing errors.
			'box-model' => true,
			'display-property-grouping' => true,
			'duplicate-properties' => true,
			'known-properties' => true,
			'outline-none' => true,
		),
		'jshint' => array(
			// The following are copied from <https://github.com/WordPress/wordpress-develop/blob/4.8.1/.jshintrc>.
			'boss' => true,
			'curly' => true,
			'eqeqeq' => true,
			'eqnull' => true,
			'es3' => true,
			'expr' => true,
			'immed' => true,
			'noarg' => true,
			'nonbsp' => true,
			'onevar' => true,
			'quotmark' => 'single',
			'trailing' => true,
			'undef' => true,
			'unused' => true,

			'browser' => true,

			'globals' => array(
				'_' => false,
				'Backbone' => false,
				'jQuery' => false,
				'JSON' => false,
				'wp' => false,
			),
		),
		'htmlhint' => array(
			'tagname-lowercase' => true,
			'attr-lowercase' => true,
			'attr-value-double-quotes' => false,
			'doctype-first' => false,
			'tag-pair' => true,
			'spec-char-escape' => true,
			'id-unique' => true,
			'src-not-empty' => true,
			'attr-no-duplication' => true,
			'alt-require' => true,
			'space-tab-mixed-disabled' => 'tab',
			'attr-unsafe-chars' => true,
		),
	);

	$type = '';
	if ( isset( $args['type'] ) ) {
		$type = $args['type'];

		// Remap MIME types to ones that CodeMirror modes will recognize.
		if ( 'application/x-patch' === $type || 'text/x-patch' === $type ) {
			$type = 'text/x-diff';
		}
	} elseif ( isset( $args['file'] ) && false !== strpos( basename( $args['file'] ), '.' ) ) {
		$extension = strtolower( pathinfo( $args['file'], PATHINFO_EXTENSION ) );
		foreach ( wp_get_mime_types() as $exts => $mime ) {
			if ( preg_match( '!^(' . $exts . ')$!i', $extension ) ) {
				$type = $mime;
				break;
			}
		}

		// Supply any types that are not matched by wp_get_mime_types().
		if ( empty( $type ) ) {
			switch ( $extension ) {
				case 'conf':
					$type = 'text/nginx';
					break;
				case 'css':
					$type = 'text/css';
					break;
				case 'diff':
				case 'patch':
					$type = 'text/x-diff';
					break;
				case 'html':
				case 'htm':
					$type = 'text/html';
					break;
				case 'http':
					$type = 'message/http';
					break;
				case 'js':
					$type = 'text/javascript';
					break;
				case 'json':
					$type = 'application/json';
					break;
				case 'jsx':
					$type = 'text/jsx';
					break;
				case 'less':
					$type = 'text/x-less';
					break;
				case 'md':
					$type = 'text/x-gfm';
					break;
				case 'php':
				case 'phtml':
				case 'php3':
				case 'php4':
				case 'php5':
				case 'php7':
				case 'phps':
					$type = 'application/x-httpd-php';
					break;
				case 'scss':
					$type = 'text/x-scss';
					break;
				case 'sass':
					$type = 'text/x-sass';
					break;
				case 'sh':
				case 'bash':
					$type = 'text/x-sh';
					break;
				case 'sql':
					$type = 'text/x-sql';
					break;
				case 'svg':
					$type = 'application/svg+xml';
					break;
				case 'xml':
					$type = 'text/xml';
					break;
				case 'yml':
				case 'yaml':
					$type = 'text/x-yaml';
					break;
				case 'txt':
				default:
					$type = 'text/plain';
					break;
			}
		}
	}

	if ( 'text/css' === $type ) {
		$settings['codemirror'] = array_merge( $settings['codemirror'], array(
			'mode' => 'css',
			'lint' => true,
			'autoCloseBrackets' => true,
			'matchBrackets' => true,
		) );
	} elseif ( 'text/x-scss' === $type || 'text/x-less' === $type || 'text/x-sass' === $type ) {
		$settings['codemirror'] = array_merge( $settings['codemirror'], array(
			'mode' => $type,
			'lint' => false,
			'autoCloseBrackets' => true,
			'matchBrackets' => true,
		) );
	} elseif ( 'text/x-diff' === $type ) {
		$settings['codemirror'] = array_merge( $settings['codemirror'], array(
			'mode' => 'diff',
		) );
	} elseif ( 'text/html' === $type ) {
		$settings['codemirror'] = array_merge( $settings['codemirror'], array(
			'mode' => 'htmlmixed',
			'lint' => true,
			'autoCloseBrackets' => true,
			'autoCloseTags' => true,
			'matchTags' => array(
				'bothTags' => true,
			),
		) );

		if ( ! current_user_can( 'unfiltered_html' ) ) {
			$settings['htmlhint']['kses'] = wp_kses_allowed_html( 'post' );
		}
	} elseif ( 'text/x-gfm' === $type ) {
		$settings['codemirror'] = array_merge( $settings['codemirror'], array(
			'mode' => 'gfm',
			'highlightFormatting' => true,
		) );
	} elseif ( 'application/javascript' === $type || 'text/javascript' === $type ) {
		$settings['codemirror'] = array_merge( $settings['codemirror'], array(
			'mode' => 'javascript',
			'lint' => true,
			'autoCloseBrackets' => true,
			'matchBrackets' => true,
		) );
	} elseif ( false !== strpos( $type, 'json' ) ) {
		$settings['codemirror'] = array_merge( $settings['codemirror'], array(
			'mode' => array(
				'name' => 'javascript',
			),
			'lint' => true,
			'autoCloseBrackets' => true,
			'matchBrackets' => true,
		) );
		if ( 'application/ld+json' === $type ) {
			$settings['codemirror']['mode']['jsonld'] = true;
		} else {
			$settings['codemirror']['mode']['json'] = true;
		}
	} elseif ( false !== strpos( $type, 'jsx' ) ) {
		$settings['codemirror'] = array_merge( $settings['codemirror'], array(
			'mode' => 'jsx',
			'autoCloseBrackets' => true,
			'matchBrackets' => true,
		) );
	} elseif ( 'text/x-markdown' === $type ) {
		$settings['codemirror'] = array_merge( $settings['codemirror'], array(
			'mode' => 'markdown',
			'highlightFormatting' => true,
		) );
	} elseif ( 'text/nginx' === $type ) {
		$settings['codemirror'] = array_merge( $settings['codemirror'], array(
			'mode' => 'nginx',
		) );
	} elseif ( 'application/x-httpd-php' === $type ) {
		$settings['codemirror'] = array_merge( $settings['codemirror'], array(
			'mode' => 'php',
			'autoCloseBrackets' => true,
			'autoCloseTags' => true,
			'matchBrackets' => true,
			'matchTags' => array(
				'bothTags' => true,
			),
		) );
	} elseif ( 'text/x-sql' === $type || 'text/x-mysql' === $type ) {
		$settings['codemirror'] = array_merge( $settings['codemirror'], array(
			'mode' => 'sql',
			'autoCloseBrackets' => true,
			'matchBrackets' => true,
		) );
	} elseif ( false !== strpos( $type, 'xml' ) ) {
		$settings['codemirror'] = array_merge( $settings['codemirror'], array(
			'mode' => 'xml',
			'autoCloseBrackets' => true,
			'autoCloseTags' => true,
			'matchTags' => array(
				'bothTags' => true,
			),
		) );
	} elseif ( 'text/x-yaml' === $type ) {
		$settings['codemirror'] = array_merge( $settings['codemirror'], array(
			'mode' => 'yaml',
		) );
	} else {
		$settings['codemirror']['mode'] = $type;
	}

	if ( ! empty( $settings['codemirror']['lint'] ) ) {
		$settings['codemirror']['gutters'][] = 'CodeMirror-lint-markers';
	}

	// Let settings supplied via args override any defaults.
	foreach ( wp_array_slice_assoc( $args, array( 'codemirror', 'csslint', 'jshint', 'htmlhint' ) ) as $key => $value ) {
		$settings[ $key ] = array_merge(
			$settings[ $key ],
			$value
		);
	}

	/**
	 * Filters settings that are passed into the code editor.
	 *
	 * Returning a falsey value will disable the syntax-highlighting code editor.
	 *
	 * @since 4.9.0
	 *
	 * @param array $settings The array of settings passed to the code editor. A falsey value disables the editor.
	 * @param array $args {
	 *     Args passed when calling `wp_enqueue_code_editor()`.
	 *
	 *     @type string   $type       The MIME type of the file to be edited.
	 *     @type string   $file       Filename being edited.
	 *     @type WP_Theme $theme      Theme being edited when on theme editor.
	 *     @type string   $plugin     Plugin being edited when on plugin editor.
	 *     @type array    $codemirror Additional CodeMirror setting overrides.
	 *     @type array    $csslint    CSSLint rule overrides.
	 *     @type array    $jshint     JSHint rule overrides.
	 *     @type array    $htmlhint   JSHint rule overrides.
	 * }
	 */
	$settings = apply_filters( 'wp_code_editor_settings', $settings, $args );

	if ( empty( $settings ) || empty( $settings['codemirror'] ) ) {
		return false;
	}

	wp_enqueue_script( 'code-editor' );
	wp_enqueue_style( 'code-editor' );

	if ( isset( $settings['codemirror']['mode'] ) ) {
		$mode = $settings['codemirror']['mode'];
		if ( is_string( $mode ) ) {
			$mode = array(
				'name' => $mode,
			);
		}

		if ( ! empty( $settings['codemirror']['lint'] ) ) {
			switch ( $mode['name'] ) {
				case 'css':
				case 'text/css':
				case 'text/x-scss':
				case 'text/x-less':
					wp_enqueue_script( 'csslint' );
					break;
				case 'htmlmixed':
				case 'text/html':
				case 'php':
				case 'application/x-httpd-php':
				case 'text/x-php':
					wp_enqueue_script( 'htmlhint' );
					wp_enqueue_script( 'csslint' );
					wp_enqueue_script( 'jshint' );
					if ( ! current_user_can( 'unfiltered_html' ) ) {
						wp_enqueue_script( 'htmlhint-kses' );
					}
					break;
				case 'javascript':
				case 'application/ecmascript':
				case 'application/json':
				case 'application/javascript':
				case 'application/ld+json':
				case 'text/typescript':
				case 'application/typescript':
					wp_enqueue_script( 'jshint' );
					wp_enqueue_script( 'jsonlint' );
					break;
			}
		}
	}

	wp_add_inline_script( 'code-editor', sprintf( 'jQuery.extend( wp.codeEditor.defaultSettings, %s );', wp_json_encode( $settings ) ) );

	/**
	 * Fires when scripts and styles are enqueued for the code editor.
	 *
	 * @since 4.9.0
	 *
	 * @param array $settings Settings for the enqueued code editor.
	 */
	do_action( 'wp_enqueue_code_editor', $settings );

	return $settings;
}

Cвязанные функции

Из раздела: Регистрация script и style

3 коммента
  • Сережа

    Интересно, а можно ли найти применение этой функции для подсветки кода в записях? Имеется в виду в качестве замены плагину Syntax Highlighter и прочим.

    • Kama6714

      Это именно редактор кода, а не его подсветка, там для подсветки много лишнего... Спец решение лучше подойдет... Но если очень хочется, то думаю можно crazy

      1
Здравствуйте, !     Войти . Зарегистрироваться