522
511
self::$plugins = $plugins;
523
512
self::$ext_plugins = $ext_plugins;
525
self::$first_init = array(
527
'skin' => 'lightgray',
528
'language' => self::$mce_locale,
531
'{selector: "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li", styles: {textAlign:"left"}},' .
532
'{selector: "img,table,dl.wp-caption", classes: "alignleft"}' .
535
'{selector: "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li", styles: {textAlign:"center"}},' .
536
'{selector: "img,table,dl.wp-caption", classes: "aligncenter"}' .
539
'{selector: "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li", styles: {textAlign:"right"}},' .
540
'{selector: "img,table,dl.wp-caption", classes: "alignright"}' .
542
'strikethrough: {inline: "del"}' .
544
'relative_urls' => false,
545
'remove_script_host' => false,
546
'convert_urls' => false,
547
'browser_spellcheck' => true,
548
'fix_list_elements' => true,
549
'entities' => '38,amp,60,lt,62,gt',
550
'entity_encoding' => 'raw',
551
'keep_styles' => false,
552
'cache_suffix' => 'wp-mce-' . $tinymce_version,
554
// Limit the preview styles in the menu/toolbar
555
'preview_styles' => 'font-family font-size font-weight font-style text-decoration text-transform',
557
'end_container_on_empty_block' => true,
558
'wpeditimage_disable_captions' => $no_captions,
559
'wpeditimage_html5_captions' => current_theme_supports( 'html5', 'caption' ),
560
'plugins' => implode( ',', $plugins ),
561
'wp_lang_attr' => get_bloginfo( 'language' ),
562
'wp_shortcut_labels' => wp_json_encode( $shortcut_labels ),
514
$settings = self::default_settings();
515
$settings['plugins'] = implode( ',', $plugins );
565
517
if ( ! empty( $mce_external_plugins ) ) {
566
self::$first_init['external_plugins'] = wp_json_encode( $mce_external_plugins );
569
$suffix = SCRIPT_DEBUG ? '' : '.min';
570
$version = 'ver=' . get_bloginfo( 'version' );
571
$dashicons = includes_url( "css/dashicons$suffix.css?$version" );
573
// WordPress default stylesheet and dashicons
576
self::$baseurl . '/skins/wordpress/wp-content.css?' . $version
518
$settings['external_plugins'] = wp_json_encode( $mce_external_plugins );
521
/** This filter is documented in wp-admin/includes/media.php */
522
if ( apply_filters( 'disable_captions', '' ) ) {
523
$settings['wpeditimage_disable_captions'] = true;
526
$mce_css = $settings['content_css'];
579
527
$editor_styles = get_editor_stylesheets();
580
529
if ( ! empty( $editor_styles ) ) {
581
foreach ( $editor_styles as $style ) {
530
// Force urlencoding of commas.
531
foreach ( $editor_styles as $key => $url ) {
532
if ( strpos( $url, ',' ) !== false ) {
533
$editor_styles[ $key ] = str_replace( ',', '%2C', $url );
537
$mce_css .= ',' . implode( ',', $editor_styles );
692
651
$body_class .= ' locale-' . sanitize_html_class( strtolower( str_replace( '_', '-', get_user_locale() ) ) );
694
if ( !empty($set['tinymce']['body_class']) ) {
653
if ( ! empty( $set['tinymce']['body_class'] ) ) {
695
654
$body_class .= ' ' . $set['tinymce']['body_class'];
696
unset($set['tinymce']['body_class']);
655
unset( $set['tinymce']['body_class'] );
699
658
$mceInit = array (
700
659
'selector' => "#$editor_id",
701
'resize' => 'vertical',
703
660
'wpautop' => (bool) $set['wpautop'],
704
661
'indent' => ! $set['wpautop'],
705
'toolbar1' => implode($mce_buttons, ','),
706
'toolbar2' => implode($mce_buttons_2, ','),
707
'toolbar3' => implode($mce_buttons_3, ','),
708
'toolbar4' => implode($mce_buttons_4, ','),
662
'toolbar1' => implode( ',', $mce_buttons ),
663
'toolbar2' => implode( ',', $mce_buttons_2 ),
664
'toolbar3' => implode( ',', $mce_buttons_3 ),
665
'toolbar4' => implode( ',', $mce_buttons_4 ),
709
666
'tabfocus_elements' => $set['tabfocus_elements'],
710
667
'body_class' => $body_class
763
720
* @param array $init
766
private static function _parse_init($init) {
723
private static function _parse_init( $init ) {
769
foreach ( $init as $k => $v ) {
771
$val = $v ? 'true' : 'false';
772
$options .= $k . ':' . $val . ',';
726
foreach ( $init as $key => $value ) {
727
if ( is_bool( $value ) ) {
728
$val = $value ? 'true' : 'false';
729
$options .= $key . ':' . $val . ',';
774
} elseif ( !empty($v) && is_string($v) && ( ('{' == $v{0} && '}' == $v{strlen($v) - 1}) || ('[' == $v{0} && ']' == $v{strlen($v) - 1}) || preg_match('/^\(?function ?\(/', $v) ) ) {
775
$options .= $k . ':' . $v . ',';
731
} elseif ( ! empty( $value ) && is_string( $value ) && (
732
( '{' == $value{0} && '}' == $value{strlen( $value ) - 1} ) ||
733
( '[' == $value{0} && ']' == $value{strlen( $value ) - 1} ) ||
734
preg_match( '/^\(?function ?\(/', $value ) ) ) {
736
$options .= $key . ':' . $value . ',';
778
$options .= $k . ':"' . $v . '",';
739
$options .= $key . ':"' . $value . '",';
781
742
return '{' . trim( $options, ' ,' ) . '}';
788
public static function enqueue_scripts() {
789
if ( self::$has_tinymce )
790
wp_enqueue_script('editor');
749
public static function enqueue_scripts( $default_scripts = false ) {
750
if ( $default_scripts || self::$has_tinymce ) {
751
wp_enqueue_script( 'editor' );
792
if ( self::$has_quicktags ) {
754
if ( $default_scripts || self::$has_quicktags ) {
793
755
wp_enqueue_script( 'quicktags' );
794
756
wp_enqueue_style( 'buttons' );
797
if ( in_array('wplink', self::$plugins, true) || in_array('link', self::$qt_buttons, true) ) {
798
wp_enqueue_script('wplink');
759
if ( $default_scripts || in_array( 'wplink', self::$plugins, true ) || in_array( 'link', self::$qt_buttons, true ) ) {
760
wp_enqueue_script( 'wplink' );
799
761
wp_enqueue_script( 'jquery-ui-autocomplete' );
802
764
if ( self::$old_dfw_compat ) {
803
wp_enqueue_script('wp-fullscreen-stub');
765
wp_enqueue_script( 'wp-fullscreen-stub' );
806
768
if ( self::$has_medialib ) {
808
770
wp_enqueue_script( 'media-upload' );
809
771
wp_enqueue_script( 'wp-embed' );
772
} elseif ( $default_scripts ) {
773
wp_enqueue_script( 'media-upload' );
818
782
* and Quicktags are being loaded.
820
784
do_action( 'wp_enqueue_editor', array(
821
'tinymce' => self::$has_tinymce,
822
'quicktags' => self::$has_quicktags,
785
'tinymce' => ( $default_scripts || self::$has_tinymce ),
786
'quicktags' => ( $default_scripts || self::$has_quicktags ),
791
* Enqueue all editor scripts.
792
* For use when the editor is going to be initialized after page load.
796
public static function enqueue_default_editor() {
797
// We are past the point where scripts can be enqueued properly.
798
if ( did_action( 'wp_enqueue_editor' ) ) {
802
self::enqueue_scripts( true );
804
// Also add wp-includes/css/editor.css
805
wp_enqueue_style( 'editor-buttons' );
808
add_action( 'admin_print_footer_scripts', array( __CLASS__, 'print_default_editor_scripts' ), 45 );
810
add_action( 'wp_print_footer_scripts', array( __CLASS__, 'print_default_editor_scripts' ), 45 );
815
* Print (output) all editor scripts and default settings.
816
* For use when the editor is going to be initialized after page load.
821
public static function print_default_editor_scripts() {
822
$settings = self::default_settings();
824
$settings['toolbar1'] = 'bold,italic,bullist,numlist,link';
825
$settings['wpautop'] = false;
826
$settings['indent'] = true;
827
$settings['elementpath'] = false;
829
// In production all plugins are loaded (they are in wp-editor.js.gz)
830
// but only these will be initialized by default.
831
$settings['plugins'] = implode( ',', array(
852
$settings = self::_parse_init( $settings );
854
$suffix = SCRIPT_DEBUG ? '' : '.min';
855
$baseurl = self::get_baseurl();
858
<script type="text/javascript">
859
window.wp = window.wp || {};
860
window.wp.editor = window.wp.editor || {};
861
window.wp.editor.getDefaultSettings = function() {
863
tinymce: <?php echo $settings; ?>,
865
buttons: 'strong,em,link,ul,ol,li,code'
870
var tinyMCEPreInit = {
871
baseURL: "<?php echo $baseurl; ?>",
872
suffix: "<?php echo $suffix; ?>",
875
load_ext: function(url,lang){var sl=tinymce.ScriptLoader;sl.markDone(url+'/langs/'+lang+'.js');sl.markDone(url+'/langs/'+lang+'_dlg.js');}
880
self::print_tinymce_scripts();
883
* Fires when the editor scripts are loaded for later initialization,
884
* after all scripts and settings are printed.
888
do_action( 'print_default_editor_scripts' );
890
self::wp_link_dialog();
893
public static function get_mce_locale() {
894
if ( empty( self::$mce_locale ) ) {
895
$mce_locale = get_user_locale();
896
self::$mce_locale = empty( $mce_locale ) ? 'en' : strtolower( substr( $mce_locale, 0, 2 ) ); // ISO 639-1
899
return self::$mce_locale;
902
public static function get_baseurl() {
903
if ( empty( self::$baseurl ) ) {
904
self::$baseurl = includes_url( 'js/tinymce' );
907
return self::$baseurl;
911
* Returns the default TinyMCE settings.
912
* Doesn't include plugins, buttons, editor selector.
916
private static function default_settings() {
917
global $tinymce_version;
919
$shortcut_labels = array();
921
foreach ( self::get_translation() as $name => $value ) {
922
if ( is_array( $value ) ) {
923
$shortcut_labels[$name] = $value[1];
929
'skin' => 'lightgray',
930
'language' => self::get_mce_locale(),
933
'{selector: "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li", styles: {textAlign:"left"}},' .
934
'{selector: "img,table,dl.wp-caption", classes: "alignleft"}' .
937
'{selector: "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li", styles: {textAlign:"center"}},' .
938
'{selector: "img,table,dl.wp-caption", classes: "aligncenter"}' .
941
'{selector: "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li", styles: {textAlign:"right"}},' .
942
'{selector: "img,table,dl.wp-caption", classes: "alignright"}' .
944
'strikethrough: {inline: "del"}' .
946
'relative_urls' => false,
947
'remove_script_host' => false,
948
'convert_urls' => false,
949
'browser_spellcheck' => true,
950
'fix_list_elements' => true,
951
'entities' => '38,amp,60,lt,62,gt',
952
'entity_encoding' => 'raw',
953
'keep_styles' => false,
954
'cache_suffix' => 'wp-mce-' . $tinymce_version,
955
'resize' => 'vertical',
959
// Limit the preview styles in the menu/toolbar
960
'preview_styles' => 'font-family font-size font-weight font-style text-decoration text-transform',
962
'end_container_on_empty_block' => true,
963
'wpeditimage_html5_captions' => true,
964
'wp_lang_attr' => get_bloginfo( 'language' ),
965
'wp_shortcut_labels' => wp_json_encode( $shortcut_labels ),
968
$suffix = SCRIPT_DEBUG ? '' : '.min';
969
$version = 'ver=' . get_bloginfo( 'version' );
971
// Default stylesheets
972
$settings['content_css'] = includes_url( "css/dashicons$suffix.css?$version" ) . ',' .
973
includes_url( "js/tinymce/skins/wordpress/wp-content.css?$version" );
826
978
private static function get_translation() {
943
1104
'Insert/edit link' => array( __( 'Insert/edit link' ), 'metaK' ),
944
1105
'Remove link' => array( __( 'Remove link' ), 'accessS' ),
1108
'Link' => __( 'Link' ),
1109
'Insert link' => __( 'Insert link' ),
1110
'Insert/edit link' => __( 'Insert/edit link' ),
1111
'Target' => __( 'Target' ),
1112
'New window' => __( 'New window' ),
1113
'Text to display' => __( 'Text to display' ),
1114
'Url' => __( 'URL' ),
1115
'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?' =>
1116
__( 'The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?' ),
1117
'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?' =>
1118
__( 'The URL you entered seems to be an external link. Do you want to add the required http:// prefix?' ),
946
1120
'Color' => __( 'Color' ),
947
1121
'Custom color' => __( 'Custom color' ),
948
1122
'Custom...' => _x( 'Custom...', 'label for custom color' ), // no ellipsis
949
1123
'No color' => __( 'No color' ),
1124
'R' => _x( 'R', 'Short for red in RGB' ),
1125
'G' => _x( 'G', 'Short for green in RGB' ),
1126
'B' => _x( 'B', 'Short for blue in RGB' ),
951
1128
// Spelling, search/replace plugins
952
1129
'Could not find the specified string.' => __( 'Could not find the specified string.' ),
1030
1207
/* translators: word count */
1031
1208
'Words: {0}' => sprintf( __( 'Words: %s' ), '{0}' ),
1032
'Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.' => __( 'Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.' ) . "\n\n" . __( 'If you’re looking to paste rich content from Microsoft Word, try turning this option off. The editor will clean up text pasted from Word automatically.' ),
1033
'Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help' => __( 'Rich Text Area. Press Alt-Shift-H for help.' ),
1209
'Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.' =>
1210
__( 'Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.' ) . "\n\n" .
1211
__( 'If you’re looking to paste rich content from Microsoft Word, try turning this option off. The editor will clean up text pasted from Word automatically.' ),
1212
'Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help' =>
1213
__( 'Rich Text Area. Press Alt-Shift-H for help.' ),
1034
1214
'Rich Text Area. Press Control-Option-H for help.' => __( 'Rich Text Area. Press Control-Option-H for help.' ),
1035
'You have unsaved changes are you sure you want to navigate away?' => __( 'The changes you made will be lost if you navigate away from this page.' ),
1036
'Your browser doesn\'t support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.' => __( 'Your browser does not support direct access to the clipboard. Please use keyboard shortcuts or your browser’s edit menu instead.' ),
1215
'You have unsaved changes are you sure you want to navigate away?' =>
1216
__( 'The changes you made will be lost if you navigate away from this page.' ),
1217
'Your browser doesn\'t support direct access to the clipboard. Please use the Ctrl+X/C/V keyboard shortcuts instead.' =>
1218
__( 'Your browser does not support direct access to the clipboard. Please use keyboard shortcuts or your browser’s edit menu instead.' ),
1038
1220
// TinyMCE menus
1039
1221
'Insert' => _x( 'Insert', 'TinyMCE menu' ),
1088
* Link plugin (not included):
1093
* The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?
1094
* The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?
1272
Imagetools plugin (not included):
1273
'Edit image' => __( 'Edit image' ),
1274
'Image options' => __( 'Image options' ),
1275
'Back' => __( 'Back' ),
1276
'Invert' => __( 'Invert' ),
1277
'Flip horizontally' => __( 'Flip horizontally' ),
1278
'Flip vertically' => __( 'Flip vertically' ),
1279
'Crop' => __( 'Crop' ),
1280
'Orientation' => __( 'Orientation' ),
1281
'Resize' => __( 'Resize' ),
1282
'Rotate clockwise' => __( 'Rotate clockwise' ),
1283
'Rotate counterclockwise' => __( 'Rotate counterclockwise' ),
1284
'Sharpen' => __( 'Sharpen' ),
1285
'Brightness' => __( 'Brightness' ),
1286
'Color levels' => __( 'Color levels' ),
1287
'Contrast' => __( 'Contrast' ),
1288
'Gamma' => __( 'Gamma' ),
1289
'Zoom in' => __( 'Zoom in' ),
1290
'Zoom out' => __( 'Zoom out' ),
1098
1293
return self::$translation;
1102
* Translates the default TinyMCE strings and returns them as JSON encoded object ready to be loaded with tinymce.addI18n().
1103
* Can be used directly (_WP_Editors::wp_mce_translation()) by passing the same locale as set in the TinyMCE init object.
1297
* Translates the default TinyMCE strings and returns them as JSON encoded object ready to be loaded with tinymce.addI18n(),
1298
* or as JS snippet that should run after tinymce.js is loaded.
1106
1301
* @param string $mce_locale The locale used for the editor.
1151
1346
return wp_json_encode( $mce_translation );
1154
$baseurl = self::$baseurl ? self::$baseurl : includes_url( 'js/tinymce' );
1349
$baseurl = self::get_baseurl();
1156
1351
return "tinymce.addI18n( '$mce_locale', " . wp_json_encode( $mce_translation ) . ");\n" .
1157
1352
"tinymce.ScriptLoader.markDone( '$baseurl/langs/$mce_locale.js' );\n";
1356
* Print (output) the main TinyMCE scripts.
1163
1361
* @global string $tinymce_version
1164
1362
* @global bool $concatenate_scripts
1165
1363
* @global bool $compress_scripts
1167
public static function editor_js() {
1365
public static function print_tinymce_scripts() {
1168
1366
global $tinymce_version, $concatenate_scripts, $compress_scripts;
1171
* Filters "tiny_mce_version" is deprecated
1173
* The tiny_mce_version filter is not needed since external plugins are loaded directly by TinyMCE.
1174
* These plugins can be refreshed by appending query string to the URL passed to "mce_external_plugins" filter.
1175
* If the plugin has a popup dialog, a query string can be added to the button action that opens it (in the plugin's code).
1177
$version = 'ver=' . $tinymce_version;
1178
$tmce_on = !empty(self::$mce_settings);
1180
if ( ! isset($concatenate_scripts) )
1368
if ( self::$tinymce_scripts_printed ) {
1372
self::$tinymce_scripts_printed = true;
1374
if ( ! isset( $concatenate_scripts ) ) {
1181
1375
script_concat_settings();
1378
$suffix = SCRIPT_DEBUG ? '' : '.min';
1379
$version = 'ver=' . $tinymce_version;
1380
$baseurl = self::get_baseurl();
1183
1382
$compressed = $compress_scripts && $concatenate_scripts && isset($_SERVER['HTTP_ACCEPT_ENCODING'])
1184
1383
&& false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip');
1385
// Load tinymce.js when running from /src, else load wp-tinymce.js.gz (production) or tinymce.min.js (SCRIPT_DEBUG)
1386
$mce_suffix = false !== strpos( get_bloginfo( 'version' ), '-src' ) ? '' : '.min';
1388
if ( $compressed ) {
1389
echo "<script type='text/javascript' src='{$baseurl}/wp-tinymce.php?c=1&$version'></script>\n";
1391
echo "<script type='text/javascript' src='{$baseurl}/tinymce{$mce_suffix}.js?$version'></script>\n";
1392
echo "<script type='text/javascript' src='{$baseurl}/plugins/compat3x/plugin{$suffix}.js?$version'></script>\n";
1395
echo "<script type='text/javascript'>\n" . self::wp_mce_translation() . "</script>\n";
1399
* Print (output) the TinyMCE configuration and initialization scripts.
1403
public static function editor_js() {
1404
global $tinymce_version;
1406
$tmce_on = ! empty( self::$mce_settings );
1186
1407
$mceInit = $qtInit = '';
1187
1409
if ( $tmce_on ) {
1188
1410
foreach ( self::$mce_settings as $editor_id => $init ) {
1189
1411
$options = self::_parse_init( $init );
1190
1412
$mceInit .= "'$editor_id':{$options},";
1192
$mceInit = '{' . trim($mceInit, ',') . '}';
1414
$mceInit = '{' . trim( $mceInit, ',' ) . '}';
1194
1416
$mceInit = '{}';
1197
if ( !empty(self::$qt_settings) ) {
1419
if ( ! empty( self::$qt_settings ) ) {
1198
1420
foreach ( self::$qt_settings as $editor_id => $init ) {
1199
1421
$options = self::_parse_init( $init );
1200
1422
$qtInit .= "'$editor_id':{$options},";
1202
$qtInit = '{' . trim($qtInit, ',') . '}';
1424
$qtInit = '{' . trim( $qtInit, ',' ) . '}';
1204
1426
$qtInit = '{}';