Skip to main content

Extending post objects

In wp-lemon it's possible to extend the post objects to add functionality if needed. This can be very useful when further customizing your site. Later on in this chapter we'll show you a couple of examples of how you can use this functionality.

Setting up

For the set-up you'll need to do the following:

  1. Create a new file in the /library/classes/ directory with the pattern class-object-<post_type_name>.php where post_type_name is the name of your post type.
  2. Add the new class to the classmap.
  3. Include the file in your functions file.

Create new file

Navigate to the /library/classes/ directory. Here you can create a new file that extends the LemonPost class. This will look something like this:


<?php

/**
* Setup an extended post query class.
* Used for post_type_name
*
* @package WordPress
* @subpackage WP_Lemon\Child
*/

namespace WP_Lemon\Child\Classes;

use WP_Lemon\Classes\LemonPost;
use Timber\Timber;

class post_type_name extends LemonPost
{
private mixed $_example = null;

public function get_example(): array|null
{
if (!is_null($this->_example)) {
return $this->_example;
}

return $this->_example;
}
}

Add to classmap

After you've created this file you'll need to add it to the classmap, this needs to be done so that Timber knows where to find the new class. You should do this inside the /library directory. In essence you could place it anywhere like in the hooks.php file but we prever to place it in the child-setup.php file since it's part of the setup process. This will look something like this:


add_filter(
'timber/post/classmap',
function ($classmap) {
$custom_classmap = [
'person' => Person::class,
'publication' => Publication::class,
'project' => Project::class,
'lectorate' => Lectorate::class,
'news' => News::class,
'post-education' => PostEduction::class,
'education' => Education::class,
];

return array_merge($classmap, $custom_classmap);
}
);

Include the file

Then last but not least you'll have to include the file so that it gets loaded when the theme is loaded. Navigate to the functions.php file in the root of your theme. Here you can include the file like this:


function parent_loaded()
{
$autoloader = new Autoloader();
$autoloader->child(['models']); // order in which our folders get autoloaded.
$autoloader->child_blocks();

$includes = [
'library/classes/class-child-site.php',
'library/classes/class-object-news.php',
'library/classes/class-object-<post_type_name>.php',
'library/child-setup.php',
'library/hooks.php',
];

foreach ($includes as $file) {
$filepath = locate_template($file);
if (!$filepath) {
/* translators: %s: file to include */
Bulldozer::frontend_error(sprintf(__('Error locating %s for inclusion', 'wp-lemon'), $file));
}
require_once $filepath;
}
unset($file, $filepath);

new WP_Lemon_Child_Site();
}
add_action('parent_loaded', __NAMESPACE__ . '\\parent_loaded');

Examples

Below you can see a couple simple examples that you could use in your extended post object, and also how you can then use it in your front-end.

Example 1

Below you'll find a simple example of a function that calculates the reading time of a post.


/**
* Calculate the reading time of the post.
*
* @return string
*/
public function reading_time(): string
{
$words_per_minute = 228;

$words = str_word_count(wp_strip_all_tags($this->content()));

if ($words / $words_per_minute < 1) {
return __('< 1 minute', 'wp-lemon-child');
}

$minutes = round($words / $words_per_minute);

/* translators: %s: Time duration in minute or minutes. */
return sprintf(_n('%s minute', '%s minutes', $minutes, 'wp-lemon-child'), (int) $minutes);
}

This newly created function can be used in your single page for example like this:

{% block content %}
<header class="section">
<div class="entry__header-top">
<div class="readingtime">
<i class="icon-clock-o"></i>
{{ post.reading_time }}
</div>
</div>
<h1>{{ post.title }}</h1>
</header>
{{ post.content }}
{% endblock %}

Example 2

In this example the name of a person needed to be formatted in a certain way, ofc we could've also done it in the front-end but we believe that it's best to let the back-end handle most of the logic.

/**
* Fetch the full name of the person, including title.
*
* @return string
*/
public function get_full_name(): string
{
if (!is_null($this->_full_name)) {
return $this->_full_name;
}
$name = null;

$names_group = $this->meta('names');

$name .= $names_group['title'] ? $names_group['title'] . ' ' : '';
$name .= $names_group['first_name'] ? $names_group['first_name'] . ' ' : '';
$name .= $names_group['last_name'] ? $names_group['last_name'] : '';

$this->_full_name = $name;

return $this->_full_name;
}

Wp-lemon queries

In wp-lemon we've added a set of predefined queries that you can use to fetch posts. You could use these for example in your block context. For more documentation on how to use them within your block context take a look at the block context documentation. Below you can find a list of all the queries that are available in wp-lemon.

FunctionDescription
latest_items_queryRetrieves the latest posts of a specific type, optionally filtered by taxonomy and terms.
other_items_queryFetches posts of a specific type, excluding a given post, optionally filtered by taxonomy and terms.
specific_items_queryRetrieves specific posts by their IDs and type.
archive_queryFetches a set of posts of a specific type for archive display, supporting pagination.
get_total_postsCalculates the total number of posts available for an AJAX "load more" functionality.
adjacent_post_infoGets information about the next or previous post, or returns the first/last post if unavailable.
next_post_infoReturns information about the next post or the first post if no next post exists.
previous_post_infoReturns information about the previous post or the last post if no previous post exists.
taxonomy_post_collectionRetrieves a collection of posts organized by category, based on a taxonomy and post type.