Assign page name/parent name to body class


#1

Looking to dynamically add a body class to each page. The titles of static page’s (without children) or the parent’s page title of child pages.

That was hard to spit out!
Like this. . .

Home -> class=“home”
Projects -> class=“projects”
- Project -> class=“projects-child”
Blog -> class=“blog”
- Articles -> class=“blog-child”
About -> class=“about”

I hope that makes sense.

For the children, I’ve been able to echo the parent’s title as the class name with this code:
<body class="<?php echo $page->parent()->title()->html() ?>">
. . . in my headers.php snippet.

But the parent pages, or pages without any children, echo my site title as the body class.

I feel like I’m close to the solution, referring to the Fun With Loops article on Kirby Docs. And possibly with the ecco function from the PHP Templates Page .

And my original intention was to build this as a controller. Not sure if that’s the right approach? Maybe snippet?

Thanks for a point in the right direction.


#2
<?= $page->parents()->count()? $page->parent()->title().'-child':$page->title(); ?>

But I’d rather use the UID here instead of the title.

If you plan to use these classes in stylesheets, make sure that the UID (URL) of the page cannot be changed by the user.

If you want to use the title, I’d sluggify it: https://github.com/texnixe/kirby-custom-methods/blob/master/field-methods/to-slug.php


#3

I do it this way, but I like the look of what Sonja suggests, as it’s nice and short.

The difference with mine is that it picks up on the template for a page. which means you can style all pages using that template. If a page has children, i regard it as a section. You could add classes to it as well quite easily if you want to target a very specific page.

<?php if ($page->isHomePage()): ?>
  <body id="home">
<?php else: ?>
  <?php if ($page->hasVisibleChildren()): ?>
    <body id="<?= $page->template() ?>-section">
  <?php else: ?>
    <body id="<?= $page->template() ?>-page">
  <?php endif ?>
<?php endif ?>

As @texnixe points out, you need something fixed to make reliable class. I have got around this before by using the AutoID plugin, and appending the id on the end of class name. Classes cannot start with number but you can use them further along. For example .12-page is not valid css but .page-12 is.


#4

No, that doesn’t really make sense. However, you could create your own $page->getBodyClass()(or whatever you want to name it) custom function to make the code in the template even shorter.

page::$methods['getBodyClass'] = function($page) {
   $class= '';
   if($page->parents()->count()) {
    $class = $page->parent()->uid(); // or title or template
  } else {
    $class = $page->uid();
  }
    return $class
};

If you have have page levels beyond the second level, you might want to adapt the code.

Then in your template:

<body class="<?= $page->getBodyClass() ?>">

#5

Just out of curiosity, is there an advantage to checking for parents rather than the other direction, looking for children?


#6

Well, I want to apply a different class if the page is a child page, not if the page has children. So it makes more sense to check for that.

My standard case is: use page title/uid/template, so I don’t need a condition for the standard case. I use a condition for the non-standard case.


#7

I see… I thought perhaps it was less strenuous performance wise since there would usually be much fewer parents to find then there would be children.


#8

That’s probably irrelevant, it’s just a question of logic. As you can see, by applying the “wrong” kind of logic, your code gets longer than necessary.


#9

Thanks for this @jimbobrjames. Works like a charm! :grinning:
Same to you @texnixe! Always appreciate your feedback. :sunglasses: