Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ The `docs/` directory contains **what** applies to this project:
- `docs/releasing.md` - Version scheme and release process
- `docs/sitemap.md` - XML sitemap module, coverage and generation
- `docs/seo.md` - Meta tags, social share cards and structured data
- `docs/related-content.md` - Related-content lists and topic pages

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

One line in the docs index, because AGENTS.md enumerates every file in docs/ with a one-line description and a new doc that is not listed there is a doc nobody finds. Nothing else in this file changed.

- `docs/performance.md` - Image styles, self-hosted fonts and layout stability
- `docs/preview-links.md` - sharing unpublished content by link
- `docs/faqs.md` - Project-specific FAQs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dependencies:
- field.field.paragraph.civictheme_automated_list.field_c_p_list_link_below
- field.field.paragraph.civictheme_automated_list.field_c_p_list_site_sections
- field.field.paragraph.civictheme_automated_list.field_c_p_list_topics
- field.field.paragraph.civictheme_automated_list.field_c_p_list_topics_from_page

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Places the new checkbox on the paragraph edit form. Weight 6 puts it directly above Topics, which is a deliberate judgment call and the one worth challenging: the checkbox makes the Topics field below it inert, so it has to be seen before Topics is filled in, not after. The alternative - grouping it with the other list-behaviour fields further down - reads more tidily but lets an editor pick topics and then discover they were ignored.

boolean_checkbox with display_label: true so the label sits beside the box rather than above it, matching the other booleans on this form.

The dependency line is added automatically by config export; it is not a separate decision.

- field.field.paragraph.civictheme_automated_list.field_c_p_list_type
- field.field.paragraph.civictheme_automated_list.field_c_p_theme
- field.field.paragraph.civictheme_automated_list.field_c_p_title
Expand Down Expand Up @@ -330,6 +331,13 @@ content:
size: 60
placeholder: ''
third_party_settings: { }
field_c_p_list_topics_from_page:
type: boolean_checkbox
weight: 6
region: content
settings:
display_label: true
third_party_settings: { }
field_c_p_list_type:
type: options_select
weight: 12
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ dependencies:
- field.field.paragraph.civictheme_automated_list.field_c_p_list_link_below
- field.field.paragraph.civictheme_automated_list.field_c_p_list_site_sections
- field.field.paragraph.civictheme_automated_list.field_c_p_list_topics
- field.field.paragraph.civictheme_automated_list.field_c_p_list_topics_from_page

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Hides the new field on the paragraph's view display. This is not a preference - it is required. Every setting field on this paragraph (field_c_p_list_limit, field_c_p_list_type, field_c_p_list_topics) is hidden here, because CivicTheme's civictheme_preprocess_paragraph__civictheme_automated_list() sets $variables['content'] = NULL and rebuilds the output from the field values itself. Anything left visible would be discarded anyway, and would show up as a stray "Use topics of the current page: On" line if that preprocessing ever changed.

The dependency line above is added by config export.

- field.field.paragraph.civictheme_automated_list.field_c_p_list_type
- field.field.paragraph.civictheme_automated_list.field_c_p_theme
- field.field.paragraph.civictheme_automated_list.field_c_p_title
Expand Down Expand Up @@ -187,4 +188,5 @@ hidden:
field_c_p_list_feed_description: true
field_c_p_list_feed_slug: true
field_c_p_list_feed_title: true
field_c_p_list_topics_from_page: true
search_api_excerpt: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
uuid: e14c416c-d960-4b6f-997a-28b9d066b806

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The field that carries the whole feature. It is a plain boolean rather than a list of modes (manual / current page) because there are exactly two states and a checkbox says so without a vocabulary of its own.

translatable: false is deliberate and was changed after review. It looks inconsistent with the storage file, which says true - the storage decides whether the field can be translated, the instance decides whether it is. The fields this one sits with (field_c_p_list_topics, field_c_p_list_limit_type, field_c_p_list_type) are all non-translatable, and a boolean switch has no content to translate. Some other fields on this paragraph are true, so the shipped convention is genuinely mixed; I matched the list-behaviour group rather than the paragraph as a whole.

The description does the real work of preventing confusion: it states that turning this on ignores the Topics field, since nothing in the UI otherwise shows that Topics has gone inert.

langcode: en
status: true
dependencies:
config:
- field.storage.paragraph.field_c_p_list_topics_from_page
- paragraphs.paragraphs_type.civictheme_automated_list
id: paragraph.civictheme_automated_list.field_c_p_list_topics_from_page
field_name: field_c_p_list_topics_from_page
entity_type: paragraph
bundle: civictheme_automated_list
label: 'Use topics of the current page'
description: 'Lists content sharing a topic with the page this list is placed on, and leaves that page out. Turning this on ignores the Topics chosen below.'
required: false
translatable: false
default_value:
-
value: 0
default_value_callback: ''
settings:
on_label: 'On'
off_label: 'Off'
field_type: boolean
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
uuid: 23a1da2f-ff37-48b0-8f36-884310059227

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Storage for the new boolean. Nothing here was chosen by hand beyond the type and cardinality: 1 - the rest is what Drupal writes for a boolean field.

translatable: true here alongside translatable: false on the field instance is not a mistake: storage-level translatability is the ceiling, the instance is the actual setting. This matches every other boolean on this paragraph.

langcode: en
status: true
dependencies:
module:
- paragraphs
id: paragraph.field_c_p_list_topics_from_page
field_name: field_c_p_list_topics_from_page
entity_type: paragraph
type: boolean
settings: { }
module: core
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false
24 changes: 24 additions & 0 deletions config/default/pathauto.pattern.civictheme_topics.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
uuid: 5d9a1e32-1f80-40d0-8067-054765cf9763

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Gives topic terms an alias, without which the "second stable inbound link" this issue asks for would be /taxonomy/term/32.

/topics/[term:name] matches the shape of the existing node patterns (/blog/[node:title], /work/...). The selection criteria restrict it to the civictheme_topics vocabulary, so civictheme_site_sections, civictheme_media_tags, do_sector and do_technology terms are untouched and keep whatever they have.

Worth knowing: adding this pattern is not enough on its own. Most existing topics carry PathautoState::SKIP and a bulk generate will not touch them, which is what the deploy hook in do_base.deploy.php is for.

langcode: en
status: true
dependencies:
config:
- taxonomy.vocabulary.civictheme_topics
module:
- taxonomy
id: civictheme_topics
label: Topic
type: 'canonical_entities:taxonomy_term'
pattern: '/topics/[term:name]'
selection_criteria:
9f1d5c7a-3e4b-4a2d-8c6f-1b7e2a9d4c53:
id: 'entity_bundle:taxonomy_term'
negate: false
context_mapping:
taxonomy_term: taxonomy_term
bundles:
civictheme_topics: civictheme_topics
uuid: 9f1d5c7a-3e4b-4a2d-8c6f-1b7e2a9d4c53
selection_logic: and
weight: -5
relationships: { }
30 changes: 19 additions & 11 deletions config/default/views.view.taxonomy_term.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,27 @@ display:
display_options:
fields: { }
pager:
type: mini
type: full

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is the widest change in the PR and the one most worth challenging.

taxonomy_term is core's shared term view: it serves the canonical /taxonomy/term/% route for every vocabulary. Restyling it to a CivicTheme promo-card grid therefore also changes how civictheme_site_sections, civictheme_media_tags, do_sector and do_technology term pages render, not just topics.

I took that blast radius deliberately. The alternative was a dedicated view at /topics/%, which I rejected because it leaves /taxonomy/term/N still serving the unstyled core page - two URLs for one topic, which is the opposite of what this issue is trying to achieve. Views cannot take over an entity's canonical route for one bundle only, so a per-vocabulary treatment here is not straightforward.

The judgment that makes it acceptable is that no other vocabulary's terms are linked from anywhere on the site, so in practice only topic pages are reachable. If that is wrong - if a site section term page is linked somewhere I did not find - this changes a page you did not ask me to change. That is the assumption to check.

Specifics: teasercivictheme_promo_card and default style → grid so the page matches the blog and work listings; every node bundle already has a civictheme_promo_card display, so no bundle falls back to an unstyled row. Pager minifull with 12 per page, matching the automated lists rather than core's 10 and ‹‹ ›› arrows.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Superseded by 1536d0a. The comment above describes a 3-column promo-card grid, which was wrong: term listings should use the snippet list, matching how views.view.civictheme_search renders results (style: grid with columns: 1, rows in the civictheme_snippet view mode).

Now changed to exactly that. Worth knowing for anyone touching it: no node bundle has a core.entity_view_display.node.*.civictheme_snippet config at all - the view mode is driven entirely by node--civictheme-snippet.html.twig, which is why this works for blog and project even though the search view only maps civictheme_event and civictheme_page explicitly.

The blast-radius point in the comment above still stands unchanged: this is core's shared term view, so it governs every vocabulary, and it rests on the assumption that no other vocabulary's term pages are linked from the site.

One thing this made visible rather than introduced: the core feed attachment renders an unstyled "Subscribe to " link at the foot of the page. It was always in this view; it is only noticeable now that the page is reachable and styled. Not touched here.

options:
offset: 0
pagination_heading_level: h4
items_per_page: 10
total_pages: 0
items_per_page: 12
total_pages: null
id: 0
tags:
next: ››
previous: ‹‹
next: Next
previous: Previous
first: First
last: Last
expose:
items_per_page: false
items_per_page_label: 'Items per page'
items_per_page_options: '5, 10, 25, 50'
items_per_page_options: '6, 12, 24, 48'
items_per_page_options_all: false
items_per_page_options_all_label: '- All -'
offset: false
offset_label: Offset
quantity: 5
exposed_form:
type: basic
options:
Expand Down Expand Up @@ -214,16 +217,21 @@ display:
default_group_multiple: { }
group_items: { }
style:
type: default
type: grid
options:
grouping: { }
row_class: ''
default_row_class: true
uses_fields: false
columns: 1
automatic_width: true
alignment: horizontal
row_class_custom: ''
row_class_default: true
col_class_custom: ''
col_class_default: true
row:
type: 'entity:node'
options:
view_mode: teaser
relationship: none
view_mode: civictheme_snippet
query:
type: views_query
options:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
status: true

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Lists topic pages in the XML sitemap. They were excluded before, correctly - they had no alias and core's teaser rendering, so there was nothing worth submitting.

priority: 0.5 is the neutral default rather than a claim that topics matter more or less than posts. changefreq: 0 leaves the hint off entirely: a topic page changes whenever a post is added to it, which is not a frequency I can state honestly, and search engines treat a wrong changefreq worse than an absent one.

Scoped to civictheme_topics only, so the other vocabularies stay out of the sitemap.

priority: 0.5
changefreq: 0
33 changes: 33 additions & 0 deletions docs/related-content.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Related content and topic pages

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

A new doc, because docs/ is where this project keeps decisions that the code cannot state for itself, and two things here will otherwise be re-broken by whoever touches them next:

  • $arguments[1] in the theme alter depends on the argument order in views.view.civictheme_automated_list. Reordering the contextual filters in the Views UI would silently point the swap at the wrong one, with no test failure at the point of the edit.
  • The topic aliases needed a deploy hook rather than a bulk generate, for a reason (PathautoState::SKIP) that is invisible from either the pattern config or the alias table.

Indexed in AGENTS.md alongside the other topic docs.


Excluding the site navigation, most pages on this site had exactly one inbound internal link, and for the majority of them that link was a pager page. Nothing was unreachable, but a post published a while ago was reachable only by paging the blog listing. Two things address that, and they work together.

## An Automated list can follow the page's own topics

The Automated list paragraph carries a **Use topics of the current page** checkbox (`field_c_p_list_topics_from_page`). With it on, the list ignores the Topics chosen on the paragraph and matches the topics of the node it is placed on instead, which turns the same component into a related-content list. Nothing new was built to do this: it is the Automated list, configured differently.

`drevops_civictheme_automated_list_view_alter()` in `web/themes/custom/drevops/includes/automated_list.inc` swaps the Topics contextual argument just before the view runs. CivicTheme fires that alter through the theme manager as well as the module handler, which is why this lives in the theme alongside the rest of the component's theming rather than in a module.

Points worth knowing before changing it:

- **The page being viewed is already excluded.** The view's fourth contextual filter is `nid` with `not` set, and it takes its value from the route, so a related list never lists the post it sits on. `_civictheme_automated_list__update_view()` passes only three arguments, which is what leaves that one to its route default.
- **The topics argument is position 1.** The arguments are ordered content type, topics, site sections. Reordering them in the view would silently point the swap at the wrong filter.
- **A post with no topics gets `none`, not `all`.** Without that, an empty topic set would fall through to the view's `all` default and advertise the whole site as related.
- **An empty result hides the heading.** `drevops_preprocess_paragraph__civictheme_automated_list()` clears the title when the list found nothing, so a post whose topics nothing else shares does not render a heading introducing empty space.

`do_base_deploy_add_related_lists()` puts one of these lists on every existing blog post. It is skipped for a post that already has one, so it is safe to re-run.

## Topic pages

Topic terms are the second, stable inbound link: unlike a pager page, a topic page does not change what it points at as content is added.

- `pathauto.pattern.civictheme_topics` puts them at `/topics/<name>`.
- `do_base_deploy_alias_topic_terms()` hands every existing topic back to that pattern. Topics created programmatically carry `PathautoState::SKIP`, which is why most of them had no alias at all and a bulk generate would not give them one.
- The topic tags at the foot of a post link to these pages. `_drevops_node_add_topic_tags()` reads the referenced terms rather than their labels so each tag gets a `url`, which is what the `civictheme:tag` component turns into a link.
- `views.view.taxonomy_term` renders term pages as a CivicTheme promo-card grid with a full pager, rather than core's teaser list. This is the shared term view, so it applies to every vocabulary - acceptable because no other vocabulary's terms are linked from the site.
- Topic pages are listed in the XML sitemap.

## Related

- [SEO](seo.md) - meta tags, social share cards and structured data
- [Development agreements](development.md) - deploy hook conventions these follow
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
@p0 @civictheme @civictheme_automated_list

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Behat rather than PHPUnit because the behaviour only exists once a real request has a node in the route: the alter reads \Drupal::routeMatch(), and the view's nid argument resolves from the route too. A kernel test would have to fake both, and would then be testing the fake.

Four scenarios, each isolating one decision rather than one feature:

  1. the list shows a post sharing the page's topic;
  2. it excludes both the page itself and posts on other topics - these are two different mechanisms (the nid argument, and the topics argument) that would otherwise pass as one assertion;
  3. a post whose topics nothing shares renders no heading - this is the 'none' sentinel and the title-clearing preprocess, and it is the scenario that fails if either is removed;
  4. the topic tags lead to a topic page that lists the post - covers the node.inc change and the alias pattern together.

field_c_p_list_topics_from_page is set to 1 rather than true because the Behat entity stub writes raw field values.

The background builds a fourth post with no topics that should never appear, so scenario 2 fails if the topics argument is dropped entirely rather than merely mis-scoped.

Feature: Automated list following the page's own topics

As a site visitor
I want a post to link to others on the same topic
So that I can keep reading without going back to a paginated listing

Background:
Given the following "civictheme_topics" terms:
| name |
| [TEST] Shared Topic |
| [TEST] Other Topic |

And the following "blog" content:
| title | moderation_state | created | field_c_n_topics |
| [TEST] Post Being Read | published | [relative:-1 day] | [TEST] Shared Topic |
| [TEST] Post Same Topic | published | [relative:-2 days] | [TEST] Shared Topic |
| [TEST] Post Other Topic | published | [relative:-3 days] | [TEST] Other Topic |
| [TEST] Post Without Topic | published | [relative:-4 days] | |

And the following fields for the paragraph "civictheme_automated_list" exist in the field "field_c_n_components" within the "blog" "node" identified by the field "title" and the value "[TEST] Post Being Read":
| field_c_p_title | [TEST] Related posts |
| field_c_p_list_type | civictheme_automated_list__block1 |
| field_c_p_list_content_type | blog |
| field_c_p_list_limit_type | limited |
| field_c_p_list_limit | 3 |
| field_c_p_list_topics_from_page | 1 |

@api
Scenario: The list shows posts sharing the page's topic
Given I am an anonymous user

When I visit the "blog" content page with the title "[TEST] Post Being Read"
Then I should see the text "[TEST] Related posts"
And I should see "[TEST] Post Same Topic"

@api
Scenario: The list leaves out the page it is on and posts on other topics
Given I am an anonymous user

When I visit the "blog" content page with the title "[TEST] Post Being Read"
Then I should not see "[TEST] Post Other Topic"
And I should not see "[TEST] Post Without Topic"
And I should see 1 ".ct-promo-card" elements

@api
Scenario: A post whose topics nothing shares shows no heading
Given the following fields for the paragraph "civictheme_automated_list" exist in the field "field_c_n_components" within the "blog" "node" identified by the field "title" and the value "[TEST] Post Without Topic":
| field_c_p_title | [TEST] Related posts |
| field_c_p_list_type | civictheme_automated_list__block1 |
| field_c_p_list_content_type | blog |
| field_c_p_list_limit_type | limited |
| field_c_p_list_limit | 3 |
| field_c_p_list_topics_from_page | 1 |

And I am an anonymous user

When I visit the "blog" content page with the title "[TEST] Post Without Topic"
Then I should not see the text "[TEST] Related posts"

@api
Scenario: A post links to the topic pages it belongs to
Given I am an anonymous user

When I visit the "blog" content page with the title "[TEST] Post Being Read"
Then I should see the link "[TEST] Shared Topic"

When I click "[TEST] Shared Topic"
Then the path should be "/topics/test-shared-topic"
And I should see "[TEST] Post Same Topic"
And I should see "[TEST] Post Being Read"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
And I should not see "[TEST] Post Other Topic"
And I should not see "[TEST] Post Without Topic"
80 changes: 80 additions & 0 deletions web/modules/custom/do_base/do_base.deploy.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use Drupal\media\MediaInterface;
use Drupal\menu_link_content\MenuLinkContentInterface;
use Drupal\node\NodeInterface;
use Drupal\paragraphs\Entity\Paragraph;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Two deploy hooks, both existing only to bring existing content up to what the new code assumes. Neither is needed for a fresh install.

do_base_deploy_alias_topic_terms() - the non-obvious one. Adding the pathauto pattern does not alias existing topics: 24 of the 33 carry PathautoState::SKIP from having been created programmatically, and drush pathauto:aliases-generate reports "no new URL aliases to generate" for them because it honours that flag. The hook sets the state back to CREATE and saves, which is what actually mints the alias. I found this the slow way - the pattern looked correct and /topics/vortex still 404'd.

do_base_deploy_add_related_lists() - creates content from code, which is worth questioning. The alternative is for editors to add the paragraph per post, which is the honest reading of "make the Automated list reusable"; but that leaves the 40+ existing posts the issue is about untouched. The hook is the migration, not the mechanism.

Two details in that hook that look odd:

  • setNewRevision(FALSE) - without it every blog post gains a revision recording a change no human made, which clutters the revision UI the editors actually use. The trade-off is that this edit is not attributable in the revision log; the deploy log records it instead.
  • The guard loops the existing components looking for an automated list that already has the flag set, rather than a simple "has any automated list" check. A post may legitimately carry an ordinary automated list already; only a related one means the hook has run.

Both follow the batching and reporting conventions in docs/development.md. Paragraph::create() is used over the storage handler only to satisfy PHPStan, which cannot see setParentEntity() on the EntityInterface the storage returns.

use Drupal\paragraphs\ParagraphInterface;
use Drupal\path_alias\PathAliasInterface;
use Drupal\pathauto\PathautoState;
Expand Down Expand Up @@ -1249,3 +1250,82 @@ function _do_base_blog_reindex(int|string $nid, array $langcodes): void {
}
}
}

/**
* Gives every topic term a URL alias so topic pages are reachable.
*/
function do_base_deploy_alias_topic_terms(?array &$sandbox = NULL): ?string {
$query = \Drupal::entityQuery('taxonomy_term')
->accessCheck(FALSE)
->condition('vid', 'civictheme_topics');

return Helper::entity($sandbox, 25)->batchQuery($query, static function (TermInterface $term): void {
_do_base_alias_topic_term($term);
}, status: Reporter::UPDATED);
}

/**
* Puts a topic term back under the alias pattern and saves it.
*/
function _do_base_alias_topic_term(TermInterface $term): void {
if (!$term->hasField('path')) {
return;
}

// Terms created programmatically carry SKIP, which is why most topics have
// no alias at all. Handing them back to the pattern is what puts them on
// /topics/<name>, and it keeps them there when an editor renames one.
$term->set('path', ['pathauto' => PathautoState::CREATE]);
$term->save();
}

/**
* Adds a related-content list to the foot of every blog post.
*/
function do_base_deploy_add_related_lists(?array &$sandbox = NULL): ?string {
$query = \Drupal::entityQuery('node')
->accessCheck(FALSE)
->condition('type', 'blog');

return Helper::entity($sandbox, 10)->batchQuery($query, static function (NodeInterface $node): void {
_do_base_add_related_list($node);
}, status: Reporter::UPDATED);
}

/**
* Appends an Automated list configured to follow the post's own topics.
*/
function _do_base_add_related_list(NodeInterface $node): void {
if (!$node->hasField('field_c_n_components')) {
return;
}

foreach ($node->get('field_c_n_components')->referencedEntities() as $existing) {
if ($existing instanceof ParagraphInterface && $existing->bundle() === 'civictheme_automated_list' && !$existing->get('field_c_p_list_topics_from_page')->isEmpty() && (bool) $existing->get('field_c_p_list_topics_from_page')->value) {
return;
}
}

$paragraph = Paragraph::create([
'type' => 'civictheme_automated_list',
'field_c_p_title' => 'Related posts',
'field_c_p_list_type' => 'civictheme_automated_list__block1',
'field_c_p_list_content_type' => 'blog',
'field_c_p_list_limit_type' => 'limited',
'field_c_p_list_limit' => 3,
'field_c_p_list_column_count' => 3,
'field_c_p_list_topics_from_page' => 1,
]);
$paragraph->setParentEntity($node, 'field_c_n_components');
$paragraph->save();

$components = $node->get('field_c_n_components')->getValue();
$components[] = [
'target_id' => $paragraph->id(),
'target_revision_id' => $paragraph->getRevisionId(),
];

$node->set('field_c_n_components', $components);
$node->setNewRevision(FALSE);
$node->save();
}
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,10 @@ protected function automatedList(int $index): array {
'field_c_p_list_filters_exp' => $this->option('civictheme_automated_list', 'field_c_p_list_filters_exp', $index),
'field_c_p_list_column_count' => $this->option('civictheme_automated_list', 'field_c_p_list_column_count', $index),
'field_c_p_list_fill_width' => CaseMatrix::bit($index, 1),
// Shares bit 0 rather than taking a high bit of its own: this component
// is itself placed on only a few nodes of a run, so a high bit turns on
// for a list that reaches a page too rarely to be worth looking at.
'field_c_p_list_topics_from_page' => CaseMatrix::bit($index, 0),
'field_c_p_list_limit' => CaseMatrix::cycle([3, 6, 9], $index),
'field_c_p_list_link_above' => $this->link('View all'),
'field_c_p_list_link_below' => $this->link('See more'),
Expand Down
1 change: 1 addition & 0 deletions web/themes/custom/drevops/drevops.theme
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ require_once __DIR__ . '/includes/banner.inc';
require_once __DIR__ . '/includes/paragraphs.inc';
require_once __DIR__ . '/includes/divider.inc';
require_once __DIR__ . '/includes/manual_list.inc';
require_once __DIR__ . '/includes/automated_list.inc';

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

One require_once for the new include. This theme has no autoloading for includes/, so a file that is not required here simply never loads and its hooks never fire - silently.

Placed next to manual_list.inc so the two list components sit together rather than at the end of the list.

require_once __DIR__ . '/includes/steps.inc';
require_once __DIR__ . '/includes/page.inc';
require_once __DIR__ . '/includes/node.inc';
Expand Down
Loading
Loading