Skip to content

chore: performance improvements for render_block and WPGraphQL 2.3.0#384

Merged
colinmurphy merged 17 commits intomainfrom
chore-reduce-render_block-callbacks
Jun 12, 2025
Merged

chore: performance improvements for render_block and WPGraphQL 2.3.0#384
colinmurphy merged 17 commits intomainfrom
chore-reduce-render_block-callbacks

Conversation

@colinmurphy
Copy link
Member

@colinmurphy colinmurphy commented May 9, 2025

Overview

What does this do?

  1. Initial short term fix for Feat: Use render_block instead of innerHTML #64 to reduce the amount of callbacks for "render_block"
  2. Lazy load the config for performance for WPGraphQL 2. 3.0 and add a fallback for users with lower versions of 2.3.0 (thanks @justlevine for the shim) (Fixes Evaluate plugin after new release of WPGraphQL 2.3.0 #382 )

As part of the work for WPGraphQL 2.3.0 we add a static function to each config for register_graphql_*

e.g.

      WPGraphQLRegisterConfig::resolve_graphql_config(
        [
	        'description' => __( 'Generic Array Scalar Type', 'wp-graphql-content-blocks' ),
	        'serialize'   => static function ( $value ) {
		        return wp_json_encode( $value );
	        },
        ]
      )

Testing

Query for testing

Click to expand the query
query GetPageBySlug($slug: ID!) {
  page(id: $slug, idType: URI) {
    id
    title
    slug
    editorBlocks {
        clientId
        parentClientId
        renderedHtml
        type
        ... on CoreAudio {
          attributes {
            autoplay
            caption
            loop
            preload
            src
            style
          }
        }
        ... on CoreButton {
          attributes {
            buttonType: type
            cssClassName
            linkClassName
            linkTarget
            rel
            style
            tagName
            text
            title
            url
          }
        }
        ... on CoreButtons {
          attributes {
            cssClassName
            style
          }
        }
        ... on CoreCode {
          attributes {
            style
            content
            cssClassName
          }
        }
        ... on CoreColumn {
          attributes {
            cssClassName
            style
            width
          }
        }
        ... on CoreColumns {
          attributes {
            cssClassName
            style
          }
        }
        ... on CoreCover {
          attributes {
            alt
            backgroundType
            contentPosition
            customGradient
            customOverlayColor
            dimRatio
            focalPoint
            gradient
            hasParallax
            isDark
            isRepeated
            minHeight
            minHeightUnit
            overlayColor
            style
            tagName
            url
            useFeaturedImage
          }
        }
        ... on CoreDetails {
          attributes {
            showContent
            style
            summary
          }
        }
        ... on CoreFile {
          attributes {
            displayPreview
            downloadButtonText
            fileId
            fileName
            href
            previewHeight
            showDownloadButton
            style
            textLinkHref
            textLinkTarget
          }
        }
        ... on CoreFreeform {
          attributes {
            content
          }
        }
        ... on CoreGallery {
          attributes {
            caption
            style
          }
        }
        ... on CoreGroup {
          attributes {
            style
            tagName
          }
        }
        ... on CoreHeading {
          attributes {
            content
            cssClassName
            level
            style
          }
        }
        ... on CoreHtml {
          attributes {
            content
          }
        }
        ... on CoreImage {
          attributes {
            alt
            aspectRatio
            caption
            href
            linkClass
            linkTarget
            rel
            scale
            style
            title
            url
            imageHeight: height
            width
            sizeSlug
            lightbox
          }
        }
        ... on CoreList {
          attributes {
            cssClassName
            ordered
            reversed
            start
            style
            type
          }
        }
        ... on CoreListItem {
          attributes {
            content
            style
          }
        }
        ... on CoreMediaText {
          attributes {
            className
            focalPoint
            href
            imageFill
            linkClass
            linkTarget
            mediaAlt
            mediaId
            mediaPosition
            mediaSizeSlug
            mediaType
            mediaUrl
            mediaWidth
            rel
            style
          }
        }
        ... on CoreParagraph {
          attributes {
            backgroundColor
            content
            cssClassName
            direction
            fontFamily
            fontSize
            style
            textColor
          }
        }
        ... on CorePostContent {
          renderedHtml
        }
        ... on CorePreformatted {
          attributes {
            content
            style
          }
        }
      ... on CorePostTerms {
          attributes {
            prefix
          }
        }
        ... on CorePullquote {
          attributes {
            citation
            style
            textAlign
            pullquoteValue: value
          }
        }
        ... on CoreQuote {
          attributes {
            citation
            cssClassName
            style
            value
          }
        }
        ... on CoreSeparator {
          attributes {
            cssClassName
            style
          }
        }
        ... on CoreSpacer {
          attributes {
            height
            style
            width
          }
        }
        ... on CoreTemplatePart {
          renderedHtml
          attributes {
            className
            slug
            templatePartTagName: tagName
            theme
          }
        }
        ... on CoreVerse {
          attributes {
            content
            style
          }
        }
        ... on CoreVideo {
          attributes {
            autoplay
            caption
            controls
            loop
            muted
            playsInline
            poster
            videoPreload: preload
            src
            style
            tracks
          }
        }
    }
  }
}

Performance Testing

Added this to evaluate memory usage

		add_action( 'graphql_init_types', function() {
			error_log( sprintf(
				'[GraphQL] Pre-type registration memory usage: %s',
				memory_get_peak_usage( true )
			) );
		} );

		add_action( 'graphql_register_types_late', function() {
			error_log( sprintf(
				'[GraphQL] Post-type registration memory usage: %s',
				memory_get_peak_usage( true )
			) );
		} );

Before

[12-May-2025 14:57:24 UTC] [GraphQL] Post-type registration memory usage: 31457280

After

[12-May-2025 15:00:03 UTC] [GraphQL] Post-type registration memory usage: 16777216

@changeset-bot
Copy link

changeset-bot bot commented May 9, 2025

⚠️ No Changeset found

Latest commit: ffd5fb1

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@colinmurphy
Copy link
Member Author

@justlevine @theodesp FYI Draft PR for render_block and lazy loaded configs.

@colinmurphy colinmurphy marked this pull request as ready for review May 12, 2025 12:50
@colinmurphy colinmurphy requested a review from a team as a code owner May 12, 2025 12:50
@colinmurphy colinmurphy requested a review from theodesp May 12, 2025 12:50
@colinmurphy colinmurphy changed the title chore: (DRAFT) performance improvements chore: performance improvements for render_block and WPGraphQL 2.3.0 May 12, 2025
@colinmurphy colinmurphy requested a review from josephfusco May 12, 2025 12:52
@colinmurphy
Copy link
Member Author

@justlevine @theodesp @josephfusco

This is ready for review. I still need to run the xprof setup as per original ticket #64

@justlevine

I thought adding a filter instead of a static function made sense here as it also gives other users the ability to use that hook too.

Also thank you so much for all your help on this ❤️

@colinmurphy
Copy link
Member Author

@justlevine @theodesp

I got some good stats on memory usage for the above query using Jason's suggestion (see the original issue) in wp-graphql/wp-graphql#3354 to check memory usage

add_action( 'graphql_init_types', function() {
    error_log( sprintf( 
        '[GraphQL] Pre-type registration memory usage: %s', 
        memory_get_peak_usage( true ) 
    ) );
} );

add_action( 'graphql_register_types_late', function() {
    error_log( sprintf( 
        '[GraphQL] Post-type registration memory usage: %s', 
        memory_get_peak_usage( true ) 
    ) );
} );

Before

[12-May-2025 14:57:24 UTC] [GraphQL] Post-type registration memory usage: 31457280

After

[12-May-2025 15:00:03 UTC] [GraphQL] Post-type registration memory usage: 16777216

@justlevine
Copy link
Contributor

@colinmurphy per Discord, I would avoid using/introducing new hooks around the config.

@colinmurphy
Copy link
Member Author

@colinmurphy per Discord, I would avoid using/introducing new hooks around the config.

Thanks @justlevine

No worries, I will remove these and use the static function instead 👍

@colinmurphy
Copy link
Member Author

@justlevine

Replaced the filter with the static function so ready for review whenever you have time please. Thanks again for all your help on this.

josephfusco
josephfusco previously approved these changes Jun 3, 2025
Copy link
Member

@josephfusco josephfusco left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@colinmurphy
Copy link
Member Author

@wpengine/headless-open-source

Going to make a few changes as suggested by @justlevine ❤️

I should have an updated PR later today. Thanks again @justlevine.

@colinmurphy
Copy link
Member Author

When trying to make the descriptions callable we are getting a fatal error

Cannot assign Closure to property GraphQL\\Type\\Definition\\ObjectType::$description of type ?string",

e.g.

	private function register_type(): void {
		register_graphql_object_type(
			$this->type_name,
			// @TODO - Remove when WPGraphQL min version is 2.3.0
			WPGraphQLRegisterConfig::resolve_graphql_config(
				[
					'description'     => static fn() => __( 'A block used for editing the site', 'wp-graphql-content-blocks' ),
					'interfaces'      => $this->get_block_interfaces(),
					'eagerlyLoadType' => true,
					'fields'          => [
						'name' => [
							'type'        => 'String',
							'description' => __( 'The name of the block', 'wp-graphql-content-blocks' ),
							'resolve'     => static function ( $block ) {
								return isset( $block['blockName'] ) ? (string) $block['blockName'] : null;
							},
						],
					],
				]
			)
		);
	}

The important part is 'description' => static fn() => __( 'A block used for editing the site', 'wp-graphql-content-blocks' ),

Copy link
Contributor

@justlevine justlevine left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@colinmurphy I caught the two following issues, but nothing that should be causing the error you reported.

Additionally in my own attempts to convert the translatable strings to callables, I havn't been able to reproduce the error either.

I cant commit to your branch and too lazy to make a PR right now, so here's the contexts of includes/blocks/Block.php you can drop in and diff.

My recommendation would be to commit a particular change that triggers the error onto the PR so I can pull with an identical replication.


WPGraphQL\ContentBlocks\Blocks\Blocks
<?php
/**
 *  Handles mapping a WP_Block_Type to the WPGraphQL Schema
 *
 * @package WPGraphQL\ContentBlocks\Blocks
 */

namespace WPGraphQL\ContentBlocks\Blocks;

use WPGraphQL\ContentBlocks\Data\BlockAttributeResolver;
use WPGraphQL\ContentBlocks\GraphQL\WPGraphQLRegisterConfig;
use WPGraphQL\ContentBlocks\Registry\Registry;
use WPGraphQL\ContentBlocks\Type\Scalar\Scalar;
use WPGraphQL\ContentBlocks\Utilities\WPGraphQLHelpers;
use WPGraphQL\Utils\Utils;
use WP_Block_Type;

/**
 * Class Block
 */
class Block {
	/**
	 * The Block Type
	 *
	 * @var \WP_Block_Type
	 */
	protected WP_Block_Type $block;

	/**
	 * The GraphQL type name of the block.
	 *
	 * @var string
	 */
	protected string $type_name;

	/**
	 * The instance of the WPGraphQL block registry.
	 *
	 * @var \WPGraphQL\ContentBlocks\Registry\Registry
	 */
	protected Registry $block_registry;

	/**
	 * The attributes of the block
	 *
	 * @var array|null
	 */
	protected ?array $block_attributes;

	/**
	 * Any Additional attributes of the block not defined in block.json
	 *
	 * @var array|null
	 */
	protected ?array $additional_block_attributes;

	/**
	 * A filterable array of block object attributes that are typed.
	 * The keys could be the object attribute names of the block and the value is an associative array where the key is the property name and the value is the type.
	 *
	 * @var array<string, array<string, "array"|"boolean"|"number"|"integer"|"object"|"rich-text"|"string">>
	 */
	protected array $typed_object_attributes = [];

	/**
	 * Block constructor.
	 *
	 * @param \WP_Block_Type                             $block The Block Type.
	 * @param \WPGraphQL\ContentBlocks\Registry\Registry $block_registry The instance of the WPGraphQL block registry.
	 */
	public function __construct( WP_Block_Type $block, Registry $block_registry ) {
		$this->block            = $block;
		$this->block_registry   = $block_registry;
		$this->block_attributes = $this->block->attributes;
		$this->type_name        = WPGraphQLHelpers::format_type_name( $block->name );

		$this->filter_typed_object_attributes();
		$this->register_block_type();
	}

	/**
	 * Filters the typed object attributes for the block.
	 *
	 * @return void
	 */
	private function filter_typed_object_attributes() {
		$block_name = str_replace( [ '/' ], '_', $this->block->name );

		if ( has_filter( 'wpgraphql_content_blocks_object_typing_' . $block_name ) ) {
			$this->typed_object_attributes = (array) apply_filters( 'wpgraphql_content_blocks_object_typing_' . $block_name, [] );
		}
	}

	/**
	 * Registers the Block Type to WPGraphQL.
	 *
	 * @return void
	 */
	private function register_block_type() {
		$this->register_block_attributes_as_fields();
		$this->register_type();
	}

	/**
	 * Registers the block attributes GraphQL type and adds it as a field on the Block.
	 */
	private function register_block_attributes_as_fields(): void {
		// Stash the typename so we can reuse it locally.
		$type_name = $this->type_name;

		// Grab any additional block attributes attached into the class itself.
		$block_attributes = array_merge(
			$this->block_attributes ?? [],
			$this->additional_block_attributes ?? [],
		);

		$block_attribute_fields = $this->get_block_attribute_fields( $block_attributes, $type_name . 'Attributes' );

		// Bail early if no attributes are defined.
		if ( empty( $block_attribute_fields ) ) {
			return;
		}

		// For each attribute, register a new object type and attach it to the block type as a field
		$block_attribute_type_name = $type_name . 'Attributes';

		register_graphql_object_type(
			$block_attribute_type_name,
			// @TODO - Remove when WPGraphQL min version is 2.3.0
			WPGraphQLRegisterConfig::resolve_graphql_config(
				[
					'description' => static function () use ( $type_name ) {
						return sprintf(
						// translators: %s is the block type name.
							__( 'Attributes of the %s Block Type', 'wp-graphql-content-blocks' ),
							$type_name
						);
					},
					'interfaces'  => $this->get_block_attributes_interfaces(),
					'fields'      => $block_attribute_fields,
				]
			)
		);
		register_graphql_field(
			$this->type_name,
			'attributes',
			// @TODO - Remove when WPGraphQL min version is 2.3.0
			WPGraphQLRegisterConfig::resolve_graphql_config(
				[
					'type'        => $block_attribute_type_name,
					'description' => static function () use ( $type_name ) {
						return sprintf(
							// translators: %s is the block type name.
							__( 'Attributes of the %s Block Type', 'wp-graphql-content-blocks' ),
							$type_name
						);
					},
					'resolve'     => static function ( $block ) {
						return $block;
					},
				]
			)
		);
	}

	/**
	 * Returns the type of the block attribute.
	 *
	 * @param string              $name The block name
	 * @param array<string,mixed> $attribute The block attribute config
	 * @param string              $prefix Current prefix string to use for the get_query_type
	 *
	 * @return mixed
	 */
	private function get_attribute_type( $name, $attribute, $prefix ) {
		$type           = null;
		$attribute_type = $attribute['type'] ?? null;

		switch ( $attribute_type ) {
			case 'rich-text':
			case 'string':
				$type = 'String';
				break;
			case 'boolean':
				$type = 'Boolean';
				break;
			case 'number':
				$type = 'Float';
				break;
			case 'integer':
				$type = 'Int';
				break;
			case 'array':
				$type = $this->process_array_attributes( $name, $attribute, $prefix );
				break;
			case 'object':
				$type = $this->process_object_attributes( $name, $attribute, $prefix );
				break;
			case null:
				// Default to String if only 'source' is defined, otherwise return null.
				$type = isset( $attribute['source'] ) ? 'String' : null;
				break;
		}

		if ( null !== $type && isset( $attribute['default'] ) ) {
			$type = [ 'non_null' => $type ];
		}

		return $type;
	}

	/**
	 * Processes the array attributes as query, list of items or scalar array.
	 *
	 * @param string              $name The block name
	 * @param array<string,mixed> $attribute The block attribute config
	 * @param string              $prefix Current prefix string to use for the get_query_type
	 *
	 * @return array|string
	 */
	private function process_array_attributes( $name, $attribute, $prefix ) {
		if ( isset( $attribute['query'] ) ) {
			return [ 'list_of' => $this->register_inner_object_type( $name, $attribute['query'], $prefix ) ];
		}

		$of_type = null;
		if ( isset( $attribute['items'] ) ) {
			$of_type = $this->get_attribute_type( $name, $attribute['items'], $prefix );
		}

		return null !== $of_type ? [ 'list_of' => $of_type ] : Scalar::get_block_attributes_array_type_name();
	}

	/**
	 * Processes the object attributes as typed object if defined within filter, otherwise as scalar.
	 *
	 * @param string              $name The block name
	 * @param array<string,mixed> $attribute The block attribute config
	 * @param string              $prefix Current prefix string to use for the get_query_type
	 *
	 * @return string
	 */
	private function process_object_attributes( $name, $attribute, $prefix ) {
		// If there is no typing for this object attribute, return the default scalar type.
		if ( empty( $this->typed_object_attributes[ $name ] ) ) {
			return Scalar::get_block_attributes_object_type_name();
		}

		$typed = $this->build_typed_object_config(
			$attribute['default'] ?? [],
			$this->typed_object_attributes[ $name ]
		);

		return $typed ? $this->register_inner_object_type( $name, $typed, $prefix ) : Scalar::get_block_attributes_object_type_name();
	}

	/**
	 * Gets the WPGraphQL field registration config for the block attributes.
	 *
	 * @param ?array $block_attributes The block attributes.
	 * @param string $prefix The current prefix string to use for the get_query_type
	 */
	private function get_block_attribute_fields( ?array $block_attributes, string $prefix = '' ): array {
		// Bail early if no attributes are defined.
		if ( null === $block_attributes ) {
			return [];
		}

		$fields = [];
		foreach ( $block_attributes as $attribute_name => $attribute_config ) {
			$graphql_type = $this->get_attribute_type( $attribute_name, $attribute_config, $prefix );

			if ( empty( $graphql_type ) ) {
				continue;
			}

			// Create the field config.
			$fields[ Utils::format_field_name( $attribute_name ) ] = WPGraphQLRegisterConfig::resolve_graphql_config(
				[
					'type'        => $graphql_type,
					'description' => static function () use ( $attribute_name, $prefix ) {
						return sprintf(
							// translators: %1$s is the attribute name, %2$s is the block name.
							__( 'The "%1$s" field on the "%2$s" block or block attributes', 'wp-graphql-content-blocks' ),
							$attribute_name,
							$prefix
						);
					},
					'resolve'     => function ( $block ) use ( $attribute_name, $attribute_config ) {
						$config = [
							$attribute_name => $attribute_config,
						];
						$result = $this->resolve_block_attributes_recursive( $block['attrs'], wp_unslash( render_block( $block ) ), $config );

						return $result[ $attribute_name ];
					},
				]
			);
		}//end foreach

		return $fields;
	}

	/**
	 * Dynamically creates and registers a GraphQL object type for queries or typed object attributes.
	 *
	 * @param string $name The block name.
	 * @param array  $config The block config.
	 * @param string $prefix The current prefix string to use for registering the new attribute type.
	 */
	private function register_inner_object_type( string $name, array $config, string $prefix ): string {
		$type   = $prefix . ucfirst( $name );
		$fields = $this->create_attributes_fields( $config, $type );

		register_graphql_object_type(
			$type,
			// @TODO - Remove when WPGraphQL min version is 2.3.0
			WPGraphQLRegisterConfig::resolve_graphql_config(
				[
					'fields'      => $fields,
					'description' => static function () use ( $type, $prefix ) {
						return sprintf(
							// translators: %1$s is the attribute name, %2$s is the block attributes field.
							__( 'The "%1$s" field on the "%2$s" block attribute field', 'wp-graphql-content-blocks' ),
							$type,
							$prefix
						);
					},
				]
			)
		);

		return $type;
	}

	/**
	 * Generates typed object-type attribute config by merging the default values with the typed object configuration.
	 * When typing is specified for an attribute, only the typed properties are returned.
	 *
	 * @param array $default_values Default record of the attribute.
	 * @param array $typed Typed object configuration.
	 */
	private function build_typed_object_config( $default_values, $typed ): array {
		return array_combine(
			array_keys( $typed ),
			array_map(
				static fn ( $key ) => [
					'type'    => $typed[ $key ],
					'default' => $default_values[ $key ] ?? null,
				],
				array_keys( $typed )
			)
		) ?: [];
	}

	/**
	 * Creates the new attribute fields for query types
	 *
	 * @param array  $attributes The query attributes config
	 * @param string $prefix The current prefix string to use for registering the new query attribute type
	 */
	private function create_attributes_fields( $attributes, $prefix ): array {
		$fields = [];
		foreach ( $attributes as $name => $attribute ) {
			$type = $this->get_attribute_type( $name, $attribute, $prefix );

			if ( isset( $type ) ) {
				$default_value = $attribute['default'] ?? null;

				$fields[ Utils::format_field_name( $name ) ] = WPGraphQLRegisterConfig::resolve_graphql_config(
					[
						'type'        => $type,
						'description' => static function () use ( $name, $prefix ) {
							return sprintf(
								// translators: %1$s is the attribute name, %2$s is the block attributes field.
								__( 'The "%1$s" field on the "%2$s" block attribute field', 'wp-graphql-content-blocks' ),
								$name,
								$prefix
							);
						},
						'resolve'     => function ( $attributes ) use ( $name, $default_value, $type ) {
							$value = $attributes[ $name ] ?? $default_value;

							return $this->normalize_attribute_value( $value, $type );
						},
					]
				);
			}
		}

		return $fields;
	}

	/**
	 * Normalizes the value of the attribute
	 *
	 * @param array|string $value The value
	 * @param string       $type The type of the value
	 *
	 * @return array|string|int|float|bool
	 */
	private function normalize_attribute_value( $value, $type ) {
		// @todo use the `source` to normalize array/object values.
		if ( is_array( $value ) ) {
			return $value;
		}

		switch ( $type ) {
			case 'array':
				// If we're here, we want an array type, even though the value is not an array.
				// @todo This should return null if the value is empty.
				return ! empty( $value ) ? [ $value ] : [];
			case 'rich-text':
			case 'string':
				return (string) $value;
			case 'number':
				return (float) $value;
			case 'boolean':
				return (bool) $value;
			case 'integer':
				return (int) $value;
			default:
				return $value;
		}
	}

	/**
	 * Register the Type for the block. This happens after all other object types are already registered.
	 */
	private function register_type(): void {
		register_graphql_object_type(
			$this->type_name,
			// @TODO - Remove when WPGraphQL min version is 2.3.0
			WPGraphQLRegisterConfig::resolve_graphql_config(
				[
					'description'     => static fn () => __( 'A block used for editing the site', 'wp-graphql-content-blocks' ),
					'interfaces'      => $this->get_block_interfaces(),
					'eagerlyLoadType' => true,
					'fields'          => [
						'name' => [
							'type'        => 'String',
							'description' => static fn () => __( 'The name of the block', 'wp-graphql-content-blocks' ),
							'resolve'     => static function ( $block ) {
								return isset( $block['blockName'] ) ? (string) $block['blockName'] : null;
							},
						],
					],
				]
			)
		);
	}

	/**
	 * Gets the GraphQL interfaces that should be implemented by the block.
	 *
	 * @return string[]
	 */
	private function get_block_interfaces(): array {
		return $this->block_registry->get_block_interfaces( $this->block->name );
	}

	/**
	 * Gets the GraphQL interfaces that should be implemented by the block attributes object.
	 *
	 * @return string[]
	 */
	private function get_block_attributes_interfaces(): array {
		return $this->block_registry->get_block_attributes_interfaces( $this->block->name );
	}

	/**
	 * Resolved the value of the block attributes based on the specified config
	 *
	 * @param array<string,mixed> $attribute_values The block current attributes value.
	 * @param string              $html The block rendered html.
	 * @param array<string,mixed> $attribute_configs The block current attribute configuration, keyed to the attribute name.
	 */
	private function resolve_block_attributes_recursive( $attribute_values, string $html, array $attribute_configs ): array {
		$result = [];

		// Clean up the html.
		$html = trim( $html );

		foreach ( $attribute_configs as $key => $config ) {
			$attribute_value = $attribute_values[ $key ] ?? null;

			$result[ $key ] = BlockAttributeResolver::resolve_block_attribute( $config, $html, $attribute_value );
		}

		return $result;
	}
}

Co-authored-by: Dovid Levine <david@axepress.dev>
@colinmurphy
Copy link
Member Author

@justlevine

Thank you so much for your help here ❤️
After committing your changes, the fatal error issue stopped (I suspect it was adding edgeFields but not 100% sure)

Anyway I have updated the PR now to include:

  1. Use callbacks for descriptions (no deprecationReason fields so not sure should we have this key?)
  2. Fixed the use of the shim

Can you review again on your side please 🚀

Copy link
Contributor

@justlevine justlevine left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if intentional but seeing a bunch that should be converted. I'm gonna fork against this and open a PR

@colinmurphy colinmurphy requested a review from justlevine June 10, 2025 08:59
@colinmurphy
Copy link
Member Author

@justlevine

Thanks so much for all your help on this and also your PR to make those changes ❤️ I have tested the PR again and it looks good to me so its ready for another review.

Copy link
Contributor

@justlevine justlevine left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤩

@colinmurphy colinmurphy merged commit 6b2d94c into main Jun 12, 2025
13 checks passed
@colinmurphy colinmurphy deleted the chore-reduce-render_block-callbacks branch June 12, 2025 16:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Evaluate plugin after new release of WPGraphQL 2.3.0

3 participants