Skip to content

Commit

Permalink
Merge pull request #147 from alleyinteractive/feature/LEDE-2650/nb-bu…
Browse files Browse the repository at this point in the history
…tton-block

LEDE-2650 Newsletter Button Block
  • Loading branch information
cahdeemer authored Jun 17, 2024
2 parents 57fb49e + bbcd204 commit dfb754f
Show file tree
Hide file tree
Showing 17 changed files with 422 additions and 17 deletions.
36 changes: 36 additions & 0 deletions block-filters/button/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
/**
* Core button block modifications.
*
* @package wp-newsletter-builder
*/

namespace WP_Newsletter_Builder;

/**
* Registers assets so that they can be enqueued through Gutenberg in
* the corresponding context.
*/
function register_button_scripts(): void {
wp_register_script(
'plugin-newsletter-button',
get_entry_asset_url( 'wp-newsletter-builder-button' ),
get_asset_dependency_array( 'wp-newsletter-builder-button' ),
get_asset_version( 'wp-newsletter-builder-button' ),
true
);
wp_set_script_translations( 'plugin-newsletter-button' );
}
add_action( 'init', __NAMESPACE__ . '\register_button_scripts' );

/**
* Enqueue block editor assets for button.
*/
function action_enqueue_button_assets(): void {
$post_type = get_edit_post_type();
if ( ( 'nb_newsletter' !== $post_type ) && ( 'nb_template' !== $post_type ) ) {
return;
}
wp_enqueue_script( 'plugin-newsletter-button' );
}
add_action( 'enqueue_block_editor_assets', __NAMESPACE__ . '\action_enqueue_button_assets' );
72 changes: 72 additions & 0 deletions block-filters/button/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { addFilter } from '@wordpress/hooks';
import domReady from '@wordpress/dom-ready';
import { unregisterBlockStyle } from '@wordpress/blocks';

/**
* Modifies supports for Button and Buttons blocks.
*
* @param {Object} settings - The original block settings.
* @param {string} name - The name of the block.
*
* @returns {Object} The modified block settings.
*/
// @ts-ignore
function modifyButtonSupports(settings, name) {
// Bail early if the block does not have supports.
if (!settings?.supports) {
return settings;
}
// Only apply to Button blocks.
if (
(name === 'core/button') || (name === 'core/buttons')
) {
return {
...settings,
supports: Object.assign(settings.supports, {
anchor: false,
color: {
background: false,
text: false,
},
customClassName: false,
inserter: false,
layout: false,
shadow: false,
spacing: false,
styles: [],
typography: {
__experimentalFontSize: false,
__experimentalLineHeight: false,
__experimentalLetterSpacing: true,
__experimentalFontFamily: false,
__experimentalFontWeight: false,
__experimentalFontStyle: false,
__experimentalTextTransform: true,
},
__experimentalBorder: {
color: false,
radius: true,
style: true,
width: false,
__experimentalSkipSerialization: true,
__experimentalDefaultControls: {
color: false,
radius: true,
style: true,
width: false,
},
},
}),
};
}
return settings;
}

addFilter(
'blocks.registerBlockType',
'wp-newsletter-builder/button',
modifyButtonSupports,
);

// @ts-ignore
domReady(() => { unregisterBlockStyle('core/button', ['fill', 'outline']); });
36 changes: 36 additions & 0 deletions blocks/button/block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "wp-newsletter-builder/button",
"version": "0.1.0",
"title": "Newsletter Button",
"allowedBlocks": ["core/button"],
"category": "design",
"icon": "button",
"description": "Button wrapper that provides email-friendly enhancements",
"textdomain": "button",
"editorScript": "file:index.ts",
"editorStyle": "file:index.css",
"style": [
"file:style-index.css"
],
"render": "file:render.php",
"attributes": {
"textColor": {
"type": "string",
"default": "#fff"
},
"bgColor": {
"type": "string",
"default": "#0279af"
},
"radius": {
"type": "string",
"default": "0"
},
"btnWidth": {
"type": "string",
"default": "max-content"
}
}
}
91 changes: 91 additions & 0 deletions blocks/button/edit.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { useEffect } from 'react';
import { __ } from '@wordpress/i18n';
import { useBlockProps, InspectorControls, InnerBlocks } from '@wordpress/block-editor';
import { ColorPicker, PanelBody } from '@wordpress/components';
import useInnerBlockAttributes from '@/hooks/useInnerBlocksAttributes';

/**
* Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
* Those files can contain any CSS code that gets applied to the editor.
*
* @see https://www.npmjs.com/package/@wordpress/scripts#using-css
*/
// Uncomment this line if you want to import a CSS file for this block.
// import './index.scss';

/**
* The edit function describes the structure of your block in the context of the
* editor. This represents what the editor will render when the block is used.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#edit
*
* @return {WPElement} Element to render.
*/
interface EditProps {
attributes: {
bgColor?: string;
btnWidth?: string,
radius?: string,
textColor?: string,
};
setAttributes: (attributes: {}) => void;
clientId: string,
}

export default function Edit({
attributes: {
bgColor = '#0279af',
btnWidth = 'max-content',
radius = '0',
textColor = '#fff',
},
setAttributes,
clientId,
}: EditProps) {
const TEMPLATE = [['core/button']];
const innerBlockAttributes = useInnerBlockAttributes(clientId);
const innerBorderRadius = innerBlockAttributes[0]?.style?.border?.radius || '0';
const innerWidth = innerBlockAttributes[0]?.width;
const buttonStyles = {
backgroundColor: bgColor,
borderRadius: radius,
color: textColor,
margin: '0 auto',
width: btnWidth,
};

useEffect(() => {
setAttributes({
radius: innerBorderRadius,
btnWidth: innerWidth !== undefined ? `${innerWidth}%` : 'max-content',
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [innerBorderRadius, innerWidth]);

return (
<>
<InspectorControls>
<PanelBody title="Button Color">
<h3>{__('Background color', 'wp-newsletter-builder')}</h3>
{/* Using ColorPicker instead of ColorPalette to ensure email-friendly values. */}
<ColorPicker
color={bgColor}
onChange={(color) => setAttributes({ bgColor: color })}
/>
<h3>{__('Text color', 'wp-newsletter-builder')}</h3>
<ColorPicker
color={textColor}
onChange={(color) => setAttributes({ textColor: color })}
/>
</PanelBody>
</InspectorControls>
<div {...useBlockProps({ style: buttonStyles })}>
<InnerBlocks
// @ts-ignore
template={TEMPLATE}
templateLock="all"
/>
</div>
</>
);
}
21 changes: 21 additions & 0 deletions blocks/button/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php
/**
* Block Name: Newsletter Button.
*
* @package wp-newsletter-builder
*/

/**
* Registers the block using the metadata loaded from the `block.json` file.
* Behind the scenes, it registers also all assets so they can be enqueued
* through the block editor in the corresponding context.
*
* @see https://developer.wordpress.org/reference/functions/register_block_type/
*/
function wp_newsletter_builder_button_block_init() {

Check failure on line 15 in blocks/button/index.php

View workflow job for this annotation

GitHub Actions / phpstan / phpstan PHP 8.2

Function wp_newsletter_builder_button_block_init() has no return type specified.
// Register the block by passing the location of block.json.
register_block_type(
__DIR__
);
}
add_action( 'init', 'wp_newsletter_builder_button_block_init' );
47 changes: 47 additions & 0 deletions blocks/button/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Registers a new block provided a unique name and an object defining its behavior.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
*/
import { registerBlockType } from '@wordpress/blocks';
import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';

/**
* Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
* All files containing `style` keyword are bundled together. The code used
* gets applied both to the front of your site and to the editor.
*
* @see https://www.npmjs.com/package/@wordpress/scripts#using-css
*/
// Uncomment this line if you want to import a CSS file for this block.
// import './style.scss';

/**
* Internal dependencies
*/
import edit from './edit';
import metadata from './block.json';

/**
* Every block starts by registering a new block type definition.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
*/
registerBlockType(
/* @ts-expect-error Provided types are inaccurate to the actual plugin API. */
metadata,
{
apiVersion: 2,
edit,
save: () => {
const blockProps = useBlockProps.save();
return (
<div {...blockProps}>
{/* @ts-ignore */}
<InnerBlocks.Content />
</div>
);
},
title: metadata.title,
},
);
20 changes: 20 additions & 0 deletions blocks/button/render.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php
/**
* All of the parameters passed to the function where this file is being required are accessible in this scope:
*
* @param array $attributes The array of attributes for this block.
* @param string $content Rendered block output. ie. <InnerBlocks.Content />.
* @param WP_Block $block_instance The instance of the WP_Block class that represents the block being rendered.
*
* @package wp-newsletter-builder
*/

$wp_newsletter_builder_button_color = $attributes['textColor'] ?? '';
$wp_newsletter_builder_button_bg_color = $attributes['bgColor'] ?? '';
$wp_newsletter_builder_button_radius = $attributes['radius'] ?? '';
$wp_newsletter_builder_button_width = $attributes['btnWidth'] ?? '';
?>

<div style="margin: 0 auto; width: <?php echo esc_attr( $wp_newsletter_builder_button_width ); ?>; color: <?php echo esc_attr( $wp_newsletter_builder_button_color ); ?>; background-color: <?php echo esc_attr( $wp_newsletter_builder_button_bg_color ); ?>; border-radius: <?php echo esc_attr( $wp_newsletter_builder_button_radius ); ?>">
<?php echo wp_kses_post( $content ?? '' ); ?>
</div>
2 changes: 1 addition & 1 deletion blocks/post-read-more/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default function Edit({
<div {...useBlockProps({ className: 'newsletter-read-more has-text-align-center' })}>
<RichText
tagName="span"
className="wp-element-button"
className="read-more-button"
value={buttonText}
onChange={(value) => setAttributes({ readMoreText: value })}
/>
Expand Down
2 changes: 1 addition & 1 deletion blocks/post-read-more/render.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<w:anchorlock/>
<center>
<![endif]-->
<a class="wp-element-button" href="<?php echo esc_url( $wp_newsletter_builder_post_permalink ); ?>">
<a class="read-more-button" href="<?php echo esc_url( $wp_newsletter_builder_post_permalink ); ?>">
<?php echo esc_html( $wp_newsletter_builder_read_more_text ); ?>
</a>
<!--[if mso]>
Expand Down
15 changes: 15 additions & 0 deletions hooks/useInnerBlocks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Custom Hooks: useInnerBlocks

A custom React hook that returns the current block's inner blocks.

## Usage

```jsx
const MyBlock = ({
clientId
}) => {
const blocks = useInnerBlocks(clientId);

...
};
```
15 changes: 15 additions & 0 deletions hooks/useInnerBlocks/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { store } from '@wordpress/block-editor';
import { useSelect } from '@wordpress/data';

/**
* Get all children blocks of any given block.
*
* @param {string} clientId The block client ID.
* @returns {Array} An array of child blocks.
*/
const useInnerBlocks = (clientId) => useSelect(
(select) => select(store).getBlocks(clientId),
[clientId],
);

export default useInnerBlocks;
15 changes: 15 additions & 0 deletions hooks/useInnerBlocksAttributes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Custom Hooks: useInnerBlocksAttributes

A custom React hook that returns the current blocks' inner block's attributes.

## Usage

```jsx
const MyBlock = ({
clientId
}) => {
const innerBlockAttributes = useInnerBlocksAttributes(clientId);

...
};
```
Loading

0 comments on commit dfb754f

Please sign in to comment.