├── readme.txt ├── .editorconfig ├── .gitignore ├── package.json ├── readme.md ├── example-query-loop-button.php └── src └── index.js /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 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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 | Xnapper-2023-11-28-21 31 38 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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------