├── .editorconfig
├── .gitignore
├── build
├── index.asset.php
├── index.js
└── index.js.map
├── example-query-loop-button.php
├── package-lock.json
├── package.json
├── readme.md
├── readme.txt
└── src
└── index.js
/.editorconfig:
--------------------------------------------------------------------------------
1 | # This file is for unifying the coding style for different editors and IDEs
2 | # editorconfig.org
3 |
4 | # WordPress Coding Standards
5 | # https://make.wordpress.org/core/handbook/coding-standards/
6 |
7 | root = true
8 |
9 | [*]
10 | charset = utf-8
11 | end_of_line = lf
12 | insert_final_newline = true
13 | trim_trailing_whitespace = true
14 | indent_style = tab
15 |
16 | [*.{yml,yaml}]
17 | indent_style = space
18 | indent_size = 2
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Coverage directory used by tools like istanbul
9 | coverage
10 |
11 | # Compiled binary addons (https://nodejs.org/api/addons.html)
12 | build/Release
13 |
14 | # Dependency directories
15 | node_modules/
16 |
17 | # Optional npm cache directory
18 | .npm
19 |
20 | # Optional eslint cache
21 | .eslintcache
22 |
23 | # Output of `npm pack`
24 | *.tgz
25 |
26 | # Output of `wp-scripts plugin-zip`
27 | *.zip
28 |
29 | # dotenv environment variables file
30 | .env
31 |
--------------------------------------------------------------------------------
/build/index.asset.php:
--------------------------------------------------------------------------------
1 | array('react', 'wp-block-editor', 'wp-components', 'wp-compose', 'wp-hooks', 'wp-i18n'), 'version' => 'e103e445eb33673d07a1');
2 |
--------------------------------------------------------------------------------
/build/index.js:
--------------------------------------------------------------------------------
1 | /******/ (() => {
2 | // webpackBootstrap
3 | /******/ "use strict";
4 | /******/ var __webpack_modules__ = {
5 | /***/ react:
6 | /*!************************!*\
7 | !*** external "React" ***!
8 | \************************/
9 | /***/ (module) => {
10 | module.exports = window["React"];
11 |
12 | /***/
13 | },
14 |
15 | /***/ "@wordpress/block-editor":
16 | /*!*************************************!*\
17 | !*** external ["wp","blockEditor"] ***!
18 | \*************************************/
19 | /***/ (module) => {
20 | module.exports = window["wp"]["blockEditor"];
21 |
22 | /***/
23 | },
24 |
25 | /***/ "@wordpress/components":
26 | /*!************************************!*\
27 | !*** external ["wp","components"] ***!
28 | \************************************/
29 | /***/ (module) => {
30 | module.exports = window["wp"]["components"];
31 |
32 | /***/
33 | },
34 |
35 | /***/ "@wordpress/compose":
36 | /*!*********************************!*\
37 | !*** external ["wp","compose"] ***!
38 | \*********************************/
39 | /***/ (module) => {
40 | module.exports = window["wp"]["compose"];
41 |
42 | /***/
43 | },
44 |
45 | /***/ "@wordpress/hooks":
46 | /*!*******************************!*\
47 | !*** external ["wp","hooks"] ***!
48 | \*******************************/
49 | /***/ (module) => {
50 | module.exports = window["wp"]["hooks"];
51 |
52 | /***/
53 | },
54 |
55 | /***/ "@wordpress/i18n":
56 | /*!******************************!*\
57 | !*** external ["wp","i18n"] ***!
58 | \******************************/
59 | /***/ (module) => {
60 | module.exports = window["wp"]["i18n"];
61 |
62 | /***/
63 | },
64 |
65 | /******/
66 | };
67 | /************************************************************************/
68 | /******/ // The module cache
69 | /******/ var __webpack_module_cache__ = {};
70 | /******/
71 | /******/ // The require function
72 | /******/ function __webpack_require__(moduleId) {
73 | /******/ // Check if module is in cache
74 | /******/ var cachedModule = __webpack_module_cache__[moduleId];
75 | /******/ if (cachedModule !== undefined) {
76 | /******/ return cachedModule.exports;
77 | /******/
78 | }
79 | /******/ // Create a new module (and put it into the cache)
80 | /******/ var module = (__webpack_module_cache__[moduleId] = {
81 | /******/ // no module.id needed
82 | /******/ // no module.loaded needed
83 | /******/ exports: {},
84 | /******/
85 | });
86 | /******/
87 | /******/ // Execute the module function
88 | /******/ __webpack_modules__[moduleId](
89 | module,
90 | module.exports,
91 | __webpack_require__
92 | );
93 | /******/
94 | /******/ // Return the exports of the module
95 | /******/ return module.exports;
96 | /******/
97 | }
98 | /******/
99 | /************************************************************************/
100 | /******/ /* webpack/runtime/compat get default export */
101 | /******/ (() => {
102 | /******/ // getDefaultExport function for compatibility with non-harmony modules
103 | /******/ __webpack_require__.n = (module) => {
104 | /******/ var getter =
105 | module && module.__esModule
106 | ? /******/ () => module["default"]
107 | : /******/ () => module;
108 | /******/ __webpack_require__.d(getter, { a: getter });
109 | /******/ return getter;
110 | /******/
111 | };
112 | /******/
113 | })();
114 | /******/
115 | /******/ /* webpack/runtime/define property getters */
116 | /******/ (() => {
117 | /******/ // define getter functions for harmony exports
118 | /******/ __webpack_require__.d = (exports, definition) => {
119 | /******/ for (var key in definition) {
120 | /******/ if (
121 | __webpack_require__.o(definition, key) &&
122 | !__webpack_require__.o(exports, key)
123 | ) {
124 | /******/ Object.defineProperty(exports, key, {
125 | enumerable: true,
126 | get: definition[key],
127 | });
128 | /******/
129 | }
130 | /******/
131 | }
132 | /******/
133 | };
134 | /******/
135 | })();
136 | /******/
137 | /******/ /* webpack/runtime/hasOwnProperty shorthand */
138 | /******/ (() => {
139 | /******/ __webpack_require__.o = (obj, prop) =>
140 | Object.prototype.hasOwnProperty.call(obj, prop);
141 | /******/
142 | })();
143 | /******/
144 | /******/ /* webpack/runtime/make namespace object */
145 | /******/ (() => {
146 | /******/ // define __esModule on exports
147 | /******/ __webpack_require__.r = (exports) => {
148 | /******/ if (typeof Symbol !== "undefined" && Symbol.toStringTag) {
149 | /******/ Object.defineProperty(exports, Symbol.toStringTag, {
150 | value: "Module",
151 | });
152 | /******/
153 | }
154 | /******/ Object.defineProperty(exports, "__esModule", { value: true });
155 | /******/
156 | };
157 | /******/
158 | })();
159 | /******/
160 | /************************************************************************/
161 | var __webpack_exports__ = {};
162 | // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
163 | (() => {
164 | /*!**********************!*\
165 | !*** ./src/index.js ***!
166 | \**********************/
167 | __webpack_require__.r(__webpack_exports__);
168 | /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ =
169 | __webpack_require__(/*! react */ "react");
170 | /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default =
171 | /*#__PURE__*/ __webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
172 | /* harmony import */ var _wordpress_hooks__WEBPACK_IMPORTED_MODULE_1__ =
173 | __webpack_require__(/*! @wordpress/hooks */ "@wordpress/hooks");
174 | /* harmony import */ var _wordpress_hooks__WEBPACK_IMPORTED_MODULE_1___default =
175 | /*#__PURE__*/ __webpack_require__.n(
176 | _wordpress_hooks__WEBPACK_IMPORTED_MODULE_1__
177 | );
178 | /* harmony import */ var _wordpress_compose__WEBPACK_IMPORTED_MODULE_2__ =
179 | __webpack_require__(/*! @wordpress/compose */ "@wordpress/compose");
180 | /* harmony import */ var _wordpress_compose__WEBPACK_IMPORTED_MODULE_2___default =
181 | /*#__PURE__*/ __webpack_require__.n(
182 | _wordpress_compose__WEBPACK_IMPORTED_MODULE_2__
183 | );
184 | /* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_3__ =
185 | __webpack_require__(
186 | /*! @wordpress/block-editor */ "@wordpress/block-editor"
187 | );
188 | /* harmony import */ var _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_3___default =
189 | /*#__PURE__*/ __webpack_require__.n(
190 | _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_3__
191 | );
192 | /* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_4__ =
193 | __webpack_require__(/*! @wordpress/components */ "@wordpress/components");
194 | /* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_4___default =
195 | /*#__PURE__*/ __webpack_require__.n(
196 | _wordpress_components__WEBPACK_IMPORTED_MODULE_4__
197 | );
198 | /* harmony import */ var _wordpress_i18n__WEBPACK_IMPORTED_MODULE_5__ =
199 | __webpack_require__(/*! @wordpress/i18n */ "@wordpress/i18n");
200 | /* harmony import */ var _wordpress_i18n__WEBPACK_IMPORTED_MODULE_5___default =
201 | /*#__PURE__*/ __webpack_require__.n(
202 | _wordpress_i18n__WEBPACK_IMPORTED_MODULE_5__
203 | );
204 |
205 | /**
206 | * Add the attribute to the block.
207 | * This is the attribute that will be saved to the database.
208 | *
209 | * @param {object} settings block settings
210 | * @param {string} name block name
211 | * @returns {object} modified settings
212 | *
213 | * @see https://developer.wordpress.org/block-editor/reference-guides/filters/block-filters/#blocks-registerblocktype
214 | */
215 | (0, _wordpress_hooks__WEBPACK_IMPORTED_MODULE_1__.addFilter)(
216 | "blocks.registerBlockType",
217 | "wpdev/is-post-link",
218 | function (settings, name) {
219 | if (name !== "core/button") {
220 | return settings;
221 | }
222 | return {
223 | ...settings,
224 | attributes: {
225 | ...settings.attributes,
226 | isPostLink: {
227 | type: "string",
228 | default: "",
229 | },
230 | customFieldName: {
231 | type: "string",
232 | default: "",
233 | },
234 | },
235 | };
236 | }
237 | );
238 |
239 | /**
240 | * Edit component for the block.
241 | *
242 | * @param {object} props block props
243 | * @returns {JSX}
244 | */
245 | function Edit(props) {
246 | const setIsPostLink = (value) => {
247 | props.setAttributes({
248 | isPostLink: value,
249 | });
250 | };
251 | const setCustomFieldName = (value) => {
252 | props.setAttributes({
253 | customFieldName: value,
254 | });
255 | };
256 | return (0, react__WEBPACK_IMPORTED_MODULE_0__.createElement)(
257 | _wordpress_block_editor__WEBPACK_IMPORTED_MODULE_3__.InspectorControls,
258 | null,
259 | (0, react__WEBPACK_IMPORTED_MODULE_0__.createElement)(
260 | _wordpress_components__WEBPACK_IMPORTED_MODULE_4__.PanelBody,
261 | {
262 | title: (0, _wordpress_i18n__WEBPACK_IMPORTED_MODULE_5__.__)(
263 | "Post Permalink"
264 | ),
265 | },
266 | (0, react__WEBPACK_IMPORTED_MODULE_0__.createElement)(
267 | _wordpress_components__WEBPACK_IMPORTED_MODULE_4__.PanelRow,
268 | null,
269 | (0, react__WEBPACK_IMPORTED_MODULE_0__.createElement)(
270 | _wordpress_components__WEBPACK_IMPORTED_MODULE_4__.SelectControl,
271 | {
272 | label: (0, _wordpress_i18n__WEBPACK_IMPORTED_MODULE_5__.__)(
273 | "Link this button to a post value?"
274 | ),
275 | value: props.attributes.isPostLink,
276 | options: [
277 | {
278 | label: (0, _wordpress_i18n__WEBPACK_IMPORTED_MODULE_5__.__)(
279 | "No"
280 | ),
281 | value: "",
282 | },
283 | {
284 | label: (0, _wordpress_i18n__WEBPACK_IMPORTED_MODULE_5__.__)(
285 | "Yes, to the permalink"
286 | ),
287 | value: "permalink",
288 | },
289 | {
290 | label: (0, _wordpress_i18n__WEBPACK_IMPORTED_MODULE_5__.__)(
291 | "Yes, to a custom field"
292 | ),
293 | value: "custom_field",
294 | },
295 | ],
296 | onChange: setIsPostLink,
297 | help: (0, _wordpress_i18n__WEBPACK_IMPORTED_MODULE_5__.__)(
298 | "This is mainly used for buttons inside query loops."
299 | ),
300 | }
301 | )
302 | ),
303 | "custom_field" === props.attributes.isPostLink &&
304 | (0, react__WEBPACK_IMPORTED_MODULE_0__.createElement)(
305 | _wordpress_components__WEBPACK_IMPORTED_MODULE_4__.PanelRow,
306 | null,
307 | (0, react__WEBPACK_IMPORTED_MODULE_0__.createElement)(
308 | _wordpress_components__WEBPACK_IMPORTED_MODULE_4__.TextControl,
309 | {
310 | label: (0, _wordpress_i18n__WEBPACK_IMPORTED_MODULE_5__.__)(
311 | "Custom field name"
312 | ),
313 | value: props.attributes.customFieldName,
314 | onChange: setCustomFieldName,
315 | help: (0, _wordpress_i18n__WEBPACK_IMPORTED_MODULE_5__.__)(
316 | "The name of the custom field to link to."
317 | ),
318 | }
319 | )
320 | )
321 | )
322 | );
323 | }
324 |
325 | /**
326 | * Add the edit component to the block.
327 | * This is the component that will be rendered in the editor.
328 | * It will be rendered after the original block edit component.
329 | *
330 | * @param {function} BlockEdit Original component
331 | * @returns {function} Wrapped component
332 | *
333 | * @see https://developer.wordpress.org/block-editor/developers/filters/block-filters/#editor-blockedit
334 | */
335 | (0, _wordpress_hooks__WEBPACK_IMPORTED_MODULE_1__.addFilter)(
336 | "editor.BlockEdit",
337 | "wpdev/is-post-link",
338 | (0,
339 | _wordpress_compose__WEBPACK_IMPORTED_MODULE_2__.createHigherOrderComponent)(
340 | (BlockEdit) => {
341 | return (props) => {
342 | if (props.name !== "core/button") {
343 | return (0, react__WEBPACK_IMPORTED_MODULE_0__.createElement)(
344 | BlockEdit,
345 | {
346 | ...props,
347 | }
348 | );
349 | }
350 | return (0, react__WEBPACK_IMPORTED_MODULE_0__.createElement)(
351 | react__WEBPACK_IMPORTED_MODULE_0__.Fragment,
352 | null,
353 | (0, react__WEBPACK_IMPORTED_MODULE_0__.createElement)(BlockEdit, {
354 | ...props,
355 | }),
356 | (0, react__WEBPACK_IMPORTED_MODULE_0__.createElement)(Edit, {
357 | ...props,
358 | })
359 | );
360 | };
361 | }
362 | )
363 | );
364 | })();
365 |
366 | /******/
367 | })();
368 | //# sourceMappingURL=index.js.map
369 |
--------------------------------------------------------------------------------
/build/index.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"index.js","mappings":"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","sources":["webpack://example-query-loop-button/external window \"React\"","webpack://example-query-loop-button/external window [\"wp\",\"blockEditor\"]","webpack://example-query-loop-button/external window [\"wp\",\"components\"]","webpack://example-query-loop-button/external window [\"wp\",\"compose\"]","webpack://example-query-loop-button/external window [\"wp\",\"hooks\"]","webpack://example-query-loop-button/external window [\"wp\",\"i18n\"]","webpack://example-query-loop-button/webpack/bootstrap","webpack://example-query-loop-button/webpack/runtime/compat get default export","webpack://example-query-loop-button/webpack/runtime/define property getters","webpack://example-query-loop-button/webpack/runtime/hasOwnProperty shorthand","webpack://example-query-loop-button/webpack/runtime/make namespace object","webpack://example-query-loop-button/./src/index.js"],"sourcesContent":["module.exports = window[\"React\"];","module.exports = window[\"wp\"][\"blockEditor\"];","module.exports = window[\"wp\"][\"components\"];","module.exports = window[\"wp\"][\"compose\"];","module.exports = window[\"wp\"][\"hooks\"];","module.exports = window[\"wp\"][\"i18n\"];","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { addFilter } from \"@wordpress/hooks\";\nimport { createHigherOrderComponent } from \"@wordpress/compose\";\nimport { InspectorControls } from \"@wordpress/block-editor\";\nimport {\n\tSelectControl,\n\tTextControl,\n\tPanelBody,\n\tPanelRow,\n} from \"@wordpress/components\";\nimport { __ } from \"@wordpress/i18n\";\n\n/**\n * Add the attribute to the block.\n * This is the attribute that will be saved to the database.\n *\n * @param {object} settings block settings\n * @param {string} name block name\n * @returns {object} modified settings\n *\n * @see https://developer.wordpress.org/block-editor/reference-guides/filters/block-filters/#blocks-registerblocktype\n */\naddFilter(\n\t\"blocks.registerBlockType\",\n\t\"wpdev/is-post-link\",\n\tfunction (settings, name) {\n\t\tif (name !== \"core/button\") {\n\t\t\treturn settings;\n\t\t}\n\n\t\treturn {\n\t\t\t...settings,\n\t\t\tattributes: {\n\t\t\t\t...settings.attributes,\n\t\t\t\tisPostLink: {\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t\tdefault: \"\",\n\t\t\t\t},\n\t\t\t\tcustomFieldName: {\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t\tdefault: \"\",\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t},\n);\n\n/**\n * Edit component for the block.\n *\n * @param {object} props block props\n * @returns {JSX}\n */\nfunction Edit(props) {\n\tconst setIsPostLink = (value) => {\n\t\tprops.setAttributes({ isPostLink: value });\n\t};\n\n\tconst setCustomFieldName = (value) => {\n\t\tprops.setAttributes({ customFieldName: value });\n\t};\n\n\treturn (\n\t\t\n\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t{\"custom_field\" === props.attributes.isPostLink && (\n\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t)}\n\t\t\t\n\t\t\n\t);\n}\n\n/**\n * Add the edit component to the block.\n * This is the component that will be rendered in the editor.\n * It will be rendered after the original block edit component.\n *\n * @param {function} BlockEdit Original component\n * @returns {function} Wrapped component\n *\n * @see https://developer.wordpress.org/block-editor/developers/filters/block-filters/#editor-blockedit\n */\naddFilter(\n\t\"editor.BlockEdit\",\n\t\"wpdev/is-post-link\",\n\tcreateHigherOrderComponent((BlockEdit) => {\n\t\treturn (props) => {\n\t\t\tif (props.name !== \"core/button\") {\n\t\t\t\treturn ;\n\t\t\t}\n\n\t\t\treturn (\n\t\t\t\t<>\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t>\n\t\t\t);\n\t\t};\n\t}),\n);\n"],"names":["addFilter","createHigherOrderComponent","InspectorControls","SelectControl","TextControl","PanelBody","PanelRow","__","settings","name","attributes","isPostLink","type","default","customFieldName","Edit","props","setIsPostLink","value","setAttributes","setCustomFieldName","createElement","title","label","options","onChange","help","BlockEdit","Fragment"],"sourceRoot":""}
2 |
--------------------------------------------------------------------------------
/example-query-loop-button.php:
--------------------------------------------------------------------------------
1 | next_tag( 'a' ) ) {
47 | $p->set_attribute( 'href', get_permalink() );
48 | $p->set_attribute( 'rel', 'bookmark' );
49 | $block_content = $p->get_updated_html();
50 | }
51 | }
52 | if ( isset( $block['attrs']['isPostLink'] ) && 'custom_field' === $block['attrs']['isPostLink'] && isset( $block['attrs']['customFieldName'] ) ) {
53 | $p = new WP_HTML_Tag_Processor( $block_content );
54 | if ( $p->next_tag( 'a' ) ) {
55 | $p->set_attribute( 'href', get_post_meta( get_the_ID(), $block['attrs']['customFieldName'], true ) );
56 | $block_content = $p->get_updated_html();
57 | }
58 | }
59 |
60 | return $block_content;
61 | }
62 | add_filter( 'render_block_core/button', __NAMESPACE__ . '\filter_button_block_render_block', 10, 2 );
63 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example-query-loop-button",
3 | "version": "0.1.0",
4 | "description": "Example block extension for the WordPress core/button block.",
5 | "author": "The WordPress Contributors",
6 | "license": "GPL-2.0-or-later",
7 | "main": "build/index.js",
8 | "scripts": {
9 | "build": "wp-scripts build",
10 | "format": "wp-scripts format",
11 | "lint:css": "wp-scripts lint-style",
12 | "lint:js": "wp-scripts lint-js",
13 | "packages-update": "wp-scripts packages-update",
14 | "plugin-zip": "wp-scripts plugin-zip",
15 | "start": "wp-scripts start"
16 | },
17 | "devDependencies": {
18 | "@wordpress/scripts": "^26.17.0"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Example Query Loop Button Extension
2 |
3 | Extends the button block to allow you to populate the `href` value automatically with the permalink or to a custom meta field. This is especially useful in the query loop, where you may want a custom button for your read more link.
4 |
5 | [🎥 The full tutorial](https://www.briancoords.com/adding-custom-fields-attributes-to-core-blocks/).
6 |
7 |
8 |
9 | This repo is part of a tutorial that teaches you how to:
10 |
11 | 1. Add custom attributes (aka custom fields) to a core block, and
12 | 2. Modify the final frontend markup of the block based on the attribute values
13 |
14 |
15 |
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 | === Example Query Loop Button ===
2 | Contributors: bacoords
3 | Tags: block
4 | Tested up to: 6.4.1
5 | Stable tag: 0.1.0
6 | License: GPL-2.0-or-later
7 | License URI: https://www.gnu.org/licenses/gpl-2.0.html
8 |
9 | Example block extension for the WordPress core/button block
10 |
11 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import { addFilter } from "@wordpress/hooks";
2 | import { createHigherOrderComponent } from "@wordpress/compose";
3 | import { InspectorControls } from "@wordpress/block-editor";
4 | import {
5 | SelectControl,
6 | TextControl,
7 | PanelBody,
8 | PanelRow,
9 | } from "@wordpress/components";
10 | import { __ } from "@wordpress/i18n";
11 |
12 | /**
13 | * Add the attribute to the block.
14 | * This is the attribute that will be saved to the database.
15 | *
16 | * @param {object} settings block settings
17 | * @param {string} name block name
18 | * @returns {object} modified settings
19 | *
20 | * @see https://developer.wordpress.org/block-editor/reference-guides/filters/block-filters/#blocks-registerblocktype
21 | */
22 | addFilter(
23 | "blocks.registerBlockType",
24 | "wpdev/is-post-link",
25 | function (settings, name) {
26 | if (name !== "core/button") {
27 | return settings;
28 | }
29 |
30 | return {
31 | ...settings,
32 | attributes: {
33 | ...settings.attributes,
34 | isPostLink: {
35 | type: "string",
36 | default: "",
37 | },
38 | customFieldName: {
39 | type: "string",
40 | default: "",
41 | },
42 | },
43 | };
44 | }
45 | );
46 |
47 | /**
48 | * Edit component for the block.
49 | *
50 | * @param {object} props block props
51 | * @returns {JSX}
52 | */
53 | function Edit(props) {
54 | const setIsPostLink = (value) => {
55 | props.setAttributes({ isPostLink: value });
56 | };
57 |
58 | const setCustomFieldName = (value) => {
59 | props.setAttributes({ customFieldName: value });
60 | };
61 |
62 | return (
63 |
64 |
65 |
66 |
77 |
78 | {"custom_field" === props.attributes.isPostLink && (
79 |
80 |
86 |
87 | )}
88 |
89 |
90 | );
91 | }
92 |
93 | /**
94 | * Add the edit component to the block.
95 | * This is the component that will be rendered in the editor.
96 | * It will be rendered after the original block edit component.
97 | *
98 | * @param {function} BlockEdit Original component
99 | * @returns {function} Wrapped component
100 | *
101 | * @see https://developer.wordpress.org/block-editor/developers/filters/block-filters/#editor-blockedit
102 | */
103 | addFilter(
104 | "editor.BlockEdit",
105 | "wpdev/is-post-link",
106 | createHigherOrderComponent((BlockEdit) => {
107 | return (props) => {
108 | if (props.name !== "core/button") {
109 | return ;
110 | }
111 |
112 | return (
113 | <>
114 |
115 |
116 | >
117 | );
118 | };
119 | })
120 | );
121 |
--------------------------------------------------------------------------------