Joomla 3 – Adding Custom Content to a single Article

I spent most of last weekend trying to work out how to add custom content to a single article (actually the homepage of a site). This was such a painful process and there was such a lack of decent explanations that I thought I’d write my own.

The task

The specific task involved the ability to enter a number of images, plus headings and captions for each image, onto the homepage of a site. These images are then formatted into a grid for display. For the purposes of this page I’ll simplify the number of field involved however.

Custom content plugin

I elected to do this via a custom content plugin which I called homegrid (although a custom module is the other option), with the fields to edit the content being available directly from the ‘Edit Article’ screen in Joomla’s admin suite. To me this is the sensible and intuitive place for this content to be managed since it doesn’t appear anywhere else in the site, just on this page.

Here’s the necessary file structure that you need to create within the plugins/content joomla directory:

Screenshot of file structure

Let’s take a look now at the individual files. There are three key files:

homegrid.xml

This file establishes the plugin within Joomla and holds any necessary data to configure the plugin. For this example it’s very simple:

<?xml version="1.0" encoding="utf-8"?>
<extension version="1.0" type="plugin" group="content">
	<name>Home Page Image Grid</name>
	<author>Simon Battersby</author>
	<creationDate>March 2015</creationDate>
	<copyright>Copyright (C) 2005 - 2014 Open Source Matters. All rights reserved.</copyright>
	<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
	<authorEmail>simon@simonbattersby.com</authorEmail>
	<authorUrl>www.simonbattersby.com</authorUrl>
	<version>2.5.0</version>
	<description>Arbitrary text describing your plugin</description>
	<files>
		<filename plugin="homegrid">homegrid.php</filename>
		<filename>index.html</filename>
	</files>
	<languages>
	</languages>
	<config>
	</config>
</extension>

Nothing very exciting there. I have ignored languages for the sake of simplicity, and you’ll see there are empty language and config tags.

homegrid.php

This file controls the display and storage of your custom content:

<?php
// no direct access
defined ( '_JEXEC' ) or die ( 'Restricted access' );
 
class plgContentHomegrid extends JPlugin {
 
        protected $autoloadLanguage = true;
 
        function onContentPrepareForm($form, $data) {
        
            $app = JFactory::getApplication();
            $option = $app->input->get('option');

            switch($option) {

                case 'com_content':
                    if ($app->isAdmin()) {
                    	                            
                        JForm::addFormPath(__DIR__ . '/forms');//load the path to the forms
						
                        if( $data->featured == 1 || $_POST['jform']['featured'] == 1 ){//if the page is a featured page, either on display or save
							
				$form->loadFile('homegrid', false);//load forms/homegrid.xml
                            
                        } 
                    }
                    return true;
            }
            return true;
        }
}
?>

So, this creates a class to manage the custom content. In my example I wanted to add custom content to my featured page, which is where the conditional code comes in. There’s a distinct gotcha here, as when the data is displayed, the $data object is populated, but when it’s saved, that object is not populated, which is why the conditional statment also references the $_POST object. If you don’t have this second condition, data will not be saved.

homegrid.xml

This file specifies the data elements on the form – the actual custom content fields that can be populated:

<?xml version="1.0" encoding="UTF-8"?>
<form>
    <fields name="attribs" >
        <fieldset name="attribs" label="Home Page Grid">

			<field name="image1"
			    type="media"
			    label="Image 1 - Large Image Top Left 589px by 383px"
				preview="true"
			    />
			<field name="image1link"
			    type="menuitem"
			    label="Image 1 - Link"
			    />
			<field name="image1headline"
			    type="text"
			    label="Image 1 - Headline"
			    />
			    
			<field name="image1caption"
				type="text"
				label="Image 1 - Caption"
				/>
			<field type="spacer" name="myspacer" hr="true" />


        </fieldset>
    </fields>
</form>

For a content field the fields and fieldset name attribute must beattribs. Read more about field types in the Joomla documentation. Here I’m using a media field, a menu item field and a couple of text fields.

index.html

These are identical empty files which prevent anyone viewing your directory content:

<!DOCTYPE html><title></title>

Loading up your plugin

I find the simplest way of installing the plugin is to simply FTP the files up to your server into the file structure defined above, then within admin go to Extensions > Extension Manager > Discover and then click the ‘Discover’ button. Joomla should find the plugin:

Screenshot Discover page

Select your plugin and click Install and all should be well. You then need to find your plugin again via Extensions > Plugin Manager and enable it. Once you’ve done this you should see a new tab on featured articles – like this:

Article edit page with new custom tab

We now have custom data stored against the article – and the last step is to display that data to a user.

Creating a template override to display the custom content

Start by navigating to Extensions > Template Manager and then click on the Template link (not the style link) for your template:

Screenshot Template Manager page

Select the ‘Create Overrides’ tab and select the component you want to alter. For featured articles it’s com_content > featured. Click this and the override files will be created within your template. Once this is done you may find it easier to download and edit them in your normal code editor, rather than editing them via the Joomla screen. In my example, the file I need to edit is now saved in my template folder under html > com_content > featured > default.php.

Nearly there…To retrieve your stored custom data (which is held in the attribs column of your joomla content table:

<?php $attributes = json_decode($item->attribs);?> 

Once this is retrieved you can access your data directly like this example:

<div class="headline-image"><a target="_self" href="<?php echo JRoute::_("index.php?Itemid={$attributes->image1link}"); ?>"><img width="589" height="383" src="<?php echo $attributes->image1; ?>" alt="<?php echo $attributes->image1headline; ?>" style="margin: 0px;"></a>
	<div class="headline">
		<h4><span><?php echo $attributes->image1headline; ?></span></h4>
	</div>
	<div class="image-caption">
		<p><?php echo $attributes->image1caption; ?></p>
	</div>
</div>

In the first highlighted example I’m translating the menuitem identifier into a URL using JRoute, in all other cases just echoing out the content.

Summary

And there it is. There are some Joomla extensions that purport to do this as well, but they either didn’t work or were paid-for…. Feel free to suggest improvements if you like.

4 responses to “Joomla 3 – Adding Custom Content to a single Article”

  1. Stenio ELson says:

    Hey,
    I followed all the tutorial. It worked perfect.
    However, when I try to save a text with a html tag within it, Joomla! removes the html tag and then saves the text to the column attribs. Do you know how to allow html tags in the column attribs?.

  2. Simon says:

    Does this help? Alternately, split your entered text up in such a way that you can build in the required html in the template file – so rather than:

    <?php echo $attributes->text; ?>

    where text contains html tags, use:

    <tag><?php echo $attributes->text; ?></tag>
  3. george g says:

    Thanks for posting this about something that is really tricky. In J3.6.4 I am trying it, but the data I enter doesn’t save. I noticed

    $input = JFactory::getApplication()->input;//read the form for use on save
    $formData = new JInput($input->get(‘jform’, ”, ‘array’));

    in your code, and wondered if I got something wrong there since $formData doesn’t appear to be used anywhere?

    Cheers !

  4. Simon says:

    Hi George
    You’re quite correct, there are two redundant lines in the original code – now removed.

Useful? Interesting? Leave me a comment

I've yet to find a way of allowing code snippets to be pasted into Wordpress comments - so if you're trying to do this you'd be better off using the contact form.