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

Navigation: Add an API to retrieve content-only inner blocks #30674

Closed
Tracked by #35521
priethor opened this issue Apr 9, 2021 · 17 comments
Closed
Tracked by #35521

Navigation: Add an API to retrieve content-only inner blocks #30674

priethor opened this issue Apr 9, 2021 · 17 comments
Labels
[Block] Navigation Affects the Navigation Block Needs Dev Ready for, and needs developer efforts [Type] New API New API to be used by plugin developers or package users.

Comments

@priethor
Copy link
Contributor

priethor commented Apr 9, 2021

What problem does this address?

As of 10.4-RC1, the Navigation block allows different kinds of inner blocks, from the most basic Navigation Link to the Search block, including layout-building ones like the Spacer block.

Because of this, obtaining a structured, link-only page hierarchy from a Navigation block (for example, to create a sitemap) is not as simple as gathering all inner blocks, as it would require discarding presentation-only blocks and other non-content ones.

What is your proposed solution?

The Navigation block should provide an API to retrieve content-only inner blocks.

@priethor priethor added [Block] Navigation Affects the Navigation Block [Type] New API New API to be used by plugin developers or package users. labels Apr 9, 2021
@mtias
Copy link
Member

mtias commented Apr 12, 2021

This will be an important server side function to retrieve a data-relational representation since the navigation block can have other blocks in the mix that are not relevant.

@gwwar
Copy link
Contributor

gwwar commented Apr 22, 2021

Do we have an example of what this API looks like and what it might return (eg either a rest call / php or JS function signature)? This would help me understand the usecase

@mtias
Copy link
Member

mtias commented Apr 22, 2021

I had in mind something similar to the nav menu walker but taking advantage of the built in object tree representation of nested blocks to be used in server-side context (could be exposed in REST as well), excluding any presentation specific elements.

@priethor
Copy link
Contributor Author

Regarding what constitutes the content to be returned by this API, I'm thinking of linking blocks in any flavor (Navigation link, Social links, Home link, Site Title/Logo...), but not other functional blocks like Search, even if it is not a presentation-specific element. Does that make sense, @mtias?

@draganescu
Copy link
Contributor

Are there two parts to this task?

  1. Add some function that gets a header template part and gets the navigation blocks in that template part
  2. Add an API in the Navigation block that can create a tree data representation of all the blocks that act as links

Without (1) how would we know where to find the blocks?

@priethor
Copy link
Contributor Author

priethor commented Jun 3, 2021

I don't think we need (1) at the moment, as the Navigation block can be placed in other template parts or posts. I can see designs having a Navigation block in their Header and Footer template parts, or different headers with different navigations, and nothing prevents them from having more than one Navigation block instance per template part.

Starting with (2) would allow wrapping items properly when rendering the frontend as suggested in #31951 (comment). Furthermore, it could also help render responsive menus by outputting different HTML for smaller screens excluding the non-content blocks.

@draganescu
Copy link
Contributor

I think I described (1) incorrectly. I meant from any generic template part a function that would get the name of the template part and the name of the block that we're looking for and gets that block back. I don't think we have such a thing.

@talldan
Copy link
Contributor

talldan commented Sep 1, 2021

Starting with (2) would allow wrapping items properly when rendering the frontend as suggested in #31951 (comment). Furthermore, it could also help render responsive menus by outputting different HTML for smaller screens excluding the non-content blocks.

I'm not sure using this for rendering is the right track, because it's shifting away from the block rendering paradigm (which should itself be able to support this use case).

Perhaps this could be something that's not so much navigation block specific, but instead works on the basis of the HTML markup. That would ensure third-party blocks aren't left out of the mix.

It could build a hierarchy of the links inside a <nav> element. Any such utility could still work on the basis of a specific navigation block if needed, it'd just use the rendered output.

The other thought I have if this path isn't considered viable is that this could take advantage of the experimentalRole property on attributes to try to apply some semantic meaning to attributes.

@dmsnell
Copy link
Member

dmsnell commented Oct 25, 2021

Adding role attributes seems a natural fit, so does hard-coding certain blocks and their meaning, like links and nav links etc…

@priethor or others, do we have an example of the format/structure of the data you would want from this hypothetical function or API call? Given an example nav block input, what do you want out, and what are you wanting to do with it? Create a sitemap.xml from the server? Create a breadcrumb in the rendered page (from the server)?

@priethor
Copy link
Contributor Author

Hi @dmsnell! Sitemaps and breadcrumbs are great examples of practical applications of this hypothetical API, whose goal is to provide the page hierarchy given a Navigation Block. There is no specific format in mind, but an equivalent to Walker_Nav_Menu for blocks would work as a first iteration.

@dmsnell
Copy link
Member

dmsnell commented Oct 26, 2021

@priethor please pardon my ignorance on the issue, I've not used Walker_Nav_Menu before and I'm not sure where the overlaps lie with this.

On the server we have access to a powerful tool with the render_block filter which can be used for much more than generating the base rendered block output.

function extract_nav_links($nav_blocks) {
	$extract_link = function($previous_output, $block) {
		// logic that takes a block and returns a nav link if one exists for that block
		$this_link = extract_nav_link($block);

		remove_filter('pre_render_block', $extract_link);
		$child_links = array_filter(extract_nav_links($block['innerBlocks']));
		add_filter('pre_render_block', $extract_link, 10, 2);

		// we could have non-link placeholder nodes in the nav tree whose children have links (some kind of group)
		// or we could have link nodes with no children (an actual nav link, URL, or logo with link)
		// or we could have non-link material without children (search bar)
		return !empty($this_link) || !empty($child_links)
			? [ 'link' => $this_link, 'sub_links' => $child_links ]
			: [];
	}

	add_filter('pre_render_block', $extract_link, 10, 2);
	$links = array_filter(array_map('render_block', $nav_blocks));
	remove_filter('pre_render_block', $extract_link);

	return $links;
}

I think something like this would get out what you are asking for. The important piece is extract_nav_link($block) which is where we'd want to encode the rules for getting those links out of blocks, but this could be fairly straightforward as long as we can add in our expectations on what makes for a nav item.

function extract_nav_link($block) {
	switch ($block['blockName']) {
		case 'core/link':
			return $block['attrs']['url'];

		case 'core/navigation-link':
			return $block['attrs']['url'];
	}

	// take a wild guess
	if (isset($block['attrs']['url']) {
		return $block['attrs']['url'];
	}

	return null;
}

@priethor
Copy link
Contributor Author

Thanks for the quick follow-up, @dmsnell ! Yeah, I think that would work 👍

this could be fairly straightforward as long as we can add in our expectations on what makes for a nav item.

From my perspective and totally open to discussion, a good first selection of blocks that make for a nav item would be:

  • core/link
  • core/navigation-link
  • core/home-link
  • core/site-logo
  • core/site-title

The reason to include core/site-logo and core/site-title is that they act as links to the homepage, too, so from a navigation point of view, they provide the same functionality as core/home-link but with a different presentation. There can be some cases where a navigation block contains more than one of these three blocks, so the function should also remove duplicate links contained at the same hierarchy level.

@dmsnell
Copy link
Member

dmsnell commented Oct 27, 2021

Give it a try @priethor and let me know if things go awry - I'm happy to help out but I don't have the time on my plate at the moment to try it myself and have any reasonable ability to know if it's right. A quick warning though: I don't make any guarantee that the code I wrote above is correct or syntactically valid. It's likely something in there is wrong, but conceptually it should be right.

Those first blocks seem fine and you'd want to put them in the extract_nav_link function, something like this…

function extract_nav_link($block) {
	$name = $block['blockName'];
	$attrs = $block['attrs'];

	switch ($name) {
		case 'core/link':
			return $attrs['href'];

		case 'core/navigation-link':
			return $attrs['url'];

		case 'core/home-link':
			return home_url(); // or whatever is appropriate

		case 'core/site-logo':
		case 'core/site-title':
			return $attrs['isLink'] ? home_url() : null;
	}

	return nulll;
}

@priethor priethor added the Needs Dev Ready for, and needs developer efforts label Oct 28, 2021
@noisysocks
Copy link
Member

noisysocks commented Oct 29, 2021

Can we consider cutting this for 5.9 so that we can free up valuable @adamziel resources for other bits? I absolutely agree we need this API for block themes to compete with classic themes going forward, but for WP 5.9 I’m personally okay with saying “yes, this is a temporary downside of using a block theme”. We are labelling them "Beta" after all.

@priethor
Copy link
Contributor Author

I think postponing this to after 5.9 can be a good compromise, as it would also allow us to define the public API better before committing to it in core.

@noisysocks
Copy link
Member

Consider it punted! 🥾

@mtias
Copy link
Member

mtias commented Dec 2, 2021

This is essentially obsolete now that wp_navigation performs the isolation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Block] Navigation Affects the Navigation Block Needs Dev Ready for, and needs developer efforts [Type] New API New API to be used by plugin developers or package users.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants