diff --git a/docs/designers-developers/developers/tutorials/create-block/author-experience.md b/docs/designers-developers/developers/tutorials/create-block/author-experience.md new file mode 100644 index 0000000000000..cab6324ff3e95 --- /dev/null +++ b/docs/designers-developers/developers/tutorials/create-block/author-experience.md @@ -0,0 +1,141 @@ +# Authoring Experience + +## Background + +One of the primary tenets of Gutenberg is as a WYSIWYG editor, what you see in the editor, should be as close to what you get when published. Keep this in mind when building blocks. + +## Placeholder + +The state when a block has been inserted, but no data has been entered yet, is called a placeholder. There is a `Placeholder` component built that gives us a standard look. You can see example placeholders in use with the image and embed blocks. + +To use the Placeholder, wrap the `` component so it becomes a child element of the `` component. Try it out in your code. After updating, you might have something like: + +```jsx +import { Placeholder, TextControl } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +export default function Edit( { attributes, className, setAttributes } ) { + return ( +
+ + setAttributes( { message: val } ) } + /> + +
+ ); +} +``` + +## isSelected Ternary Function + +The placeholder looks ok, for a simple text message it may or may not be what you are looking for. However, the placeholder can be useful if you are replacing the block after what is typed in, similar to the embed blocks. + +For this we can use a ternary function, to display content based on a value being set or not. A ternary function is an inline if-else statement, using the syntax: + +```js +clause ? doIfTrue : doIfFalse; +``` + +This can be used inside a block to control what shows when a parameter is set or not. A simple case that displays a `message` if set, otherwise show the form element: + +```jsx + return ( +
+ { attributes.message ? +
Message: { attributes.message }
: +
+

No Message.

+ setAttributes( { message: val } ) } + /> +
+ } + ); +``` + +There is a problem with the above, if we only use the `attributes.message` check, as soon as we type in the text field it would disappear since the message would then be set to a value. So we need to pair with an additional `isSelected` parameter. + +The `isSelected` parameter is passed in to the `edit` function and is set to true if the block is selected in the editor (currently editing) otherwise set to false (editing elsewhere). + +Using that parameter, we can use the logic: + +```js +attributes.message && ! isSelected; +``` + +If the message is set and `!isSelected`, meaning we are not editing the block, the focus is elsewhere, then display the message not the text field. + +All so this combined together here's what the edit function looks like this: + +```jsx +import { Placeholder, TextControl } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +export default function Edit( { + attributes, + className, + isSelected, + setAttributes, +} ) { + return ( +
+ { attributes.message && ! isSelected ? ( +
{ attributes.message }
+ ) : ( + + + setAttributes( { message: val } ) + } + /> + + ) } +
+ ); +} +``` + +With that in place, rebuild and reload and when you are not editing the message is displayed as it would be for the view, when you click into the block you see the text field. + +## A Better Solution + +The switching between a Placeholder and input control works well with a visual element like an image or video, but for the text example in this block we can do better. + +The simpler and better solution is to modify the `editor.css` to include the proper stylized text while typing. + +Update `editor.css` to: + +```css +.wp-block-create-block-gutenpride input[type='text'] { + font-family: Gilbert; + font-size: 64px; +} +``` + +The edit function can simply be: + +```jsx +import { TextControl } from '@wordpress/components'; + +export default function Edit( { attributes, className, setAttributes } ) { + return ( + setAttributes( { message: val } ) } + /> + ); +} +``` + +Next Section: [Finishing Touches](finishing.md) diff --git a/docs/designers-developers/developers/tutorials/create-block/block-anatomy.md b/docs/designers-developers/developers/tutorials/create-block/block-anatomy.md new file mode 100644 index 0000000000000..1ce0a2b22a51e --- /dev/null +++ b/docs/designers-developers/developers/tutorials/create-block/block-anatomy.md @@ -0,0 +1,54 @@ +# Anatomy of a Gutenberg Block + +At its simplest, a block in Gutenberg is a JavaScript object with a specific set of properties. Here is the complete code for registering a block: + +```js +import { registerBlockType } from '@wordpress/blocks'; + +registerBlockType( 'create-block/gutenpride', { + title: 'Gutenpride', + description: 'Example block.', + category: 'widgets', + icon: 'smiley', + supports: { + // Removes support for an HTML mode. + html: false, + }, + + edit: () => { + return
Hello in Editor.
; + }, + + save: () => { + return
Hello in Save.
; + }, +} ); +``` + +The first parameter in the **registerBlockType** function is the block name, this should match exactly to the name registered in the PHP file. + +The second parameter to the function is the block object. See the [block registration documentation](/docs/designers-developers/developers/block-api/block-registration.md) for full details. + +The **title** is the title of the block shown in the Inserter. + +The **icon** is the icon shown in the Inserter. The icon property expects any Dashicon name as a string, see [list of available icons](https://developer.wordpress.org/resource/dashicons/). You can also provide an SVG object, but for now it's easiest to just pick a Dashicon name. + +The **category** specified is a string and must be one of: "common, formatting, layout, widgets, or embed". You can create your own custom category name, [see documentation for details](/docs/designers-developers/developers/filters/block-filters.md#managing-block-categories). For this tutorial, I specified "widgets" as the category. + +The last two block object properties are **edit** and **save**, these are the key parts of a block. Both properties should be defined as functions. + +The results of the edit function is what the editor will render to the editor page when the block is inserted. + +The results of the save function is what the editor will insert into the **post_content** field when the post is saved. The post_content field is the field in the WordPress database used to store the content of the post. + +## Internationalization + +If you look at the generated `src/index.js` file, the block title and description are wrapped in a function that looks like this: + +```js +__( 'Gutenpride', 'create_block' ); +``` + +This is an internationalization wrapper that allows for the string "Gutenpride" to be translated. The second parameter, "create_block" is called the text domain and gives context for where the string is from. The JavaScript internationalization, often abbreviated i18n, matches the core WordPress internationalization process. See the [I18n for WordPress documentation](https://codex.wordpress.org/I18n_for_WordPress_Developers) for more details. + +Next Section: [Block Attributes](block-attributes.md) diff --git a/docs/designers-developers/developers/tutorials/create-block/block-attributes.md b/docs/designers-developers/developers/tutorials/create-block/block-attributes.md new file mode 100644 index 0000000000000..267db3120f3af --- /dev/null +++ b/docs/designers-developers/developers/tutorials/create-block/block-attributes.md @@ -0,0 +1,74 @@ +# Block Attributes + +Attributes are the way a block stores data, they define how a block is parsed to extract data from the saved content. + +For this block tutorial, we want to allow the user to type in a message that we will display stylized in the published post. So, we need to add a **message** attribute that will hold the user message. The following code defines a **message** attribute; the attribute type is a string; the source is the text from the selector which is a `div` tag. + +```js +attributes: { + message: { + type: 'string', + source: 'text', + selector: 'div', + }, +}, +``` + +Add this to the `index.js` file within the `registerBlockType` function. The `attributes` are at the same level as the title and description fields. + +When the block loads it will: look at the saved content for the block, look for the div tag, take the text portion, and store the content in an `attributes.message` variable. + +Note: The text portion is equivalent to `innerText` attribute of a DOM element. For more details and other examples see the [Block Attributes documentation](/docs/designers-developers/developers/block-api/block-attributes.md). + +## Edit and Save + +The **attributes** are passed to the `edit` and `save` functions, along with a **setAttributes** function to set the values. Additional parameters are also passed in to this functions, see [the edit/save documentation](/docs/designers-developers/developers/block-api/block-edit-save.md) for more details. + +The `attributes` is a JavaScript object containing the values of each attribute, or default values if defined. The `setAttributes` is a function to update an attribute. + +```js +export default function Edit( { attributes, setAttributes } ) { + // ... +} +``` + +## TextControl Component + +For our example block, the component we are going to use is the **TextControl** component, it is similar to an HTML text input field. You can see [documentation for TextControl component](/packages/components/src/text-control/README.md). You can browse an [interactive set of components in this Storybook](https://wordpress.github.io/gutenberg/). + +The component is added similar to an HTML tag, setting a label, the `value` is set to the `attributes.message` and the `onChange` function uses the `setAttributes` to update the url attribute value. + +The save function will simply write the `attributes.message` as a div tag since that is how we defined it to be parsed. + +Update the edit.js and save.js files to the following, replacing the existing functions. + +**edit.js** + +```js +import { TextControl } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +export default function Edit( { attributes, className, setAttributes } ) { + return ( +
+ setAttributes( { message: val } ) } + /> +
+ ); +} +``` + +**save.js** + +```jsx +export default function Save( { attributes, className } ) { + return
{ attributes.message }
; +} +``` + +Rebuild the block using `npm run build`, reload the editor and add the block. Type a message in the editor, save, and view it in the post. + +Next Section: [Code Implementation](block-code.md) diff --git a/docs/designers-developers/developers/tutorials/create-block/block-code.md b/docs/designers-developers/developers/tutorials/create-block/block-code.md new file mode 100644 index 0000000000000..df6d3f9c800b0 --- /dev/null +++ b/docs/designers-developers/developers/tutorials/create-block/block-code.md @@ -0,0 +1,67 @@ +# Code Implementation + +The basic block is in place, the next step is to add styles to the block. Feel free to style and adjust for your own preference, the main lesson is showing how to create and load external resources. For this example I'm going to load the colorized gilbert font from [Type with Pride](https://www.typewithpride.com/). + +Note: The color may not work with all browsers until they support the proper color font properly, but the font itself still loads and styles. See [colorfonts.wtf](https://www.colorfonts.wtf/) for browser support and details on color fonts. + +## Load Font File + +Download and extract the font from the Type with Pride site, and copy it to your plugin directory naming it `gilbert-color.otf`. To load the font file, we need to add CSS using standard WordPress enqueue, [see Including CSS & JavaScript documentation](https://developer.wordpress.org/themes/basics/including-css-javascript/). + +In the `gutenpride.php` file, the enqueue process is already setup from the generated script, so `editor.css` and `style.css` files are loaded using: + +```php +register_block_type( 'create-block/gutenpride', array( + 'editor_script' => 'create-block-gutenpride-block-editor', + 'editor_style' => 'create-block-gutenpride-block-editor', + 'style' => 'create-block-gutenpride-block', +) ); +``` + +The `editor_style` and `style` parameters refer to the files that match the handles in the `wp_register_style` functions. + +Note: the `editor_style` loads only within the editor, and after the `style`. The `style` CSS loads in both the editor and front-end — published post view. + +## Add CSS Style for Block + +We only need to add the style to `style.css` since it will show while editing and viewing the post. Edit the style.css to add the following. + +Note: the block classname is prefixed with `wp-block`. The `create-block/gutenpride` is converted to the classname `.wp-block-create-block-gutenpride`. + +```css +@font-face { + font-family: Gilbert; + src: url( gilbert-color.otf ); + font-weight: bold; +} + +.wp-block-create-block-gutenpride { + font-family: Gilbert; + font-size: 64px; +} +``` + +After updating, reload the post and refresh the brwoser. If you are using a browser that supports color fonts (Firefox) then you will see it styled. + +## Use Sass for Style (optional) + +The wp-scripts package provides support for using the Sass/Scss languages, to generate CSS, added in @wordpress/scripts v9.1.0. See the [Sass language site](https://sass-lang.com/) to learn more about Sass. + +To use Sass, you need to import a `editor.scss` or `style.scss` in the `index.js` JavaScript file and it will build and output the generated file in the build directory. Note: You need to update the enqueing functions in PHP to load from the correct location. + +Add the following imports to **index.js**: + +```js +import '../editor.scss'; + +import Edit from './edit'; +import save from './save'; +``` + +Update **gutenpride.php** to enqueue from generated file location: + +```php +$editor_css = "build/index.css"; +``` + +Next Section: [Authoring Experience](author-experience.md) diff --git a/docs/designers-developers/developers/tutorials/create-block/devenv.md b/docs/designers-developers/developers/tutorials/create-block/devenv.md new file mode 100644 index 0000000000000..a648edcceae12 --- /dev/null +++ b/docs/designers-developers/developers/tutorials/create-block/devenv.md @@ -0,0 +1,91 @@ +# Development Environment + +We will need a place to work and tools for creating a block, this is often referred to as the development enviornment. The three main pieces needed for our development environment are: + +1. Node/NPM Development Tools +2. WordPress Development Site +3. Code Editor + +## Development Tools + +The tools needed for development are **Node** and **NPM**. **Nodejs** is a runtime environment that allows running JavaScript outside of the browser. NPM is the Node Package Manager, it is used for installing dependencies and running scripts. The script `npx` is installed with `npm` and is used to run packages not yet installed, we will use this to bootstrap a block. + +The tools are used to convert the JavaScript we are going to write into a format that browsers can run. This is called transpiling or the build step. + +For Mac and Linux, it is recommended to use the [Node Version Manager](https://github.com/nvm-sh/nvm) (nvm). Using `nvm` to install node allows installing specific versions, plus installs locally in your home directory and avoids any global permission issues. + +For Windows, or alternative installs, you can [download a Nodejs installer](https://nodejs.org/en/download/) directly from the main Node.js website, the long term support (LTS) version is recommeneded. Installers are available for Windows and Mac, and binaries available for Linux. See Node.js site for additional installation methods. + +Here are the quick instructions to install using nvm, see the [full installation instructions](https://github.com/nvm-sh/nvm#installing-and-updating) for additional details. + +A tip for macOS Catalina, the default profile file may not be created, you can create the required file typing `touch ~/.zshrc` on the command-line. It is fine to run if the file already exists. Note, `~/` is a shortcut to your home directory. + +Run the following on the command-line to install nvm: + +``` +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash +``` + +After installing nvm, you need to use it to install node, to install the latest version of node, run: + +``` +nvm install --lts +``` + +The important part after installing is being able to use them in your terminal. Open a terminal command-line and type `node -v` and `npm -v` to confirm they are installed. + +``` +> node -v +v12.18.0 + +> npm -v +6.14.4 +``` + +Your versions may not match exactly, that is fine. The minimum version for node is >= 10.x and for npm >= 6.9x, using the current LTS version will always be supported. + +## WordPress Development Site + +There are several ways to run WordPress locally on your own computer, or you could even develop on a cloud hosted computer, though this may be slower. + +The WordPress [wp-env package](https://www.npmjs.com/package/@wordpress/env) lets you set up a local WordPress environment for building and testing plugins and themes, without any additional configuration. + +The `wp-env` package requires Docker to be installed. There are instructions available for installing Docker on [Windows 10 Pro](https://docs.docker.com/docker-for-windows/install/), [all other versions of Windows](https://docs.docker.com/toolbox/toolbox_install_windows/), [macOS](https://docs.docker.com/docker-for-mac/install/), and [Linux](https://docs.docker.com/v17.12/install/linux/docker-ce/ubuntu/#install-using-the-convenience-script). + +After confirming that the prerequisites are installed, install `wp-env` globally from the command-line using: + +```bash +npm -g install @wordpress/env +``` + +This will be used in the next [Plugin step](wp-plugin.ms). To confirm it is installed and available, run: + +``` +wp-env --version +> 1.4.0 +``` + +### Alternatives + +A block is just a plugin, so any WordPress environment can be used for development. A couple of alternatives that might be easier, since they do not require Docker install and setup. + +- [Local by Flywheel](https://localbyflywheel.com/) - Local is a single application you download and install. You will need to know where the plugin directory is located after install. If you create a site called `mywp` typically the plugin directory is installed at `~\Local Sites\mywp\app\public\wp-content\plugins` + +- [WampServer](http://www.wampserver.com/en/) or + [MAMP](https://www.mamp.info/) environments, both are quite similar to + Local, combining a web server, PHP, and database. However these tools + are not WordPress specific, so if you are not already using them, Local might be an easier option + +- Remote server - you could work on remote server that is easy to setup, since most hosts have a standard WordPress install. However, this may require additonal development time to sync to the server. + +The important part is having a WordPress site installed, and know where and how to update files in the plugins directory. + +## Code Editor + +[Visual Studio Code](https://code.visualstudio.com/) is a popular code editor for JavaScript development. It works quite well across the three major platforms (Windows, Linux, and Mac), it is open-source and actively maintained by Microsoft. Plus Visual Studio Code has a vibrant community providing plugins and extensions; it is becoming the defacto standard for web development. + +Alternative editors include [Sublime Text](https://www.sublimetext.com/) that is also available across platforms, though is a commercial product; or other free alternatives include [Vim](https://www.vim.org/), [Atom](https://atom.io/), and [Notepad++](https://notepad-plus-plus.org/) all support standard JavaScript style development. + +You can use any editor you're comfortable with, it is more a personal preference. The development setup for WordPress block editor is a common JavaScript environment and most editors have plugins and suppport. The key is having a way to open, edit, and save text files. + +Next Section: [WordPress Plugin](wp-plugin.md) diff --git a/docs/designers-developers/developers/tutorials/create-block/esnext-js.md b/docs/designers-developers/developers/tutorials/create-block/esnext-js.md new file mode 100644 index 0000000000000..e5661cd4d97d9 --- /dev/null +++ b/docs/designers-developers/developers/tutorials/create-block/esnext-js.md @@ -0,0 +1,127 @@ +# ESNext Syntax + +A brief aside to discuss JavaScript. + +## Background + +The JavaScript language continues to evolve, the syntax used to write JavaScript code is not fixed but changes over time. [Ecma International](https://en.wikipedia.org/wiki/Ecma_International) is the organization that sets the standard for the language, officially called [ECMAScript](https://en.wikipedia.org/wiki/ECMAScript). A new standard for JavaScript is published each year, the 6th edition published in 2015 is often referred to as ES6. Our usage would more appropriately be **ESNext** referring to the latest standard. The build step is what converts this latest syntax of JavaScript to a version understood by browsers. + +## Destructuring Assignments + +The [destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) syntax allows you to pull apart arrays, or properties from objects into their own variable. + +For the object `const obj = { foo: "bar" }` + +Creating and assigning a new variable `foo` can be done in a single step: `const { foo } = obj;` + +The curly brackets on the left side tells JavaScript to inspect the object `obj` for the property `foo` and assign its value to the new variable of the same name. + +## Arrow Functions + +Arrow functions provide a shorter syntax for defining a function; this is such a common task in JavaScript that having a syntax a bit shorter is quite helpful. + +Before you might define a function like: + +```js +const f = function ( param ) { + console.log( param ); +}; +``` + +Using arrow function, you can define the same using: + +```js +const g = ( param ) => { + console.log( param ); +}; +``` + +Or even shorter, if the function is only a single-line you can omit the +curly braces: + +```js +const g2 = ( param ) => console.log( param ); +``` + +In the examples above, using `console.log` we aren't too concerned about the return values. However, when using arrow functions in this way, the return value is set whatever the line returns. + +For example, our save function could be shortened from: + +```js +save: ( { attributes } ) => { + return
{ attributes.url }
; +}; +``` + +To: + +```js +save: ( { attributes } ) =>
{ attributes.url }
; +``` + +There are even more ways to shorten code, but you don't want to take it too far and make it harder to read what is going on. + +## Imports + +The [import statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import) is used to import variables or functions from an exported file. You can use destructuring on imports, for example: + +```js +import { TextControl } from '@wordpress/components'; +``` + +This will look in the `@wordpress/components` package for the exported `TextControl` variable. + +A package or file can also set a `default` export, this is imported without using the curly brackets. For example + +```js +const edit = ( { attributes, setAttributes } ) => { + return ( +
+ +
+ ); +}; + +export default edit; +``` + +To import, you would use: + +```js +import edit from './edit'; + +registerBlockType( 'mkaz/qrcode-block', { + title: 'QRCode Block', + icon: 'visibility', + category: 'widgets', + attributes: { + url: { + type: 'string', + source: 'text', + selector: '.theurl', + }, + }, + edit, + save: ( { attributes } ) => { + return
...
; + }, +} ); +``` + +Note, you can also shorten `edit: edit` to just `edit` as shown above. JavaScript will automatically assign the property `edit` to the value of `edit`. This is another form of destructuring. + +## Summary + +It helps to become familiar with the ESNext syntax and the common shorter forms. It will give you a greater understanding of reading code examples and what is going on. + +Here are a few more resources that may help + +- [ES5 vs ES6 with example code](https://medium.com/recraftrelic/es5-vs-es6-with-example-code-9901fa0136fc) +- [Top 10 ES6 Features by Example](https://blog.pragmatists.com/top-10-es6-features-by-example-80ac878794bb) +- [ES6 Syntax and Feature Overview](https://www.taniarascia.com/es6-syntax-and-feature-overview/) + +Next Section: [Anatomy of a Gutenberg Block](block-anatomy.md) diff --git a/docs/designers-developers/developers/tutorials/create-block/finishing.md b/docs/designers-developers/developers/tutorials/create-block/finishing.md new file mode 100644 index 0000000000000..d5e22e3c9a7a7 --- /dev/null +++ b/docs/designers-developers/developers/tutorials/create-block/finishing.md @@ -0,0 +1,27 @@ + +# Finishing Touches + +This tutorial covers the basic structure of building a block, and the general concepts for creating a basic blocks. This sets you up for creating numerous more complicated blocks iterating and adding to this. + +## Additional Components + +The block editor provides a [components package](/packages/components/README.md) which contains numerous prebuilt components you can use to build your block. + +You can visually browse the components and what their implementation looks like using the Storybook tool published at https://wordpress.github.io/gutenberg + +## Additional Tutorials + +The **RichText component** allows for creating a richer input besides plain text, allowing for bold, italic, links, and other inline formating. See the [RichText Reference](/docs/designers-developers/developers/richtext.md) for documentation using this component. + +The InspectorPanel, the settings on the right for a block, and Block Controls have a standard way to implement. See the [Block controls tutorial](/docs/designers-developers/developers/tutorials/block-tutorial/block-controls-toolbar-and-sidebar.md) for additional information. + + +The [Sidebar tutorial](/docs/designers-developers/developers/tutorials/plugin-sidebar-0.md) is a good resource on how to creat a sidebar for your plugin. + +Nested blocks, a block that contains additional blocks, is a common pattern used by various blocks such as Columns, Cover, and Social Links. The **InnerBlocks component** enables this functionality, see the [Using InnerBlocks documentation](/docs/designers-developers/developers/tutorials/block-tutorial/nested-blocks-inner-blocks.md) + +## How did they do that? + +One of the best sources for information and reference is the Block Editor itself, all the core blocks are built the same way and the code is available to browse. A good way is to find a core block doing something close to what you are interested, and read through its code to see how things are done. + +All core blocks are in the [block library package](https://github.com/WordPress/gutenberg/tree/master/packages/block-library/src). diff --git a/docs/designers-developers/developers/tutorials/create-block/readme.md b/docs/designers-developers/developers/tutorials/create-block/readme.md new file mode 100644 index 0000000000000..17713b641044a --- /dev/null +++ b/docs/designers-developers/developers/tutorials/create-block/readme.md @@ -0,0 +1,32 @@ +# Create Block Tutorial + +The goal of this tutorial is to get you started creating your first block for the WordPress Block Editor. We will create a simple block that allows the user to type a message and styles it. + +The tutorial includes setting up your development environment, tools, and getting comfortable with the new development model. If you are already comfortable, try the quick start below, otherwise step through whatever part of the tutorial you need. + +## Quick Start + +The `@wordpress/create-block` package exists to create the necessary block scaffolding to get you started. See [create-block package documentation](https://www.npmjs.com/package/@wordpress/create-block) for additional features. This quick start assumes you have a development environment with node installed, and a WordPress site. + +From your plugins directory, to create your block run: + +```bash +npx @wordpress/create-block starter-block +``` + +The above command will ask you a few questions to customize, then will create a new directory called `starter-block`, installs the necessary files, and builds the block plugin. + +You now need to activate the plugin from inside wp-admin plugins page. + +After activated, go to the block editor and use the inserter to search and add your new block. + +## Table of Contents + +1. [Development Environment](devenv.md) +2. [WordPress Plugin](wp-plugin.md) +3. [ESNext Syntax](esnext-js.md) +4. [Anatomy of a Gutenberg Block ](block-anatomy.md) +5. [Block Attributes](block-attributes.md) +6. [Code Implementation](block-code.md) +7. [Authoring Experience](author-experience.md) +8. [Finishing Touches](finishing.md) diff --git a/docs/designers-developers/developers/tutorials/create-block/wp-plugin.md b/docs/designers-developers/developers/tutorials/create-block/wp-plugin.md new file mode 100644 index 0000000000000..39e589a7d9f0c --- /dev/null +++ b/docs/designers-developers/developers/tutorials/create-block/wp-plugin.md @@ -0,0 +1,159 @@ +# WordPress Plugin + +A new block in the WordPress block editor is added by creating a WordPress plugin, installing, and activating the plugin. This page covers the details of a WordPress plugin if you are not already familiar. + +## Plugin Details + +A WordPress plugin is a set of files in a directory within the site's `wp-content/plugins` directory. For this example, we will use the `create-block` package to generate the necessary plugin files. + +### Switch to Working Directory + +(1A) If you do not plan to use `wp-env` change to your local WordPress plugin directory. For example in Local it is: `~\Local Sites\mywp\wp-content\plugins` + +-or- + +(1B) If you do use `wp-env` start, you can start from any directory for your project. `wp-env` will use it as a plugin directory for your site. + +### Generate Plugin Files + +(2) Once in the right directory for your enviornment, the next step is to +Regardless of environment, run the Run the following command to generate plugin files: + +``` +npx @wordpress/create-block gutenpride +cd gutenpride +``` + +All of the plugin files we develop will be in this `gutenpride` directory. + +The script created a PHP file `gutenpride.php` that is the main plugin file. At the top of this file is the appropriate Plugin Header comment block which defines the plugin. + +```php +/** + * Plugin Name: Gutenpride + * Description: Example block + * Version: 0.1.0 + * Author: The WordPress Contributors + * License: GPL-2.0-or-later + * License URI: https://www.gnu.org/licenses/gpl-2.0.html + * Text Domain: create-block + * + * @package create-block + */ +``` + +### Start WordPress + +(3A) If you are using Local, or other environment confirm it is started and running. + +-or- + +(3B) If you are using `wp-env`, see [Development Environment setup](devenv.md), then you should now run from inside the `gutenpride` directory: + +``` +wp-env start +``` + +This will start your local WordPress site and use the current directory as your plugin directory. In your browser, go to https://localhost:8888/wp-admin/ and login, the default username is "admin" and password is "password", no quotes. + +### Confirm Plugin Installed + +The generated plugin should now be listed on the Plugins admin page in your WordPress install. Switch WorPress to the plugins page and activate. + +For more on creating a WordPress plugin see [Plugin Basics](https://developer.wordpress.org/plugins/plugin-basics/), and [Plugin Header requirements](https://developer.wordpress.org/plugins/plugin-basics/header-requirements/) for explanation and additional fields you can include in your plugin +header. + +## package.json + +The package.json file defines the JavaScript properties for your project. This is a standard file used by NPM for defining properties and scripts it can run, the file and process is not specific to WordPress. + +A package.json file was created with the create script, this defines the dependecies and scripts needed. you can install dependencies. The only initial dependency is the `@wordpress/scripts` package which bundles the tools and configurations needed to build blocks. + +To use the scripts package, the `scripts` property of package.json defines the parameter called and what to run, the two main scripts are: + +```json + "scripts": { + "build": "wp-scripts build", + "start": "wp-scripts start" + }, +``` + +These are run using: `npm run build` or `npm run start` which will call the appropriate binary and command we need. + +Use `npm run build` for running once to create a production build. + +Use `npm run start` for creating a development build that also starts a watch process that waits and watches for changes to the file and will rebuild each time it is saved. + +By default, the build scripts looks for `src/index.js` for the JavaScript file to build and will save the built file to `build/index.js`. + +## Plugin to Load Script + +To load the built script, so it is run within the editor, you need to tell WordPress about the script. This done in the init action in the `gutenpride.php` file. + +```php +function create_block_gutenpride_block_init() { + $dir = dirname( __FILE__ ); + + $script_asset_path = "$dir/build/index.asset.php"; + if ( ! file_exists( $script_asset_path ) ) { + throw new Error( + 'You need to run `npm start` or `npm run build` for the "create-block/gutenpride" block first.' + ); + } + $index_js = 'build/index.js'; + $script_asset = require( $script_asset_path ); + wp_register_script( + 'create-block-gutenpride-block-editor', + plugins_url( $index_js, __FILE__ ), + $script_asset['dependencies'], + $script_asset['version'] + ); + + $editor_css = 'editor.css'; + wp_register_style( + 'create-block-gutenpride-block-editor', + plugins_url( $editor_css, __FILE__ ), + array(), + filemtime( "$dir/$editor_css" ) + ); + + $style_css = 'style.css'; + wp_register_style( + 'create-block-gutenpride-block', + plugins_url( $style_css, __FILE__ ), + array(), + filemtime( "$dir/$style_css" ) + ); + + register_block_type( 'create-block/gutenpride', array( + 'editor_script' => 'create-block-gutenpride-block-editor', + 'editor_style' => 'create-block-gutenpride-block-editor', + 'style' => 'create-block-gutenpride-block', + ) ); +} +add_action( 'init', 'create_block_gutenpride_block_init' ); +``` + +The build process creates a secondary asset file that contains the list of dependencies and a file version based on the timestamp, this is the `index.asset.php` file. + +The `wp_register_script` function registers a name, called the handle, and relates that name to the script file. The dependencies are used to specify if the script requires including other libraries. The version is specified so the browser will reload if the file changed. + +The `register_block_type` function registers the block we are going to create and specifies the editor_script file handle registered. So now when the editor loads it will load this script. + +With the above in place, create a new post to load the editor and check the you can add the block in the inserter. You can use `/` to search, or click the box with the [+] and search for "Gutenpride" to find the block. + +## Troubleshooting + +It is a good skill to learn and get comfortable using the web console. This is where JavaScript errors are shown and a nice way to test out snippets of JavaScript. See [Firefox Developer Tools documentation](https://developer.mozilla.org/en-US/docs/Tools). + +To open the developer tools in Firefox, use the menu selecting Web Developer : Toggle Tools, on Chrome, select More Tools -> Developers Tools. For both browers, the keyboard shortcut on Windows is Ctrl+Shift+I, or on Mac Cmd+Shift+I. On Windows & Linux, the F12 key also works. You can then click Console to view logs. + +Try running `npm run start` that will start the watch process for automatic rebuilds. If you then make an update to `src/index.js` file, you will see the build run, and if you reload the WordPress editor you'll see the change. + +For more info, see the build section of the [Getting Started with JavaScript tutorial](/docs/designers-developers/developers/tutorials/javascript/js-build-setup.md) in the WordPress Handbook. + +## Summary + +Hopefully, at this point, you have your plugin created and activated. We have the package.json with the `@wordpress/scripts` dependency, that defines the build and start scripts. The basic block is in place and can be added to the editor. + +Next Section: [ESNext Syntax](esnext-js.md)