Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Post level components to allow easy building of page level blocks #178

Merged
merged 122 commits into from
Feb 15, 2023

Conversation

fabiankaegy
Copy link
Member

@fabiankaegy fabiankaegy commented Dec 9, 2022

High-Level Goal

WordPress itself ships a lot of Post- level blocks. These are atomic building blocks that are mostly usefull within the site editor and post templates inside of the Query Loop block.

The issue though is that often times on tightly controlled client builds we want to be able to have more control over the actual markup generated by these elements. And the fact that blocks only support one InnerBlock area means that we cannot achieve every layout and markup with the Post- level blocks.

In order to combat this the idea in this PR is to introduce Block Components that resemble the functionality of the Post- level component that can be used freely inside any block and take care of all the complex logic required to get these to read/write the correct data from the global post and or query loop post template.

The Components:

  • PostTitle
  • PostFeaturedImage
  • PostExcerpt
  • PostAuthor
    • PostAuthor.Avatar
    • PostAuthor.Name
    • PostAuthor.LastName
    • PostAuthor.Bio
    • PostAuthor.Email
  • PostTermList
    • PostTermList.ListItem
    • PostTermList.TermLink
  • PostCategoryList
    • PostCategoryList.ListItem
    • PostCategoryList.TermLink
  • PostPrimaryTerm (Requires Yoast SEO for the Primary Term functionality)
  • PostPrimaryCategory (Requires Yoast SEO for the Primary Term functionality)
  • PostDate
  • PostContext
  • PostMeta

Component Structure

These components can be grouped into two categories. There are the components which save and display a singular entity like the PostTitle, PostExcerpt, PostPrimaryTerm etc. These pass through all of the attributes to the actual HTML element and therefore allow full customization of the markup straight out of the box.

<figure className="wp-block-example-hero__media">
    <PostFeaturedImage className="wp-block-example-hero__image" />
</figure>
<PostTitle className="wp-block-example-hero__title" tagName="h2" />

But then there also are components that can render multiple pieces of information at once. Some examples of this are the PostAuthor or PostTerms. These can also be used in the same way but then you don't have full control over the markup they produce. In order to still have full control over the markup these components accept render functions or even child components in order to build the markup.

<PostAuthor className="wp-block-example-hero__author">
    <PostAuthor.Avatar className="wp-block-example-hero__author-avatar" />
    <PostAuthor.Name className="wp-block-example-hero__author-name" />
    <PostAuthor.FirstName className="wp-block-example-hero__author-first-name" />
    <PostAuthor.LastName className="wp-block-example-hero__author-last-name" />
    <PostAuthor.Bio className="wp-block-example-hero__author-bio" />
</PostAuthor>
<PostCategoryList className="wp-block-example-hero__categories">
    <PostCategoryList.ListItem className="wp-block-example-hero__category">
        <PostCategoryList.TermLink className="wp-block-example-hero__category-link" />
    </PostCategoryList.ListItem >
</PostCategoryList>

All these components are reading the current postId / postType of the post that is getting edited. This however can be changed by wrapping the Post components in the PostContext wrapper which makes the postId, postType and whether or not the elements should be editable to all the elements wrapped within.

image

Examples

All the Post components are reading/writing data to a post instead of an attribute. They can be used in any block and can inherit both the global post (currently being edited) or also the current post when the block these components are getting used in is a descendant of a query loop.

If you just want to use the global post you can use these components like shown in the Hero block in the examples

<header {...blockProps}>
    <figure className="wp-block-example-hero__media">
        <PostFeaturedImage className="wp-block-example-hero__image" />
    </figure>
    <PostPrimaryCategory className="wp-block-example-hero__category" />
    <PostTitle className="wp-block-example-hero__title" />
    <PostCategoryList className="wp-block-example-hero__categories">
        <PostCategoryList.ListItem className="wp-block-example-hero__category">
            <PostCategoryList.TermLink className="wp-block-example-hero__category-link" />
        </PostCategoryList.ListItem >
    </PostCategoryList>
    <PostDate className="wp-block-example-hero__date" />
    <PostExcerpt className="wp-block-example-hero__excerpt" />
    <PostAuthor className="wp-block-example-hero__author">
        <PostAuthor.Avatar className="wp-block-example-hero__author-avatar" />
        <PostAuthor.Name className="wp-block-example-hero__author-name" />
        <PostAuthor.FirstName className="wp-block-example-hero__author-first-name" />
        <PostAuthor.LastName className="wp-block-example-hero__author-last-name" />
        <PostAuthor.Bio className="wp-block-example-hero__author-bio" />
    </PostAuthor>
</header>

If on the other hand, you want to get the info from the current post within a query loop/post template you can pass in the block context.

{
    "usesContext" : [ "postId", "postType", "queryId" ]
}

These values can then be used in the <PostContext> component to make the values available to all Post- level components used within.

<article {...blockProps}>
    <PostContext postId={context.postId} postType={context.postType} isEditable={Number.isFinite(context.queryId)}>
        <figure className="wp-block-example-content-item__media">
            <PostFeaturedImage className="wp-block-example-content-item__image" />
        </figure>
        <PostPrimaryCategory className="wp-block-example-content-item__category" />
        <PostTitle className="wp-block-example-content-item__title" />
        <PostCategoryList className="wp-block-example-hero__categories">
            <PostCategoryList.ListItem className="wp-block-example-hero__category">
                <PostCategoryList.TermLink className="wp-block-example-hero__category-link" />
            </PostCategoryList.ListItem >
        </PostCategoryList>
        <PostDate className="wp-block-example-content-item__date" />
        <PostExcerpt className="wp-block-example-content-item__excerpt" />
        <PostAuthor className="wp-block-example-content-item__author">
            <PostAuthor.Avatar className="wp-block-example-content-item__author-avatar" />
            <PostAuthor.Name as="a" className="wp-block-example-content-item__author-name" />
            <PostAuthor.FirstName className="wp-block-example-content-item__author-first-name" />
            <PostAuthor.LastName className="wp-block-example-content-item__author-last-name" />
            <PostAuthor.Bio className="wp-block-example-content-item__author-bio" />
            <PostAuthor.Email className="wp-block-example-content-item__author-email" />
        </PostAuthor>
    </PostContext>
</article>

Closing #177

Testing Instructions

If you want to test this PR you can either clone this repo and build something in the example project bundled with the repo. Or you can install this prerelease version like so:

npm install @10up/[email protected]

Props: @fabiankaegy @Antonio-Laguna

Copy link
Member

@Antonio-Laguna Antonio-Laguna left a comment

Choose a reason for hiding this comment

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

@fabiankaegy awesome work as usual!

I've left some minor comments and one suggestion for improvement with onChange. I think aside from some minor things this is good to go as is and the rest can be follow up too.
I didn't add comments on every repeated occurrence of the defaultProps subject but I can do that too if useful.

I can't wait for this to be out!

fabiankaegy and others added 21 commits February 15, 2023 11:37
@fabiankaegy
Copy link
Member Author

Thank you so much @Antonio-Laguna for you thorough feedback :) I've addressed all your feedback and think I got all the instances of the defaultProps definition :)

As mentioned above I will create a follow up for the onChange idea :)

Once the CI checks are passing I will merge this into develop as the initial round ready for some more wider testing :)

@fabiankaegy fabiankaegy merged commit 45a4c9d into develop Feb 15, 2023
@fabiankaegy fabiankaegy deleted the feature/post-level-components branch February 15, 2023 11:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add "post" related components
2 participants