Create a custom HivePress extension
Last updated
Was this helpful?
Last updated
Was this helpful?
In this tutorial, we'll create a custom HivePress extension that allows users to:
Follow or unfollow any vendor
View listings from the followed vendors on a single page
Get emails about new listings from the followed vendors
Unfollow all vendors with one click
While this extension is pretty simple, it covers the main aspects of the HivePress framework, so by the end of this tutorial, you should be able to create your own extension for HivePress.
Before we begin, please make sure that you have a working WordPress installation and at least basic WordPress development skills. The result of this tutorial is available on , so you can browse the complete source code or download the extension to test it locally.
First, create a directory in the wp-content/plugins
WordPress subdirectory. The directory name will be used as the extension identifier, so make sure it's unique enough to avoid conflicts with other HivePress extensions (use lowercase letters, numbers, and hyphens only).
For this tutorial, we'll name it "foo-followers", where "foo" is a unique prefix (e.g. your company name or abbreviation), and the "followers" part describes the extension purpose.
Next, create a PHP file with the same name inside the extension directory. This is the main file that is loaded by WordPress automatically when the extension is active.
As you can see, this file contains the extension details, such as:
Plugin Name & Description - the extension name and short description of its purpose;
Author & Author URI - your or your company name with an optional website URL;
Text Domain - used for translating the extension, matches the main file name.
Also, there’s a simple code that prevents direct file access by URL so that it can be loaded by WordPress only. We’ll add the same code to every file created in this tutorial:
The only thing the main file does is register the extension directory via the hivepress/v1/extensions
hook to allow HivePress to detect and load all the other extension files automatically:
After you create the main file, go to WordPress > Plugins and activate the extension:
Create a class-followers.php
file in the includes/components
extension subdirectory. Notice that it has the class-
prefix, and its name matches the extension name. It must be unique enough to avoid conflicts with other HivePress components (use lowercase letters, numbers, and hyphens only).
The PHP class name must be based on the file name, but with underscores instead of hyphens and no lowercase restriction (e.g. Foo_Bar
class for the class-foo-bar.php
file).
Let’s create a Follow
model for storing the follower ID along with the followed vendor ID. Create a class-follow.php
file in the includes/models
extension subdirectory. The file and PHP class naming conventions are the same as for components.
The Follow
model contains 2 fields:
user - mapped to the user_id
database field, used for storing the follower ID;
vendor - mapped to the comment_post_ID
database field, used for storing the followed vendor ID.
Also, if the model is based on the Comment
class, WordPress will show the model objects in the comment feeds. To keep the model objects hidden, create a comment-types.php
file in the includes/configs
extension subdirectory:
The code above contains a configuration that makes the follow
comment type registered by the model we created private.
Let’s create a template for a page that displays all listings from the followed vendors. Create a class-listings-feed-page.php
file in the includes/templates
extension subdirectory. The file and PHP class naming conventions are the same as for components.
As you can see, the template class is based on the User_Account_Page
class. This means that the template inherits the user account page layout and adds custom blocks to it.
The template we created adds 2 blocks to the page_content
area:
listings - displays listings for the current page;
listing_pagination - displays the page links for navigation.
The block names must be unique within the template scope. Each block is defined as an array containing the block type and extra parameters used to render the block.
Create a class-followers.php
file in the includes/controllers
extension subdirectory. The file and PHP class naming conventions are the same as for components.
Let's define a new URL route in the controller constructor:
The route we defined uses these parameters:
title - used for the page title and menu label;
base - used for inheriting another route path
;
path - the relative route URL path;
redirect - points to the URL redirect function;
action - points to the route action function;
paginated - flag required for paginated URLs.
Based on the parameter values, the listings_feed_page
route has the /account/feed
URL, renders a page with the “Feed” title and supports pagination.
Next, let's implement the redirect and action functions for this route below the constructor:
When the route URL is visited, the redirect function is called first. In our case, it checks if the current user is logged in and has any followed vendor IDs. It returns the corresponding redirect URL or false
if all checks are passed.
If there was no redirect, the action function is called next. As you can see, it creates a query for listings published by the followed vendors, sets it as the main page query, and finally renders the template we created earlier. Notice that this function returns the rendered HTML instead of outputting it with echo
.
Now, if you refresh permalinks in Settings > Permalinks and try to visit the /account/feed
URL, you will be redirected because you haven’t followed any vendors yet.
We already used a code that checks if the current user follows any vendors by checking the vendor_follow_ids
value in the request context, but there’s no function that sets this value in context yet. Add this code to the component constructor:
The code above hooks a custom filtering function to the request context values. Let’s implement this function in the component below the constructor:
This function checks if the followed vendor IDs are cached for the current user, and if not, it queries the Follow
model objects by user ID and fills an array of vendor IDs, then caches this array. Finally, it sets an array of vendor IDs in the vendor_follow_ids
context, this allows us to get it anywhere in the code this way:
Also, the listing feed page we created doesn’t have any links on the front-end yet, so let’s add it to the user account menu. Add this code to the component constructor:
The code above hooks a custom filtering function to the user account menu parameters. Next, implement this function in the component below the constructor:
As you can see, it adds a custom menu item linked to the listings_feed_page
route we created previously. You can adjust the _order
parameter value to change the menu item position. The menu item will appear only if the current user follows any vendors.
method - restricts the accepted HTTP method (e.g. GET
, POST
);
rest - flag required for REST API routes.
The code above defines 2 REST API routes, both accept requests via the POST
method. The first route will follow or unfollow a vendor on every subsequent request, while the second one will unfollow all vendors at once. Next, implement the action functions for these routes:
The follow_vendor
function checks if the current user is logged in, gets a Vendor
object by ID, and queries the Follow
objects by the user and vendor IDs.
Then, if any Follow
objects are found, they are deleted. If not, a new Follow
object is created and saved in the database. This way, every subsequent call of this function will follow or unfollow a vendor, creating or deleting a Follow
object.
The unfollow_vendors
function checks if the current user is logged in, then queries the Follow
objects by the user ID and deletes them, thus unfollowing all vendors.
We created REST API routes, but there are no links or forms on the front-end that send requests to these routes yet. Let’s add a toggle link that sends a request to the vendor_follow_action
on click and add it somewhere on the vendor page. We need to create a new block type for this.
Create a class-follow-toggle.php
file in the includes/blocks
extension subdirectory. The file and PHP class naming conventions are the same as for components.
Notice that the block class is based on the Toggle
class – this is an existing block type available in HivePress, so all the properties and methods are inherited from it.
Before the block is rendered, it fetches the Vendor
object from the current template context and sets the toggle url
to the vendor_follow_action
route we created previously. It also enables the active
flag if the vendor ID is among the followed vendor IDs.
This way, the toggle will show the “Follow” or “Unfollow” label on every subsequent click and send an AJAX request to the vendor_follow_action
route URL. Also, it will show the “Unfollow” label by default if the vendor is already followed.
Next, let’s add this block to the vendor templates. Add this code to the component constructor:
The code above hooks a custom filtering function to the vendor template parameters. Now, implement this function in the component below the constructor:
The function above filters the template parameters and adds a new block using the block type we created earlier. Let’s check if the toggle link is added on the front-end:
Now you can try clicking on the Follow toggle and check if the vendor listings appear on the listing feed page, and unfollow a vendor to check if listings disappear.
We still have one action left that is not used anywhere, the one that unfollows all vendors at once. So let’s create a form for it and add a button to show the form on click.
Create a class-vendors-unfollow.php
file in the includes/forms
extension subdirectory. The file and PHP class naming conventions are the same as for components.
The form we’ve created defines these parameters:
description - text displayed before the form;
action - URL for sending requests on submission;
method - HTTP method for sending requests (e.g. POST
, GET
);
redirect - flag to refresh or redirect the page;
button - the submit button parameters.
Next, let’s add new blocks to the Listings_Feed_Page
template we created earlier:
As you can see, there’s a part
block that loads a specific HTML file and a modal
block that contains the form we’ve just created. The part block points to a non-existing file, so we need to create a vendors-unfollow-link.php
file in the templates/vendor/follow
extension subdirectory:
Now, let’s check the listing feed page. It should have the “Unfollow” button that opens a modal window on click. The modal window contains a form that sends a request to the vendors_unfollow_action
route URL, thus unfollowing all vendors at once.
Finally, let’s add an email notification sent to users about new listings from the followed vendors.
Create a class-listing-feed.php
file in the includes/emails
extension subdirectory. The file and PHP class naming conventions are the same as for components.
The email we’ve just created defines these parameters:
subject - the email subject;
body - the email message with placeholders.
Next, let’s add a function that sends an email to the vendor followers if there’s a newly published listing. Add this code to the component constructor:
The code above hooks a custom function to the listing status change action. Now, implement this function in the component below the constructor:
The function above checks if the listing got the "published" status, gets all the Follow
objects by vendor ID and sends an email to each follower, providing the email address and tokens to be replaced in the email text.
Now, if you follow a vendor and this vendor publishes a new listing, you will get an email notification that contains the listing title and URL.
That's it. Now website owners can translate or change any of the extension texts via Loco Translate or POEdit without editing the source code directly.
Congratulations! You’ve just developed a fully-functional HivePress extension. Even though there's a lot more to the HivePress framework than what you’ve seen so far, you’re now ready to start developing your own HivePress extensions.
If you plan to submit your extension to the repository, make sure to follow and add the readme.txt
along with the license file.
In HivePress, are PHP classes used to group actions, filters, and helper functions. Let’s create an empty component and add the extension-specific functions to it later.
In HivePress, are PHP classes that represent the WordPress database entities such as posts, comments, or terms. Using models makes working with the database much easier.
Notice that the model class is based on the Comment
class. This means that the model objects will be stored as WordPress comments of a custom type. We implement the model this way because comments are linked to both users and posts in the WordPress . Since vendors are implemented as posts of a custom type, we can use this model to store both the follower (user) and the followed vendor IDs.
In HivePress, are defined as PHP classes that contain arrays of . With blocks, it’s easy to re-use and customize specific layout parts without affecting the whole template.
Now, we need to define custom URLs that will render the template we created and perform specific actions, such as following or unfollowing a vendor. In HivePress, this can be done using – PHP classes that define URL routes and implement actions corresponding to them.
Let’s also create URL routes that allow users to follow or unfollow vendors. Since these routes don’t render anything and are used for performing actions only, we will define them as routes. These routes don’t require the title
, redirect
, and paginated
parameters, but other parameters are needed instead:
Now we have all the URL routes and actions according to the extension requirements. You can view the complete controller on GitHub for reference.
In HivePress, are defined as PHP classes with properties and methods that determine the behavior and rendering of the block.
The Follow_Toggle
block type we created defines 2 states for the toggle, setting the icon name and a label for each state.
You probably noticed that we wrapped all the texts in the code with the . We also need to generate a POT file for translation to work properly.
Create a new languages
extension subdirectory and install the plugin. Go to Loco Translate > Plugins > Followers for HivePress and click Create template, then proceed.
For example, you can develop a custom HivePress extension for a client, share it on the repository or even sell it on the marketplace.
If you have any questions about the HivePress framework, please check the available docs and feel free to join the HivePress .