diff --git a/.travis.yml b/.travis.yml
index 51ae7a8eaa9e08..5dc3f1ee26230a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -67,5 +67,9 @@ jobs:
- stage: test
env: WP_VERSION=latest
script:
- - npm install || exit 1
+ - ./bin/run-e2e-tests.sh || exit 1
+
+ - stage: test
+ env: WP_VERSION=latest E2E_ROLE=author
+ script:
- ./bin/run-e2e-tests.sh || exit 1
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 0b1cd656f6bdd9..e3dd47a328047e 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -2,100 +2,100 @@
Gutenberg is built by many contributors and volunteers. Thanks to all of them for their work!
-This list is manually curated to include valuable contributions by volunteers that do not include code, such as user testing, providing feedback, or mockups. Please edit this list to include new contributors as they come in. There is no particular order to this list. If you or someone else were omitted from this list, we assure you that was not intentional. Please let us know and we'll add you. For volunteers who contributed their translations, your names are listed on [WordPress Translate site here](https://translate.wordpress.org/projects/wp-plugins/gutenberg/contributors).
+This list is manually curated to include valuable contributions by volunteers that do not include code, such as user testing, providing feedback, or mockups. Please edit this list to include new contributors as they come in. There is no particular order to this list. If you or someone else was omitted from this list, we assure you that was not intentional. Please let us know and we'll add you. For volunteers who contributed their translations, your names are listed on [WordPress Translate site here](https://translate.wordpress.org/projects/wp-plugins/gutenberg/contributors).
| GitHub Username | WordPress.org Username|
| --------------- | --------------------- |
-| @youknowriad | |
-| @aduth | |
-| @jasmussen | |
-| @iseulde | |
-| @mtias | |
-| @nylen | |
+| @youknowriad | @youknowriad |
+| @aduth | @aduth |
+| @jasmussen | @joen |
+| @iseulde | @iseulde |
+| @mtias | @mtias |
+| @nylen | @jnylen0 |
| @EphoxJames | |
-| @mkaz | |
-| @notnownikki | |
-| @BE-Webdesign | |
+| @mkaz | @mkaz |
+| @notnownikki | @notnownikki |
+| @BE-Webdesign | @chopinbach |
| @njpanderson | |
| @mimo84 | |
| @intronic | |
-| @westonruter | |
-| @mcsf | |
-| @dmsnell | |
-| @afercia | |
-| @paulwilde | |
-| @mitogh | |
-| @codebykat | |
+| @westonruter | @westonruter |
+| @mcsf | @mcsf |
+| @dmsnell | @dmsnell |
+| @afercia | @afercia |
+| @paulwilde | @paulwilde |
+| @mitogh | @mitogh |
+| @codebykat | @codebykat |
| @ahmadawais | @mrahmadawais |
-| @kopepasah | |
-| @circlecube | |
-| @adamsilverstein | |
-| @timmyc | |
+| @kopepasah | @kopepasah |
+| @circlecube | @circlecube |
+| @adamsilverstein | @adamsilverstein |
+| @timmyc | @timmydcrawford |
| @ephox-mogran | |
-| @nb | |
-| @JDGrimes | |
-| @Soean | |
-| @mapk | |
-| @sirjonathan | |
-| @j-falk | |
-| @ryelle | |
+| @nb | @nbachiyski |
+| @JDGrimes | @JDGrimes |
+| @Soean | @Soean |
+| @mapk | @mapk |
+| @sirjonathan | @sirjonathan |
+| @j-falk | @j-falk |
+| @ryelle | @ryelle |
| @ntwb | @netweb |
-| @lamosty | |
-| @willybahuaud | |
-| @maurobringolf | |
+| @lamosty | @lamosty |
+| @willybahuaud | @willybahuaud |
+| @maurobringolf | @maurobringolf |
| @aaronjorbin | @jorbin |
-| @spocke | |
-| @androb | |
-| @annaephox | |
+| @spocke | @spocke |
+| @androb | @androb |
+| @annaephox | @annaharrison |
| @Afraithe | |
| @georgeh | |
-| @m | |
-| @melchoyce | |
-| @pento | |
-| @karmatosed | |
-| @nitrajka | |
+| @m | @matt |
+| @melchoyce | @melchoyce |
+| @pento | @pento |
+| @karmatosed | @karmatosed |
+| @nitrajka | @nitrajka |
| @sirreal | |
| @inhil | |
-| @georgeolaru | |
-| @martinlugton | |
-| @joyously | |
-| @rileybrook | |
-| @azaozz | |
-| @folletto | |
-| @ianstewart | |
-| @johnpixle | |
-| @mrwweb | |
-| @diegoliv | |
-| @lukecav | |
-| @shaunandrews | |
-| @hugobaeta | |
-| @mizejewski | |
-| @buzztone | |
-| @mathetos | |
-| @GaryJones | |
+| @georgeolaru | @babbardel |
+| @martinlugton | @martinlugton |
+| @joyously | @joyously |
+| @rileybrook | @rileybrook |
+| @azaozz | @azaozz |
+| @folletto | @folletto |
+| @ianstewart | @iandstewart |
+| @johnpixle | @johnpixle |
+| @mrwweb | @mrwweb |
+| @diegoliv | @diegoliv |
+| @lukecav | @lukecavanagh |
+| @shaunandrews | @shaunandrews |
+| @hugobaeta | @hugobaeta |
+| @mizejewski | @mizejewski |
+| @buzztone | @buzztone |
+| @mathetos | @webdevmattcrom |
+| @GaryJones | @garyj |
| @jasonagnew | |
-| @brickbones | |
-| @iamgabrielma | |
-| @swissspidy | |
+| @brickbones | @ieatwebsites |
+| @iamgabrielma | @gma992 |
+| @swissspidy | @swissspidy |
| @dixitadusara | |
-| @ameeker | |
-| @StaggerLeee | |
-| @jblz | |
+| @ameeker | @ameeker |
+| @StaggerLeee | @stagger-lee |
+| @jblz | @jblz |
| @nic-bertino | @nicbertino |
| @rahmon | @rahmohn |
| @vladanost | |
| @gziolo | @gziolo |
-| @lancewillett
-| | @lynneux
-| | @betsela
-| | @fuyuko
-| | @msdesign21
-| @thrijith |
-| @Cloud887 |
-| @hblackett |
-| @vishalkakadiya |
-| @c-shultz |
-| @nfmohit-wpmudev |
+| @lancewillett | @lancewillett |
+| @lynneux | @lynneux |
+| @betsela | @betsela |
+| @fuyuko | @fuyuko |
+| | @msdesign21 |
+| @thrijith | @thrijith |
+| @Cloud887 | |
+| @hblackett | @hblackett |
+| @vishalkakadiya | @vishalkakadiya |
+| @c-shultz | |
+| @nfmohit-wpmudev | @nfmohit |
| @noisysocks | @noisysocks |
| @omarreiss | @omarreiss |
| @hedgefield | @hedgefield |
@@ -106,9 +106,12 @@ This list is manually curated to include valuable contributions by volunteers th
| @burhandodhy | @burhandodhy |
| @ZebulanStanphill | @zebulan |
| @BenjaminZekavica | @benjamin_zekavica |
-| @danielbachhuber | |
-| @jorgefilipecosta | |
-| @ajitbohra | |
-| @ChrisVanPatten | |
+| @danielbachhuber | @danielbachhuber |
+| @jorgefilipecosta | @jorgefilipecosta |
+| @ajitbohra | @ajitbohra |
+| @ChrisVanPatten | @chrisvanpatten |
+| @mayukojpn | @mayukojpn |
| @tofumatt | @lonelyvegan |
-| @LukePettway | @luke_pettway |
\ No newline at end of file
+| @LukePettway | @luke_pettway |
+| @pratikthink | @pratikthink |
+| @amdrew | @sumobi |
diff --git a/assets/stylesheets/_breakpoints.scss b/assets/stylesheets/_breakpoints.scss
index 020b945b1d5e92..066d7d8f250e5e 100644
--- a/assets/stylesheets/_breakpoints.scss
+++ b/assets/stylesheets/_breakpoints.scss
@@ -7,7 +7,6 @@ $break-huge: 1440px;
$break-wide: 1280px;
$break-xlarge: 1080px;
$break-large: 960px; // admin sidebar auto folds
-$break-large: 960px; // admin sidebar auto folds
$break-medium: 782px; // adminbar goes big
$break-small: 600px;
$break-mobile: 480px;
diff --git a/assets/stylesheets/_z-index.scss b/assets/stylesheets/_z-index.scss
index b494e9f6fdc500..39e1bb461d46b1 100644
--- a/assets/stylesheets/_z-index.scss
+++ b/assets/stylesheets/_z-index.scss
@@ -37,6 +37,9 @@ $z-layers: (
// Active pill button
".components-button.is-button {:focus or .is-primary}": 1,
+ // Reusable blocks UI, needs to be above sibling inserter.
+ ".editor-block-list__layout .reusable-block-edit-panel": 7,
+
// The draggable element should show up above the entire UI
".components-draggable__clone": 1000000000,
diff --git a/bin/install-wordpress.sh b/bin/install-wordpress.sh
index c2ddd14f30b6f5..643c42b972f347 100755
--- a/bin/install-wordpress.sh
+++ b/bin/install-wordpress.sh
@@ -54,6 +54,13 @@ echo -e $(status_message "Installing WordPress...")
# prevents permissions errors. See: https://github.com/WordPress/gutenberg/pull/8427#issuecomment-410232369
docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI core install --title="$SITE_TITLE" --admin_user=admin --admin_password=password --admin_email=test@test.com --skip-email --url=http://localhost:$HOST_PORT >/dev/null
+if [ "$E2E_ROLE" = "author" ]; then
+ # Create an additional author user for testsing.
+ docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI user create author author@example.com --role=author --user_pass=authpass
+ # Assign the existing Hello World post to the author.
+ docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI post update 1 --post_author=2
+fi
+
if [ "$WP_VERSION" == "latest" ]; then
# Check for WordPress updates, to make sure we're running the very latest version.
docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm -u 33 $CLI core update >/dev/null
@@ -69,3 +76,6 @@ fi
# Activate Gutenberg.
echo -e $(status_message "Activating Gutenberg...")
docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm $CLI plugin activate gutenberg >/dev/null
+
+# Install a dummy favicon to avoid 404 errors.
+docker-compose $DOCKER_COMPOSE_FILE_OPTIONS run --rm $CONTAINER touch /var/www/html/favicon.ico
diff --git a/bin/run-e2e-tests.sh b/bin/run-e2e-tests.sh
index f0d70fe438861e..98a6c179309727 100755
--- a/bin/run-e2e-tests.sh
+++ b/bin/run-e2e-tests.sh
@@ -7,5 +7,8 @@ cd "$(dirname "$0")/../"
# Setup local environement
( ./bin/setup-local-env.sh )
-# Run the tests
-npm run test-e2e
+if [ "$E2E_ROLE" = "author" ]; then
+ WP_PASSWORD=authpass WP_USERNAME=author npm run test-e2e
+else
+ npm run test-e2e
+fi
diff --git a/docs/block-api.md b/docs/block-api.md
index a3df73ffcb80e6..01b2295b46de0b 100644
--- a/docs/block-api.md
+++ b/docs/block-api.md
@@ -504,6 +504,13 @@ inserter: false,
multiple: false,
```
+- `reusable` (default `true`): A block may want to disable the ability of being converted into a reusable block.
+By default all blocks can be converted to a reusable block. If supports reusable is set to false, the option to convert the block into a reusable block will not appear.
+
+```js
+// Don't allow the block to be converted into a reusable block.
+reusable: false,
+```
## Edit and Save
The `edit` and `save` functions define the editor interface with which a user would interact, and the markup to be serialized back when a post is saved. They are the heart of how a block operates, so they are [covered separately](../docs/block-api/block-edit-save.md).
diff --git a/docs/blocks/applying-styles-with-stylesheets.md b/docs/blocks/applying-styles-with-stylesheets.md
index 756741b38253a7..47d2f70876143e 100644
--- a/docs/blocks/applying-styles-with-stylesheets.md
+++ b/docs/blocks/applying-styles-with-stylesheets.md
@@ -21,8 +21,8 @@ registerBlockType( 'gutenberg-boilerplate-es5/hello-world-step-02', {
return el( 'p', { className: props.className }, 'Hello editor.' );
},
- save: function( props ) {
- return el( 'p', { className: props.className }, 'Hello saved content.' );
+ save: function() {
+ return el( 'p', {}, 'Hello saved content.' );
}
} );
```
@@ -41,8 +41,8 @@ registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-02', {
return
Hello editor.
;
},
- save( { className } ) {
- return
Hello saved content.
;
+ save() {
+ return
Hello saved content.
;
}
} );
```
diff --git a/docs/blocks/block-controls-toolbars-and-inspector.md b/docs/blocks/block-controls-toolbars-and-inspector.md
index 5b9f97a3e63cf8..236e9856197696 100644
--- a/docs/blocks/block-controls-toolbars-and-inspector.md
+++ b/docs/blocks/block-controls-toolbars-and-inspector.md
@@ -152,12 +152,11 @@ registerBlockType( 'gutenberg-boilerplate-esnext/hello-world-step-04', {
);
},
- save( { attributes, className } ) {
+ save( { attributes } ) {
const { content, alignment } = attributes;
return (
);
diff --git a/docs/data/README.md b/docs/data/README.md
index 1f99bcb017f5b9..ac44230651976e 100644
--- a/docs/data/README.md
+++ b/docs/data/README.md
@@ -1,6 +1,7 @@
# Data Module Reference
- [**core**: WordPress Core Data](../../docs/data/data-core.md)
+ - [**core/annotations**: Annotations](../../docs/data/data-core-annotations.md)
- [**core/blocks**: Block Types Data](../../docs/data/data-core-blocks.md)
- [**core/editor**: The Editor’s Data](../../docs/data/data-core-editor.md)
- [**core/edit-post**: The Editor’s UI Data](../../docs/data/data-core-edit-post.md)
diff --git a/docs/data/data-core-annotations.md b/docs/data/data-core-annotations.md
new file mode 100644
index 00000000000000..f4f7d8cb5ff072
--- /dev/null
+++ b/docs/data/data-core-annotations.md
@@ -0,0 +1,84 @@
+# **core/annotations**: Annotations
+
+## Selectors
+
+### __experimentalGetAnnotationsForBlock
+
+Returns the annotations for a specific client ID.
+
+*Parameters*
+
+ * state: Editor state.
+ * clientId: The ID of the block to get the annotations for.
+
+### __experimentalGetAnnotationsForRichText
+
+Returns the annotations that apply to the given RichText instance.
+
+Both a blockClientId and a richTextIdentifier are required. This is because
+a block might have multiple `RichText` components. This does mean that every
+block needs to implement annotations itself.
+
+*Parameters*
+
+ * state: Editor state.
+ * blockClientId: The client ID for the block.
+ * richTextIdentifier: Unique identifier that identifies the given RichText.
+
+*Returns*
+
+All the annotations relevant for the `RichText`.
+
+### __experimentalGetAnnotations
+
+Returns all annotations in the editor state.
+
+*Parameters*
+
+ * state: Editor state.
+
+*Returns*
+
+All annotations currently applied.
+
+## Actions
+
+### __experimentalAddAnnotation
+
+Adds an annotation to a block.
+
+The `block` attribute refers to a block ID that needs to be annotated.
+`isBlockAnnotation` controls whether or not the annotation is a block
+annotation. The `source` is the source of the annotation, this will be used
+to identity groups of annotations.
+
+The `range` property is only relevant if the selector is 'range'.
+
+*Parameters*
+
+ * annotation: The annotation to add.
+ * blockClientId: The blockClientId to add the annotation to.
+ * richTextIdentifier: Identifier for the RichText instance the annotation applies to.
+ * range: The range at which to apply this annotation.
+ * range.start: The offset where the annotation should start.
+ * range.end: The offset where the annotation should end.
+ * string: [selector="range"] The way to apply this annotation.
+ * string: [source="default"] The source that added the annotation.
+ * string: [id=uuid()] The ID the annotation should have.
+ Generates a UUID by default.
+
+### __experimentalRemoveAnnotation
+
+Removes an annotation with a specific ID.
+
+*Parameters*
+
+ * annotationId: The annotation to remove.
+
+### __experimentalRemoveAnnotationsBySource
+
+Removes all annotations of a specific source.
+
+*Parameters*
+
+ * source: The source to remove.
\ No newline at end of file
diff --git a/docs/data/data-core-blocks.md b/docs/data/data-core-blocks.md
index 9a2524905fa40f..aea753fad47576 100644
--- a/docs/data/data-core-blocks.md
+++ b/docs/data/data-core-blocks.md
@@ -23,6 +23,19 @@ Returns a block type by name.
Block Type.
+### getBlockStyles
+
+Returns block styles by block name.
+
+*Parameters*
+
+ * state: Data state.
+ * name: Block type name.
+
+*Returns*
+
+Block Styles.
+
### getCategories
Returns all the available categories.
@@ -161,6 +174,24 @@ Returns an action object used to remove a registered block type.
* names: Block name.
+### addBlockStyles
+
+Returns an action object used in signalling that new block styles have been added.
+
+*Parameters*
+
+ * blockName: Block name.
+ * styles: Block styles.
+
+### removeBlockStyles
+
+Returns an action object used in signalling that block styles have been removed.
+
+*Parameters*
+
+ * blockName: Block name.
+ * styleNames: Block style names.
+
### setDefaultBlockName
Returns an action object used to set the default block name.
diff --git a/docs/data/data-core-edit-post.md b/docs/data/data-core-edit-post.md
index 7e0dc7c8ceb5a3..93e658e91d4798 100644
--- a/docs/data/data-core-edit-post.md
+++ b/docs/data/data-core-edit-post.md
@@ -103,20 +103,6 @@ enabled by default.
Whether or not the panel is enabled.
-### isEditorSidebarPanelOpened
-
-Returns true if the given panel is enabled, or false otherwise. Panels are
-enabled by default.
-
-*Parameters*
-
- * state: Global application state.
- * panel: A string that identifies the panel.
-
-*Returns*
-
-Whether or not the panel is enabled.
-
### isEditorPanelOpened
Returns true if the given panel is open, or false otherwise. Panels are
@@ -311,14 +297,6 @@ Returns an action object used to enable or disable a panel in the editor.
Returns an action object used to open or close a panel in the editor.
-*Parameters*
-
- * panelName: A string that identifies the panel to open or close.
-
-### toggleGeneralSidebarEditorPanel
-
-Returns an action object used to open or close a panel in the editor.
-
*Parameters*
* panelName: A string that identifies the panel to open or close.
diff --git a/docs/data/data-core-editor.md b/docs/data/data-core-editor.md
index ebbc303649e17e..1517f5b5317cc0 100644
--- a/docs/data/data-core-editor.md
+++ b/docs/data/data-core-editor.md
@@ -36,6 +36,18 @@ the post has been saved.
Whether the post is new.
+### hasChangedContent
+
+Returns true if content includes unsaved changes, or false otherwise.
+
+*Parameters*
+
+ * state: Editor state.
+
+*Returns*
+
+Whether content includes unsaved changes.
+
### isEditedPostDirty
Returns true if there are unsaved values for the current edit session, or
@@ -139,6 +151,20 @@ been saved.
Object of key value pairs comprising unsaved edits.
+### getReferenceByDistinctEdits
+
+Returns a new reference when edited values have changed. This is useful in
+inferring where an edit has been made between states by comparison of the
+return values using strict equality.
+
+*Parameters*
+
+ * state: Editor state.
+
+*Returns*
+
+A value whose reference will change only when an edit occurs.
+
### getCurrentPostAttribute
Returns an attribute value of the saved post.
@@ -871,7 +897,7 @@ True if multi-selecting, false if not.
### isSelectionEnabled
-Whether is selection disable or not.
+Selector that returns if multi-selection is enabled or not.
*Parameters*
@@ -879,7 +905,7 @@ Whether is selection disable or not.
*Returns*
-True if multi is disable, false if not.
+True if it should be possible to multi-select blocks, false if multi-selection is disabled.
### getBlockMode
@@ -1377,6 +1403,7 @@ the specified post object and editor settings.
*Parameters*
* post: Post object.
+ * edits: Initial edited attributes object.
### resetPost
@@ -1413,7 +1440,6 @@ Returns an action object used to setup the editor state when first opening an ed
* post: Post object.
* blocks: Array of blocks.
- * edits: Initial edited attributes object.
### resetBlocks
@@ -1518,8 +1544,8 @@ inserted, optionally at a specific index respective a root block list.
* block: Block object to insert.
* index: Index at which block should be inserted.
- * rootClientId: Optional root client ID of block list on which
- to insert.
+ * rootClientId: Optional root client ID of block list on which to insert.
+ * updateSelection: If true block selection will be updated. If false, block selection will not change. Defaults to true.
### insertBlocks
@@ -1530,8 +1556,8 @@ be inserted, optionally at a specific index respective a root block list.
* blocks: Block objects to insert.
* index: Index at which block should be inserted.
- * rootClientId: Optional root client ID of block list on
- which to insert.
+ * rootClientId: Optional root cliente ID of block list on which to insert.
+ * updateSelection: If true block selection will be updated. If false, block selection will not change. Defaults to true.
### showInsertionPoint
@@ -1560,6 +1586,15 @@ Returns an action object resetting the template validity.
Returns an action object synchronize the template with the list of blocks
+### editPost
+
+Returns an action object used in signalling that attributes of the post have
+been edited.
+
+*Parameters*
+
+ * edits: Post attributes to edit.
+
### savePost
Returns an action object to save the post.
@@ -1769,15 +1804,6 @@ Returns an action object used to signal that post saving is unlocked.
* lockName: The lock name.
-### addTermToEditedPost
-
-Returns an action object signaling that a new term is added to the edited post.
-
-*Parameters*
-
- * slug: Taxonomy slug.
- * term: Term object.
-
### createNotice
### fetchReusableBlocks
\ No newline at end of file
diff --git a/docs/design/block-design.md b/docs/design/block-design.md
index 5163f177447ffc..7849cf693b9303 100644
--- a/docs/design/block-design.md
+++ b/docs/design/block-design.md
@@ -27,11 +27,11 @@ A block should have a straightforward, short name so users can easily find it in
Blocks should have an identifying icon, ideally using a single color. Try to avoid using the same icon used by an existing block. The core block icons are based on [Material Design Icons](https://material.io/tools/icons/). Look to that icon set, or to [Dashicons](https://developer.wordpress.org/resource/dashicons/) for style inspiration.
-
+
**Do:**
Use conise block names.
-
+
**Don't:**
Avoid long, multi-line block names.
@@ -39,11 +39,11 @@ Avoid long, multi-line block names.
Every block should include a description in the “Block” tab of the Settings sidebar. This description should explain your block's function clearly. Keep it to a single sentence.
-
+
**Do:**
Use a short, simple, block description.
-
+
**Don't:**
Avoid long descriptions and branding.
@@ -51,11 +51,11 @@ Avoid long descriptions and branding.
If your block requires a user to configure some options before you can display it, you should provide an instructive placeholder state.
-
+
**Do:**
Provide an instructive placeholder state.
-
+
**Don't:**
Avoid branding and relying on the title alone to convey instructions.
@@ -65,11 +65,11 @@ When unselected, your block should preview its content as closely to the front-e
When selected, your block may surface additional options like input fields or buttons to configure the block directly, especially when they are necessary for basic operation.
-
+
**Do:**
For controls that are essential the the operation of the block, provide them directly in inside the block edit view.
-
+
**Don't:**
Do not put controls that are essential to the block in the sidebar, or the block will appear non-functional to mobile users, or desktop users who have dismissed the sidebar.
@@ -77,7 +77,7 @@ Do not put controls that are essential to the block in the sidebar, or the block
The “Block” tab of the Settings Sidebar can contain additional block options and configuration. Keep in mind that a user can dismiss the sidebar and never use it. You should not put critical options in the Sidebar.
-
+
**Do:**
Because the Drop Cap feature is not necessary for the basic operation of the block, you can put it ub the Block tab as optional configuration.
@@ -97,7 +97,7 @@ The most basic unit of the editor. The paragraph block is a simple input field.
### Placeholder:
-- Simple placeholder text that says “Add text or type / to add content.” The placeholder disappears when the block is selected.
+- Simple placeholder text that reads “Start writing or type / to choose a block”. The placeholder disappears when the block is selected.
### Selected state:
diff --git a/docs/extensibility/annotations.md b/docs/extensibility/annotations.md
new file mode 100644
index 00000000000000..70df5b61e5d187
--- /dev/null
+++ b/docs/extensibility/annotations.md
@@ -0,0 +1,55 @@
+# Annotations
+
+**Note: This API is experimental, that means it is subject to non-backward compatible changes or removal in any future version.**
+
+Annotations are a way to highlight a specific piece in a Gutenberg post. Examples of this include commenting on a piece of text and spellchecking. Both can use the annotations API to mark a piece of text.
+
+## API
+
+To see the API for yourself the easiest way is to have a block that is at least 200 characters long without formatting and putting the following in the console:
+
+```js
+wp.data.dispatch( 'core/annotations' ).addAnnotation( {
+ source: "my-annotations-plugin",
+ blockClientId: wp.data.select( 'core/editor' ).getBlockOrder()[0],
+ richTextIdentifier: "content",
+ range: {
+ start: 50,
+ end: 100,
+ },
+} );
+```
+
+The start and the end of the range should be calculated based only on the text of the relevant `RichText`. For example, in the following HTML position 0 will refer to the position before the capital S:
+
+```html
+Strong text
+```
+
+To help with determining the correct positions, the `wp.richText.create` method can be used. This will split a piece of HTML into text and formats.
+
+All available properties can be found in the API documentation of the `addAnnotation` action.
+
+## Block annotation
+
+It is also possible to annotate a block completely. In that case just provide the `selector` property and set it to `block`. The default `selector` is `range`, which can be used for text annotation.
+
+```js
+wp.data.dispatch( 'core/annotations' ).addAnnotation( {
+ source: "my-annotations-plugin",
+ blockClientId: wp.data.select( 'core/editor' ).getBlockOrder()[0],
+ selector: "block",
+} );
+```
+
+This doesn't provide any styling out of the box, so you have to provide some CSS to make sure your annotation is shown:
+
+```css
+.is-annotated-by-my-annotations-plugin {
+ outline: 1px solid black;
+}
+```
+
+## Text annotation
+
+The text annotation is controlled by the `start` and `end` properties. Simple `start` and `end` properties don't work for HTML, so these properties are assumed to be offsets within the `rich-text` internal structure. For simplicity you can think about this as if all HTML would be stripped out and then you calculate the `start` and the `end` of the annotation.
diff --git a/docs/extensibility/extending-blocks.md b/docs/extensibility/extending-blocks.md
index 11daff62329ed3..d00282e6b4665a 100644
--- a/docs/extensibility/extending-blocks.md
+++ b/docs/extensibility/extending-blocks.md
@@ -333,9 +333,13 @@ function my_plugin_block_categories( $categories, $post ) {
array(
'slug' => 'my-category',
'title' => __( 'My category', 'my-plugin' ),
+ 'icon' => '',
),
)
);
}
add_filter( 'block_categories', 'my_plugin_block_categories', 10, 2 );
```
+
+You can also display an icon with your block category by setting an `icon` attribute. The value can be the slug of a [WordPress Dashicon](https://developer.wordpress.org/resource/dashicons/), or a custom `svg` element.
+
diff --git a/docs/extensibility/meta-box.md b/docs/extensibility/meta-box.md
index ca5e9783b8be90..eb96bfc38e0ffb 100644
--- a/docs/extensibility/meta-box.md
+++ b/docs/extensibility/meta-box.md
@@ -73,7 +73,7 @@ So an example url would look like:
This url is automatically passed into React via a `_wpMetaBoxUrl` global variable.
-This page page mimics the `post.php` post form, so when it is submitted it will fire all of the normal hooks and actions, and have the proper global state to correctly fire any PHP meta box mumbo jumbo without needing to modify any existing code. On successful submission, React will signal a `handleMetaBoxReload` to remove the updating overlay.
+This page mimics the `post.php` post form, so when it is submitted it will fire all of the normal hooks and actions, and have the proper global state to correctly fire any PHP meta box mumbo jumbo without needing to modify any existing code. On successful submission, React will signal a `handleMetaBoxReload` to remove the updating overlay.
### Common Compatibility Issues
diff --git a/docs/manifest.json b/docs/manifest.json
index efab957c872c6c..075d922f2cad93 100644
--- a/docs/manifest.json
+++ b/docs/manifest.json
@@ -89,6 +89,12 @@
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/extensibility/autocomplete.md",
"parent": "extensibility"
},
+ {
+ "title": "Annotations",
+ "slug": "annotations",
+ "markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/extensibility/annotations.md",
+ "parent": "extensibility"
+ },
{
"title": "Design",
"slug": "design",
@@ -257,6 +263,12 @@
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/packages/a11y/README.md",
"parent": "packages"
},
+ {
+ "title": "@wordpress/annotations",
+ "slug": "packages-annotations",
+ "markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/packages/annotations/README.md",
+ "parent": "packages"
+ },
{
"title": "@wordpress/api-fetch",
"slug": "packages-api-fetch",
@@ -929,6 +941,12 @@
"markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/data/data-core.md",
"parent": "data"
},
+ {
+ "title": "Annotations",
+ "slug": "data-core-annotations",
+ "markdown_source": "https://raw.githubusercontent.com/WordPress/gutenberg/master/docs/data/data-core-annotations.md",
+ "parent": "data"
+ },
{
"title": "Block Types Data",
"slug": "data-core-blocks",
diff --git a/docs/reference/deprecated.md b/docs/reference/deprecated.md
index 252b56c2ef809d..13efe9f8940bdf 100644
--- a/docs/reference/deprecated.md
+++ b/docs/reference/deprecated.md
@@ -1,5 +1,9 @@
Gutenberg's deprecation policy is intended to support backwards-compatibility for releases, when possible. The current deprecations are listed below and are grouped by _the version at which they will be removed completely_. If your plugin depends on these behaviors, you must update to the recommended alternative before the noted version.
+## 4.5.0
+- `Dropdown.refresh()` has been deprecated as the contained `Popover` is now automatically refreshed.
+- `wp.editor.PostPublishPanelToggle` has been deprecated in favor of `wp.editor.PostPublishButton`.
+
## 4.4.0
- `wp.date.getSettings` has been removed. Please use `wp.date.__experimentalGetSettings` instead.
@@ -7,6 +11,11 @@ Gutenberg's deprecation policy is intended to support backwards-compatibility fo
- The following editor store actions have been removed: `createNotice`, `removeNotice`, `createSuccessNotice`, `createInfoNotice`, `createErrorNotice`, `createWarningNotice`. Use the equivalent actions by the same name from the `@wordpress/notices` module.
- The id prop of wp.nux.DotTip has been removed. Please use the tipId prop instead.
- `wp.blocks.isValidBlock` has been removed. Please use `wp.blocks.isValidBlockContent` instead but keep in mind that the order of params has changed.
+- `wp.data` `registry.registerReducer` has been deprecated. Use `registry.registerStore` instead.
+- `wp.data` `registry.registerSelectors` has been deprecated. Use `registry.registerStore` instead.
+- `wp.data` `registry.registerActions` has been deprecated. Use `registry.registerStore` instead.
+- `wp.data` `registry.registerResolvers` has been deprecated. Use `registry.registerStore` instead.
+- `moment` has been removed from the public API for the date module.
## 4.3.0
diff --git a/docs/reference/faq.md b/docs/reference/faq.md
index 449b028a87d86a..740c641f7914e5 100644
--- a/docs/reference/faq.md
+++ b/docs/reference/faq.md
@@ -219,8 +219,8 @@ This is the canonical list of keyboard shortcuts:
Remove a link.
-
Shift+Alt+S
-
⌃⌥S
+
Ctrl+Shift+K
+
⇧⌘K
Add a strikethrough to the selected text.
diff --git a/docs/reference/scripts.md b/docs/reference/scripts.md
index 4fba8a1cbea67f..0bd0cf98927921 100644
--- a/docs/reference/scripts.md
+++ b/docs/reference/scripts.md
@@ -60,10 +60,9 @@ It is recommened to use the main `wp-polyfill` script handle which takes care of
| Script Name | Handle | Description |
|-------------|--------|-------------|
-| polyfill | wp-polyfill | Main script to load all the below mentioned polyfills |
+| [Babel Polyfill](https://babeljs.io/docs/en/babel-polyfill) | wp-polyfill | Emulate a full ES2015+ environment. Main script to load all the below mentioned additional polyfills |
| [Fetch Polyfill](https://www.npmjs.com/package/whatwg-fetch) | wp-polyfill-fetch | Polyfill that implements a subset of the standard Fetch specification |
| [Promise Polyfill](https://www.npmjs.com/package/promise-polyfill) | wp-polyfill-promise| Lightweight ES6 Promise polyfill for the browser and node |
| [Formdata Polyfill](https://www.npmjs.com/package/formdata-polyfill) | wp-polyfill-formdata| Polyfill conditionally replaces the native implementation |
| [Node Contains Polyfill](https://polyfill.io) | wp-polyfill-node-contains |Polyfill for Node.contains |
| [Element Closest Polyfill](https://www.npmjs.com/package/element-closest) | wp-polyfill-element-closest| Return the closest element matching a selector up the DOM tree |
-| [ECMAScript Polyfill](https://babeljs.io/docs/en/babel-polyfill) | wp-polyfill-ecmascript | Emulate a full ES2015+ environment |
diff --git a/docs/root-manifest.json b/docs/root-manifest.json
index 759792a857b733..1202ab14eacb4a 100644
--- a/docs/root-manifest.json
+++ b/docs/root-manifest.json
@@ -89,6 +89,12 @@
"markdown_source": "https:\/\/raw.githubusercontent.com\/WordPress\/gutenberg\/master\/docs\/extensibility/autocomplete.md",
"parent": "extensibility"
},
+ {
+ "title": "Annotations",
+ "slug": "annotations",
+ "markdown_source": "https:\/\/raw.githubusercontent.com\/WordPress\/gutenberg\/master\/docs\/extensibility/annotations.md",
+ "parent": "extensibility"
+ },
{
"title": "Design",
"slug": "design",
diff --git a/docs/tool/config.js b/docs/tool/config.js
index b7b0fa3ef4ad66..6758ac592a72f7 100644
--- a/docs/tool/config.js
+++ b/docs/tool/config.js
@@ -15,6 +15,11 @@ module.exports = {
selectors: [ path.resolve( root, 'packages/core-data/src/selectors.js' ) ],
actions: [ path.resolve( root, 'packages/core-data/src/actions.js' ) ],
},
+ 'core/annotations': {
+ title: 'Annotations',
+ selectors: [ path.resolve( root, 'packages/annotations/src/store/selectors.js' ) ],
+ actions: [ path.resolve( root, 'packages/annotations/src/store/actions.js' ) ],
+ },
'core/blocks': {
title: 'Block Types Data',
selectors: [ path.resolve( root, 'packages/blocks/src/store/selectors.js' ) ],
diff --git a/gutenberg.php b/gutenberg.php
index 09ed86af7aa590..7e130a7034bc28 100644
--- a/gutenberg.php
+++ b/gutenberg.php
@@ -3,7 +3,7 @@
* Plugin Name: Gutenberg
* Plugin URI: https://github.com/WordPress/gutenberg
* Description: Printing since 1440. This is the development plugin for the new block editor in core.
- * Version: 4.2.0-rc.1
+ * Version: 4.3.0-rc.1
* Author: Gutenberg Team
*
* @package gutenberg
diff --git a/lib/client-assets.php b/lib/client-assets.php
index b68c2fa5c99036..71fb20403897e3 100644
--- a/lib/client-assets.php
+++ b/lib/client-assets.php
@@ -144,13 +144,6 @@ function gutenberg_register_scripts_and_styles() {
register_tinymce_scripts();
- gutenberg_override_script(
- 'wp-polyfill',
- null,
- array(
- 'wp-polyfill-ecmascript',
- )
- );
wp_script_add_data(
'wp-polyfill',
'data',
@@ -299,6 +292,7 @@ function gutenberg_register_scripts_and_styles() {
array(
'lodash',
'wp-compose',
+ 'wp-deprecated',
'wp-element',
'wp-is-shallow-equal',
'wp-polyfill',
@@ -322,6 +316,13 @@ function gutenberg_register_scripts_and_styles() {
)
)
);
+ gutenberg_override_script(
+ 'wp-annotations',
+ gutenberg_url( 'build/annotations/index.js' ),
+ array( 'wp-polyfill', 'wp-data', 'wp-rich-text', 'wp-hooks', 'wp-i18n' ),
+ filemtime( gutenberg_dir_path() . 'build/annotations/index.js' ),
+ true
+ );
gutenberg_override_script(
'wp-core-data',
gutenberg_url( 'build/core-data/index.js' ),
@@ -485,7 +486,7 @@ function gutenberg_register_scripts_and_styles() {
'lodash',
'wp-a11y',
'wp-data',
- 'wp-polyfill-ecmascript',
+ 'wp-polyfill',
),
filemtime( gutenberg_dir_path() . 'build/notices/index.js' ),
true
@@ -604,28 +605,26 @@ function gutenberg_register_scripts_and_styles() {
),
'toolbar1' => implode(
',',
- array_merge(
- apply_filters(
- 'mce_buttons',
- array(
- 'formatselect',
- 'bold',
- 'italic',
- 'bullist',
- 'numlist',
- 'blockquote',
- 'alignleft',
- 'aligncenter',
- 'alignright',
- 'link',
- 'unlink',
- 'wp_more',
- 'spellchecker',
- 'wp_add_media',
- ),
- 'editor'
+ apply_filters(
+ 'mce_buttons',
+ array(
+ 'formatselect',
+ 'bold',
+ 'italic',
+ 'bullist',
+ 'numlist',
+ 'blockquote',
+ 'alignleft',
+ 'aligncenter',
+ 'alignright',
+ 'link',
+ 'unlink',
+ 'wp_more',
+ 'spellchecker',
+ 'wp_add_media',
+ 'kitchensink',
),
- array( 'kitchensink' )
+ 'editor'
)
),
'toolbar2' => implode(
@@ -724,7 +723,6 @@ function gutenberg_register_scripts_and_styles() {
'wp-compose',
'wp-core-data',
'wp-data',
- 'wp-deprecated',
'wp-dom-ready',
'wp-editor',
'wp-element',
@@ -751,7 +749,7 @@ function gutenberg_register_scripts_and_styles() {
'wp-compose',
'wp-element',
'wp-i18n',
- 'wp-polyfill-ecmascript',
+ 'wp-polyfill',
),
filemtime( gutenberg_dir_path() . 'build/list-reusable-blocks/index.js' ),
true
@@ -867,6 +865,24 @@ function gutenberg_register_scripts_and_styles() {
$live_reload_url
);
}
+
+ // Temporary backward compatibility for `wp-polyfill-ecmascript`, which has
+ // since been absorbed into `wp-polyfill`.
+ //
+ // [TODO][REMOVEME] To be removed in Gutenberg v4.5.
+ gutenberg_override_script(
+ 'wp-polyfill-ecmascript',
+ null,
+ array(
+ 'wp-polyfill',
+ 'wp-deprecated',
+ )
+ );
+ wp_script_add_data(
+ 'wp-polyfill-ecmascript',
+ 'data',
+ 'wp.deprecated( "wp-polyfill-ecmascript script handle", { plugin: "Gutenberg", version: "4.5" } );'
+ );
}
add_action( 'wp_enqueue_scripts', 'gutenberg_register_scripts_and_styles', 5 );
add_action( 'admin_enqueue_scripts', 'gutenberg_register_scripts_and_styles', 5 );
@@ -979,7 +995,7 @@ function gutenberg_register_vendor_scripts() {
'https://unpkg.com/element-closest@2.0.2/element-closest.js'
);
gutenberg_register_vendor_script(
- 'wp-polyfill-ecmascript',
+ 'wp-polyfill',
'https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.0.0/polyfill' . $suffix . '.js'
);
}
@@ -1325,6 +1341,33 @@ function gutenberg_load_locale_data() {
);
}
+/**
+ * Retrieve The available image sizes for a post
+ *
+ * @return array
+ */
+function gutenberg_get_available_image_sizes() {
+ $size_names = apply_filters(
+ 'image_size_names_choose',
+ array(
+ 'thumbnail' => __( 'Thumbnail', 'gutenberg' ),
+ 'medium' => __( 'Medium', 'gutenberg' ),
+ 'large' => __( 'Large', 'gutenberg' ),
+ 'full' => __( 'Full Size', 'gutenberg' ),
+ )
+ );
+
+ $all_sizes = array();
+ foreach ( $size_names as $size_slug => $size_name ) {
+ $all_sizes[] = array(
+ 'slug' => $size_slug,
+ 'name' => $size_name,
+ );
+ }
+
+ return $all_sizes;
+}
+
/**
* Scripts & Styles.
*
@@ -1437,26 +1480,16 @@ function gutenberg_editor_scripts_and_styles( $hook ) {
$demo_content = ob_get_clean();
$initial_edits = array(
- 'title' => array(
- 'raw' => __( 'Welcome to the Gutenberg Editor', 'gutenberg' ),
- ),
- 'content' => array(
- 'raw' => $demo_content,
- ),
+ 'title' => __( 'Welcome to the Gutenberg Editor', 'gutenberg' ),
+ 'content' => $demo_content,
);
} elseif ( $is_new_post ) {
// Override "(Auto Draft)" new post default title with empty string,
// or filtered value.
$initial_edits = array(
- 'title' => array(
- 'raw' => $post->post_title,
- ),
- 'content' => array(
- 'raw' => $post->post_content,
- ),
- 'excerpt' => array(
- 'raw' => $post->post_excerpt,
- ),
+ 'title' => $post->post_title,
+ 'content' => $post->post_content,
+ 'excerpt' => $post->post_excerpt,
);
} else {
$initial_edits = null;
@@ -1596,20 +1629,25 @@ function gutenberg_editor_scripts_and_styles( $hook ) {
'disableCustomFontSizes' => get_theme_support( 'disable-custom-font-sizes' ),
'disablePostFormats' => ! current_theme_supports( 'post-formats' ),
'titlePlaceholder' => apply_filters( 'enter_title_here', __( 'Add title', 'gutenberg' ), $post ),
- 'bodyPlaceholder' => apply_filters( 'write_your_story', __( 'Write your story', 'gutenberg' ), $post ),
+ 'bodyPlaceholder' => apply_filters( 'write_your_story', __( 'Start writing or type / to choose a block', 'gutenberg' ), $post ),
'isRTL' => is_rtl(),
'autosaveInterval' => 10,
'maxUploadFileSize' => $max_upload_size,
'allowedMimeTypes' => get_allowed_mime_types(),
'styles' => $styles,
- 'postLock' => $lock_details,
+ 'imageSizes' => gutenberg_get_available_image_sizes(),
// Ideally, we'd remove this and rely on a REST API endpoint.
+ 'postLock' => $lock_details,
'postLockUtils' => array(
'nonce' => wp_create_nonce( 'lock-post_' . $post->ID ),
'unlockNonce' => wp_create_nonce( 'update-post_' . $post->ID ),
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
),
+
+ // Whether or not to load the 'postcustom' meta box is stored as a user meta
+ // field so that we're not always loading its assets.
+ 'enableCustomFields' => (bool) get_user_meta( get_current_user_id(), 'enable_custom_fields', true ),
);
$post_autosave = gutenberg_get_autosave_newer_than_post_save( $post );
diff --git a/lib/meta-box-partial-page.php b/lib/meta-box-partial-page.php
index e50aaffb8c3a40..aec680bd8dd24d 100644
--- a/lib/meta-box-partial-page.php
+++ b/lib/meta-box-partial-page.php
@@ -113,7 +113,6 @@ function gutenberg_filter_meta_boxes( $meta_boxes ) {
$core_normal_meta_boxes = array(
'revisionsdiv',
'postexcerpt',
- 'postcustom',
'trackbacksdiv',
'commentstatusdiv',
'commentsdiv',
@@ -121,6 +120,13 @@ function gutenberg_filter_meta_boxes( $meta_boxes ) {
'authordiv',
);
+ // Whether or not to load the 'postcustom' meta box is stored as a user meta
+ // field so that we're not always loading its assets.
+ $enable_custom_fields = (bool) get_user_meta( get_current_user_id(), 'enable_custom_fields', true );
+ if ( ! $enable_custom_fields ) {
+ $core_normal_meta_boxes[] = 'postcustom';
+ }
+
$taxonomy_callbacks_to_unset = array(
'post_tags_meta_box',
'post_categories_meta_box',
@@ -233,10 +239,15 @@ function gutenberg_show_meta_box_warning( $callback ) {
return;
}
- if ( is_array( $callback ) ) {
- $reflection = new ReflectionMethod( $callback[0], $callback[1] );
- } else {
- $reflection = new ReflectionFunction( $callback );
+ try {
+ if ( is_array( $callback ) ) {
+ $reflection = new ReflectionMethod( $callback[0], $callback[1] );
+ } else {
+ $reflection = new ReflectionFunction( $callback );
+ }
+ } catch ( ReflectionException $exception ) {
+ // We could not properly reflect on the callable, so we abort here.
+ return;
}
if ( $reflection->isInternal() ) {
@@ -298,6 +309,10 @@ function the_gutenberg_metaboxes() {
+