From f3c1022b826cbf2aa4e8b04c65343e788781d53e Mon Sep 17 00:00:00 2001 From: James Nylen Date: Fri, 7 Jul 2017 21:03:01 +0200 Subject: [PATCH] Improve PHP parsing performance (#1775) --- lib/parser.php | 140 ++++++++++++++++------------- package.json | 2 +- phpcs.xml.dist | 3 + phpunit/class-performance-test.php | 36 ++++++++ phpunit/fixtures/long-content.html | 131 +++++++++++++++++++++++++++ 5 files changed, 251 insertions(+), 61 deletions(-) create mode 100644 phpunit/class-performance-test.php create mode 100644 phpunit/fixtures/long-content.html diff --git a/lib/parser.php b/lib/parser.php index c9b872c1017ca..2ae0b369a9385 100644 --- a/lib/parser.php +++ b/lib/parser.php @@ -1,6 +1,6 @@ peg_currPos = 0; $this->peg_reportedPos = 0; $this->peg_cachedPos = 0; @@ -56,10 +56,23 @@ private function cleanup_state(){ $this->peg_maxFailPos = 0; $this->peg_maxFailExpected = array(); $this->peg_silentFails = 0; - $this->input = ""; + $this->input = array(); + $this->input_length = 0; } + private function input_substr($start, $length) { + if ($length === 1) { + return $this->input[$start]; + } + $substr = ''; + $max = min($start + $length, $this->input_length); + for ($i = $start; $i < $max; $i++) { + $substr .= $this->input[$i]; + } + return $substr; + } + private function text() { return substr($this->input, $this->peg_reportedPos, $this->peg_reportedPos + $this->peg_currPos); @@ -93,7 +106,7 @@ private function error($message) { private function peg_advancePos(&$details, $startPos, $endPos) { for ($p = $startPos; $p < $endPos; $p++) { - $ch = mb_substr($this->input, $p, 1, "UTF-8"); + $ch = $this->input_substr($p, 1); if ($ch === "\n") { if (!$details["seenCR"]) { $details["line"]++; } $details["column"] = 1; @@ -145,7 +158,7 @@ private function peg_buildException_expectedComparator($a, $b) { private function peg_buildException($message, $expected, $pos) { $posDetails = $this->peg_computePosDetails($pos); - $found = $pos < mb_strlen($this->input, "UTF-8") ? mb_substr($this->input, $pos, 1, "UTF-8") : null; + $found = $pos < $this->input_length ? $this->input_substr($pos, 1) : null; if ($expected !== null) { usort($expected, array($this, "peg_buildException_expectedComparator")); @@ -309,7 +322,7 @@ private function peg_parseWP_Block() { private function peg_parseWP_Tag_More() { $s0 = $this->peg_currPos; - if (mb_substr($this->input, $this->peg_currPos, 4, "UTF-8") === $this->peg_c0) { + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c0) { $s1 = $this->peg_c0; $this->peg_currPos += 4; } else { @@ -324,7 +337,7 @@ private function peg_parseWP_Tag_More() { $s3 = $this->peg_parseWS(); } if ($s2 !== $this->peg_FAILED) { - if (mb_substr($this->input, $this->peg_currPos, 4, "UTF-8") === $this->peg_c2) { + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c2) { $s3 = $this->peg_c2; $this->peg_currPos += 4; } else { @@ -357,7 +370,7 @@ private function peg_parseWP_Tag_More() { $s12 = $this->peg_parseWS(); } if ($s11 !== $this->peg_FAILED) { - if (mb_substr($this->input, $this->peg_currPos, 3, "UTF-8") === $this->peg_c4) { + if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c4) { $s12 = $this->peg_c4; $this->peg_currPos += 3; } else { @@ -383,8 +396,8 @@ private function peg_parseWP_Tag_More() { $s9 = $this->peg_FAILED; } if ($s9 !== $this->peg_FAILED) { - if (mb_strlen($this->input, "UTF-8") > $this->peg_currPos) { - $s10 = mb_substr($this->input, $this->peg_currPos, 1, "UTF-8"); + if ($this->input_length > $this->peg_currPos) { + $s10 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s10 = $this->peg_FAILED; @@ -415,7 +428,7 @@ private function peg_parseWP_Tag_More() { $s12 = $this->peg_parseWS(); } if ($s11 !== $this->peg_FAILED) { - if (mb_substr($this->input, $this->peg_currPos, 3, "UTF-8") === $this->peg_c4) { + if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c4) { $s12 = $this->peg_c4; $this->peg_currPos += 3; } else { @@ -441,8 +454,8 @@ private function peg_parseWP_Tag_More() { $s9 = $this->peg_FAILED; } if ($s9 !== $this->peg_FAILED) { - if (mb_strlen($this->input, "UTF-8") > $this->peg_currPos) { - $s10 = mb_substr($this->input, $this->peg_currPos, 1, "UTF-8"); + if ($this->input_length > $this->peg_currPos) { + $s10 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s10 = $this->peg_FAILED; @@ -464,7 +477,7 @@ private function peg_parseWP_Tag_More() { $s7 = $this->peg_FAILED; } if ($s7 !== $this->peg_FAILED) { - $s6 = mb_substr($this->input, $s6, $this->peg_currPos - $s6, "UTF-8"); + $s6 = $this->input_substr($s6, $this->peg_currPos - $s6); } else { $s6 = $s7; } @@ -491,7 +504,7 @@ private function peg_parseWP_Tag_More() { $s6 = $this->peg_parseWS(); } if ($s5 !== $this->peg_FAILED) { - if (mb_substr($this->input, $this->peg_currPos, 3, "UTF-8") === $this->peg_c4) { + if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c4) { $s6 = $this->peg_c4; $this->peg_currPos += 3; } else { @@ -507,7 +520,7 @@ private function peg_parseWP_Tag_More() { $s9 = $this->peg_parseWS(); } if ($s8 !== $this->peg_FAILED) { - if (mb_substr($this->input, $this->peg_currPos, 15, "UTF-8") === $this->peg_c7) { + if ($this->input_substr($this->peg_currPos, 15) === $this->peg_c7) { $s9 = $this->peg_c7; $this->peg_currPos += 15; } else { @@ -567,7 +580,7 @@ private function peg_parseWP_Tag_More() { private function peg_parseWP_Block_Void() { $s0 = $this->peg_currPos; - if (mb_substr($this->input, $this->peg_currPos, 4, "UTF-8") === $this->peg_c0) { + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c0) { $s1 = $this->peg_c0; $this->peg_currPos += 4; } else { @@ -586,7 +599,7 @@ private function peg_parseWP_Block_Void() { $s2 = $this->peg_FAILED; } if ($s2 !== $this->peg_FAILED) { - if (mb_substr($this->input, $this->peg_currPos, 3, "UTF-8") === $this->peg_c9) { + if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c9) { $s3 = $this->peg_c9; $this->peg_currPos += 3; } else { @@ -636,7 +649,7 @@ private function peg_parseWP_Block_Void() { $s6 = null; } if ($s6 !== $this->peg_FAILED) { - if (mb_substr($this->input, $this->peg_currPos, 4, "UTF-8") === $this->peg_c11) { + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c11) { $s7 = $this->peg_c11; $this->peg_currPos += 4; } else { @@ -875,7 +888,7 @@ private function peg_parseWP_Block_Html() { private function peg_parseWP_Block_Start() { $s0 = $this->peg_currPos; - if (mb_substr($this->input, $this->peg_currPos, 4, "UTF-8") === $this->peg_c0) { + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c0) { $s1 = $this->peg_c0; $this->peg_currPos += 4; } else { @@ -894,7 +907,7 @@ private function peg_parseWP_Block_Start() { $s2 = $this->peg_FAILED; } if ($s2 !== $this->peg_FAILED) { - if (mb_substr($this->input, $this->peg_currPos, 3, "UTF-8") === $this->peg_c9) { + if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c9) { $s3 = $this->peg_c9; $this->peg_currPos += 3; } else { @@ -944,7 +957,7 @@ private function peg_parseWP_Block_Start() { $s6 = null; } if ($s6 !== $this->peg_FAILED) { - if (mb_substr($this->input, $this->peg_currPos, 3, "UTF-8") === $this->peg_c4) { + if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c4) { $s7 = $this->peg_c4; $this->peg_currPos += 3; } else { @@ -990,7 +1003,7 @@ private function peg_parseWP_Block_Start() { private function peg_parseWP_Block_End() { $s0 = $this->peg_currPos; - if (mb_substr($this->input, $this->peg_currPos, 4, "UTF-8") === $this->peg_c0) { + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c0) { $s1 = $this->peg_c0; $this->peg_currPos += 4; } else { @@ -1009,7 +1022,7 @@ private function peg_parseWP_Block_End() { $s2 = $this->peg_FAILED; } if ($s2 !== $this->peg_FAILED) { - if (mb_substr($this->input, $this->peg_currPos, 4, "UTF-8") === $this->peg_c13) { + if ($this->input_substr($this->peg_currPos, 4) === $this->peg_c13) { $s3 = $this->peg_c13; $this->peg_currPos += 4; } else { @@ -1030,7 +1043,7 @@ private function peg_parseWP_Block_End() { $s5 = $this->peg_FAILED; } if ($s5 !== $this->peg_FAILED) { - if (mb_substr($this->input, $this->peg_currPos, 3, "UTF-8") === $this->peg_c4) { + if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c4) { $s6 = $this->peg_c4; $this->peg_currPos += 3; } else { @@ -1079,7 +1092,7 @@ private function peg_parseWP_Block_Name() { $s4 = $this->peg_parseASCII_AlphaNumeric(); if ($s4 === $this->peg_FAILED) { $s4 = $this->peg_currPos; - if (mb_substr($this->input, $this->peg_currPos, 1, "UTF-8") === $this->peg_c15) { + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c15) { $s5 = $this->peg_c15; $this->peg_currPos++; } else { @@ -1105,7 +1118,7 @@ private function peg_parseWP_Block_Name() { $s4 = $this->peg_parseASCII_AlphaNumeric(); if ($s4 === $this->peg_FAILED) { $s4 = $this->peg_currPos; - if (mb_substr($this->input, $this->peg_currPos, 1, "UTF-8") === $this->peg_c15) { + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c15) { $s5 = $this->peg_c15; $this->peg_currPos++; } else { @@ -1139,7 +1152,7 @@ private function peg_parseWP_Block_Name() { $s1 = $this->peg_FAILED; } if ($s1 !== $this->peg_FAILED) { - $s0 = mb_substr($this->input, $s0, $this->peg_currPos - $s0, "UTF-8"); + $s0 = $this->input_substr($s0, $this->peg_currPos - $s0); } else { $s0 = $s1; } @@ -1152,7 +1165,7 @@ private function peg_parseWP_Block_Attributes() { $s0 = $this->peg_currPos; $s1 = $this->peg_currPos; $s2 = $this->peg_currPos; - if (mb_substr($this->input, $this->peg_currPos, 1, "UTF-8") === $this->peg_c17) { + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c17) { $s3 = $this->peg_c17; $this->peg_currPos++; } else { @@ -1165,7 +1178,7 @@ private function peg_parseWP_Block_Attributes() { $s6 = $this->peg_currPos; $this->peg_silentFails++; $s7 = $this->peg_currPos; - if (mb_substr($this->input, $this->peg_currPos, 1, "UTF-8") === $this->peg_c19) { + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c19) { $s8 = $this->peg_c19; $this->peg_currPos++; } else { @@ -1186,7 +1199,7 @@ private function peg_parseWP_Block_Attributes() { if ($s9 !== $this->peg_FAILED) { $s10 = $this->peg_c21; if ($s10 !== $this->peg_FAILED) { - if (mb_substr($this->input, $this->peg_currPos, 1, "UTF-8") === $this->peg_c15) { + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c15) { $s11 = $this->peg_c15; $this->peg_currPos++; } else { @@ -1197,7 +1210,7 @@ private function peg_parseWP_Block_Attributes() { $s11 = null; } if ($s11 !== $this->peg_FAILED) { - if (mb_substr($this->input, $this->peg_currPos, 3, "UTF-8") === $this->peg_c4) { + if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c4) { $s12 = $this->peg_c4; $this->peg_currPos += 3; } else { @@ -1235,8 +1248,8 @@ private function peg_parseWP_Block_Attributes() { $s6 = $this->peg_FAILED; } if ($s6 !== $this->peg_FAILED) { - if (mb_strlen($this->input, "UTF-8") > $this->peg_currPos) { - $s7 = mb_substr($this->input, $this->peg_currPos, 1, "UTF-8"); + if ($this->input_length > $this->peg_currPos) { + $s7 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s7 = $this->peg_FAILED; @@ -1259,7 +1272,7 @@ private function peg_parseWP_Block_Attributes() { $s6 = $this->peg_currPos; $this->peg_silentFails++; $s7 = $this->peg_currPos; - if (mb_substr($this->input, $this->peg_currPos, 1, "UTF-8") === $this->peg_c19) { + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c19) { $s8 = $this->peg_c19; $this->peg_currPos++; } else { @@ -1280,7 +1293,7 @@ private function peg_parseWP_Block_Attributes() { if ($s9 !== $this->peg_FAILED) { $s10 = $this->peg_c21; if ($s10 !== $this->peg_FAILED) { - if (mb_substr($this->input, $this->peg_currPos, 1, "UTF-8") === $this->peg_c15) { + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c15) { $s11 = $this->peg_c15; $this->peg_currPos++; } else { @@ -1291,7 +1304,7 @@ private function peg_parseWP_Block_Attributes() { $s11 = null; } if ($s11 !== $this->peg_FAILED) { - if (mb_substr($this->input, $this->peg_currPos, 3, "UTF-8") === $this->peg_c4) { + if ($this->input_substr($this->peg_currPos, 3) === $this->peg_c4) { $s12 = $this->peg_c4; $this->peg_currPos += 3; } else { @@ -1329,8 +1342,8 @@ private function peg_parseWP_Block_Attributes() { $s6 = $this->peg_FAILED; } if ($s6 !== $this->peg_FAILED) { - if (mb_strlen($this->input, "UTF-8") > $this->peg_currPos) { - $s7 = mb_substr($this->input, $this->peg_currPos, 1, "UTF-8"); + if ($this->input_length > $this->peg_currPos) { + $s7 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s7 = $this->peg_FAILED; @@ -1349,7 +1362,7 @@ private function peg_parseWP_Block_Attributes() { } } if ($s4 !== $this->peg_FAILED) { - if (mb_substr($this->input, $this->peg_currPos, 1, "UTF-8") === $this->peg_c19) { + if ($this->input_substr($this->peg_currPos, 1) === $this->peg_c19) { $s5 = $this->peg_c19; $this->peg_currPos++; } else { @@ -1372,7 +1385,7 @@ private function peg_parseWP_Block_Attributes() { $s2 = $this->peg_FAILED; } if ($s2 !== $this->peg_FAILED) { - $s1 = mb_substr($this->input, $s1, $this->peg_currPos - $s1, "UTF-8"); + $s1 = $this->input_substr($s1, $this->peg_currPos - $s1); } else { $s1 = $s2; } @@ -1400,8 +1413,8 @@ private function peg_parseASCII_AlphaNumeric() { private function peg_parseASCII_Letter() { - if (Gutenberg_PEG_peg_regex_test($this->peg_c22, mb_substr($this->input, $this->peg_currPos, 1, "UTF-8"))) { - $s0 = mb_substr($this->input, $this->peg_currPos, 1, "UTF-8"); + if (Gutenberg_PEG_peg_regex_test($this->peg_c22, $this->input_substr($this->peg_currPos, 1))) { + $s0 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; @@ -1413,8 +1426,8 @@ private function peg_parseASCII_Letter() { private function peg_parseASCII_Digit() { - if (Gutenberg_PEG_peg_regex_test($this->peg_c24, mb_substr($this->input, $this->peg_currPos, 1, "UTF-8"))) { - $s0 = mb_substr($this->input, $this->peg_currPos, 1, "UTF-8"); + if (Gutenberg_PEG_peg_regex_test($this->peg_c24, $this->input_substr($this->peg_currPos, 1))) { + $s0 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; @@ -1426,8 +1439,8 @@ private function peg_parseASCII_Digit() { private function peg_parseSpecial_Chars() { - if (Gutenberg_PEG_peg_regex_test($this->peg_c26, mb_substr($this->input, $this->peg_currPos, 1, "UTF-8"))) { - $s0 = mb_substr($this->input, $this->peg_currPos, 1, "UTF-8"); + if (Gutenberg_PEG_peg_regex_test($this->peg_c26, $this->input_substr($this->peg_currPos, 1))) { + $s0 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; @@ -1439,8 +1452,8 @@ private function peg_parseSpecial_Chars() { private function peg_parseWS() { - if (Gutenberg_PEG_peg_regex_test($this->peg_c28, mb_substr($this->input, $this->peg_currPos, 1, "UTF-8"))) { - $s0 = mb_substr($this->input, $this->peg_currPos, 1, "UTF-8"); + if (Gutenberg_PEG_peg_regex_test($this->peg_c28, $this->input_substr($this->peg_currPos, 1))) { + $s0 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; @@ -1452,8 +1465,8 @@ private function peg_parseWS() { private function peg_parseNewline() { - if (Gutenberg_PEG_peg_regex_test($this->peg_c30, mb_substr($this->input, $this->peg_currPos, 1, "UTF-8"))) { - $s0 = mb_substr($this->input, $this->peg_currPos, 1, "UTF-8"); + if (Gutenberg_PEG_peg_regex_test($this->peg_c30, $this->input_substr($this->peg_currPos, 1))) { + $s0 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; @@ -1465,8 +1478,8 @@ private function peg_parseNewline() { private function peg_parse_() { - if (Gutenberg_PEG_peg_regex_test($this->peg_c32, mb_substr($this->input, $this->peg_currPos, 1, "UTF-8"))) { - $s0 = mb_substr($this->input, $this->peg_currPos, 1, "UTF-8"); + if (Gutenberg_PEG_peg_regex_test($this->peg_c32, $this->input_substr($this->peg_currPos, 1))) { + $s0 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; @@ -1494,8 +1507,8 @@ private function peg_parse__() { private function peg_parseAny() { - if (mb_strlen($this->input, "UTF-8") > $this->peg_currPos) { - $s0 = mb_substr($this->input, $this->peg_currPos, 1, "UTF-8"); + if ($this->input_length > $this->peg_currPos) { + $s0 = $this->input_substr($this->peg_currPos, 1); $this->peg_currPos++; } else { $s0 = $this->peg_FAILED; @@ -1509,7 +1522,11 @@ public function parse($input) { $arguments = func_get_args(); $options = count($arguments) > 1 ? $arguments[1] : array(); $this->cleanup_state(); - $this->input = $input; + + preg_match_all("/./us", $input, $match); + $this->input = $match[0]; + $this->input_length = count($this->input); + $old_regex_encoding = mb_regex_encoding(); mb_regex_encoding("UTF-8"); @@ -1569,14 +1586,17 @@ public function parse($input) { $peg_result = call_user_func($peg_startRuleFunction); mb_regex_encoding($old_regex_encoding); - if ($peg_result !== $this->peg_FAILED && $this->peg_currPos === mb_strlen($input, "UTF-8")) { + if ($peg_result !== $this->peg_FAILED && $this->peg_currPos === $this->input_length) { + $this->cleanup_state(); // Free up memory return $peg_result; } else { - if ($peg_result !== $this->peg_FAILED && $this->peg_currPos < mb_strlen($input, "UTF-8")) { + if ($peg_result !== $this->peg_FAILED && $this->peg_currPos < $this->input_length) { $this->peg_fail(array("type" => "end", "description" => "end of input" )); } - throw $this->peg_buildException(null, $this->peg_maxFailExpected, $this->peg_maxFailPos); + $exception = $this->peg_buildException(null, $this->peg_maxFailExpected, $this->peg_maxFailPos); + $this->cleanup_state(); // Free up memory + throw $exception; } } diff --git a/package.json b/package.json index c62a5a7370b53..dc34d96f9949a 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "node-sass": "^4.5.0", "pegjs": "^0.10.0", "pegjs-loader": "^0.5.1", - "phpegjs": "1.0.0-beta3", + "phpegjs": "1.0.0-beta5", "postcss-loader": "^1.3.3", "prismjs": "^1.6.0", "raw-loader": "^0.5.1", diff --git a/phpcs.xml.dist b/phpcs.xml.dist index a471c290142a7..5b86b1adfe476 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -31,6 +31,9 @@ phpunit/* + + phpunit/* + phpunit/* diff --git a/phpunit/class-performance-test.php b/phpunit/class-performance-test.php new file mode 100644 index 0000000000000..e6a0526ec24f1 --- /dev/null +++ b/phpunit/class-performance-test.php @@ -0,0 +1,36 @@ +parse( $html ); + + $time = microtime( true ) - $start; + $mem = memory_get_usage() - $start_mem; + + $this->assertLessThanOrEqual( + 0.3, // Seconds. + $time, + sprintf( + "Parsing 'phpunit/fixtures/long-content.html' took too long. Time: %s (seconds), memory used: %sKB.", + ( round( $time * 100 ) / 100 ), + round( $mem / 1024 ) + ) + ); + } + } +} diff --git a/phpunit/fixtures/long-content.html b/phpunit/fixtures/long-content.html new file mode 100644 index 0000000000000..ea076954d91df --- /dev/null +++ b/phpunit/fixtures/long-content.html @@ -0,0 +1,131 @@ + +

Of mountains & printing presses

+ + + + +

The goal of this new editor is to make adding rich content to WordPress simple and enjoyable. This whole post is composed of pieces of content—somewhat similar to LEGO bricks—that you can move around and interact with. Move your cursor around and you'll notice the different blocks light up with outlines and arrows. Press the arrows to reposition blocks quickly, without fearing about losing things in the process of copying and pasting.

+ + +

What you are reading now is a text block, the most basic block of all. The text block has its own controls to be moved freely around the post...

+ + +

... like this one, which is right aligned.

+ + + +

Headings are separate blocks as well, which helps with the outline and organization of your content.

+ + +

A picture is worth a thousand words, or so the saying goes

+ + +

Handling images and media with the utmost care is a primary focus of the new editor. Hopefully, you'll find aspects of adding captions or going full-width with your pictures much easier and robust than before.

+ + +
Beautiful landscape
Give it a try. Press the "really wide" button on the image toolbar.
+ + +

Try selecting and removing or editing the caption, now you don't have to be careful about selecting the image or other text by mistake and ruining the presentation.

+ + +

The Inserter Tool

+ + +

Imagine everything that WordPress can do is available to you quickly and in the same place on the interface. No need to figure out HTML tags, classes, or remember complicated shortcode syntax. That's the spirit behind the inserter—the (+) button you'll see around the editor—which allows you to browse all available content blocks and insert them into your post. Plugins and themes are able to register their own, opening up all sort of possibilities for rich editing and publishing.

+ + +

Go give it a try, you may discover things WordPress can already insert into your posts that you didn't know about. Here's a short list of what you can currently find there:

+ + + + + +

If you want to learn more about how to build additional blocks, or if you are interested in helping with the project, head over to the GitHub repository.

+ + +
Help build Gutenberg
+ + +
+ + +

Visual Editing

+ + +

A huge benefit of blocks is that you can edit them in place and manipulate your content directly. Instead of having fields for editing things like the source of a quote, or the text of a button, you can directly change the content. Try editing the following quote:

+ + +

The editor will endeavour to create a new page and post building experience that makes writing rich posts effortless, and has “blocks” to make it easy what today might take shortcodes, custom HTML, or “mystery meat” embed discovery.

Matt Mullenweg, 2017
+ + +

The information corresponding to the source of the quote is a separate text field, similar to captions under images, so the structure of the quote is protected even if you select, modify, or remove the source. It's always easy to add it back.

+ + +

Blocks can be anything you need. For instance, you may want to insert a subdued quote as part of the composition of your text, or you may prefer to display a giant stylized one. All of these options are available in the inserter.

+ + +

There is no greater agony than bearing an untold story inside you.

Maya Angelou
+ + +
+ + +

Sea id autem nominavi deseruisse

+ + +

Ea veniam homero eam. Ex inimicus molestiae cum, debet scaevola at eos. Vis assum veritus ut, has ea nostrud accusata, offendit appareat comprehensam ea pro. Ad quo quem veritus appellantur, te est quas phaedrum, eum alia habeo ad. Ei est erroribus imperdiet, omnis dicam propriae sed no. His vitae oratio fierent ne, cu duo tota eligendi, electram rationibus in qui.

+ + +
Accessibility is important don't forget image alt attribute
+ + +

Est quis reque cetero ad. Sea id autem nominavi deseruisse. Veniam qualisque definitionem pri id, ea autem feugiat delenit ius, mei at loem affert accumsan. Dicat eruditi cu est, te pro dicant pericula conclusionemque, ei vim detracto euripidis intellegam. Eius postea volumus mei ad.

+ + +

Prima ridens denique his te, ferri illum volumus an his. Eu vel dicat homero qualisqu, vitae regione deserunt vis ei. Graeci incorrupte liberavisse no mea, saepe voluptaria usu ex, vis dicant euismod id. At dolor reprimique eos, quo altera detraxit moderatius id. Quo iudico utinam eu, ad alia munere mel.

+ + +
export default function MyButton() {
+	return <Button>Click Me!</Button>;
+}
+ + + + + +
An old silent pond...
A frog jumps into the pond,
splash! Silence again.
+ + +

Eu integre accusata prodesset est, sed te impetus gubergren conceptam, ex sed wisi nostrum ocurreret. Esse velit omittantur ius te, alii dissentias ei vis. At sed unum veritus fabellas. Te volutpat appellantur duo. Ad natum fuisset intellegebat eam, causae invidunt usu id, et vis impetus appetere.

+ + +
Nominavi deseruisse
+ + + + + +

Code is Poetry

The WordPress community
+ + +
+ + +
VersionMusicianDate
4.4Clifford BrownDecember 8, 2015
4.5Coleman HawkinsApril 12, 2016
4.6Pepper AdamsAugust 16, 2016
4.7Sarah VaughanDecember 6, 2016
+ + +

All that you can embed!

+ + +
https://www.youtube.com/watch?v=Nl6U7UotA-M
State of the Word 2016
+ + +https://twitter.com/photomatt/status/868657763970404352 + + +https://make.wordpress.org/core/2017/01/17/editor-technical-overview/ +