PageSourceSearch

https://perko.dev/assets/2022-02-21-understanding-how-gutenberg-saves-data-CNcJEy0P.js

js perko.dev collected 2026-10-07 16:50:07 UTC 19,768 bytes, 161 lines download raw bytes

1const n=`---
2date: 2022-02-21
3slug: 2022-02-21-understanding-how-gutenberg-saves-data
4title: Understanding How Gutenberg Saves Data
5image: wordpress.jpg
6categories: WordPress
7tags: gutenberg,wordpress
8---
9
10<p>With full-site editing released in WordPress 5.9, it&#39;s becoming 
11impossible to ignore Gutenberg, the block editor.  I&#39;ve been avoiding
12it, as I think creating WordPress sites in plain PHP works great.
13One of the pain points that I&#39;ve had in the past learning to write
14custom blocks is that it takes me much longer to create a custom block
15than to just style a custom shortcode.  However, it is hard to beat
16that slick Gutenberg UI for users.</p><p>I spent some time recently digging through the ever-changing WordPress
17codex, learning as much as I could about the system.  Once thing that 
18always bugged me was understanding how the code <em>worked</em>, and how the
19content of the blocks were <em>saved</em> to the database.  I knew that
20there was an <strong>edit</strong> and a <strong>save</strong> function, but it never really
21made much sense to me.  I was used to just using PHP to echo out my content,
22and styling it with CSS.  If I wanted to change the way something looked,
23I could easily change it in code.</p><p>After doing some experimenting, I learned a lot, and I think that I can provide
24a concise and easy way of understanding what you&#39;re actually developing
25when you are creating a custom block.</p><h3 id="separation-of-two-presentations">Separation of Two Presentations</h3>
26<p>It&#39;s kind of strange to think about, but you really have two different 
27presentations.  One is for the block editor itself, and one is for what
28the readers will see on the front-end of the WordPress site.  </p><p>At first thought when reading that sentence you would probably think that
29they would be the same, since after all we are working with a WYSIWYG
30editor, right?</p><p>The main difference to remember here is that the editor will need to 
31use special components that allow the user to interact and change content
32within the block.  On the front-end, we&#39;re just needing to display
33the saved data in a stylish way.  It should look very similar in the
34editor and on the front-end.</p><blockquote>
35<p>When I say &quot;front-end&quot;, I am specifically referring to what the reader
36on the site would see.</p></blockquote>
37<h3 id="a-simple-example">A Simple Example</h3>
38<p>I&#39;ve created a simple block using the <a href="https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block/">Create Block</a>
39package provided by WordPress.  Let&#39;s take a look at the <em>edit</em> function:</p><pre><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> useBlockProps <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@wordpress/block-editor'</span><span class="token punctuation">;</span>
40<span class="token keyword">import</span> <span class="token string">'./editor.scss'</span><span class="token punctuation">;</span>
41
42<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Edit</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
43	<span class="token keyword">return</span> <span class="token punctuation">(</span>
44		<span class="token operator">&lt;</span>p <span class="token punctuation">{</span><span class="token operator">...</span><span class="token function">useBlockProps</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span>
45			This is the editor text<span class="token operator">!</span>
46		<span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">></span>
47	<span class="token punctuation">)</span><span class="token punctuation">;</span>
48<span class="token punctuation">}</span>
49</code></pre><p>And we can take a look at it in the editor by adding the block to a new post:</p><p><img src="/images/simple-editor-block.png" alt="The simple example block shown in the Gutenberg editor"></p><p>This is pretty straightforward.  The <em>edit</em> function is called when the example block is 
50added to the editor, and renders out a paragraph with some text.  But what happens when
51we publish it?  Here&#39;s what we have in our <em>save</em> function:</p><pre><code class="language-javascript"><span class="token keyword">
51import</span> <span class="token punctuation">{</span> useBlockProps <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@wordpress/block-editor'</span><span class="token punctuation">;</span>
52
53<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Save</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
54	<span class="token keyword">return</span> <span class="token punctuation">(</span>
55		<span class="token operator">&lt;</span>p <span class="token punctuation">{</span><span class="token operator">...</span>useBlockProps<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span>
56			This is the saved text<span class="token operator">!</span>
57		<span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">></span>
58	<span class="token punctuation">)</span><span class="token punctuation">;</span>
59<span class="token punctuation">}</span>
60</code></pre><p>And here is what is saved in the database:</p><pre><code class="language-html"><span class="token comment">&lt;!-- wp:create-block/simple --></span>
61<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>wp-block-create-block-simple<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>This is the saved text!<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
62<span class="token comment">&lt;!-- /wp:create-block/simple --></span>
63</code></pre><p>Let&#39;s unpack a couple of things here.  The <em>save</em> function renders out the 
64HTML that is actually saved to the database.  The comment that is at the
65beginning and end of the content notes the block that created this content.
66This corresponds to the name of the block that you specify within your
67<strong>block.json</strong> file.  Take a look at the <em>name</em> property, it matches
68what is saved in the database.</p><pre><code class="language-json"><span class="token punctuation">{</span>
69	<span class="token property">"$schema"</span><span class="token operator">:</span> <span class="token string">"https://schemas.wp.org/trunk/block.json"</span><span class="token punctuation">,</span>
70	<span class="token property">"apiVersion"</span><span class="token operator">:</span> <span class="token number">2</span><span class="token punctuation">,</span>
71	<span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"create-block/simple"</span><span class="token punctuation">,</span>
72  ...
73</code></pre><blockquote>
74<p>Since the block content is saved to the
75database, this means that any changes to your block code will not
76affect existing saved blocks. That content would have to be 
77opened in the editor, and re-published.</p></blockquote>
78<h3 id="saving-content-data-with-attributes">Saving Content Data with Attributes</h3>
79<p>So you have your <em>edit</em> and <em>save</em> functions created, but you want
80to allow the user to actually input something.  How is this data
81actually translated from the <em>edit</em> function over to the <em>save</em>
82function, and then actually persisted in the database?  If we are 
83making editable content, let&#39;s say allowing the user to input the
84text in the paragraph tag, how will that be used in the editor
85when the user opens up saved content and wants to change it?</p><p>This is where attributes come in.</p><p>It&#39;s an odd name in my opinion, but the attributes are how we
86describe the metadata and content associated with an individual
87block.</p><p>Attributes are defined within our <strong>index.js</strong> file (if you&#39;re using
88the code generated using the WordPress generator).  This is an object
89that is passed in to the <em>registerBlockType</em> function.</p><pre><code class="language-javascript"><span class="token keyword">
89import</span> <span class="token punctuation">{</span>registerBlockType<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@wordpress/blocks'</span><span class="token punctuation">;</span>
90<span class="token keyword">import</span> <span class="token string">'./style.scss'</span><span class="token punctuation">;</span>
91<span class="token keyword">import</span> Edit <span class="token keyword">from</span> <span class="token string">'./edit'</span><span class="token punctuation">;</span>
92<span class="token keyword">import</span> Save <span class="token keyword">from</span> <span class="token string">'./save'</span><span class="token punctuation">;</span>
93
94<span class="token function">registerBlockType</span><span class="token punctuation">(</span><span class="token string">'create-block/simple'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
95	<span class="token literal-property property">edit</span><span class="token operator">:</span> Edit<span class="token punctuation">,</span>
96	<span class="token literal-property property">save</span><span class="token operator">:</span> Save<span class="token punctuation">,</span>
97	<span class="token literal-property property">attributes</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
98<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
99</code></pre><p>For this example, we will do a simple attribute.  We will dive deeper
100into different ways of storing data within attributes in a later post.
101Let&#39;s add a <em>text</em> property, with a type of <em>string</em> to our <em>attributes</em>.</p><pre><code class="language-javascript"><span class="token literal-property property">attributes</span><span class="token operator">:</span> <span class="token punctuation">{</span>
102  <span class="token literal-property property">text</span><span class="token operator">:</span> <span class="token punctuation">{</span>
103    <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">'string'</span>
104  <span class="token punctuation">}</span>
105<span class="token punctuation">}</span>
106</code></pre><p>Now that we have our attribute, let&#39;s change the <em>edit</em> function to
107allow the user to input some text.  We will use the <strong>TextControl</strong> 
108component to do so.  We will also destructure a couple of items 
109from the properties that are passed into the <em>edit</em> function.  We
110will need the <em>attributes</em> and the <em>setAttributes</em>.</p><p>The <em>attributes</em> gives us access to the content that is currenly
111saved to the database.  The <em>setAttributes</em> function allows us
112to update that data.</p><pre><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> useBlockProps <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@wordpress/block-editor'</span><span class="token punctuation">;</span>
113<span class="token keyword">import</span> <span class="token punctuation">{</span> TextControl <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@wordpress/components'</span><span class="token punctuation">;</span>
114<span class="token keyword">import</span> <span class="token string">'./editor.scss'</span><span class="token punctuation">;</span>
115
116<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Edit</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>attributes<span class="token punctuation">,</span> setAttributes<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
117	<span class="token keyword">return</span> <span class="token punctuation">(</span>
118		<span class="token operator">&lt;</span>p <span class="token punctuation">{</span><span class="token operator">...</span><span class="token function">useBlockProps</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span>
119			<span class="token operator">&lt;</span>TextControl
120				label<span class="token operator">=</span><span class="token string">"Write your text"</span>
121				value<span class="token operator">=</span><span class="token punctuation">{</span>attributes<span class="token punctuation">.</span>text<span class="token punctuation">}</span>
122				onChange<span class="token operator">=</span><span class="token punctuation">{</span><span class="token parameter">value</span> <span class="token operator">=></span> <span class="token function">setAttributes</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token literal-property property">text</span><span class="token operator">:</span> value<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">/</span><span class="token operator">></span>
123		<span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">></span>
124	<span class="token punctuation">)</span><span class="token punctuation">;</span>
125<span class="token punctuation">}</span>
126</code></pre><p>Save your work, and update your post.  I&#39;ve entered &quot;hello world&quot;
127into my newly updated block.</p><p><img src="/images/simple-editor-block-with-input.png" alt="Updated block with text input"></p><p>Let&#39;s publish the work and check what&#39;s in the database.  Here&#39;s where
128things get strange.  We already stated that the <em>save</em> function is responsible
129for saving the content to the database, and the <em>edit</em> function is for
130the presentation in the editor.  You&#39;d expect the database to look exactly
131the same, wouldn&#39;t you?  You&#39;d be wrong.</p><pre><code class="language-html"><span class="token comment">&lt;!-- wp:create-block/simple {"text":"hello world"} --></span>
132<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>wp-block-create-block-simple<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
132This is the saved text!<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
133<span class="token comment">&lt;!-- /wp:create-block/simple --></span>
134</code></pre><p>The content within the paragraph tag is still the same, as you&#39;d expect.
135However, you can now see a JSON object that represents the attributes of 
136this block.</p><p>If you reload the editor in your browser, you&#39;ll see that your text
137remains.  It works by pulling this text off of the attributes object.
138Pretty cool, huh?</p><h3 id="displaying-attribute-data-on-the-front-end">Displaying Attribute Data on the Front-End</h3>
139<p>Let&#39;s revisit our <em>save</em> function and update it so that it will now
140display to readers the text that we allowed our editor to add to it.</p><p>All we need to do, is destructure the <em>attributes</em> from the 
141parameter that is passed by WordPress into the <em>save</em> function.
142Then, we can simply output the <em>text attribute</em> into the 
143paragraph.</p><pre><code class="language-javascript"><span class="token keyword">import</span> <span class="token punctuation">{</span> useBlockProps <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@wordpress/block-editor'</span><span class="token punctuation">;</span>
144
145<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token keyword">function</span> <span class="token function">Save</span><span class="token punctuation">(</span><span class="token parameter"><span class="token punctuation">{</span>attributes<span class="token punctuation">}</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
146	<span class="token keyword">return</span> <span class="token punctuation">(</span>
147		<span class="token operator">&lt;</span>p <span class="token punctuation">{</span><span class="token operator">...</span>useBlockProps<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token operator">></span>
148			<span class="token punctuation">{</span>attributes<span class="token punctuation">.</span>text<span class="token punctuation">}</span>
149		<span class="token operator">&lt;</span><span class="token operator">/</span>p<span class="token operator">></span>
150	<span class="token punctuation">)</span><span class="token punctuation">;</span>
151<span class="token punctuation">}</span>
152</code></pre><p>And here is how it persists in the database after it is
153re-published:</p><pre><code class="language-html"><span class="token comment">&lt;!-- wp:create-block/simple {"text":"hello world"} --></span>
154<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>p</span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>wp-block-create-block-simple<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>hello world<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>p</span><span class="token punctuation">></span></span>
155<span class="token comment">&lt;!-- /wp:create-block/simple --></span>
156</code></pre><p>As you can see, the attribute still exists within the 
157attribute object in the initial comment, so that the
158editor can easily fetch it.  The same text now also exists
159on the paragraph tag, allowing the front-end to render
160the text properly.</p><p>That&#39;s it!  That&#39;s the basics of using attributes within a 
161custom Gutenberg block!  </p>`;export{n as default};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.