Add emoji support, with Twemoji fallback.

Replace exisiting smilies with equivalent emoji, or with shiny new smiley images where no emoji existed.

Props batmoo, joen and mkaz for the original plugin upon which this is based.

Props pento, iseulde, kraftbj and peterwilsoncc for making the internet's dreams come true.

See #31242


Built from https://develop.svn.wordpress.org/trunk@31733


git-svn-id: http://core.svn.wordpress.org/trunk@31714 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Gary Pendergast 2015-03-11 22:49:28 +00:00
parent 7d2b380330
commit 46e2a65cf1
17 changed files with 1077 additions and 45 deletions

View File

@ -360,6 +360,7 @@ final class _WP_Editors {
'wordpress', 'wordpress',
'wpautoresize', 'wpautoresize',
'wpeditimage', 'wpeditimage',
'wpemoji',
'wpgallery', 'wpgallery',
'wplink', 'wplink',
'wpdialogs', 'wpdialogs',

View File

@ -160,15 +160,20 @@ add_filter( 'the_title_rss', 'strip_tags' );
add_filter( 'the_title_rss', 'ent2ncr', 8 ); add_filter( 'the_title_rss', 'ent2ncr', 8 );
add_filter( 'the_title_rss', 'esc_html' ); add_filter( 'the_title_rss', 'esc_html' );
add_filter( 'the_content_rss', 'ent2ncr', 8 ); add_filter( 'the_content_rss', 'ent2ncr', 8 );
add_filter( 'the_content_feed', 'feed_emoji' );
add_filter( 'the_excerpt_rss', 'convert_chars' ); add_filter( 'the_excerpt_rss', 'convert_chars' );
add_filter( 'the_excerpt_rss', 'ent2ncr', 8 ); add_filter( 'the_excerpt_rss', 'ent2ncr', 8 );
add_filter( 'comment_author_rss', 'ent2ncr', 8 ); add_filter( 'comment_author_rss', 'ent2ncr', 8 );
add_filter( 'comment_text_rss', 'ent2ncr', 8 ); add_filter( 'comment_text_rss', 'ent2ncr', 8 );
add_filter( 'comment_text_rss', 'esc_html' ); add_filter( 'comment_text_rss', 'esc_html' );
add_filter( 'comment_text_rss', 'feed_emoji' );
add_filter( 'bloginfo_rss', 'ent2ncr', 8 ); add_filter( 'bloginfo_rss', 'ent2ncr', 8 );
add_filter( 'the_author', 'ent2ncr', 8 ); add_filter( 'the_author', 'ent2ncr', 8 );
add_filter( 'the_guid', 'esc_url' ); add_filter( 'the_guid', 'esc_url' );
// Email filters
add_filter( 'wp_mail', 'mail_emoji' );
// Misc filters // Misc filters
add_filter( 'option_ping_sites', 'privacy_ping_filter' ); add_filter( 'option_ping_sites', 'privacy_ping_filter' );
add_filter( 'option_blog_charset', '_wp_specialchars' ); // IMPORTANT: This must not be wp_specialchars() or esc_html() or it'll cause an infinite loop add_filter( 'option_blog_charset', '_wp_specialchars' ); // IMPORTANT: This must not be wp_specialchars() or esc_html() or it'll cause an infinite loop
@ -218,6 +223,7 @@ add_action( 'template_redirect', 'wp_shortlink_header', 11, 0 );
add_action( 'wp_print_footer_scripts', '_wp_footer_scripts' ); add_action( 'wp_print_footer_scripts', '_wp_footer_scripts' );
add_action( 'init', 'check_theme_switched', 99 ); add_action( 'init', 'check_theme_switched', 99 );
add_action( 'after_switch_theme', '_wp_sidebars_changed' ); add_action( 'after_switch_theme', '_wp_sidebars_changed' );
add_action( 'wp_print_styles', 'print_emoji_styles' );
if ( isset( $_GET['replytocom'] ) ) if ( isset( $_GET['replytocom'] ) )
add_action( 'wp_head', 'wp_no_robots' ); add_action( 'wp_head', 'wp_no_robots' );
@ -248,6 +254,7 @@ add_action( 'sanitize_comment_cookies', 'sanitize_comment_cookies'
add_action( 'admin_print_scripts', 'print_head_scripts', 20 ); add_action( 'admin_print_scripts', 'print_head_scripts', 20 );
add_action( 'admin_print_footer_scripts', '_wp_footer_scripts' ); add_action( 'admin_print_footer_scripts', '_wp_footer_scripts' );
add_action( 'admin_print_styles', 'print_admin_styles', 20 ); add_action( 'admin_print_styles', 'print_admin_styles', 20 );
add_action( 'admin_print_styles', 'print_emoji_styles' );
add_action( 'init', 'smilies_init', 5 ); add_action( 'init', 'smilies_init', 5 );
add_action( 'plugins_loaded', 'wp_maybe_load_widgets', 0 ); add_action( 'plugins_loaded', 'wp_maybe_load_widgets', 0 );
add_action( 'plugins_loaded', 'wp_maybe_load_embeds', 0 ); add_action( 'plugins_loaded', 'wp_maybe_load_embeds', 0 );

View File

@ -649,3 +649,14 @@ function fetch_feed( $url ) {
return $feed; return $feed;
} }
/**
* Convert emoji characters in a feed into static images.
*
* @param string $content The content to convert.
*
* @return The converted content.
*/
function feed_emoji( $content ) {
return wp_staticize_emoji( $content, true );
}

View File

@ -2038,6 +2038,15 @@ function translate_smiley( $matches ) {
$smiley = trim( reset( $matches ) ); $smiley = trim( reset( $matches ) );
$img = $wpsmiliestrans[ $smiley ]; $img = $wpsmiliestrans[ $smiley ];
$matches = array();
$ext = preg_match( '/\.([^.]+)$/', $img, $matches ) ? strtolower( $matches[1] ) : false;
$image_exts = array( 'jpg', 'jpeg', 'jpe', 'gif', 'png' );
// Don't convert smilies that aren't images - they're probably emoji.
if ( ! in_array( $ext, $image_exts ) ) {
return $img;
}
/** /**
* Filter the Smiley image URL before it's used in the image element. * Filter the Smiley image URL before it's used in the image element.
* *
@ -4015,3 +4024,155 @@ function wp_spaces_regexp() {
return $spaces; return $spaces;
} }
/**
* Print the important emoji-related styles.
*
* @since 4.2.0
*/
function print_emoji_styles() {
?>
<style type="text/css">
img.wp-smiley,
img.emoji {
border: none !important;
box-shadow: none !important;
height: 1em !important;
width: 1em !important;
margin: 0 .05em 0 .1em !important;
vertical-align: -0.1em !important;
background: none !important;
padding: 0 !important;
}
</style>
<?php
}
/**
* Convert any 4 byte emoji in a string to their equivalent HTML entity.
* Currently, only Unicode 7 emoji are supported. Unicode 8 emoji will be added
* when the spec in finalised, along with the new skin-tone modifiers.
*
* This allows us to store emoji in a DB using the utf8 character set.
*
* @since 4.2.0
*
* @param string $content The content to encode.
* @return string The encoded content.
*/
function wp_encode_emoji( $content ) {
if ( function_exists( 'mb_convert_encoding' ) ) {
$regex = '/(
\x23\xE2\x83\xA3 # Digits
[\x30-\x39]\xE2\x83\xA3
| \xF0\x9F[\x85-\x88][\xA6-\xBF] # Enclosed characters
| \xF0\x9F[\x8C-\x97][\x80-\xBF] # Misc
| \xF0\x9F\x98[\x80-\xBF] # Smilies
| \xF0\x9F\x99[\x80-\x8F]
| \xF0\x9F\x9A[\x80-\xBF] # Transport and map symbols
| \xF0\x9F\x99[\x80-\x85]
)/x';
$matches = array();
if ( preg_match_all( $regex, $content, $matches ) ) {
if ( ! empty( $matches[1] ) ) {
foreach( $matches[1] as $emoji ) {
/*
* UTF-32's hex encoding is the same as HTML's hex encoding.
* So, by converting the emoji from UTF-8 to UTF-32, we magically
* get the correct hex encoding.
*/
$unpacked = unpack( 'H*', mb_convert_encoding( $emoji, 'UTF-32', 'UTF-8' ) );
if ( isset( $unpacked[1] ) ) {
$entity = '&#x' . trim( $unpacked[1], '0' ) . ';';
$content = str_replace( $emoji, $entity, $content );
}
}
}
}
}
return $content;
}
/**
* Convert emoji to a static <img> link.
*
* @since 4.2.0
*
* @param string $content The content to encode.
* @return string The encoded content.
*/
function wp_staticize_emoji( $content ) {
$content = wp_encode_emoji( $content );
if ( ! class_exists( 'DOMDocument' ) ) {
return $content;
}
/** This filter is documented in wp-includes/script-loader.php */
$cdn_url = apply_filters( 'emoji_url', '//s0.wp.com/wp-content/mu-plugins/emoji/twemoji/72x72/' );
/** This filter is documented in wp-includes/script-loader.php */
$ext = apply_filters( 'emoji_ext', '.png' );
$html = '<!DOCTYPE html><html><head></head><body>' . $content . '</body></html>';
$document = new DOMDocument;
if ( ! $document->loadHTML( $html ) ) {
return $content;
}
$xpath = new DOMXPath( $document );
$textnodes = $xpath->query( '//text()' );
foreach( $textnodes as $node ) {
$originalText = $text = wp_encode_emoji( $node->nodeValue );
$matches = array();
if ( preg_match_all( '/(&#x1f1(e[6-9a-f]|f[0-9a-f]);){2}/', $text, $matches ) ) {
if ( ! empty( $matches[0] ) ) {
foreach ( $matches[0] as $flag ) {
$chars = str_replace( array( '&#x', ';'), '', $flag );
list( $char1, $char2 ) = str_split( $chars, 5 );
$entity = '<img src="https:' . $cdn_url . $char1 . '-' . $char2 . $ext . '" class="wp-smiley" style="height: 1em;" />';
$text = str_replace( $flag, $entity, $text );
}
}
}
// Loosely match the Emoji Unicode range.
$regex = '/(&#x[2-3][0-9a-f]{3};|&#x1f[1-6][0-9a-f]{2};)/';
$matches = array();
if ( preg_match_all( $regex, $text, $matches ) ) {
if ( ! empty( $matches[1] ) ) {
foreach ( $matches[1] as $emoji ) {
$char = str_replace( array( '&#x', ';'), '', $emoji );
$entity = '<img src="https:' . $cdn_url . $char . $ext . '" class="wp-smiley" style="height: 1em;" />';
$text = str_replace( $emoji, $entity, $text );
}
}
}
if ( $originalText !== $text ) {
$content = str_replace( $originalText, $text, $content );
}
}
return $content;
}
/**
* Convert emoji in emails into static images.
*
* @param array $mail The email data array.
*
* @return array The email data array, with emoji in the message staticized.
*/
function mail_emoji( $mail ) {
$mail['message'] = wp_staticize_emoji( $mail['message'], true );
return $mail;
}

View File

@ -2945,51 +2945,51 @@ function smilies_init() {
if ( !isset( $wpsmiliestrans ) ) { if ( !isset( $wpsmiliestrans ) ) {
$wpsmiliestrans = array( $wpsmiliestrans = array(
':mrgreen:' => 'icon_mrgreen.gif', ':mrgreen:' => 'mrgreen.png',
':neutral:' => 'icon_neutral.gif', ':neutral:' => "\xf0\x9f\x98\x90",
':twisted:' => 'icon_twisted.gif', ':twisted:' => "\xf0\x9f\x98\x88",
':arrow:' => 'icon_arrow.gif', ':arrow:' => "\xe2\x9e\xa1",
':shock:' => 'icon_eek.gif', ':shock:' => "\xf0\x9f\x98\xaf",
':smile:' => 'icon_smile.gif', ':smile:' => 'simple-smile.png',
':???:' => 'icon_confused.gif', ':???:' => "\xf0\x9f\x98\xaf",
':cool:' => 'icon_cool.gif', ':cool:' => "\xf0\x9f\x98\x8e",
':evil:' => 'icon_evil.gif', ':evil:' => "\xf0\x9f\x91\xbf",
':grin:' => 'icon_biggrin.gif', ':grin:' => "\xf0\x9f\x98\x84",
':idea:' => 'icon_idea.gif', ':idea:' => "\xf0\x9f\x92\xa1",
':oops:' => 'icon_redface.gif', ':oops:' => "\xf0\x9f\x98\xb3",
':razz:' => 'icon_razz.gif', ':razz:' => "\xf0\x9f\x98\x9b",
':roll:' => 'icon_rolleyes.gif', ':roll:' => 'rolleyes.png',
':wink:' => 'icon_wink.gif', ':wink:' => "\xf0\x9f\x98\x89",
':cry:' => 'icon_cry.gif', ':cry:' => "\xf0\x9f\x98\xa5",
':eek:' => 'icon_surprised.gif', ':eek:' => "\xf0\x9f\x98\xaf",
':lol:' => 'icon_lol.gif', ':lol:' => "\xf0\x9f\x98\x84",
':mad:' => 'icon_mad.gif', ':mad:' => "\xf0\x9f\x98\xa1",
':sad:' => 'icon_sad.gif', ':sad:' => "\xf0\x9f\x98\xa6",
'8-)' => 'icon_cool.gif', '8-)' => "\xf0\x9f\x98\x8e",
'8-O' => 'icon_eek.gif', '8-O' => "\xf0\x9f\x98\xaf",
':-(' => 'icon_sad.gif', ':-(' => "\xf0\x9f\x98\xa6",
':-)' => 'icon_smile.gif', ':-)' => 'simple-smile.png',
':-?' => 'icon_confused.gif', ':-?' => "\xf0\x9f\x98\xaf",
':-D' => 'icon_biggrin.gif', ':-D' => "\xf0\x9f\x98\x84",
':-P' => 'icon_razz.gif', ':-P' => "\xf0\x9f\x98\x9b",
':-o' => 'icon_surprised.gif', ':-o' => "\xf0\x9f\x98\xaf",
':-x' => 'icon_mad.gif', ':-x' => "\xf0\x9f\x98\xa1",
':-|' => 'icon_neutral.gif', ':-|' => "\xf0\x9f\x98\x90",
';-)' => 'icon_wink.gif', ';-)' => "\xf0\x9f\x98\x89",
// This one transformation breaks regular text with frequency. // This one transformation breaks regular text with frequency.
// '8)' => 'icon_cool.gif', // '8)' => "\xf0\x9f\x98\x8e",
'8O' => 'icon_eek.gif', '8O' => "\xf0\x9f\x98\xaf",
':(' => 'icon_sad.gif', ':(' => "\xf0\x9f\x98\xa6",
':)' => 'icon_smile.gif', ':)' => 'simple-smile.png',
':?' => 'icon_confused.gif', ':?' => "\xf0\x9f\x98\xaf",
':D' => 'icon_biggrin.gif', ':D' => "\xf0\x9f\x98\x84",
':P' => 'icon_razz.gif', ':P' => "\xf0\x9f\x98\x9b",
':o' => 'icon_surprised.gif', ':o' => "\xf0\x9f\x98\xaf",
':x' => 'icon_mad.gif', ':x' => "\xf0\x9f\x98\xa1",
':|' => 'icon_neutral.gif', ':|' => "\xf0\x9f\x98\x90",
';)' => 'icon_wink.gif', ';)' => "\xf0\x9f\x98\x89",
':!:' => 'icon_exclaim.gif', ':!:' => "\xe2\x9d\x97",
':?:' => 'icon_question.gif', ':?:' => "\xe2\x9d\x93",
); );
} }

201
wp-includes/js/emoji.js Normal file
View File

@ -0,0 +1,201 @@
/* global EmojiSettings, twemoji */
var WPEmoji;
(function() {
WPEmoji = {
/**
* The CDN URL for where emoji files are hosted.
*
* @since 4.2.0
*
* @var string
*/
base_url: '//s0.wp.com/wp-content/mu-plugins/emoji/twemoji/72x72',
/**
* The extension of the hosted emoji files.
*
* @since 4.2.0
*
* @var string
*/
ext: '.png',
/**
* Flag to determine if we should parse all emoji characters into Twemoji images.
*
* @since 4.2.0
*
* @var bool
*/
parseAllEmoji: false,
/**
* Flag to determine if we should consider parsing emoji characters into Twemoji images.
*
* @since 4.2.0
*
* @var bool
*/
parseEmoji: false,
/**
* Flag to determine if we should parse flag characters into Twemoji images.
*
* @since 4.2.0
*
* @var bool
*/
parseFlags: false,
/**
* Initialize our emoji support, and set up listeners.
*
* @since 4.2.0
*/
init: function() {
if ( typeof EmojiSettings !== 'undefined' ) {
this.base_url = EmojiSettings.base_url || this.base_url;
this.ext = EmojiSettings.ext || this.ext;
}
WPEmoji.parseAllEmoji = ! WPEmoji.browserSupportsEmoji();
WPEmoji.parseFlags = ! WPEmoji.browserSupportsFlagEmoji();
WPEmoji.parseEmoji = WPEmoji.parseAllEmoji || WPEmoji.parseFlags;
if ( ! WPEmoji.parseEmoji ) {
return;
}
},
/**
* Runs when the document load event is fired, so we can do our first parse of the page.
*
* @since 4.2.0
*/
load: function() {
WPEmoji.parse( document.body );
},
/**
* Detect if the browser supports rendering emoji.
*
* @since 4.2.0
*
* @return {bool} True if the browser can render emoji, false if it cannot.
*/
browserSupportsEmoji: function() {
var context, smile;
if ( ! document.createElement( 'canvas' ).getContext ) {
return;
}
context = document.createElement( 'canvas' ).getContext( '2d' );
if ( typeof context.fillText != 'function' ) {
return;
}
smile = String.fromCharCode( 55357 ) + String.fromCharCode( 56835 );
/*
* Chrome OS X added native emoji rendering in M41. Unfortunately,
* it doesn't work when the font is bolder than 500 weight. So, we
* check for bold rendering support to avoid invisible emoji in Chrome.
*/
context.textBaseline = 'top';
context.font = '600 32px Arial';
context.fillText( smile, 0, 0 );
return context.getImageData( 16, 16, 1, 1 ).data[0] !== 0;
},
/**
* Detect if the browser supports rendering flag emoji. Flag emoji are a single glyph
* made of two characters, so some browsers (notably, Firefox OS X) don't support them.
*
* @since 4.2.0
* @return {bool} True if the browser renders flag characters as a flag glyph, false if it does not.
*/
browserSupportsFlagEmoji: function() {
var context, flag, canvas;
canvas = document.createElement( 'canvas' );
if ( ! canvas.getContext ) {
return;
}
context = canvas.getContext( '2d' );
if ( typeof context.fillText != 'function' ) {
return;
}
flag = String.fromCharCode(55356) + String.fromCharCode(56812); // [G]
flag += String.fromCharCode(55356) + String.fromCharCode(56807); // [B]
context.textBaseline = 'top';
context.font = '32px Arial';
context.fillText( flag, 0, 0 );
/*
* This works because the image will be one of three things:
* - Two empty squares, if the browser doen't render emoji
* - Two squares with 'G' and 'B' in them, if the browser doen't render flag emoji
* - The British flag
*
* The first two will encode to small images (1-2KB data URLs), the third will encode
* to a larger image (4-5KB data URL).
*/
return canvas.toDataURL().length > 3000;
},
/**
* Given a DOM node, parse any emoji characters into Twemoji images.
*
* @since 4.2.0
*
* @param {Element} element The DOM node to parse.
*/
parse: function( element ) {
if ( ! WPEmoji.parseEmoji ) {
return;
}
return twemoji.parse( element, {
base: this.base_url,
ext: this.ext,
callback: function( icon, options ) {
// Ignore some standard characters that TinyMCE recommends in its character map.
switch ( icon ) {
case 'a9':
case 'ae':
case '2122':
case '2194':
case '2660':
case '2663':
case '2665':
case '2666':
return false;
}
if ( WPEmoji.parseFlags && ! WPEmoji.parseAllEmoji && ! icon.match( /^1f1(e[6-9a-f]|f[1-9a-f])-1f1(e[6-9a-f]|f[1-9a-f])$/ ) ) {
return false;
}
return ''.concat( options.base, '/', icon, options.ext );
}
} );
}
};
if ( window.addEventListener ) {
window.addEventListener( 'load', WPEmoji.load, false );
} else if ( window.attachEvent ) {
window.attachEvent( 'onload', WPEmoji.load );
}
WPEmoji.init();
})();

1
wp-includes/js/emoji.min.js vendored Normal file
View File

@ -0,0 +1 @@
var WPEmoji;!function(){WPEmoji={base_url:"//s0.wp.com/wp-content/mu-plugins/emoji/twemoji/72x72",ext:".png",parseAllEmoji:!1,parseEmoji:!1,parseFlags:!1,init:function(){"undefined"!=typeof EmojiSettings&&(this.base_url=EmojiSettings.base_url||this.base_url,this.ext=EmojiSettings.ext||this.ext),WPEmoji.parseAllEmoji=!WPEmoji.browserSupportsEmoji(),WPEmoji.parseFlags=!WPEmoji.browserSupportsFlagEmoji(),WPEmoji.parseEmoji=WPEmoji.parseAllEmoji||WPEmoji.parseFlags,!WPEmoji.parseEmoji},load:function(){WPEmoji.parse(document.body)},browserSupportsEmoji:function(){var a,b;if(document.createElement("canvas").getContext&&(a=document.createElement("canvas").getContext("2d"),"function"==typeof a.fillText))return b=String.fromCharCode(55357)+String.fromCharCode(56835),a.textBaseline="top",a.font="600 32px Arial",a.fillText(b,0,0),0!==a.getImageData(16,16,1,1).data[0]},browserSupportsFlagEmoji:function(){var a,b,c;return c=document.createElement("canvas"),c.getContext&&(a=c.getContext("2d"),"function"==typeof a.fillText)?(b=String.fromCharCode(55356)+String.fromCharCode(56812),b+=String.fromCharCode(55356)+String.fromCharCode(56807),a.textBaseline="top",a.font="32px Arial",a.fillText(b,0,0),c.toDataURL().length>3e3):void 0},parse:function(a){return WPEmoji.parseEmoji?twemoji.parse(a,{base:this.base_url,ext:this.ext,callback:function(a,b){switch(a){case"a9":case"ae":case"2122":case"2194":case"2660":case"2663":case"2665":case"2666":return!1}return!WPEmoji.parseFlags||WPEmoji.parseAllEmoji||a.match(/^1f1(e[6-9a-f]|f[1-9a-f])-1f1(e[6-9a-f]|f[1-9a-f])$/)?"".concat(b.base,"/",a,b.ext):!1}}):void 0}},window.addEventListener?window.addEventListener("load",WPEmoji.load,!1):window.attachEvent&&window.attachEvent("onload",WPEmoji.load),WPEmoji.init()}();

View File

@ -0,0 +1,15 @@
.emoji-wrapper,
.emoji-spacer {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
img.emoji {
height: 1em;
width: 1em;
margin: 0 .05em 0 .1em;
vertical-align: -0.1em;
border: none;
padding: 0;
}

View File

@ -0,0 +1,17 @@
/* This file was automatically generated on Nov 19 2014 05:08:11 */
.emoji-wrapper,
.emoji-spacer {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
}
img.emoji {
height: 1em;
width: 1em;
margin: 0 .1em 0 .05em;
vertical-align: -0.1em;
border: none;
padding: 0;
}

View File

@ -0,0 +1,64 @@
( function( tinymce, WPEmoji ) {
tinymce.PluginManager.add( 'wpemoji', function( editor, url ) {
var typing;
if ( ! WPEmoji.parseEmoji ) {
return;
}
// Loads stylesheet for custom styles within the editor
editor.on( 'init', function() {
var cssId = editor.dom.uniqueId();
var linkElm = editor.dom.create( 'link', {
id: cssId,
rel: 'stylesheet',
href: url + '/css/editor.css'
});
editor.getDoc().getElementsByTagName( 'head' )[0].appendChild( linkElm );
} );
editor.on( 'keydown keyup', function( event ) {
typing = event.type === 'keydown';
} );
editor.on( 'input setcontent', function() {
var selection, node, bookmark, imgs;
if ( typing ) {
return;
}
selection = editor.selection;
node = selection.getNode();
bookmark = selection.getBookmark();
WPEmoji.parse( node );
imgs = editor.dom.select( 'img.emoji', node );
tinymce.each( imgs, function( elem ) {
if ( ! elem.getAttribute( 'data-wp-emoji' ) ) {
elem.setAttribute( 'data-mce-resize', 'false' );
elem.setAttribute( 'data-mce-placeholder', '1' );
elem.setAttribute( 'data-wp-emoji', elem.alt );
}
} );
selection.moveToBookmark( bookmark );
} );
editor.on( 'postprocess', function( event ) {
if ( event.content ) {
event.content = event.content.replace( /<img[^>]+data-wp-emoji="([^"]+)"[^>]*>/g, function( match, emoji ) {
return emoji;
} );
}
} );
editor.on( 'resolvename', function( event ) {
if ( event.target.nodeName === 'IMG' && editor.dom.getAttrib( event.target, 'data-wp-emoji' ) ) {
event.preventDefault();
}
} );
} );
} )( window.tinymce, window.WPEmoji );

View File

@ -0,0 +1 @@
!function(a,b){a.PluginManager.add("wpemoji",function(c,d){var e;b.parseEmoji&&(c.on("init",function(){var a=c.dom.uniqueId(),b=c.dom.create("link",{id:a,rel:"stylesheet",href:d+"/css/editor.css"});c.getDoc().getElementsByTagName("head")[0].appendChild(b)}),c.on("keydown keyup",function(a){e="keydown"===a.type}),c.on("input setcontent",function(){var d,f,g,h;e||(d=c.selection,f=d.getNode(),g=d.getBookmark(),b.parse(f),h=c.dom.select("img.emoji",f),a.each(h,function(a){a.getAttribute("data-wp-emoji")||(a.setAttribute("data-mce-resize","false"),a.setAttribute("data-mce-placeholder","1"),a.setAttribute("data-wp-emoji",a.alt))}),d.moveToBookmark(g))}),c.on("postprocess",function(a){a.content&&(a.content=a.content.replace(/<img[^>]+data-wp-emoji="([^"]+)"[^>]*>/g,function(a,b){return b}))}),c.on("resolvename",function(a){"IMG"===a.target.nodeName&&c.dom.getAttrib(a.target,"data-wp-emoji")&&a.preventDefault()}))})}(window.tinymce,window.WPEmoji);

519
wp-includes/js/twemoji.js Normal file

File diff suppressed because one or more lines are too long

1
wp-includes/js/twemoji.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -3329,6 +3329,17 @@ function wp_insert_post( $postarr, $wp_error = false ) {
// Expected_slashed (everything!). // Expected_slashed (everything!).
$data = compact( 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_content_filtered', 'post_title', 'post_excerpt', 'post_status', 'post_type', 'comment_status', 'ping_status', 'post_password', 'post_name', 'to_ping', 'pinged', 'post_modified', 'post_modified_gmt', 'post_parent', 'menu_order', 'post_mime_type', 'guid' ); $data = compact( 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_content_filtered', 'post_title', 'post_excerpt', 'post_status', 'post_type', 'comment_status', 'ping_status', 'post_password', 'post_name', 'to_ping', 'pinged', 'post_modified', 'post_modified_gmt', 'post_parent', 'menu_order', 'post_mime_type', 'guid' );
$emoji_fields = array( 'post_title', 'post_content', 'post_excerpt' );
foreach( $emoji_fields as $emoji_field ) {
if ( isset( $data[ $emoji_field ] ) ) {
$charset = $wpdb->get_col_charset( $wpdb->posts, $emoji_field );
if ( 'utf8' === $charset ) {
$data[ $emoji_field ] = wp_encode_emoji( $data[ $emoji_field ] );
}
}
}
if ( 'attachment' === $post_type ) { if ( 'attachment' === $post_type ) {
/** /**
* Filter attachment post data before it is updated in or added to the database. * Filter attachment post data before it is updated in or added to the database.

View File

@ -424,6 +424,28 @@ function wp_default_scripts( &$scripts ) {
$scripts->add( 'media-audiovideo', "/wp-includes/js/media/audio-video$suffix.js", array( 'media-editor' ), false, 1 ); $scripts->add( 'media-audiovideo', "/wp-includes/js/media/audio-video$suffix.js", array( 'media-editor' ), false, 1 );
$scripts->add( 'mce-view', "/wp-includes/js/mce-view$suffix.js", array( 'shortcode', 'media-models', 'media-audiovideo', 'wp-playlist' ), false, 1 ); $scripts->add( 'mce-view', "/wp-includes/js/mce-view$suffix.js", array( 'shortcode', 'media-models', 'media-audiovideo', 'wp-playlist' ), false, 1 );
$scripts->add( 'twemoji', "/wp-includes/js/twemoji$suffix.js", array(), false, 1 );
$scripts->add( 'emoji', "/wp-includes/js/emoji$suffix.js", array( 'twemoji' ), false, 1 );
did_action( 'init' ) && $scripts->localize( 'emoji', 'EmojiSettings', array(
/**
* Filter the URL where emoji images are hosted.
*
* @since 4.2.0
*
* @param string The emoji base URL.
*/
'base_url' => apply_filters( 'emoji_url', '//s0.wp.com/wp-content/mu-plugins/emoji/twemoji/72x72/' ),
/**
* Filter the extension of the emoji files.
*
* @since 4.2.0
*
* @param string The emoji extension.
*/
'ext' => apply_filters( 'emoji_ext', '.png' ),
) );
$scripts->enqueue( 'emoji' );
if ( is_admin() ) { if ( is_admin() ) {
$scripts->add( 'admin-tags', "/wp-admin/js/tags$suffix.js", array('jquery', 'wp-ajax-response'), false, 1 ); $scripts->add( 'admin-tags', "/wp-admin/js/tags$suffix.js", array('jquery', 'wp-ajax-response'), false, 1 );
did_action( 'init' ) && $scripts->localize( 'admin-tags', 'tagsl10n', array( did_action( 'init' ) && $scripts->localize( 'admin-tags', 'tagsl10n', array(

View File

@ -4,7 +4,7 @@
* *
* @global string $wp_version * @global string $wp_version
*/ */
$wp_version = '4.2-alpha-31732'; $wp_version = '4.2-alpha-31733';
/** /**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.