coko
December 8, 2019, 12:01pm
1
(Kirby v 3.3.0)
Taking the {{ gallery }}
tag as an example, I’m making a {{ accordion }}
tag.
But I’m running into this error: Maximum function nesting level …
when I’m trying to display the accordion content panel.
This doesn’t work: <?= $item->accordion_content()->kt() ?>
This does work: <?= $item->accordion_content()->md() ?>
Using md()
will limit me in the display of (custom) KirbyTags so I’d rather not use it.
Blueprint:
accordion:
label: Accordion
type: structure
fields:
accordion_heading:
label: Heading
type: text
accordion_content:
label: Content
type: textarea
buttons:
- italic
- bold
- link
- '|'
- email
- file
- code
- '|'
- ul
- ol
Plugin (plugins/accordion/index.php):
<?php Kirby::plugin('kirby/accordion', [
'hooks' => [
'kirbytags:after' => function ($text, $data, $options) {
if ($page = $data['parent']->accordion()->toStructure()) {
$items = snippet('accordion', ['items' => $page], true);
} else {
$items = '';
}
return str_replace('{{ accordion }}', $items, $text);
}
]
]);
Snippet (snippets/accordion.php) that doesn’t work:
<div id="accordionGroup" class="accordion" data-allow-toggle>
<?php
$n=0;
foreach ($items as $item): $n++;
?>
<h3>
<button aria-expanded="<?= e($n > 1, 'false', 'true') ?>" class="accordion-trigger" aria-controls="<?= 'sect' . $n ?>" id="<?= 'accordion' . $n . 'id' ?>">
<span class="accordion-title">
<?= $item->accordion_heading()->html() ?>
<span class="accordion-icon"></span>
</span>
</button>
</h3>
<div id="<?= 'sect' . $n ?>" role="region" aria-labelledby="<?= 'accordion' . $n . 'id' ?>" class="accordion-panel" <?= e($n > 1, 'hidden=""', '') ?>>
<div>
<?= $item->accordion_content()->kt() ?>
</div>
</div>
<?php endforeach ?>
</div>
I remember running into this problem before and was able to solve it with something like: <?= kt($item->accordion_content()) ?>
but that doesn’t help in this case.
Also I noticed: using the snippet with 4 spaces indentation will break my layout because <pre>
tags are placed at certain points in the markup of the accordion.
texnixe
December 8, 2019, 12:27pm
2
You are running into an endless loop because you are trying to call the kirbytext()
method inside your snippet, which will then trigger the hook etc.
You can replace your hook code like this:
Kirby::plugin('kirby/accordion', [
'hooks' => [
'kirbytags:before' => function ($text, $data) {
return preg_replace_callback('!{{(.*)}}!siU', function($match) use ($data) {
$block = '';
if ($items = $data['parent']->accordion()->toStructure()) {
$block = snippet('accordion', ['items' => $items]);
}
return $block;
}, $text);
}
]
]);
coko
December 8, 2019, 2:22pm
5
I had already given up on it, cool thanks a bunch!
coko
December 8, 2019, 2:58pm
6
Just tried this: this places two accordions on the page. One before and one after a cover image.
Also doesn’t play nicely with the {{ gallery }}
tag, breaks it.
Oh, I applied that to every tag, should of course just apply to the accordion tag:
'kirbytags:before' => function ($text, $data) {
return preg_replace_callback('!{{ accordion }}!siU', function($match) use ($data) {
$block = '';
if ($items = $data['parent']->accordion()->toStructure()) {
$block = snippet('accordion', ['items' => $items]);
}
return $block;
}, $text);
}
You might want to adapt the regex to make sure it also works when the user doesn’t use spaces between the curly braces.
coko
December 8, 2019, 3:29pm
8
Yes, I already tried that, but it doesn’t solve the double accordion.
Hm, I can’t reproduce the double accordion.
coko
December 8, 2019, 4:45pm
10
When I trash this toc-code it works:
Can you see the problem?
<?php Kirby::plugin('kirby/toc', [
'fieldMethods' => [
'headlines' => function($field, $headline = 'h2') {
preg_match_all('!<' . $headline . '.*?>(.*?)</' . $headline . '>!s', $field->kt()->value(), $matches);
$headlines = new Collection;
foreach ($matches[1] as $text) {
$headline = new Obj([
'id' => $id = '#' . Str::slug(Str::unhtml($text)),
'url' => $id,
'text' => trim(strip_tags($text)),
]);
$headlines->append($headline->url(), $headline);
}
return $headlines;
}
]
]);
texnixe
December 8, 2019, 6:14pm
11
No, you took that code from the getkirby.com repo, right?
I can reproduce your issue with the duplicate accordions when I use the headlines
method in the same template, but I currently don’t know how to solve this.
coko
December 8, 2019, 6:32pm
12
That’s right, it was from a thread where you explained how to use it and I followed that example.
I will use the markdown version for now and maybe you will have a moment.
texnixe
December 8, 2019, 7:05pm
13
If you don’t call your headlines()
method directly in the same template, but in a snippet like in the. getkirby.com repo, it should work:
/snippets/toc.php
<?php if($item->count() > 3): ?>
<nav class="toc | -mb:large">
<h2 class="h4">Table of Contents</h2>
<ol>
<?php foreach($item as $headline): ?>
<li><a href="<?= $headline->url() ?>"><span><?= $headline->text() ?></span></a></li>
<?php endforeach ?>
</ol>
</nav>
<?php endif ?>
And in template
snippet('toc', $page->description()->headlines())
coko
December 8, 2019, 7:18pm
14
Currently:
plugin: plugins/toc/index.php
snippet: toc.php
(code where I have conditionals at work to combine toc with cover image)
snippet: page-content.php
where I call: snippet('toc', $page->text()->headlines())
more stuff in here though
page template: snippet('page-content')
No doubt you would clean this up and maybe this is the source of all the troubles?
I’ll try your suggestion …
texnixe
December 8, 2019, 7:36pm
15
Actually, I had a typo in my code, so with the changes above, everything should actually work as expected. Still doesn’t in your case?
coko
December 8, 2019, 7:37pm
16
Bit confused about dump($field->headlines());
what $field
etc.
But what typo was that?
texnixe
December 8, 2019, 7:41pm
17
That was just from my first test. The code just dumps the content of $field->headlines()
. It’s a way to check what you get back from your code. Just stick with the toc
snippet from the getkirby.com repo. I removed the dump()
code again.
coko:
But what typo was that?
Just in my local code, I made changes and forgot to add true
as third param to a snippet, which resulted in the wrong order.
coko
December 8, 2019, 7:49pm
18
snippet/toc.php:
<?php // ToC combined with cover
if($item->count() and $page->toc()->bool() and $page->cover_toc()->bool()): ?>
<nav class="toc-cover" aria-labelledby="toc-head">
<div class="toc">
<h2 class="toc-heading" id="toc-head">On this page</h2>
<ol>
<?php foreach($item as $headline): ?>
<li><a href="<?= $headline->url() ?>"><?= $headline->text() ?></a></li>
<?php endforeach ?>
</ol>
</div>
<?php // cover image
if($cover = $page->cover()->toFile() and $page->showcover()->bool()): ?>
<figure>
<img src="<?= $cover->url(); ?>" srcset="<?= $cover->srcset() ?>" alt="<?= $cover->alt(); ?>">
</figure>
<?php endif ?>
</nav>
<?php endif ?>
plugin:
<?php Kirby::plugin('kirby/toc', [
'fieldMethods' => [
'headlines' => function($field, $headline = 'h2') {
preg_match_all('!<' . $headline . '.*?>(.*?)</' . $headline . '>!s', $field->kt()->value(), $matches);
$headlines = new Collection;
foreach ($matches[1] as $text) {
$headline = new Obj([
'id' => $id = '#' . Str::slug(Str::unhtml($text)),
'url' => $id,
'text' => trim(strip_tags($text)),
]);
$headlines->append($headline->url(), $headline);
}
return $headlines;
}
]
]);
snippet page-content:
<?php snippet('toc', $page->text()->headlines()) ?>
Which all worked fine but not with the accordion {{ accordion }}
and the preg_replace_callback
.
coko
December 8, 2019, 7:55pm
19
Thanks you are amazingly kind to stick with this.
I have to go now but again thanks for all your efforts!
coko
December 9, 2019, 5:48am
20
I found the/a solution. In the toc plugin I replaced:
preg_match_all('!<' . $headline . '.*?>(.*?)</' . $headline . '>!s', $field->kt()->value(), $matches);
replaced with:
preg_match_all('!<' . $headline . '.*?>(.*?)</' . $headline . '>!s', $field->md()->value(), $matches);
Swapping kt() for md() .
Resulting in a nice toc and one accordion (including kt link):
btw: I’m calling the toc and my page text field in the same template:
<?php // ToC and cover image see also plugins › toc
snippet('toc', $page->text()->headlines()) ?>
<?php // page text replacing escaped opening parenthesis '(\' for kirbytext examples
echo str_replace('(\\', '(', kirbytext($page->text())) ?>