From 5eeeeb3f5b02bbbe093cbf63d3c6804ecc642f00 Mon Sep 17 00:00:00 2001 From: Rob Skilling Date: Tue, 17 May 2022 11:54:36 +0100 Subject: [PATCH] Add class to generate in-page navigation items Following on from the previous commit, we need a class that can generate a list of items that represent H2s within a long-read post to be navigated to. This class parses the blocks in the content of a post, and then returns an array of objects (one for each H2 in the content), where each object has a 'title' property of the heading text, and an 'id' property of the id attached to that H2, that we will then be able to use in an anchor link. Functionality to ensure WordPress auto-generates IDs for all heading blocks will need to be activated for this to work correctly, and this will be enforced in a forthcoming commit. For: https://trello.com/c/KuFLpg6U/570-%F0%9F%8E%AF-goal-implement-long-read-template-for-lambeth-together-and-enable-gutenberg-for-this --- spec/in_page_navigation.spec.php | 77 ++++++++++++++++++++++++++++++++ src/InPageNavigation.php | 24 ++++++++++ 2 files changed, 101 insertions(+) create mode 100644 spec/in_page_navigation.spec.php create mode 100644 src/InPageNavigation.php diff --git a/spec/in_page_navigation.spec.php b/spec/in_page_navigation.spec.php new file mode 100644 index 0000000..eb7f37b --- /dev/null +++ b/spec/in_page_navigation.spec.php @@ -0,0 +1,77 @@ +inPageNavigation = new \LongReadPlugin\InPageNavigation(); + }); + + describe('->getItems()', function () { + it('does not return anything for non-heading blocks', function () { + global $post; + $post->post_content = 'Some content'; + $blocks = [ + [ + 'blockName' => 'not-heading' + ], + [ + 'blockName' => 'also-not-heading' + ], + ]; + allow('parse_blocks')->toBeCalled()->andReturn($blocks); + + $result = $this->inPageNavigation->getItems(); + + expect($result)->toEqual([]); + }); + + it('does not return anything for heading blocks not of level 2', function () { + global $post; + $post->post_content = 'Some content'; + $blocks = [ + [ + 'blockName' => 'core/heading', + 'attrs' => [ + 'level' => 3 + ] + ], + [ + 'blockName' => 'core/heading', + 'attrs' => [ + 'level' => 4 + ] + ], + ]; + allow('parse_blocks')->toBeCalled()->andReturn($blocks); + + $result = $this->inPageNavigation->getItems(); + + expect($result)->toEqual([]); + }); + + it('returns items for heading blocks with no level (as level 2 is the default)', function () { + global $post; + $post->post_content = 'Some content'; + $blocks = [ + [ + 'blockName' => 'core/heading', + 'attrs' => [], + 'innerHTML' => '

First heading

' + ], + [ + 'blockName' => 'core/heading', + 'attrs' => [], + 'innerHTML' => '

Second heading

' + ], + ]; + allow('parse_blocks')->toBeCalled()->andReturn($blocks); + + $result = $this->inPageNavigation->getItems(); + + expect(count($result))->toEqual(2); + expect($result[0]->title)->toEqual("First heading"); + expect($result[0]->id)->toEqual('first-heading'); + expect($result[1]->title)->toEqual("Second heading"); + expect($result[1]->id)->toEqual('second-heading'); + }); + }); +}); diff --git a/src/InPageNavigation.php b/src/InPageNavigation.php new file mode 100644 index 0000000..e6d2d71 --- /dev/null +++ b/src/InPageNavigation.php @@ -0,0 +1,24 @@ +post_content); + foreach ($blocks as $block) { + if ($block['blockName'] == 'core/heading' && array_key_exists('attrs', $block) && (!isset($block['attrs']['level']) || $block['attrs']['level'] == 2)) { + $matches = []; + preg_match('/(id=")(.*)"/', $block['innerHTML'], $matches); + $inPageNavItems[] = (object) [ + 'title' => trim(strip_tags($block["innerHTML"])), + 'id' => $matches[2] + ]; + } + } + return $inPageNavItems; + } +}