Skip to content

Commit

Permalink
Fix: duplicate markup on anchor attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
t-hamano committed Mar 28, 2023
1 parent 3d51087 commit 528a08d
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 42 deletions.
25 changes: 1 addition & 24 deletions lib/block-supports/anchor.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,6 @@
* @package gutenberg
*/

/**
* Registers the anchor block attribute for block types that support it.
*
* @param WP_Block_Type $block_type Block Type.
*/
function gutenberg_register_anchor_support( $block_type ) {
$has_anchor_support = _wp_array_get( $block_type->supports, array( 'anchor' ), true );
if ( ! $has_anchor_support ) {
return;
}

if ( ! $block_type->attributes ) {
$block_type->attributes = array();
}

if ( ! array_key_exists( 'anchor', $block_type->attributes ) ) {
$block_type->attributes['anchor'] = array(
'type' => 'string',
);
}
}

/**
* Add the anchor to the output.
*
Expand Down Expand Up @@ -61,7 +39,6 @@ function gutenberg_apply_anchor_support( $block_type, $block_attributes ) {
WP_Block_Supports::get_instance()->register(
'anchor',
array(
'register_attribute' => 'gutenberg_register_anchor_support',
'apply' => 'gutenberg_apply_anchor_support',
'apply' => 'gutenberg_apply_anchor_support',
)
);
37 changes: 32 additions & 5 deletions packages/block-editor/src/hooks/anchor.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,39 @@ export function addAttribute( settings ) {
if ( 'type' in ( settings.attributes?.anchor ?? {} ) ) {
return settings;
}

// Gracefully handle if settings.attributes is undefined.
if ( hasBlockSupport( settings, 'anchor' ) ) {
// Gracefully handle if settings.attributes is undefined.
settings.attributes = {
...settings.attributes,
anchor: ANCHOR_SCHEMA,
};
let saveElement;
try {
saveElement =
typeof settings.save === 'function'
? settings.save()
: settings.save;
if ( saveElement === null || saveElement === undefined ) {
// If the save function returns null or undefined, save the anchor
// attribute as a block's comment delimiter without specifying
// the source.
settings.attributes = {
...settings.attributes,
anchor: {
type: ANCHOR_SCHEMA.type,
},
};
} else {
settings.attributes = {
...settings.attributes,
anchor: ANCHOR_SCHEMA,
};
}
} catch ( error ) {
// If the save function returns an error, the anchor will be saved
// in the markup as an id attribute.
settings.attributes = {
...settings.attributes,
anchor: ANCHOR_SCHEMA,
};
}
}

return settings;
Expand Down
51 changes: 41 additions & 10 deletions packages/block-editor/src/hooks/test/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import { applyFilters } from '@wordpress/hooks';
import '../anchor';
import { immutableSet } from '../utils';

const noop = () => {};

describe( 'immutableSet', () => {
describe( 'handling falsy values properly', () => {
it( 'should create a new object if `undefined` is passed', () => {
Expand Down Expand Up @@ -116,7 +114,6 @@ describe( 'immutableSet', () => {

describe( 'anchor', () => {
const blockSettings = {
save: noop,
category: 'text',
title: 'block title',
};
Expand All @@ -133,15 +130,49 @@ describe( 'anchor', () => {
expect( settings.attributes ).toBe( undefined );
} );

it( 'should assign a new anchor attribute', () => {
const settings = registerBlockType( {
...blockSettings,
supports: {
anchor: true,
it( 'should assign a new anchor attribute depending on the value of the save property', () => {
const saveDefinitions = [
// The anchor attribute should be stored as a comment delimiter.
{
value: null,
schema: {
type: 'string',
},
},
} );
{
value: () => null,
schema: {
type: 'string',
},
},
{
value: undefined,
schema: {
type: 'string',
},
},
// The anchor attributes should be saved as part of the markup.
{
value: () => <div className="default" />,
schema: {
attribute: 'id',
selector: '*',
source: 'attribute',
type: 'string',
},
},
];

expect( settings.attributes ).toHaveProperty( 'anchor' );
saveDefinitions.forEach( ( { value, schema } ) => {
const settings = registerBlockType( {
...blockSettings,
save: value,
supports: {
anchor: true,
},
} );
expect( settings.attributes.anchor ).toEqual( schema );
} );
} );

it( 'should not override attributes defined in settings', () => {
Expand Down
12 changes: 9 additions & 3 deletions packages/server-side-render/src/server-side-render.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,15 @@ export default function ServerSideRender( props ) {

setIsLoading( true );

let sanitizedAttributes =
attributes &&
__experimentalSanitizeBlockAttributes( block, attributes );
let sanitizedAttributes;
if ( attributes ) {
// Anchor attribute isn't supported on the server side and
// should be excluded from the parameters.
const { anchor, ...restAttributes } = attributes;
sanitizedAttributes =
restAttributes &&
__experimentalSanitizeBlockAttributes( block, restAttributes );
}

if ( skipBlockSupportAttributes ) {
sanitizedAttributes =
Expand Down

0 comments on commit 528a08d

Please sign in to comment.