diff --git a/src/blocks/my-account-button/README.md b/src/blocks/my-account-button/README.md index 82b1349410..df303d6b9d 100644 --- a/src/blocks/my-account-button/README.md +++ b/src/blocks/my-account-button/README.md @@ -6,6 +6,11 @@ Provides a reader account/sign-in button for sites using Newspack Reader Activat - Signed in label (`signedInLabel`): Text shown when the reader is authenticated. - Signed out label (`signedOutLabel`): Text shown when the reader is not authenticated. +### Display +The button also has the ability to toggle on/off the display of the icon or text label. You cannot toggle off both the icon and label at the same time. + +When only the icon is visible, screenreaders will still be able to read the label, even if it's not visible. If this hidden label needs to be edited, it will need to be toggled back on in the editor, changed, and then hidden again. + ## Editor behavior - Use the toolbar toggle (Signed in / Signed out) to edit each label. diff --git a/src/blocks/my-account-button/block.json b/src/blocks/my-account-button/block.json index e4d50aafa9..1a0ecac5ac 100644 --- a/src/blocks/my-account-button/block.json +++ b/src/blocks/my-account-button/block.json @@ -20,6 +20,10 @@ "signedOutLabel": { "type": "string", "default": "Sign in" + }, + "className": { + "type": "string", + "default": "" } }, "supports": { diff --git a/src/blocks/my-account-button/class-my-account-button-block.php b/src/blocks/my-account-button/class-my-account-button-block.php index a7a85a4cd7..766fd7a87e 100644 --- a/src/blocks/my-account-button/class-my-account-button-block.php +++ b/src/blocks/my-account-button/class-my-account-button-block.php @@ -93,18 +93,31 @@ public static function render_block( $attrs ) { $default_attrs = [ 'signedInLabel' => __( 'My Account', 'newspack-plugin' ), 'signedOutLabel' => __( 'Sign in', 'newspack-plugin' ), + 'className' => '', ]; $attrs = \wp_parse_args( $attrs, $default_attrs ); - $is_signed_in = \is_user_logged_in(); - $label = $is_signed_in ? $attrs['signedInLabel'] : $attrs['signedOutLabel']; - if ( '' === trim( (string) $label ) ) { - return ''; + $is_signed_in = \is_user_logged_in(); + $signed_in_label = '' === trim( (string) $attrs['signedInLabel'] ) ? $default_attrs['signedInLabel'] : $attrs['signedInLabel']; + $signed_out_label = '' === trim( (string) $attrs['signedOutLabel'] ) ? $default_attrs['signedOutLabel'] : $attrs['signedOutLabel']; + $label = $is_signed_in ? $signed_in_label : $signed_out_label; + + // Display mode from block style class in className (default = icon + text). + $classes = explode( ' ', (string) $attrs['className'] ); + if ( in_array( 'is-style-icon-only', $classes, true ) ) { + $show_label = false; + $show_icon = true; + } elseif ( in_array( 'is-style-text-only', $classes, true ) ) { + $show_label = true; + $show_icon = false; + } else { + $show_label = true; + $show_icon = true; } $account_url = self::get_account_url(); - /** Do not render link for authenticated readers if account page doesn't exist. */ + // Do not render link for authenticated readers if account page doesn't exist. if ( empty( $account_url ) && \is_user_logged_in() ) { return ''; } @@ -118,8 +131,8 @@ public static function render_block( $attrs ) { } $labels = [ - 'signedin' => $attrs['signedInLabel'], - 'signedout' => $attrs['signedOutLabel'], + 'signedin' => $signed_in_label, + 'signedout' => $signed_out_label, ]; $extra_classes = [ @@ -128,45 +141,50 @@ public static function render_block( $attrs ) { 'newspack-reader__account-link', ]; - /** Get default wrapper attributes to extract custom classes */ + // Get default wrapper attributes to extract custom classes. $default_wrapper_attributes = \get_block_wrapper_attributes(); - /** Extract custom classes (everything except the default block class) */ - $default_block_class = 'wp-block-newspack-my-account-button'; - $custom_classes = []; + // Extract custom classes (everything except the default block class). + $custom_classes = []; - /** Parse class attribute from default wrapper */ + // Parse class attribute from default wrapper. if ( \preg_match( '/class=["\']([^"\']+)["\']/', $default_wrapper_attributes, $matches ) ) { $all_classes = \explode( ' ', $matches[1] ); foreach ( $all_classes as $class ) { $class = \trim( $class ); - /** Only include classes that contain "-size" (e.g., has-small-size) */ + // Only include classes that contain "-size" (e.g., has-small-size). if ( ! empty( $class ) && \strpos( $class, '-size' ) !== false ) { $custom_classes[] = $class; } } } - /** Build wrapper div classes */ - $wrapper_div_classes = [ 'wp-block-buttons' ]; + // Build wrapper div classes. + $wrapper_div_classes = [ 'wp-block-buttons', 'is-layout-flex' ]; if ( ! empty( $custom_classes ) ) { $wrapper_div_classes = \array_merge( $wrapper_div_classes, $custom_classes ); } - $wrapper_attributes = \get_block_wrapper_attributes( - [ - 'class' => implode( ' ', $extra_classes ), - 'href' => \esc_url_raw( $href ), - ] - ); + $wrapper_attribute_args = [ + 'class' => implode( ' ', $extra_classes ), + 'href' => \esc_url_raw( $href ), + 'data-newspack-logged-in' => $is_signed_in ? '1' : '0', + ]; + $wrapper_attributes = \get_block_wrapper_attributes( $wrapper_attribute_args ); $link = '
'; $link .= '
'; $link .= ''; - $link .= ''; - $link .= ''; + if ( $show_icon ) { + $link .= ''; + } + $label_classes = [ 'newspack-reader__account-link__label' ]; + if ( ! $show_label ) { + $label_classes[] = 'screen-reader-text'; + } + $link .= '' . \esc_html( $label ) . ''; $link .= ''; $link .= '
'; $link .= '
'; diff --git a/src/blocks/my-account-button/edit.js b/src/blocks/my-account-button/edit.js index fcca8703c7..edede478d1 100644 --- a/src/blocks/my-account-button/edit.js +++ b/src/blocks/my-account-button/edit.js @@ -24,16 +24,20 @@ import { } from '@wordpress/block-editor'; import { ToolbarButton, ToolbarGroup } from '@wordpress/components'; -/** - * Internal dependencies - */ function MyAccountButtonEdit( { attributes, setAttributes } ) { - const { signedInLabel, signedOutLabel, style, className: customClassName } = attributes; + const { signedInLabel, signedOutLabel, style, className: blockClassName } = attributes; const borderProps = useBorderProps( attributes ); const colorProps = useColorProps( attributes ); const spacingProps = useSpacingProps( attributes ); + const classes = ( blockClassName || '' ).split( ' ' ); + const isIconOnly = classes.includes( 'is-style-icon-only' ); + const isTextOnly = classes.includes( 'is-style-text-only' ); + const isLabelVisible = ! isIconOnly; + const isIconVisible = ! isTextOnly; + const blockProps = useBlockProps( { className: classnames( + blockClassName, 'wp-block-button__link', 'newspack-reader__account-link', 'wp-block-newspack-my-account-button__link', @@ -51,52 +55,62 @@ function MyAccountButtonEdit( { attributes, setAttributes } ) { ...spacingProps.style, }, } ); - const isReaderActivationEnabled = typeof newspack_blocks === 'undefined' || newspack_blocks.has_reader_activation; + const isReaderActivationEnabled = typeof newspack_blocks === 'undefined' || newspack_blocks.has_reader_activation; const [ previewState, setPreviewState ] = useState( 'signedout' ); const isSignedOutPreview = previewState === 'signedout'; const activeLabel = isSignedOutPreview ? signedOutLabel : signedInLabel; const placeholderText = isSignedOutPreview ? __( 'Sign in', 'newspack-plugin' ) : __( 'My Account', 'newspack-plugin' ); function setButtonText( newText ) { - const cleaned = stripHTML( newText ); - setAttributes( isSignedOutPreview ? { signedOutLabel: cleaned } : { signedInLabel: cleaned } ); + setAttributes( isSignedOutPreview ? { signedOutLabel: stripHTML( newText ) } : { signedInLabel: stripHTML( newText ) } ); + } + + if ( ! isReaderActivationEnabled ) { + return
; } - return ! isReaderActivationEnabled ? ( -
- ) : ( + return ( <> - - - setPreviewState( 'signedout' ) } - style={ { paddingLeft: '12px', paddingRight: '12px' } } - > - { __( 'Signed out', 'newspack-plugin' ) } - - setPreviewState( 'signedin' ) } - style={ { paddingLeft: '12px', paddingRight: '12px' } } - > - { __( 'Signed in', 'newspack-plugin' ) } - - - -
+ { isLabelVisible && ( + + + setPreviewState( 'signedout' ) } + style={ { paddingLeft: '12px', paddingRight: '12px' } } + > + { __( 'Signed out', 'newspack-plugin' ) } + + setPreviewState( 'signedin' ) } + style={ { paddingLeft: '12px', paddingRight: '12px' } } + > + { __( 'Signed in', 'newspack-plugin' ) } + + + + ) } +
- + { isIconVisible && ( + + ) } setButtonText( value ) } + onChange={ setButtonText } withoutInteractiveFormatting />
diff --git a/src/blocks/my-account-button/index.js b/src/blocks/my-account-button/index.js index ac415011d3..c8bd03462b 100644 --- a/src/blocks/my-account-button/index.js +++ b/src/blocks/my-account-button/index.js @@ -9,12 +9,30 @@ import './style.scss'; /** * WordPress dependencies */ +import { registerBlockStyle } from '@wordpress/blocks'; +import { __ } from '@wordpress/i18n'; import { button as icon } from '@wordpress/icons'; const { name } = metadata; export { metadata, name }; +registerBlockStyle( name, { + name: 'default', + label: __( 'Default', 'newspack-plugin' ), + isDefault: true, +} ); + +registerBlockStyle( name, { + name: 'icon-only', + label: __( 'Icon only', 'newspack-plugin' ), +} ); + +registerBlockStyle( name, { + name: 'text-only', + label: __( 'Text only', 'newspack-plugin' ), +} ); + export const settings = { title: metadata.title, icon: { diff --git a/src/blocks/my-account-button/style.scss b/src/blocks/my-account-button/style.scss index 5a9fa2b644..789de292f3 100644 --- a/src/blocks/my-account-button/style.scss +++ b/src/blocks/my-account-button/style.scss @@ -2,13 +2,22 @@ &__icon { display: grid; place-items: center; + } + + svg { + fill: currentcolor; + height: max(24px, 1.5em); + width: max(24px, 1.5em); + } + &:not(:has(.screen-reader-text)) { svg { - fill: currentcolor; - height: max(24px, 1.5em); margin-left: calc( max(4px, 0.25em) * -1); margin-right: calc( max(4px, 0.25em) * -1); - width: max(24px, 1.5em); } } + + .wp-block-buttons > .wp-block-button:has(&) { + display: inline-flex; + } } diff --git a/src/reader-activation-auth/index.js b/src/reader-activation-auth/index.js index 9a159f3584..3142e86add 100644 --- a/src/reader-activation-auth/index.js +++ b/src/reader-activation-auth/index.js @@ -103,6 +103,12 @@ window.newspackRAS.push( readerActivation => { const labels = JSON.parse( link.getAttribute( 'data-labels' ) ); const labelEl = link.querySelector( '.newspack-reader__account-link__label' ); if ( labelEl ) { + // Change the label for the My Account button only. + const isLoggedIn = link.getAttribute( 'data-newspack-logged-in' ) === '1'; + if ( isLoggedIn ) { + labelEl.textContent = labels.signedin; + return; + } labelEl.textContent = reader?.authenticated ? labels.signedin : labels.signedout; // Set my account link href if the reader is authenticated. diff --git a/tests/unit-tests/class-test-my-account-button-block.php b/tests/unit-tests/class-test-my-account-button-block.php index 6eece748cc..a3fff2e41a 100644 --- a/tests/unit-tests/class-test-my-account-button-block.php +++ b/tests/unit-tests/class-test-my-account-button-block.php @@ -96,16 +96,81 @@ public function test_render_block_signed_in() { } /** - * Test empty labels -- render nothing if a button's state has an empty label. + * Test empty signed-out label falls back to default. */ - public function test_render_block_empty_label() { + public function test_render_block_empty_signed_out_label() { self::$reader_activation_enabled = true; $signed_out_output = do_blocks( '' ); - $this->assertSame( '', trim( $signed_out_output ) ); + $this->assertNotEmpty( $signed_out_output ); + $this->assertStringContainsString( '"signedout":"Sign in"', $signed_out_output ); + } + + /** + * Test icon-only style applies the screen-reader-text class to the label. + */ + public function test_render_block_icon_only_style_adds_screen_reader_text_class() { + self::$reader_activation_enabled = true; + + $output = do_blocks( + '' + ); + + $this->assertNotEmpty( $output ); + $this->assertStringContainsString( 'newspack-reader__account-link__label screen-reader-text', $output ); + } + + /** + * Test text-only style removes the icon markup. + */ + public function test_render_block_text_only_style_removes_icon_markup() { + self::$reader_activation_enabled = true; + + $output = do_blocks( + '' + ); + + $this->assertNotEmpty( $output ); + $this->assertStringNotContainsString( 'wp-block-newspack-my-account-button__icon', $output ); + } + + /** + * Test default style renders the icon markup. + */ + public function test_render_block_default_style_renders_icon_markup() { + self::$reader_activation_enabled = true; + + $output = do_blocks( + '' + ); + + $this->assertNotEmpty( $output ); + $this->assertStringContainsString( 'wp-block-newspack-my-account-button__icon', $output ); + } + + /** + * Test default style (no className) renders both label and icon. + */ + public function test_render_block_default_style_renders_label_and_icon() { + self::$reader_activation_enabled = true; + + $output = do_blocks( + '' + ); + + $this->assertNotEmpty( $output ); + $this->assertStringContainsString( 'newspack-reader__account-link__label', $output ); + $this->assertStringContainsString( 'wp-block-newspack-my-account-button__icon', $output ); + } + + /** + * Test empty signed-in label falls back to default. + */ + public function test_render_block_empty_signed_in_label() { + self::$reader_activation_enabled = true; $user_id = self::factory()->user->create( [ @@ -118,7 +183,8 @@ public function test_render_block_empty_label() { '' ); - $this->assertSame( '', trim( $signed_in_output ) ); + $this->assertNotEmpty( $signed_in_output ); + $this->assertStringContainsString( '"signedin":"My Account"', $signed_in_output ); } /** diff --git a/webpack.config.js b/webpack.config.js index ebf5e89673..7d6f9bf642 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -49,6 +49,7 @@ const entry = { 'content-gate-countdown-box-block': path.join( __dirname, 'src', 'blocks', 'content-gate', 'countdown-box', 'index.js' ), 'contribution-meter-block': path.join( __dirname, 'src', 'blocks', 'contribution-meter', 'index.js' ), 'avatar-block': path.join( __dirname, 'src', 'blocks', 'avatar', 'index.js' ), + 'my-account-button-block': path.join( __dirname, 'src', 'blocks', 'my-account-button', 'index.js' ), 'my-account': path.join( __dirname, 'src', 'my-account', 'index.js' ), 'my-account-v0': path.join( __dirname, 'src', 'my-account', 'v0', 'index.js' ), 'my-account-v1': path.join( __dirname, 'src', 'my-account', 'v1', 'index.js' ),