Skip to content

Bug: reduce excessive calls to render_block() #378

@justlevine

Description

@justlevine

Problem

Currently, WPGraphQL for Content Blocks calls render_block() repeatedly and unnecessarily:

  • Whenever the renderedHtml for a block is returned, (even if it was rendered by a parentBlock):
    'renderedHtml' => [
    'type' => 'String',
    'description' => __( 'The rendered HTML for the block', 'wp-graphql-content-blocks' ),
    'resolve' => static function ( $block ) {
    return render_block( $block );
    },
  • Whenever an anchor field is resolved:
    'anchor' => [
    'type' => 'string',
    'description' => __( 'The anchor field for the block.', 'wp-graphql-content-blocks' ),
    'resolve' => static function ( $block ) {
    $rendered_block = wp_unslash( render_block( $block ) );
    (related Implement Block Supports as GraphQL Interfaces #354 )
  • Whenever each and every Block Attribute attempts to resolve:
    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 ) ] = [
    'type' => $graphql_type,
    'description' => 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

This results in various issues and incompatibilities, but the biggest one is performance as the number of calls increases exponentially depending on the number of nested blocks and individual fields requested by graphql.

Proposed Solution

We should limit our calls to render_block() and reuse the results once we have them.

There are multiple different ways we can reduce these calls, and they don't all need to be breaking, or done together:

Details

I'm highlighting some findings from a Performance Audit conducted by my friend and colleague @aryanjasala . I'll be sharing the link in the wp-graphql maintainer's discord channel - it's too big for a GH issue.

When comparing FSE on Traditional WP to WPGraphQL Content Blocks on a basic page with patterns.

Keep in mind that traditional WordPress is actually doing even more heavy lifting than nodeByUri(...) { editorBlocks {...} }, since it needs to parse and render the entire template.

Test Data

Post content 👇 ```html

I’m Leia Acosta, a passionate photographer who finds inspiration in capturing the fleeting beauty of life.

```
GraphQL Query 👇
query GetContentNode($uri: String!) {
  nodeByUri(uri: $uri) {
    __typename
    ... on Page {
      id
      title
      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 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
          }
        }
      }
    }
  }
}

Environment

  • WPGraphQL: 2.1.1
  • WPGraphQL Content Blocks: 4.8.2
  • WordPress Core: 6.7.2
  • WP_ENVIRONMENT_TYPE: production
  • PHP:8.2.27
  • Benchmarked using| LocalWP + XHProf + XHGUI

Metadata

Metadata

Assignees

Labels

impact: highUnblocks new use cases, substantial improvement to existing feature, fixes a major bugscope: performanceEnhancing speed and efficiencystatus: actionableReady for work to begintype: enhancementImprovements to existing functionality

Type

No type

Projects

Status

✅ Closed

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions