PageRenderTime 280ms CodeModel.GetById 81ms app.highlight 133ms RepoModel.GetById 30ms app.codeStats 19ms

/APP/wp-includes/class-wp-editor.php

https://bitbucket.org/AFelipeTrujillo/goblog
PHP | 1444 lines | 899 code | 207 blank | 338 comment | 150 complexity | fb209d1794f4d0112aed3e14f713b7a3 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2/**
   3 * Facilitates adding of the WordPress editor as used on the Write and Edit screens.
   4 *
   5 * @package WordPress
   6 * @since 3.3.0
   7 *
   8 * Private, not included by default. See wp_editor() in wp-includes/general-template.php.
   9 */
  10
  11final class _WP_Editors {
  12	public static $mce_locale;
  13
  14	private static $mce_settings = array();
  15	private static $qt_settings = array();
  16	private static $plugins = array();
  17	private static $qt_buttons = array();
  18	private static $ext_plugins;
  19	private static $baseurl;
  20	private static $first_init;
  21	private static $this_tinymce = false;
  22	private static $this_quicktags = false;
  23	private static $has_tinymce = false;
  24	private static $has_quicktags = false;
  25	private static $has_medialib = false;
  26	private static $editor_buttons_css = true;
  27	private static $drag_drop_upload = false;
  28
  29	private function __construct() {}
  30
  31	/**
  32	 * Parse default arguments for the editor instance.
  33	 *
  34	 * @param string $editor_id ID for the current editor instance.
  35	 * @param array  $settings {
  36	 *     Array of editor arguments.
  37	 *
  38	 *     @type bool       $wpautop           Whether to use wpautop(). Default true.
  39	 *     @type bool       $media_buttons     Whether to show the Add Media/other media buttons.
  40	 *     @type string     $default_editor    When both TinyMCE and Quicktags are used, set which
  41	 *                                         editor is shown on page load. Default empty.
  42	 *     @type bool       $drag_drop_upload  Whether to enable drag & drop on the editor uploading. Default false.
  43	 *                                         Requires the media modal.
  44	 *     @type string     $textarea_name     Give the textarea a unique name here. Square brackets
  45	 *                                         can be used here. Default $editor_id.
  46	 *     @type int        $textarea_rows     Number rows in the editor textarea. Default 20.
  47	 *     @type string|int $tabindex          Tabindex value to use. Default empty.
  48	 *     @type string     $tabfocus_elements The previous and next element ID to move the focus to
  49	 *                                         when pressing the Tab key in TinyMCE. Defualt ':prev,:next'.
  50	 *     @type string     $editor_css        Intended for extra styles for both Visual and Text editors.
  51	 *                                         Should include <style> tags, and can use "scoped". Default empty.
  52	 *     @type string     $editor_class      Extra classes to add to the editor textarea elemen. Default empty.
  53	 *     @type bool       $teeny             Whether to output the minimal editor config. Examples include
  54	 *                                         Press This and the Comment editor. Default false.
  55	 *     @type bool       $dfw               Whether to replace the default fullscreen with "Distraction Free
  56	 *                                         Writing". DFW requires specific DOM elements and css). Default false.
  57	 *     @type bool|array $tinymce           Whether to load TinyMCE. Can be used to pass settings directly to
  58	 *                                         TinyMCE using an array. Default true.
  59	 *     @type bool|array $quicktags         Whether to load Quicktags. Can be used to pass settings directly to
  60	 *                                         Quicktags using an array. Default true.
  61	 * }
  62	 * @return array Parsed arguments array.
  63	 */
  64	public static function parse_settings( $editor_id, $settings ) {
  65		$set = wp_parse_args( $settings,  array(
  66			'wpautop'           => true,
  67			'media_buttons'     => true,
  68			'default_editor'    => '',
  69			'drag_drop_upload'  => false,
  70			'textarea_name'     => $editor_id,
  71			'textarea_rows'     => 20,
  72			'tabindex'          => '',
  73			'tabfocus_elements' => ':prev,:next',
  74			'editor_css'        => '',
  75			'editor_class'      => '',
  76			'teeny'             => false,
  77			'dfw'               => false,
  78			'tinymce'           => true,
  79			'quicktags'         => true
  80		) );
  81
  82		self::$this_tinymce = ( $set['tinymce'] && user_can_richedit() );
  83
  84		if ( self::$this_tinymce ) {
  85			if ( false !== strpos( $editor_id, '[' ) ) {
  86				self::$this_tinymce = false;
  87				_deprecated_argument( 'wp_editor()', '3.9', 'TinyMCE editor IDs cannot have brackets.' );
  88			}
  89		}
  90
  91		self::$this_quicktags = (bool) $set['quicktags'];
  92
  93		if ( self::$this_tinymce )
  94			self::$has_tinymce = true;
  95
  96		if ( self::$this_quicktags )
  97			self::$has_quicktags = true;
  98
  99		if ( empty( $set['editor_height'] ) )
 100			return $set;
 101
 102		if ( 'content' === $editor_id ) {
 103			// A cookie (set when a user resizes the editor) overrides the height.
 104			$cookie = (int) get_user_setting( 'ed_size' );
 105
 106			// Upgrade an old TinyMCE cookie if it is still around, and the new one isn't.
 107			if ( ! $cookie && isset( $_COOKIE['TinyMCE_content_size'] ) ) {
 108				parse_str( $_COOKIE['TinyMCE_content_size'], $cookie );
 109 				$cookie = $cookie['ch'];
 110			}
 111
 112			if ( $cookie )
 113				$set['editor_height'] = $cookie;
 114		}
 115
 116		if ( $set['editor_height'] < 50 )
 117			$set['editor_height'] = 50;
 118		elseif ( $set['editor_height'] > 5000 )
 119			$set['editor_height'] = 5000;
 120
 121		return $set;
 122	}
 123
 124	/**
 125	 * Outputs the HTML for a single instance of the editor.
 126	 *
 127	 * @param string $content The initial content of the editor.
 128	 * @param string $editor_id ID for the textarea and TinyMCE and Quicktags instances (can contain only ASCII letters and numbers).
 129	 * @param array $settings See the _parse_settings() method for description.
 130	 */
 131	public static function editor( $content, $editor_id, $settings = array() ) {
 132
 133		$set = self::parse_settings( $editor_id, $settings );
 134		$editor_class = ' class="' . trim( $set['editor_class'] . ' wp-editor-area' ) . '"';
 135		$tabindex = $set['tabindex'] ? ' tabindex="' . (int) $set['tabindex'] . '"' : '';
 136		$switch_class = 'html-active';
 137		$toolbar = $buttons = $autocomplete = '';
 138
 139		if ( $set['drag_drop_upload'] ) {
 140			self::$drag_drop_upload = true;
 141		}
 142
 143		if ( ! empty( $set['editor_height'] ) )
 144			$height = ' style="height: ' . $set['editor_height'] . 'px"';
 145		else
 146			$height = ' rows="' . $set['textarea_rows'] . '"';
 147
 148		if ( !current_user_can( 'upload_files' ) )
 149			$set['media_buttons'] = false;
 150
 151		if ( ! self::$this_quicktags && self::$this_tinymce ) {
 152			$switch_class = 'tmce-active';
 153			$autocomplete = ' autocomplete="off"';
 154		} elseif ( self::$this_quicktags && self::$this_tinymce ) {
 155			$default_editor = $set['default_editor'] ? $set['default_editor'] : wp_default_editor();
 156			$autocomplete = ' autocomplete="off"';
 157
 158			// 'html' is used for the "Text" editor tab.
 159			if ( 'html' === $default_editor ) {
 160				add_filter('the_editor_content', 'wp_htmledit_pre');
 161				$switch_class = 'html-active';
 162			} else {
 163				add_filter('the_editor_content', 'wp_richedit_pre');
 164				$switch_class = 'tmce-active';
 165			}
 166
 167			$buttons .= '<a id="' . $editor_id . '-html" class="wp-switch-editor switch-html" onclick="switchEditors.switchto(this);">' . _x( 'Text', 'Name for the Text editor tab (formerly HTML)' ) . "</a>\n";
 168			$buttons .= '<a id="' . $editor_id . '-tmce" class="wp-switch-editor switch-tmce" onclick="switchEditors.switchto(this);">' . __('Visual') . "</a>\n";
 169		}
 170
 171		$wrap_class = 'wp-core-ui wp-editor-wrap ' . $switch_class;
 172
 173		if ( $set['dfw'] ) {
 174			$wrap_class .= ' has-dfw';
 175		}
 176
 177		echo '<div id="wp-' . $editor_id . '-wrap" class="' . $wrap_class . '">';
 178
 179		if ( self::$editor_buttons_css ) {
 180			wp_print_styles('editor-buttons');
 181			self::$editor_buttons_css = false;
 182		}
 183
 184		if ( !empty($set['editor_css']) )
 185			echo $set['editor_css'] . "\n";
 186
 187		if ( !empty($buttons) || $set['media_buttons'] ) {
 188			echo '<div id="wp-' . $editor_id . '-editor-tools" class="wp-editor-tools hide-if-no-js">';
 189
 190			if ( $set['media_buttons'] ) {
 191				self::$has_medialib = true;
 192
 193				if ( !function_exists('media_buttons') )
 194					include(ABSPATH . 'wp-admin/includes/media.php');
 195
 196				echo '<div id="wp-' . $editor_id . '-media-buttons" class="wp-media-buttons">';
 197
 198				/**
 199				 * Fires after the default media button(s) are displayed.
 200				 *
 201				 * @since 2.5.0
 202				 *
 203				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
 204				 */
 205				do_action( 'media_buttons', $editor_id );
 206				echo "</div>\n";
 207			}
 208
 209			echo '<div class="wp-editor-tabs">' . $buttons . "</div>\n";
 210			echo "</div>\n";
 211		}
 212
 213		/**
 214		 * Filter the HTML markup output that displays the editor.
 215		 *
 216		 * @since 2.1.0
 217		 *
 218		 * @param string $output Editor's HTML markup.
 219		 */
 220		$the_editor = apply_filters( 'the_editor', '<div id="wp-' . $editor_id . '-editor-container" class="wp-editor-container">' .
 221			'<textarea' . $editor_class . $height . $tabindex . $autocomplete . ' cols="40" name="' . $set['textarea_name'] . '" ' .
 222			'id="' . $editor_id . '">%s</textarea></div>' );
 223
 224		/**
 225		 * Filter the default editor content.
 226		 *
 227		 * @since 2.1.0
 228		 *
 229		 * @param string $content Default editor content.
 230		 */
 231		$content = apply_filters( 'the_editor_content', $content );
 232
 233		printf( $the_editor, $content );
 234		echo "\n</div>\n\n";
 235
 236		self::editor_settings($editor_id, $set);
 237	}
 238
 239	public static function editor_settings($editor_id, $set) {
 240		$first_run = false;
 241
 242		if ( empty(self::$first_init) ) {
 243			if ( is_admin() ) {
 244				add_action( 'admin_print_footer_scripts', array( __CLASS__, 'editor_js'), 50 );
 245				add_action( 'admin_footer', array( __CLASS__, 'enqueue_scripts'), 1 );
 246			} else {
 247				add_action( 'wp_print_footer_scripts', array( __CLASS__, 'editor_js'), 50 );
 248				add_action( 'wp_footer', array( __CLASS__, 'enqueue_scripts'), 1 );
 249			}
 250		}
 251
 252		if ( self::$this_quicktags ) {
 253
 254			$qtInit = array(
 255				'id' => $editor_id,
 256				'buttons' => ''
 257			);
 258
 259			if ( is_array($set['quicktags']) )
 260				$qtInit = array_merge($qtInit, $set['quicktags']);
 261
 262			if ( empty($qtInit['buttons']) )
 263				$qtInit['buttons'] = 'strong,em,link,block,del,ins,img,ul,ol,li,code,more,close';
 264
 265			if ( $set['dfw'] )
 266				$qtInit['buttons'] .= ',fullscreen';
 267
 268			/**
 269			 * Filter the Quicktags settings.
 270			 *
 271			 * @since 3.3.0
 272			 *
 273			 * @param array  $qtInit    Quicktags settings.
 274			 * @param string $editor_id The unique editor ID, e.g. 'content'.
 275			 */
 276			$qtInit = apply_filters( 'quicktags_settings', $qtInit, $editor_id );
 277
 278			self::$qt_settings[$editor_id] = $qtInit;
 279
 280			self::$qt_buttons = array_merge( self::$qt_buttons, explode(',', $qtInit['buttons']) );
 281		}
 282
 283		if ( self::$this_tinymce ) {
 284
 285			if ( empty( self::$first_init ) ) {
 286				self::$baseurl = includes_url( 'js/tinymce' );
 287
 288				$mce_locale = get_locale();
 289				self::$mce_locale = $mce_locale = empty( $mce_locale ) ? 'en' : strtolower( substr( $mce_locale, 0, 2 ) ); // ISO 639-1
 290
 291				/** This filter is documented in wp-admin/includes/media.php */
 292				$no_captions = (bool) apply_filters( 'disable_captions', '' );
 293				$first_run = true;
 294				$ext_plugins = '';
 295
 296				if ( $set['teeny'] ) {
 297
 298					/**
 299					 * Filter the list of teenyMCE plugins.
 300					 *
 301					 * @since 2.7.0
 302					 *
 303					 * @param array  $plugins   An array of teenyMCE plugins.
 304					 * @param string $editor_id Unique editor identifier, e.g. 'content'.
 305					 */
 306					self::$plugins = $plugins = apply_filters( 'teeny_mce_plugins', array( 'fullscreen', 'image', 'wordpress', 'wpeditimage', 'wplink' ), $editor_id );
 307				} else {
 308
 309					/**
 310					 * Filter the list of TinyMCE external plugins.
 311					 *
 312					 * The filter takes an associative array of external plugins for
 313					 * TinyMCE in the form 'plugin_name' => 'url'.
 314					 *
 315					 * The url should be absolute, and should include the js filename
 316					 * to be loaded. For example:
 317					 * 'myplugin' => 'http://mysite.com/wp-content/plugins/myfolder/mce_plugin.js'.
 318					 *
 319					 * If the external plugin adds a button, it should be added with
 320					 * one of the 'mce_buttons' filters.
 321					 *
 322					 * @since 2.5.0
 323					 *
 324					 * @param array $external_plugins An array of external TinyMCE plugins.
 325					 */
 326					$mce_external_plugins = apply_filters( 'mce_external_plugins', array() );
 327
 328					$plugins = array(
 329						'charmap',
 330						'hr',
 331						'media',
 332						'paste',
 333						'tabfocus',
 334						'textcolor',
 335						'fullscreen',
 336						'wordpress',
 337						'wpeditimage',
 338						'wpgallery',
 339						'wplink',
 340						'wpdialogs',
 341						'wpview',
 342					);
 343
 344					if ( ! self::$has_medialib ) {
 345						$plugins[] = 'image';
 346					}
 347
 348					/**
 349					 * Filter the list of default TinyMCE plugins.
 350					 *
 351					 * The filter specifies which of the default plugins included
 352					 * in WordPress should be added to the TinyMCE instance.
 353					 *
 354					 * @since 3.3.0
 355					 *
 356					 * @param array $plugins An array of default TinyMCE plugins.
 357					 */
 358					$plugins = array_unique( apply_filters( 'tiny_mce_plugins', $plugins ) );
 359
 360					if ( ( $key = array_search( 'spellchecker', $plugins ) ) !== false ) {
 361						// Remove 'spellchecker' from the internal plugins if added with 'tiny_mce_plugins' filter to prevent errors.
 362						// It can be added with 'mce_external_plugins'.
 363						unset( $plugins[$key] );
 364					}
 365
 366					if ( ! empty( $mce_external_plugins ) ) {
 367
 368						/**
 369						 * Filter the translations loaded for external TinyMCE 3.x plugins.
 370						 *
 371						 * The filter takes an associative array ('plugin_name' => 'path')
 372						 * where 'path' is the include path to the file.
 373						 *
 374						 * The language file should follow the same format as wp_mce_translation(),
 375						 * and should define a variable ($strings) that holds all translated strings.
 376						 *
 377						 * @since 2.5.0
 378						 *
 379						 * @param array $translations Translations for external TinyMCE plugins.
 380						 */
 381						$mce_external_languages = apply_filters( 'mce_external_languages', array() );
 382
 383						$loaded_langs = array();
 384						$strings = '';
 385
 386						if ( ! empty( $mce_external_languages ) ) {
 387							foreach ( $mce_external_languages as $name => $path ) {
 388								if ( @is_file( $path ) && @is_readable( $path ) ) {
 389									include_once( $path );
 390									$ext_plugins .= $strings . "\n";
 391									$loaded_langs[] = $name;
 392								}
 393							}
 394						}
 395
 396						foreach ( $mce_external_plugins as $name => $url ) {
 397							if ( in_array( $name, $plugins, true ) ) {
 398								unset( $mce_external_plugins[ $name ] );
 399								continue;
 400							}
 401
 402							$url = set_url_scheme( $url );
 403							$mce_external_plugins[ $name ] = $url;
 404							$plugurl = dirname( $url );
 405							$strings = $str1 = $str2 = '';
 406
 407							// Try to load langs/[locale].js and langs/[locale]_dlg.js
 408							if ( ! in_array( $name, $loaded_langs, true ) ) {
 409								$path = str_replace( content_url(), '', $plugurl );
 410								$path = WP_CONTENT_DIR . $path . '/langs/';
 411
 412								if ( function_exists('realpath') )
 413									$path = trailingslashit( realpath($path) );
 414
 415								if ( @is_file( $path . $mce_locale . '.js' ) )
 416									$strings .= @file_get_contents( $path . $mce_locale . '.js' ) . "\n";
 417
 418								if ( @is_file( $path . $mce_locale . '_dlg.js' ) )
 419									$strings .= @file_get_contents( $path . $mce_locale . '_dlg.js' ) . "\n";
 420
 421								if ( 'en' != $mce_locale && empty( $strings ) ) {
 422									if ( @is_file( $path . 'en.js' ) ) {
 423										$str1 = @file_get_contents( $path . 'en.js' );
 424										$strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str1, 1 ) . "\n";
 425									}
 426
 427									if ( @is_file( $path . 'en_dlg.js' ) ) {
 428										$str2 = @file_get_contents( $path . 'en_dlg.js' );
 429										$strings .= preg_replace( '/([\'"])en\./', '$1' . $mce_locale . '.', $str2, 1 ) . "\n";
 430									}
 431								}
 432
 433								if ( ! empty( $strings ) )
 434									$ext_plugins .= "\n" . $strings . "\n";
 435							}
 436
 437							$ext_plugins .= 'tinyMCEPreInit.load_ext("' . $plugurl . '", "' . $mce_locale . '");' . "\n";
 438							$ext_plugins .= 'tinymce.PluginManager.load("' . $name . '", "' . $url . '");' . "\n";
 439						}
 440					}
 441				}
 442
 443				if ( $set['dfw'] )
 444					$plugins[] = 'wpfullscreen';
 445
 446				self::$plugins = $plugins;
 447				self::$ext_plugins = $ext_plugins;
 448
 449				self::$first_init = array(
 450					'theme' => 'modern',
 451					'skin' => 'lightgray',
 452					'language' => self::$mce_locale,
 453					'formats' => "{
 454						alignleft: [
 455							{selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles: {textAlign:'left'}},
 456							{selector: 'img,table,dl.wp-caption', classes: 'alignleft'}
 457						],
 458						aligncenter: [
 459							{selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles: {textAlign:'center'}},
 460							{selector: 'img,table,dl.wp-caption', classes: 'aligncenter'}
 461						],
 462						alignright: [
 463							{selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li', styles: {textAlign:'right'}},
 464							{selector: 'img,table,dl.wp-caption', classes: 'alignright'}
 465						],
 466						strikethrough: {inline: 'del'}
 467					}",
 468					'relative_urls' => false,
 469					'remove_script_host' => false,
 470					'convert_urls' => false,
 471					'browser_spellcheck' => true,
 472					'fix_list_elements' => true,
 473					'entities' => '38,amp,60,lt,62,gt',
 474					'entity_encoding' => 'raw',
 475					'keep_styles' => false,
 476					'paste_webkit_styles' => 'font-weight font-style color',
 477
 478					// Limit the preview styles in the menu/toolbar
 479					'preview_styles' => 'font-family font-size font-weight font-style text-decoration text-transform',
 480
 481					'wpeditimage_disable_captions' => $no_captions,
 482					'wpeditimage_html5_captions' => current_theme_supports( 'html5', 'caption' ),
 483					'plugins' => implode( ',', $plugins ),
 484				);
 485
 486				if ( ! empty( $mce_external_plugins ) ) {
 487					self::$first_init['external_plugins'] = json_encode( $mce_external_plugins );
 488				}
 489
 490				$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
 491				$version = 'ver=' . $GLOBALS['wp_version'];
 492				$dashicons = includes_url( "css/dashicons$suffix.css?$version" );
 493				$mediaelement = includes_url( "js/mediaelement/mediaelementplayer.min.css?$version" );
 494				$wpmediaelement = includes_url( "js/mediaelement/wp-mediaelement.css?$version" );
 495
 496				// WordPress default stylesheet and dashicons
 497				$mce_css = array(
 498					$dashicons,
 499					$mediaelement,
 500					$wpmediaelement,
 501					self::$baseurl . '/skins/wordpress/wp-content.css?' . $version
 502				);
 503
 504				// load editor_style.css if the current theme supports it
 505				if ( ! empty( $GLOBALS['editor_styles'] ) && is_array( $GLOBALS['editor_styles'] ) ) {
 506					$editor_styles = $GLOBALS['editor_styles'];
 507
 508					$editor_styles = array_unique( array_filter( $editor_styles ) );
 509					$style_uri = get_stylesheet_directory_uri();
 510					$style_dir = get_stylesheet_directory();
 511
 512					// Support externally referenced styles (like, say, fonts).
 513					foreach ( $editor_styles as $key => $file ) {
 514						if ( preg_match( '~^(https?:)?//~', $file ) ) {
 515							$mce_css[] = esc_url_raw( $file );
 516							unset( $editor_styles[ $key ] );
 517						}
 518					}
 519
 520					// Look in a parent theme first, that way child theme CSS overrides.
 521					if ( is_child_theme() ) {
 522						$template_uri = get_template_directory_uri();
 523						$template_dir = get_template_directory();
 524
 525						foreach ( $editor_styles as $key => $file ) {
 526							if ( $file && file_exists( "$template_dir/$file" ) )
 527								$mce_css[] = "$template_uri/$file";
 528						}
 529					}
 530
 531					foreach ( $editor_styles as $file ) {
 532						if ( $file && file_exists( "$style_dir/$file" ) )
 533							$mce_css[] = "$style_uri/$file";
 534					}
 535				}
 536
 537				/**
 538				 * Filter the comma-delimited list of stylesheets to load in TinyMCE.
 539				 *
 540				 * @since 2.1.0
 541				 *
 542				 * @param array $stylesheets Comma-delimited list of stylesheets.
 543				 */
 544				$mce_css = trim( apply_filters( 'mce_css', implode( ',', $mce_css ) ), ' ,' );
 545
 546				if ( ! empty($mce_css) )
 547					self::$first_init['content_css'] = $mce_css;
 548			}
 549
 550			if ( $set['teeny'] ) {
 551
 552				/**
 553				 * Filter the list of teenyMCE buttons (Text tab).
 554				 *
 555				 * @since 2.7.0
 556				 *
 557				 * @param array  $buttons   An array of teenyMCE buttons.
 558				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
 559				 */
 560				$mce_buttons = apply_filters( 'teeny_mce_buttons', array('bold', 'italic', 'underline', 'blockquote', 'strikethrough', 'bullist', 'numlist', 'alignleft', 'aligncenter', 'alignright', 'undo', 'redo', 'link', 'unlink', 'fullscreen'), $editor_id );
 561				$mce_buttons_2 = $mce_buttons_3 = $mce_buttons_4 = array();
 562			} else {
 563
 564				/**
 565				 * Filter the first-row list of TinyMCE buttons (Visual tab).
 566				 *
 567				 * @since 2.0.0
 568				 *
 569				 * @param array  $buttons   First-row list of buttons.
 570				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
 571				 */
 572				$mce_buttons = apply_filters( 'mce_buttons', array('bold', 'italic', 'strikethrough', 'bullist', 'numlist', 'blockquote', 'hr', 'alignleft', 'aligncenter', 'alignright', 'link', 'unlink', 'wp_more', 'spellchecker', 'fullscreen', 'wp_adv' ), $editor_id );
 573
 574				/**
 575				 * Filter the second-row list of TinyMCE buttons (Visual tab).
 576				 *
 577				 * @since 2.0.0
 578				 *
 579				 * @param array  $buttons   Second-row list of buttons.
 580				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
 581				 */
 582				$mce_buttons_2 = apply_filters( 'mce_buttons_2', array( 'formatselect', 'underline', 'alignjustify', 'forecolor', 'pastetext', 'removeformat', 'charmap', 'outdent', 'indent', 'undo', 'redo', 'wp_help' ), $editor_id );
 583
 584				/**
 585				 * Filter the third-row list of TinyMCE buttons (Visual tab).
 586				 *
 587				 * @since 2.0.0
 588				 *
 589				 * @param array  $buttons   Third-row list of buttons.
 590				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
 591				 */
 592				$mce_buttons_3 = apply_filters( 'mce_buttons_3', array(), $editor_id );
 593
 594				/**
 595				 * Filter the fourth-row list of TinyMCE buttons (Visual tab).
 596				 *
 597				 * @since 2.5.0
 598				 *
 599				 * @param array  $buttons   Fourth-row list of buttons.
 600				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
 601				 */
 602				$mce_buttons_4 = apply_filters( 'mce_buttons_4', array(), $editor_id );
 603			}
 604
 605			$body_class = $editor_id;
 606
 607			if ( $post = get_post() ) {
 608				$body_class .= ' post-type-' . sanitize_html_class( $post->post_type ) . ' post-status-' . sanitize_html_class( $post->post_status );
 609				if ( post_type_supports( $post->post_type, 'post-formats' ) ) {
 610					$post_format = get_post_format( $post );
 611					if ( $post_format && ! is_wp_error( $post_format ) )
 612						$body_class .= ' post-format-' . sanitize_html_class( $post_format );
 613					else
 614						$body_class .= ' post-format-standard';
 615				}
 616			}
 617
 618			if ( !empty($set['tinymce']['body_class']) ) {
 619				$body_class .= ' ' . $set['tinymce']['body_class'];
 620				unset($set['tinymce']['body_class']);
 621			}
 622
 623			if ( $set['dfw'] ) {
 624				// replace the first 'fullscreen' with 'wp_fullscreen'
 625				if ( ($key = array_search('fullscreen', $mce_buttons)) !== false )
 626					$mce_buttons[$key] = 'wp_fullscreen';
 627				elseif ( ($key = array_search('fullscreen', $mce_buttons_2)) !== false )
 628					$mce_buttons_2[$key] = 'wp_fullscreen';
 629				elseif ( ($key = array_search('fullscreen', $mce_buttons_3)) !== false )
 630					$mce_buttons_3[$key] = 'wp_fullscreen';
 631				elseif ( ($key = array_search('fullscreen', $mce_buttons_4)) !== false )
 632					$mce_buttons_4[$key] = 'wp_fullscreen';
 633			}
 634
 635			$mceInit = array (
 636				'selector' => "#$editor_id",
 637				'resize' => 'vertical',
 638				'menubar' => false,
 639				'wpautop' => (bool) $set['wpautop'],
 640				'indent' => ! $set['wpautop'],
 641				'toolbar1' => implode($mce_buttons, ','),
 642				'toolbar2' => implode($mce_buttons_2, ','),
 643				'toolbar3' => implode($mce_buttons_3, ','),
 644				'toolbar4' => implode($mce_buttons_4, ','),
 645				'tabfocus_elements' => $set['tabfocus_elements'],
 646				'body_class' => $body_class
 647			);
 648
 649			if ( $first_run )
 650				$mceInit = array_merge( self::$first_init, $mceInit );
 651
 652			if ( is_array( $set['tinymce'] ) )
 653				$mceInit = array_merge( $mceInit, $set['tinymce'] );
 654
 655			/*
 656			 * For people who really REALLY know what they're doing with TinyMCE
 657			 * You can modify $mceInit to add, remove, change elements of the config
 658			 * before tinyMCE.init. Setting "valid_elements", "invalid_elements"
 659			 * and "extended_valid_elements" can be done through this filter. Best
 660			 * is to use the default cleanup by not specifying valid_elements,
 661			 * as TinyMCE contains full set of XHTML 1.0.
 662			 */
 663			if ( $set['teeny'] ) {
 664
 665				/**
 666				 * Filter the teenyMCE config before init.
 667				 *
 668				 * @since 2.7.0
 669				 *
 670				 * @param array  $mceInit   An array with teenyMCE config.
 671				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
 672				 */
 673				$mceInit = apply_filters( 'teeny_mce_before_init', $mceInit, $editor_id );
 674			} else {
 675
 676				/**
 677				 * Filter the TinyMCE config before init.
 678				 *
 679				 * @since 2.5.0
 680				 *
 681				 * @param array  $mceInit   An array with TinyMCE config.
 682				 * @param string $editor_id Unique editor identifier, e.g. 'content'.
 683				 */
 684				$mceInit = apply_filters( 'tiny_mce_before_init', $mceInit, $editor_id );
 685			}
 686
 687			if ( empty( $mceInit['toolbar3'] ) && ! empty( $mceInit['toolbar4'] ) ) {
 688				$mceInit['toolbar3'] = $mceInit['toolbar4'];
 689				$mceInit['toolbar4'] = '';
 690			}
 691
 692			self::$mce_settings[$editor_id] = $mceInit;
 693		} // end if self::$this_tinymce
 694	}
 695
 696	private static function _parse_init($init) {
 697		$options = '';
 698
 699		foreach ( $init as $k => $v ) {
 700			if ( is_bool($v) ) {
 701				$val = $v ? 'true' : 'false';
 702				$options .= $k . ':' . $val . ',';
 703				continue;
 704			} elseif ( !empty($v) && is_string($v) && ( ('{' == $v{0} && '}' == $v{strlen($v) - 1}) || ('[' == $v{0} && ']' == $v{strlen($v) - 1}) || preg_match('/^\(?function ?\(/', $v) ) ) {
 705				$options .= $k . ':' . $v . ',';
 706				continue;
 707			}
 708			$options .= $k . ':"' . $v . '",';
 709		}
 710
 711		return '{' . trim( $options, ' ,' ) . '}';
 712	}
 713
 714	public static function enqueue_scripts() {
 715		wp_enqueue_script('word-count');
 716
 717		if ( self::$has_tinymce )
 718			wp_enqueue_script('editor');
 719
 720		if ( self::$has_quicktags ) {
 721			wp_enqueue_script( 'quicktags' );
 722			wp_enqueue_style( 'buttons' );
 723		}
 724
 725		if ( in_array('wplink', self::$plugins, true) || in_array('link', self::$qt_buttons, true) ) {
 726			wp_enqueue_script('wplink');
 727		}
 728
 729		if ( in_array('wpfullscreen', self::$plugins, true) || in_array('fullscreen', self::$qt_buttons, true) )
 730			wp_enqueue_script('wp-fullscreen');
 731
 732		if ( self::$has_medialib ) {
 733			add_thickbox();
 734			wp_enqueue_script('media-upload');
 735		}
 736
 737		/**
 738		 * Fires when scripts and styles are enqueued for the editor.
 739		 *
 740		 * @since 3.9.0
 741		 *
 742		 * @param array $to_load An array containing boolean values whether TinyMCE
 743		 *                       and Quicktags are being loaded.
 744		 */
 745		do_action( 'wp_enqueue_editor', array(
 746			'tinymce'   => self::$has_tinymce,
 747			'quicktags' => self::$has_quicktags,
 748		) );
 749	}
 750
 751	public static function wp_mce_translation() {
 752
 753		$mce_translation = array(
 754			// Default TinyMCE strings
 755			'New document' => __( 'New document' ),
 756			'Formats' => _x( 'Formats', 'TinyMCE' ),
 757
 758			'Headings' => _x( 'Headings', 'TinyMCE' ),
 759			'Heading 1' => __( 'Heading 1' ),
 760			'Heading 2' => __( 'Heading 2' ),
 761			'Heading 3' => __( 'Heading 3' ),
 762			'Heading 4' => __( 'Heading 4' ),
 763			'Heading 5' => __( 'Heading 5' ),
 764			'Heading 6' => __( 'Heading 6' ),
 765
 766			/* translators: block tags */
 767			'Blocks' => _x( 'Blocks', 'TinyMCE' ),
 768			'Paragraph' => __( 'Paragraph' ),
 769			'Blockquote' => __( 'Blockquote' ),
 770			'Div' => _x( 'Div', 'HTML tag' ),
 771			'Pre' => _x( 'Pre', 'HTML tag' ),
 772			'Address' => _x( 'Address', 'HTML tag' ),
 773
 774			'Inline' => _x( 'Inline', 'HTML elements' ),
 775			'Underline' => __( 'Underline' ),
 776			'Strikethrough' => __( 'Strikethrough' ),
 777			'Subscript' => __( 'Subscript' ),
 778			'Superscript' => __( 'Superscript' ),
 779			'Clear formatting' => __( 'Clear formatting' ),
 780			'Bold' => __( 'Bold' ),
 781			'Italic' => __( 'Italic' ),
 782			'Code' => _x( 'Code', 'editor button' ),
 783			'Source code' => __( 'Source code' ),
 784			'Font Family' => __( 'Font Family' ),
 785			'Font Sizes' => __( 'Font Sizes' ),
 786
 787			'Align center' => __( 'Align center' ),
 788			'Align right' => __( 'Align right' ),
 789			'Align left' => __( 'Align left' ),
 790			'Justify' => __( 'Justify' ),
 791			'Increase indent' => __( 'Increase indent' ),
 792			'Decrease indent' => __( 'Decrease indent' ),
 793
 794			'Cut' => __( 'Cut' ),
 795			'Copy' => __( 'Copy' ),
 796			'Paste' => __( 'Paste' ),
 797			'Select all' => __( 'Select all' ),
 798			'Undo' => __( 'Undo' ),
 799			'Redo' => __( 'Redo' ),
 800
 801			'Ok' => __( 'OK' ),
 802			'Cancel' => __( 'Cancel' ),
 803			'Close' => __( 'Close' ),
 804			'Visual aids' => __( 'Visual aids' ),
 805
 806			'Bullet list' => __( 'Bulleted list' ),
 807			'Numbered list' => __( 'Numbered list' ),
 808			'Square' => _x( 'Square', 'list style' ),
 809			'Default' => _x( 'Default', 'list style' ),
 810			'Circle' => _x( 'Circle', 'list style' ),
 811			'Disc' => _x('Disc', 'list style' ),
 812			'Lower Greek' => _x( 'Lower Greek', 'list style' ),
 813			'Lower Alpha' => _x( 'Lower Alpha', 'list style' ),
 814			'Upper Alpha' => _x( 'Upper Alpha', 'list style' ),
 815			'Upper Roman' => _x( 'Upper Roman', 'list style' ),
 816			'Lower Roman' => _x( 'Lower Roman', 'list style' ),
 817
 818			// Anchor plugin
 819			'Name' => _x( 'Name', 'Name of link anchor (TinyMCE)' ),
 820			'Anchor' => _x( 'Anchor', 'Link anchor (TinyMCE)' ),
 821			'Anchors' => _x( 'Anchors', 'Link anchors (TinyMCE)' ),
 822
 823			// Fullpage plugin
 824			'Document properties' => __( 'Document properties' ),
 825			'Robots' => __( 'Robots' ),
 826			'Title' => __( 'Title' ),
 827			'Keywords' => __( 'Keywords' ),
 828			'Encoding' => __( 'Encoding' ),
 829			'Description' => __( 'Description' ),
 830			'Author' => __( 'Author' ),
 831
 832			// Media, image plugins
 833			'Insert/edit image' => __( 'Insert/edit image' ),
 834			'General' => __( 'General' ),
 835			'Advanced' => __( 'Advanced' ),
 836			'Source' => __( 'Source' ),
 837			'Border' => __( 'Border' ),
 838			'Constrain proportions' => __( 'Constrain proportions' ),
 839			'Vertical space' => __( 'Vertical space' ),
 840			'Image description' => __( 'Image description' ),
 841			'Style' => __( 'Style' ),
 842			'Dimensions' => __( 'Dimensions' ),
 843			'Insert image' => __( 'Insert image' ),
 844			'Insert date/time' => __( 'Insert date/time' ),
 845			'Insert/edit video' => __( 'Insert/edit video' ),
 846			'Poster' => __( 'Poster' ),
 847			'Alternative source' => __( 'Alternative source' ),
 848			'Paste your embed code below:' => __( 'Paste your embed code below:' ),
 849			'Insert video' => __( 'Insert video' ),
 850			'Embed' => __( 'Embed' ),
 851
 852			// Each of these have a corresponding plugin
 853			'Special character' => __( 'Special character' ),
 854			'Right to left' => _x( 'Right to left', 'editor button' ),
 855			'Left to right' => _x( 'Left to right', 'editor button' ),
 856			'Emoticons' => __( 'Emoticons' ),
 857			'Nonbreaking space' => __( 'Nonbreaking space' ),
 858			'Page break' => __( 'Page break' ),
 859			'Paste as text' => __( 'Paste as text' ),
 860			'Preview' => __( 'Preview' ),
 861			'Print' => __( 'Print' ),
 862			'Save' => __( 'Save' ),
 863			'Fullscreen' => __( 'Fullscreen' ),
 864			'Horizontal line' => __( 'Horizontal line' ),
 865			'Horizontal space' => __( 'Horizontal space' ),
 866			'Restore last draft' => __( 'Restore last draft' ),
 867			'Insert/edit link' => __( 'Insert/edit link' ),
 868			'Remove link' => __( 'Remove link' ),
 869
 870			// Spelling, search/replace plugins
 871			'Could not find the specified string.' => __( 'Could not find the specified string.' ),
 872			'Replace' => _x( 'Replace', 'find/replace' ),
 873			'Next' => _x( 'Next', 'find/replace' ),
 874			/* translators: previous */
 875			'Prev' => _x( 'Prev', 'find/replace' ),
 876			'Whole words' => _x( 'Whole words', 'find/replace' ),
 877			'Find and replace' => __( 'Find and replace' ),
 878			'Replace with' => _x('Replace with', 'find/replace' ),
 879			'Find' => _x( 'Find', 'find/replace' ),
 880			'Replace all' => _x( 'Replace all', 'find/replace' ),
 881			'Match case' => __( 'Match case' ),
 882			'Spellcheck' => __( 'Check Spelling' ),
 883			'Finish' => _x( 'Finish', 'spellcheck' ),
 884			'Ignore all' => _x( 'Ignore all', 'spellcheck' ),
 885			'Ignore' => _x( 'Ignore', 'spellcheck' ),
 886
 887			// TinyMCE tables
 888			'Insert table' => __( 'Insert table' ),
 889			'Delete table' => __( 'Delete table' ),
 890			'Table properties' => __( 'Table properties' ),
 891			'Row properties' => __( 'Table row properties' ),
 892			'Cell properties' => __( 'Table cell properties' ),
 893
 894			'Row' => __( 'Row' ),
 895			'Rows' => __( 'Rows' ),
 896			'Column' => _x( 'Column', 'table column' ),
 897			'Cols' => _x( 'Cols', 'table columns' ),
 898			'Cell' => _x( 'Cell', 'table cell' ),
 899			'Header cell' => __( 'Header cell' ),
 900			'Header' => _x( 'Header', 'table header' ),
 901			'Body' => _x( 'Body', 'table body' ),
 902			'Footer' => _x( 'Footer', 'table footer' ),
 903
 904			'Insert row before' => __( 'Insert row before' ),
 905			'Insert row after' => __( 'Insert row after' ),
 906			'Insert column before' => __( 'Insert column before' ),
 907			'Insert column after' => __( 'Insert column after' ),
 908			'Paste row before' => __( 'Paste table row before' ),
 909			'Paste row after' => __( 'Paste table row after' ),
 910			'Delete row' => __( 'Delete row' ),
 911			'Delete column' => __( 'Delete column' ),
 912			'Cut row' => __( 'Cut table row' ),
 913			'Copy row' => __( 'Copy table row' ),
 914			'Merge cells' => __( 'Merge table cells' ),
 915			'Split cell' => __( 'Split table cell' ),
 916
 917			'Height' => __( 'Height' ),
 918			'Width' => __( 'Width' ),
 919			'Caption' => __( 'Caption' ),
 920			'Alignment' => __( 'Alignment' ),
 921			'Left' => __( 'Left' ),
 922			'Center' => __( 'Center' ),
 923			'Right' => __( 'Right' ),
 924			'None' => _x( 'None', 'table cell alignment attribute' ),
 925
 926			'Row group' => __( 'Row group' ),
 927			'Column group' => __( 'Column group' ),
 928			'Row type' => __( 'Row type' ),
 929			'Cell type' => __( 'Cell type' ),
 930			'Cell padding' => __( 'Cell padding' ),
 931			'Cell spacing' => __( 'Cell spacing' ),
 932			'Scope' => _x( 'Scope', 'table cell scope attribute' ),
 933
 934			'Insert template' => _x( 'Insert template', 'TinyMCE' ),
 935			'Templates' => _x( 'Templates', 'TinyMCE' ),
 936
 937			'Background color' => __( 'Background color' ),
 938			'Text color' => __( 'Text color' ),
 939			'Show blocks' => _x( 'Show blocks', 'editor button' ),
 940			'Show invisible characters' => __( 'Show invisible characters' ),
 941
 942			/* translators: word count */
 943			'Words: {0}' => sprintf( __( 'Words: %s' ), '{0}' ),
 944			'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&#8217;re looking to paste rich content from Microsoft Word, try turning this option off. The editor will clean up text pasted from Word automatically.' ),
 945			'Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help' => __( 'Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help' ),
 946			'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.' ),
 947			'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 the Ctrl+X/C/V keyboard shortcuts instead.' ),
 948
 949			// TinyMCE menus
 950			'Insert' => _x( 'Insert', 'TinyMCE menu' ),
 951			'File' => _x( 'File', 'TinyMCE menu' ),
 952			'Edit' => _x( 'Edit', 'TinyMCE menu' ),
 953			'Tools' => _x( 'Tools', 'TinyMCE menu' ),
 954			'View' => _x( 'View', 'TinyMCE menu' ),
 955			'Table' => _x( 'Table', 'TinyMCE menu' ),
 956			'Format' => _x( 'Format', 'TinyMCE menu' ),
 957
 958			// WordPress strings
 959			'Keyboard Shortcuts' => __( 'Keyboard Shortcuts' ),
 960			'Toolbar Toggle' => __( 'Toolbar Toggle' ),
 961			'Insert Read More tag' => __( 'Insert Read More tag' ),
 962			'Distraction Free Writing' => __( 'Distraction Free Writing' ),
 963		);
 964
 965		/**
 966		 * Link plugin (not included):
 967		 *	Insert link
 968		 *	Target
 969		 *	New window
 970		 *	Text to display
 971		 *	The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?
 972		 *	The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?
 973		 *	Url
 974		 */
 975
 976		$baseurl = self::$baseurl;
 977		$mce_locale = self::$mce_locale;
 978
 979		/**
 980		 * Filter translated strings prepared for TinyMCE.
 981		 *
 982		 * @since 3.9.0
 983		 *
 984		 * @param array  $mce_translation Key/value pairs of strings.
 985		 * @param string $mce_locale      Locale.
 986		 */
 987		$mce_translation = apply_filters( 'wp_mce_translation', $mce_translation, $mce_locale );
 988
 989		foreach ( $mce_translation as $key => $value ) {
 990			if ( false !== strpos( $value, '&' ) ) {
 991				$mce_translation[$key] = html_entity_decode( $value, ENT_QUOTES, 'UTF-8' );
 992			}
 993		}
 994
 995		// Set direction
 996		if ( is_rtl() ) {
 997			$mce_translation['_dir'] = 'rtl';
 998		}
 999
1000		return "tinymce.addI18n( '$mce_locale', " . json_encode( $mce_translation ) . ");\n" .
1001			"tinymce.ScriptLoader.markDone( '$baseurl/langs/$mce_locale.js' );\n";
1002	}
1003
1004	public static function editor_js() {
1005		global $tinymce_version, $concatenate_scripts, $compress_scripts;
1006
1007		/**
1008		 * Filter "tiny_mce_version" is deprecated
1009		 *
1010		 * The tiny_mce_version filter is not needed since external plugins are loaded directly by TinyMCE.
1011		 * These plugins can be refreshed by appending query string to the URL passed to "mce_external_plugins" filter.
1012		 * 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).
1013		 */
1014		$version = 'ver=' . $tinymce_version;
1015		$tmce_on = !empty(self::$mce_settings);
1016
1017		if ( ! isset($concatenate_scripts) )
1018			script_concat_settings();
1019
1020		$compressed = $compress_scripts && $concatenate_scripts && isset($_SERVER['HTTP_ACCEPT_ENCODING'])
1021			&& false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip');
1022
1023		$mceInit = $qtInit = '';
1024		if ( $tmce_on ) {
1025			foreach ( self::$mce_settings as $editor_id => $init ) {
1026				$options = self::_parse_init( $init );
1027				$mceInit .= "'$editor_id':{$options},";
1028			}
1029			$mceInit = '{' . trim($mceInit, ',') . '}';
1030		} else {
1031			$mceInit = '{}';
1032		}
1033
1034		if ( !empty(self::$qt_settings) ) {
1035			foreach ( self::$qt_settings as $editor_id => $init ) {
1036				$options = self::_parse_init( $init );
1037				$qtInit .= "'$editor_id':{$options},";
1038			}
1039			$qtInit = '{' . trim($qtInit, ',') . '}';
1040		} else {
1041			$qtInit = '{}';
1042		}
1043
1044		$ref = array(
1045			'plugins' => implode( ',', self::$plugins ),
1046			'theme' => 'modern',
1047			'language' => self::$mce_locale
1048		);
1049
1050		$suffix = ( defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ) ? '' : '.min';
1051
1052		/**
1053		 * Fires immediately before the TinyMCE settings are printed.
1054		 *
1055		 * @since 3.2.0
1056		 *
1057		 * @param array $mce_settings TinyMCE settings array.
1058		 */
1059		do_action( 'before_wp_tiny_mce', self::$mce_settings );
1060		?>
1061
1062		<script type="text/javascript">
1063		tinyMCEPreInit = {
1064			baseURL: "<?php echo self::$baseurl; ?>",
1065			suffix: "<?php echo $suffix; ?>",
1066			<?php
1067
1068			if ( self::$drag_drop_upload ) {
1069				echo 'dragDropUpload: true,';
1070			}
1071
1072			?>
1073			mceInit: <?php echo $mceInit; ?>,
1074			qtInit: <?php echo $qtInit; ?>,
1075			ref: <?php echo self::_parse_init( $ref ); ?>,
1076			load_ext: function(url,lang){var sl=tinymce.ScriptLoader;sl.markDone(url+'/langs/'+lang+'.js');sl.markDone(url+'/langs/'+lang+'_dlg.js');}
1077		};
1078		</script>
1079		<?php
1080
1081		$baseurl = self::$baseurl;
1082		// Load tinymce.js when running from /src, else load wp-tinymce.js.gz (production) or tinymce.min.js (SCRIPT_DEBUG)
1083		$mce_suffix = false !== strpos( $GLOBALS['wp_version'], '-src' ) ? '' : '.min';
1084
1085		if ( $tmce_on ) {
1086			if ( $compressed ) {
1087				echo "<script type='text/javascript' src='{$baseurl}/wp-tinymce.php?c=1&amp;$version'></script>\n";
1088			} else {
1089				echo "<script type='text/javascript' src='{$baseurl}/tinymce{$mce_suffix}.js?$version'></script>\n";
1090				echo "<script type='text/javascript' src='{$baseurl}/plugins/compat3x/plugin{$suffix}.js?$version'></script>\n";
1091			}
1092
1093			echo "<script type='text/javascript'>\n" . self::wp_mce_translation() . "</script>\n";
1094
1095			if ( self::$ext_plugins ) {
1096				// Load the old-format English strings to prevent unsightly labels in old style popups
1097				echo "<script type='text/javascript' src='{$baseurl}/langs/wp-langs-en.js?$version'></script>\n";
1098			}
1099		}
1100
1101		/**
1102		 * Fires after tinymce.js is loaded, but before any TinyMCE editor
1103		 * instances are created.
1104		 *
1105		 * @since 3.9.0
1106		 *
1107		 * @param array $mce_settings TinyMCE settings array.
1108		 */
1109		do_action( 'wp_tiny_mce_init', self::$mce_settings );
1110
1111		?>
1112		<script type="text/javascript">
1113		<?php
1114
1115		if ( self::$ext_plugins )
1116			echo self::$ext_plugins . "\n";
1117
1118		if ( ! is_admin() )
1119			echo 'var ajaxurl = "' . admin_url( 'admin-ajax.php', 'relative' ) . '";';
1120
1121		?>
1122
1123		( function() {
1124			var init, edId, qtId, firstInit, wrapper;
1125
1126			if ( typeof tinymce !== 'undefined' ) {
1127				for ( edId in tinyMCEPreInit.mceInit ) {
1128					if ( firstInit ) {
1129						init = tinyMCEPreInit.mceInit[edId] = tinymce.extend( {}, firstInit, tinyMCEPreInit.mceInit[edId] );
1130					} else {
1131						init = firstInit = tinyMCEPreInit.mceInit[edId];
1132					}
1133
1134					wrapper = tinymce.DOM.select( '#wp-' + edId + '-wrap' )[0];
1135
1136					if ( ( tinymce.DOM.hasClass( wrapper, 'tmce-active' ) || ! tinyMCEPreInit.qtInit.hasOwnProperty( edId ) ) &&
1137						! init.wp_skip_init ) {
1138
1139						try {
1140							tinymce.init( init );
1141
1142							if ( ! window.wpActiveEditor ) {
1143								window.wpActiveEditor = edId;
1144							}
1145						} catch(e){}
1146					}
1147				}
1148			}
1149
1150			if ( typeof quicktags !== 'undefined' ) {
1151				for ( qtId in tinyMCEPreInit.qtInit ) {
1152					try {
1153						quicktags( tinyMCEPreInit.qtInit[qtId] );
1154
1155						if ( ! window.wpActiveEditor ) {
1156							window.wpActiveEditor = qtId;
1157						}
1158					} catch(e){};
1159				}
1160			}
1161
1162			if ( typeof jQuery !== 'undefined' ) {
1163				jQuery('.wp-editor-wrap').on( 'click.wp-editor', function() {
1164					if ( this.id ) {
1165						window.wpActiveEditor = this.id.slice( 3, -5 );
1166					}
1167				});
1168			} else {
1169				for ( qtId in tinyMCEPreInit.qtInit ) {
1170					document.getElementById( 'wp-' + qtId + '-wrap' ).onclick = function() {
1171						window.wpActiveEditor = this.id.slice( 3, -5 );
1172					}
1173				}
1174			}
1175		}());
1176		</script>
1177		<?php
1178
1179		if ( in_array( 'wplink', self::$plugins, true ) || in_array( 'link', self::$qt_buttons, true ) )
1180			self::wp_link_dialog();
1181
1182		if ( in_array( 'wpfullscreen', self::$plugins, true ) || in_array( 'fullscreen', self::$qt_buttons, true ) )
1183			self::wp_fullscreen_html();
1184
1185		/**
1186		 * Fires after any core TinyMCE editor instances are created.
1187		 *
1188		 * @since 3.2.0
1189		 *
1190		 * @param array $mce_settings TinyMCE settings array.
1191		 */
1192		do_action( 'after_wp_tiny_mce', self::$mce_settings );
1193	}
1194
1195	public static function wp_fullscreen_html() {
1196		global $content_width;
1197		$post = get_post();
1198
1199		$width = isset( $content_width ) && 800 > $content_width ? $content_width : 800;
1200		$width = $width + 22; // compensate for the padding and border
1201		$dfw_width = get_user_setting( 'dfw_width', $width );
1202		$save = isset( $post->post_status ) && $post->post_status == 'publish' ? __('Update') : __('Save');
1203
1204		?>
1205		<div id="wp-fullscreen-body" class="wp-core-ui<?php if ( is_rtl() ) echo ' rtl'; ?>" data-theme-width="<?php echo (int) $width; ?>" data-dfw-width="<?php echo (int) $dfw_width; ?>">
1206		<div id="fullscreen-topbar">
1207			<div id="wp-fullscreen-toolbar">
1208			<div id="wp-fullscreen-close"><a href="#" onclick="wp.editor.fullscreen.off();return false;"><?php _e('Exit fullscreen'); ?></a></div>
1209			<div id="wp-fullscreen-central-toolbar" style="width:<?php echo $width; ?>px;">
1210
1211			<div id="wp-fullscreen-mode-bar">
1212				<div id="wp-fullscreen-modes" class="button-group">
1213					<a class="button wp-fullscreen-mode-tinymce" href="#" onclick="wp.editor.fullscreen.switchmode( 'tinymce' ); return false;"><?php _e( 'Visual' ); ?></a>
1214					<a class="button wp-fullscreen-mode-html" href="#" onclick="wp.editor.fullscreen.switchmode( 'html' ); return false;"><?php _ex( 'Text', 'Name for the Text editor tab (formerly HTML)' ); ?></a>
1215				</div>
1216			</div>
1217
1218			<div id="wp-fullscreen-button-bar"><div id="wp-fullscreen-buttons" class="mce-toolbar">
1219		<?php
1220
1221		$buttons = array(
1222			// format: title, onclick, show in both editors
1223			'bold' => array( 'title' => __('Bold (Ctrl + B)'), 'both' => false ),
1224			'italic' => array( 'title' => __('Italic (Ctrl + I)'), 'both' => false ),
1225			'bullist' => array( 'title' => __('Unordered list (Alt + Shift + U)'), 'both' => false ),
1226			'numlist' => array( 'title' => __('Ordered list (Alt + Shift + O)'), 'both' => false ),
1227			'blockquote' => array( 'title' => __('Blockquote (Alt + Shift + Q)'), 'both' => false ),
1228			'wp-media-library' => array( 'title' => __('Media library (Alt + Shift + M)'), 'both' => true ),
1229			'link' => array( 'title' => __('Insert/edit link (Alt + Shift + A)'), 'both' => true ),
1230			'unlink' => array( 'title' => __('Unlink (Alt + Shift + S)'), 'both' => false ),
1231			'help' => array( 'title' => __('Help (Alt + Shift + H)'), 'both' => false ),
1232		);
1233
1234		/**
1235		 * Filter the list of TinyMCE buttons for the fullscreen
1236		 * 'Distraction Free Writing' editor.
1237		 *
1238		 * @since 3.2.0
1239		 *
1240		 * @param array $buttons An array of TinyMCE buttons for the DFW editor.
1241		 */
1242		$buttons = apply_filters( 'wp_fullscreen_buttons', $buttons );
1243
1244		foreach ( $buttons as $button => $args ) {
1245			if ( 'separator' == $args ) {
1246				continue;
1247			}
1248
1249			$onclick = ! empty( $args['onclick'] ) ? ' onclick="' . $args['onclick'] . '"' : '';
1250			$title = esc_attr( $args['title'] );
1251			?>
1252
1253			<div class="mce-widget mce-btn<?php if ( $args['both'] ) { ?> wp-fullscreen-both<?php } ?>">
1254			<button type="button" aria-label="<?php echo $title; ?>" title="<?php echo $title; ?>"<?php echo $onclick; ?> id="wp_fs_<?php echo $button; ?>">
1255				<i class="mce-ico mce-i-<?php echo $button; ?>"></i>
1256			</button>
1257			</div>
1258			<?php
1259		}
1260
1261		?>
1262
1263		</div></div>
1264
1265		<div id="wp-fullscreen-save">
1266			<input type="button" class="button button-primary right" value="<?php echo $save; ?>" onclick="wp.editor.fullscreen.save();" />
1267			<span class="wp-fullscreen-saved-message"><?php if ( $post->post_status == 'publish' ) _e('Updated.'); else _e('Saved.'); ?></span>
1268			<span class="wp-fullscreen-error-message"><?php _e('Save failed.'); ?></span>
1269			<span class="spinner"></span>
1270		</div>
1271
1272		</div>
1273		</div>
1274	</div>
1275	<div id="wp-fullscreen-statusbar">
1276		<div id="wp-fullscreen-status">
1277			<div id="wp-fullscreen-count"><?php printf( __( 'Word count: %s' ), '<span class="word-count">0</span>' ); ?></div>
1278			<div id="wp-fullscreen-tagline"><?php _e('Just write.'); ?></div>
1279		</div>
1280	</div>
1281	</div>
1282
1283	<div class="fullscreen-overlay" id="fullscreen-overlay"></div>
1284	<div class="fullscreen-overlay fullscreen-fader fade-300" id="fullscreen-fader"></div>
1285	<?php
1286	}
1287
1288	/**
1289	 * Performs post queries for internal linking.
1290	 *
1291	 * @since 3.1.0
1292	 *
1293	 * @param array $args Optional. Accepts 'pagenum' and 's' (search) arguments.
1294	 * @return array Results.
1295	 */
1296	public static function wp_link_query( $args = array() ) {
1297		$pts = get_post_types( array( 'public' => true ), 'objects' );
1298		$pt_names = array_keys( $pts );
1299
1300		$query = array(
1301			'post_type' => $pt_names,
1302			'suppress_filters' => true,
1303			'update_post_term_cache' => false,
1304			'update_post_meta_cache' => false,
1305			'post_status' => 'publish',
1306			'posts_per_page' => 20,
1307		);
1308
1309		$args['pagenum'] = isset( $args['pagenum'] ) ? absint( $args['pagenum'] ) : 1;
1310
1311		if ( isset( $args['s'] ) )
1312			$query['s'] = $args['s'];
1313
1314		$query['offset'] = $args['pagenum'] > 1 ? $query['posts_per_page'] * ( $args['pagenum'] - 1 ) : 0;
1315
1316		/**
1317		 * Filter the link query arguments.
1318		 *
1319		 * Allows modification of the link query arguments before querying.
1320		 *
1321		 * @see WP_Query for a full list of arguments
1322		 *
1323		 * @since 3.7.0
1324		 *
1325		 * @param array $query An array of WP_Query arguments.
1326		 */
1327		$query = apply_filters( 'wp_link_query_args', $query );
1328
1329		// Do main query.
1330		$get_posts = new WP_Query;
1331		$posts = $get_posts->query( $query );
1332		// Check if any posts were found.
1333		if ( ! $get_posts->post_count )
1334			return false;
1335
1336		// Build results.
1337		$results = array();
1338		foreach ( $posts as $post ) {
1339			if ( 'post' == $post->post_type )
1340				$info = mysql2date( __( 'Y/m/d' ), $post->post_date );
1341			else
1342				$info = $pts[ $post->post_type ]->labels->singular_name;
1343
1344			$results[] = array(
1345				'ID' => $post->ID,
1346				'title' => trim( esc_html( strip_tags( get_the_title( $post ) ) ) ),
1347				'permalink' => get_permalink( $post->ID ),
1348				'info' => $info,
1349			);
1350		}
1351
1352		/**
1353		 * Filter the link query results.
1354		 *
1355		 * Allows modification of the returned link query results.
1356		 *
1357		 * @since 3.7.0
1358		 *
1359		 * @see 'wp_link_query_args' filter
1360		 *
1361		 * @param array $results {
1362		 *     An associative array of query results.
1363		 *
1364		 *     @type array {
1365		 *         @type int    $ID        Post ID.
1366		 *         @type string $title     The trimmed, escaped post title.
1367		 *         @type string $permalink Post permalink.
1368		 *         @type string $info      A 'Y/m/d'-formatted date for 'post' post type,
1369		 *                                 the 'singular_name' post type label otherwise.
1370		 *     }
1371		 * }
1372		 * @param array $query  An array of WP_Query arguments.
1373		 */
1374		return apply_filters( 'wp_link_query', $results, $query );
1375	}
1376
1377	/**
1378	 * Dialog for internal linking.
1379	 *
1380	 * @since 3.1.0
1381	 */
1382	public static function wp_link_dialog() {
1383		$search_panel_visible = '1' == get_user_setting( 'wplink', '0' ) ? ' search-panel-visible' : '';
1384
1385		// display: none is required here, see #WP27605
1386		?>
1387		<div id="wp-link-backdrop" style="display: none"></div>
1388		<div id="wp-link-wrap" class="wp-core-ui<?php echo $search_panel_visible; ?>" style="display: none">
1389		<form id="wp-link" tabindex="-1">
1390		<?php wp_nonce_field( 'internal-linking', '_ajax_linking_nonce', false ); ?>
1391		<div id="link-modal-title">
1392			<?php _e( 'Insert/edit link' ) ?>
1393			<div id="wp-link-close" tabindex="0"></div>
1394	 	</div>
1395		<div id="link-selector">
1396			<div id="link-options">
1397				<p class="howto"><?php _e( 'Enter the destination URL' ); ?></p>
1398				<div>
1399					<label><span><?php _e( 'URL' ); ?></span><input id="url-field" type="text" name="href" /></label>
1400				</div>
1401				<div>
1402					<label><span><?php _e( 'Title' ); ?></span><input id="link-title-field" type="text" name="linktitle" /></label>
1403				</div>
1404				<div class="link-target">
1405					<label><span>&nbsp;</span><input type="checkbox" id="link-target-checkbox" /> <?php _e( 'Open li…

Large files files are truncated, but you can click here to view the full file