Customizing Plugins in Joomla! 1.5x (Part 2)

Exclusive offer: get 50% off this eBook here
Joomla! 1.5x Customization: Make Your Site Adapt to Your Needs

Joomla! 1.5x Customization: Make Your Site Adapt to Your Needs — Save 50%

Create and customize a professional Joomla! site that suits your business requirements

$26.99    $13.50
by Daniel Chapman | October 2009 | Joomla! Content Management Open Source PHP

Read Part One of Customizing Plugins in Joomla! 1.5x here.

Step 2: Plan out our changes

Just like with our module, we are going to be systematic about our customization. This keeps us organized and reduces the chances for mistakes.

Really, these changes are so simple we could probably just dive in and do them, but we want to build good habits for when we want to customize more complex extensions.

Step 2.1: Decide on our changes

Our plugin is going to be essentially the same, hiding or showing parts of our content depending on a particular condition. Only we want to change it so the condition we use is user's subscription and not their user group. We will need to put in some code to search the database for the visitor's subscription information.

We also want to clean out any code we don't need, such as the description HTML page and images.

We will go a little bit further and rename our extension and functions. One day we may want to distribute this plugin to get some traffic to our site, and help other developers like ourselves.

Also, seeing as we are going to rebuild most of this plugin, let's put a short description in to remind us what it is for, or in case we hire another developer to help with our site later, they can see what it does.

Step 2.2: Mark out our changes

Remember that before we actually make our changes, we want to go through the code and mark them with comments first. This way we are forced to think the whole process through from start to finish before we write any code, and we can see any potential problems before they happen. This beats finding them after we have spent a few hours writing code, and wasting that time going back to repair them.

en-GB.plg_content_njaccess.ini

First, we are going to edit our language file, en-GB.plg_content_njaccess.ini.

If we were making a complex component, we would usually keep the language file open the entire time, and add new entries to it every time we wanted to put some text onto the screen. But our plugin is pretty much a 'behind the scenes' plugin so we don't need much text.

So what text do we need?

Well, as we discussed above, when we hide some content from a user, we probably want to display a message that tells them that it has been hidden, and that they should get a subscription to read it. We also want to remove the current rich description and replace it with simpler, normal text.

So let's add a note to our current code,

NINJACONTENT=<IFRAME SRC="../plugins/content/njaccess/njaccess_desc.html" WIDTH=600
HEIGHT=600 FRAMEBORDER=0 SCROLLING=yes></IFRAME>

that tells us to delete it completely. Then we will add a note to write our description and message in its place.

# TODO-Remove this
NINJACONTENT=<IFRAME SRC="../plugins/content/njaccess/njaccess_desc.html" WIDTH=600
HEIGHT=600 FRAMEBORDER=0 SCROLLING=yes></IFRAME>
# TODO-Add plain text description
# TODO-Add message for hidden text

Wait a minute! What are these hashes? We haven't seen them before. Up until now we were told that comments were either double slashes (//), enclosing slash asterisks (/* … */), or for HTML some long tags (<!-- … -->).

Well, .ini files are different from our .php files, and are processed differently. As a result, they use a different symbol to indicate for comments. So now, we can add # to our list of comment symbols, but for .ini (language) files only.

njaccess.php

Next, open up njaccess.php. As we are basically re-writing this plugin, we might as well change the name of this file and all the functions to something more relevant.

// TODO-Rename this file
// Ensure this file is being included by a parent file. defined('_JEXEC') or
die( "Direct Access Is Not Allowed" );
jimport('joomla.eventplugin');
// TODO- Rename the class to match our new filename
class plgContentNJaccess extends JPlugin {
// TODO- Rename this constructor
function plgContentNJaccess( &$subject )
{...

We don't have any parameters, so we can remove the parameter loading from the constructor.

...
parent::__construct( $subject );
// TODO-
Remove these as we have no need for parameters
$this->_plugin = JPluginHelper::getPlugin( 'Content',
'ninjaacess' );
$this->_params = new JParameter( $this->_plugin->params );
}

We are renaming everything, so we should rename our regex tags and the function call via preg_replace_callback as well.

function onPrepareContent(&$article, &$params, $limitstart) {
// TODO- Adjust our regex to look for a shorter tag
// and one collector function between the tags
$regex = "#{njaccess(.*?)}(.*?){/njaccess}#s";
// TODO- Rename the function call
$article->text = preg_replace_callback($regex,array($this,"njaccess"), $article->text);
return true;
}
// TODO- Rename the function
function njaccess(&$matches) {

We also want to remove any references to the ACL. We do want to continue to load the user information though, as we need their user id (if logged in) to compare it to the subscriptions in the AEC tables.

$user = &JFactory::getUser();
// TODO- Remove the next 3 lines as we don't need ACL
$acl = &JFactory::getACL();
$myRealGid = intval( $acl->get_group_id( $user->usertype ) );
$accessLevels = '';

We are only going to have one collector pattern now, so only one set of information, the text to be shown/hidden, needs to be collected. To do this, we need to change all the references to $matches[2] into $matches[1] and remove the old $matches[1] checks.

// TODO-change this to matches[1] as we only have
// one collector now
$output= $matches[2];
// TODO-Remove this
if (@$matches[1]) {
$accessLevels = explode(",", trim($matches[1]));
}

Lastly, we need to replace the main processing with a query to check our visitor's user id against the AEC subscription tables for an active paying subscription.

// TODO-Replace this with a query searching for the
// user's id in the subscriptions table, searching
// for a paying subscription
if (in_array($myRealGid,$accessLevels))
return $output;
// TODO- Get the visitor's id if available.
// If a guest (id = 0) then skip this and display
// the please subscribe message
// TODO- Look for the id in the AEC subscriptions
// table, and check if they have a valid, paid
// subscription. If so, return the text
// if not, skip it and return the message
// TODO- Instead of blank, return our message from our
// language file
return "";
}
}

njaccess.xml

Finally, we come to our njaccess.xml file. Comments can be made into XML files in the same way as HTML <!-- … -->.

For our XML manifest, we have a few things to do. At first, we want to rename everything from njaccess, including the manifest itself.

<?xml version="1.0" encoding="utf-8"?>
<install version="1.5" type="plugin" group="content">
<!-- TODO- Rename this file and plugin -->
<name>Ninja Access</name>
<author>Daniel Chapman</author>
<creationDate>February 2008</creationDate>
<copyright>(C) 2008 Ninja Forge</copyright>
<license>http://www.gnu.org/copyleft/gpl.html GNU/GPL</license>
<authorEmail>daniel@ninjaforge.com</authorEmail>
<authorUrl>www.ninjaforge.com</authorUrl>

Also, let's change the version number of our new plugin to 1.0. Then change the description as well, to suit what we put into our language file.

<!-- TODO- Change to 1.0 -->
<version>1.1</version>
<!-- TODO- Change to match our language file -->
<description>NINJACONTENT</description>

Then, we want to remove all the unnecessary files from the description

<!-- TODO- Remove unneeded files -->
<files>
<filename plugin="njaccess">njaccess.php</filename>
<filename>njaccess/njaccess_desc.html</filename>
<filename>njaccess/js/ninja.js</filename>
<filename>njaccess/images/logo.jpg</filename>
<filename>njaccess/images/ninjoomla.png</filename>
<filename>njaccess/images/firefox2.gif</filename>
<filename>njaccess/images/jcda.png</filename>
<filename>njaccess/images/validation_xhtml.png</filename>
<filename>njaccess/images/validation_css.png</filename>
<filename>njaccess/images/info.png</filename>
<filename>njaccess/images/change.png</filename>
<filename>njaccess/images/inst.png</filename>
<filename>njaccess/images/tabbg.gif</filename>
<filename>njaccess/images/tab2.png</filename>
<filename>njaccess/images/gnugpl.png</filename>
</files>

Finally, rename the reference to our language file to suit the new filename:

<params>
</params>
<!-- TODO- Rename the language file -->
<languages>
<language tag="en-GB">en-GB.plg_content_njaccess.ini</language>
</languages>
</install>
Joomla! 1.5x Customization: Make Your Site Adapt to Your Needs Create and customize a professional Joomla! site that suits your business requirements
Published: August 2009
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

Step 3: Make our changes

Now comes the big moment of putting in our actual changes.

Before we do anything, we need to make a decision. We said we are going to rename everything, but to what?

Well, what is our plugin going to do? It hides text based on AEC subscriptions. Keeping this in mind, we should think of a name that captures that as much as possible so we can recognize our plugin easily.

Something like this really comes down to personal choice, but generally we want to keep it around the 10-15 characters mark. Too many characters and it starts to make things like filenames and class names too long to be useful.

We are going to go with AEC Subscription Hider, abbreviated aecsubshider. It's informative enough to give us an idea of what it does, but not so long that we get lost reading it.

The very first thing we will do now is rename and remove our files.

To get rid of the rich description files is quite easy. Just remove the entire njaccess folder.

Next, we need to rename the remaining three files, njaccess.xml, njaccess.php, and en-GB.plg_content_njaccess.ini. So edit the file names by changing them to the following:

  • aecsubshider.xml
  • aecsubshider.php
  • en-GB.plg_content_aecsubshider.ini

Now let's fix the internals of our files.

en-GB.plg_content_aecsubshider.ini

Let's just follow our own comments here and remove the old Ninja Access description, replace it with one of our own, and add a message for people to get a subscription. In the end, our language file should look like this:

# Plain text description
AECSUBSHIDER DESC=This plugin hides or shows text based on whether the
visitor has an active AEC subscription or not.
# Message for hidden text
HIDDEN=The next portion of this article is for paying subscribers only.
Please become a member to view it.

Notice that we left part of our comments in there this time? This is to help us, or another developer, in the future if we want to edit this file. Leaving the comments leaves us hints on what each piece of text is for.

aecsubshider.php

First, let's remove and rename all our marked code. We can also remove the comments for these too as we don't need to be reminded of the code we removed or renamed.

We will handle our regex tag a bit differently, so leave it for now.

That will leave us with the following code:

// Ensure this file is being included by a parent file. defined('_JEXEC') or
die( "Direct Access Is Not Allowed" );
jimport('joomla.eventplugin');
class plgContentAECSubsHider extends JPlugin {
function plgContentAECSubsHider ( &$subject )
{
parent::__construct( $subject );
}
function onPrepareContent(&$article, &$params, $limitstart) {
// TODO- Adjust our regex to look for a shorter tag
// and one collector function between the tags
$regex = "#{njaccess(.*?)}(.*?){/njaccess}#s";
$article->text = preg_replace_callback($regex,array($this,"aecsubshider"), $article->text);
return true;
}
function aecsubshider(&$matches) {
$user = &JFactory::getUser();
// TODO-change this to matches[1] as we only have
// one collector now
$output= $matches[2];
// TODO- Get the visitor's id if available.
// If a guest (id = 0) then skip this and display
// the please subscribe message
// TODO- Look for the id in the AEC subscriptions
// table, and check if they have a valid, paid
// subscription. If so, return the text
// if not, skip it and return the message
// TODO- Instead of blank, return our message from our
// language file
return "";
}
}

For our regex, we could change it to {aecsubshider}text to hide{/aecsubshider}, but that is even longer than it is now and not exactly easier to type. Instead, let's shorten it further to the idea we had earlier, soc—subscriber only content. This will leave us with {soc}text for subscribers{/soc} which is much easier to type.

So let's change our regex pattern to the new tags, and only one collector.

$regex = "#{soc}(.*?){/soc}#s";

Next, let's do the quick change to our $output declaration so it can handle the new single collector.

$output= $matches[1];

Next up, we need to get our visitor's user id.

Add in the following code, and change the comments:

$output= $matches[1];
// Get the visitor's id if available.
// If a guest (id = 0) then skip this and display
// the please subscribe message
$userid = $user->get('id');
if ( !$userid )
{
// TODO- Look for the id in the AEC subscriptions
// table, and check if they have a valid, paid
// subscription. If so, return the text
// if not, skip it and return the message
}

Here we said if(!$userid). What does this mean? An exclamation mark in PHP indicates that something IS NOT, != for example means NOT equal to.

So we are saying if (IS NOT $userid). Well it still doesn't make much sense does it? This is because in PHP a value of 0 is considered to be the same as FALSE and any value other than 0 is considered to be TRUE. So what this is in effect saying is if($userid IS NOT 0) then do something. A userid of 0 indicates that this is a guest.

Now we need to work out a query to find out if our user has a valid paying subscription.

First, like with our module, we will open up EasySQL and try to find the AEC tables.

And as before, they are pretty easy to spot.

Joomla! 1.5x Customization

Looking down that list, the one most likely to hold our subscription data is jos_acctexp_subscr. Sure enough, if we do a select * query in EasySQL with it, we will see that it contains exactly the sort of columns we are looking for. Particularly:

  • userid—the id of our user
  • status—the status will be either Active, Expired or Excluded
  • plan—the id of the AEC subscription plan

With these three fields we can find out which users have an active paying subscription.

Before we build our query, we need to know the ids for our paying plans. Lets use EasySQL again and do a select * query on the table jos_acctexp_plans. The results tell us that plan ids 1, 2, and 3 are our paying plans. If we were to add a free plan now, it would be id 4 so not included in our query.

If we were making this plugin to distribute, we would use a parameter for the plan ids and ask the user to enter the plan ids. Since this is our own site, and it won't be changing often, if at all, hard coding is fine.

So now we can build our query. It will look something like this:

SELECT count(*)
FROM
jos_acctexp_subscr
WHERE userid = $userid
AND ((status = "Active" AND plan IN (1,2,3))
OR (status = "Excluded"))

Of course, we still need to format it and put it into PHP but that is the structure it will take.

Why are we only selecting count(*)? Because we don't actually need any data from this query apart from a yes or no that this user has a valid subscription. In SQL, the asterisk character, *, is used to indicate "all columns" so we are saying please count all columns. We could just specify a single column such as count(userid), which would make the query a tiny bit faster, but we need to be careful that we don't count a column that can contain null values, or it may change our results.

Remember above how we discussed that 0 = FALSE, so if our count returns 0 it is the same as returning FALSE, and if it returns 1 or more, then it is the same as returning TRUE.

Also, why did we split up the two statuses Active and Excluded?

Excluded is a special status that is reserved for people who don't need a subscription, for example administrators. Giving an administrator a subscription might limit what they can do on the site, and we don't want to have to make a special 'unlimited powers' subscription just for administrators. So to fix this, administrators and other special people can simply be given that status of Excluded in order to avoid being affected by the subscription system, and in this case our content hider as well.

So now let's build it. Remember that first we need to create a database object, write our query, set the query, and finally load our records. Don't forget to fix up our comments either.

if ( !$userid )
{
// Look for the id in the AEC subscriptions
// table, and check if they have a valid, paid
// subscription. If so, return the text
// if not, skip it and return the message
$db = &JFactory::getDBO();
$query ='SELECT count(*)
FROM jos_acctexp_subscr
WHERE userid = "'.$userid.'"
AND ((status = "Active" AND plan IN (1,2,3))
OR (status = "Excluded")) ';
$db->setQuery($query);
$count = $db->loadResult();
}

Notice that we used $db->loadResult instead of $db->loadObjectList, which we used in our module. This is because here we only need the first value of the first record and not a complete list of objects with various fields, which is what $db->loadResult is designed to return.

So now, we have our answer to the question "is this person a paying subscriber?", but what do we do with it? We will check it to see that it is not 0, and if it isn't, we will return the text. If, however, it is 0, then we will do nothing and continue to the next return, which returns our "please subscribe" message.

Before we display our message though, we need to do a little work. By default, Joomla! doesn't load language strings for pugins on the front end. So we will have to manually load the language file for our plugin, and then we can use it.

if ($count)
return $output;
$lang = & JFactory::getLanguage();
$lang->load('plg_content_aecsubshider', JPATH_ADMINISTRATOR);
return JText::_( 'Hidden' );

JText::_() is a function we can use to help us access the text inside our language files. Here we are calling the Hidden key from our language file, which contains our "please subscribe" message. When we enter our text into the JText::_() function, it can be in any case we like. What is important is that the Key in the language file itself is always in uppercase.

There is a lot more to language files than what is covered here. Please refer to the Joomla! documentation for more information.

aecsubshider.xml

Our XML manifest is the last file we need to change, and thankfully it is a fairly simple one, with no surprises. If we follow the comments we placed earlier, we will remove the unneeded files, rename the others, and change the description.

While we are here, we may as well update the author information to indicate ourselves, because we are now the new author of this extension.

This leaves us with the following file:

<?xml version="1.0" encoding="utf-8"?>
<install version="1.5" type="plugin" group="content">
<name>AEC Subscription Hider</name>
<author>Daniel Chapman</author>
<creationDate>February 2009</creationDate>
<copyright>(C) 2009 Your Japanese House</copyright>
<license>http://www.gnu.org/copyleft/gpl.html GNU/GPL</license>
<authorEmail>daniel@yourjapanesehouse.com</authorEmail>
<authorUrl>www.yourjapanesehouse.com</authorUrl>
<version>1.0</version>
<description>AECSUBSHIDER DESC</description>
<files>
<filename plugin="aecsubshider">aecsubshider.php</filename>
</files>
<params>
</params>
<languages>
<language tag="en-GB">en-GB.plg_content_aecsubshider.ini</language>
</languages>
</install>

We should now be able to package up our plugin and install it.

Step 4: Install and test our Plugin

A mistake I often make myself when testing a new plugin is forgetting to enable it after I install it. So we should make sure we go to the Plugin Manager and enable our AEC Subscriptions Hider plugin before we start.

Now we can create a new article and put some text into it.

A test article
{soc}hidden text{/soc}

This isn't particularly complicated, but enough to test.

Now make sure we are logged out on the front end of our site, and thus a guest.

Let's see what we get.

Joomla! 1.5x Customization

Looks great! Now let's try the reverse and login to see what we get.

Joomla! 1.5x Customization

Perfect. Now we can hide our best content from non-subscribers, and hopefully entice them to subscribe.

If we wanted to, we now also have the ability to take the Ninja Access Module and make the same changes to it so we can show and hide modules depending on the visitor's subscription status.

Summary

Congratulations! We have now finished our first successful plugin customization and cleaned out a lot of unnecessary code as well. We should now have an understanding of:

  • How a plugin is constructed
  • The types of plugins
  • plugin events
  • plugin order
  • The different types of files we need for a plugin
  • How to customize a plugin

We should now be comfortable enough to study and make changes to any plugin we wish.

 

If you have read this article you may be interested to view :

 

Joomla! 1.5x Customization: Make Your Site Adapt to Your Needs Create and customize a professional Joomla! site that suits your business requirements
Published: August 2009
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

About the Author :


Daniel Chapman

Daniel Chapman has been working in IT since 1995, firstly as an Oracle Database consultant and trainer, then in freelance web development, and now as a Joomla extension developer. He is the founder and CEO of Ninja Forge, a leading Joomla! extension club. Currently based in Japan, he is an entrepreneur with extensive experience in designing and customizing sites, as well as in building successful web-based businesses, having worked on the design and development of several.

Books From Packt

Joomla! 1.5 Template Design
Joomla! 1.5 Template Design

Joomla! E-Commerce with VirtueMart
Joomla! E-Commerce with VirtueMart

Learning Joomla! 1.5 Extension Development
Learning Joomla! 1.5 Extension Development

WordPress 2.7 Cookbook
WordPress 2.7 Cookbook

Drupal 6 Site Blueprints
Drupal 6 Site Blueprints

Flex 3 with Java
Flex 3 with Java

ASP.NET 3.5 CMS Development
ASP.NET 3.5 CMS Development

Drools JBoss Rules 5.0 Developer's Guide
Drools JBoss Rules 5.0 Developer's Guide

 

Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software