MODX Snippet Development VII

In the last article, we cleaned up our code, improved the design, and made the snippet MODX logomore flexible by adding properties to the snippet tag. In this article we’ll look at a way to make the specification of the time interval more user friendly.

Starting Point

For reference here’s where we left off in the last article:

[code language=”php”]
/* NewResource snippet */

/* Default return value */
$output = ”;

/* Optional placeholder */
$ph = $modx->getOption(‘ph’, $scriptProperties, ”, true);

/* Return value for new resources that are published */
$newOutput = $modx->getOption(‘showNew’, $scriptProperties,
‘<span class="new_resource">NEW!</span>’, true);

/* Set $interval as the number of seconds in two weeks */
$interval = $modx->getOption(‘interval’, $scriptProperties, ‘2 weeks’, true);

$cutoffTime = strtotime(‘now – ‘ . $interval);

if ($cutoffTime === false) {
$output = ‘[NewResource] Invalid interval’;
}

/* See if the resource is published */
$published = $modx->resource->get(‘published’);

/* See if publication date is within the last two weeks */
if ($published && $cutoffTime) {
/* Get the current time as a timestamp */
$currentTime = time();

/* Get the publishedon date and
convert it to a unix timestamp */
$ptime = strtotime($modx->resource->get(‘publishedon’));

if ($ptime > $cutoffTime) {
/* Yes, it’s recent — Set the return value */
$output = $newOutput;
}
}
}

if (!empty($ph)) {
$modx->setPlaceholder($ph, $output);
$output = ”;
}

return $output;
[/code]

Internationalization

Now that our snippet is in its final form, it’s time to think about making it useful in other languages. This means using the MODX lexicon for all language strings that will be displayed (though in this snippet, there aren’t very many of them).

The MODX lexicon is actually very simple. A lexicon file has series of key/value pairs. When MODX sees a call to the lexicon containing a lexicon key, it checks the lexicon array in memory, looks up the value associated with that key and returns it. If it doesn’t find one, it simply returns the key unchanged. We’ll look at the format of a lexicon file in the bit, but first, let’s look at how one is loaded.

Loading the Lexicon

In order for MODX to find our lexicon strings, they must first be loaded. Typically, there will only be one lexicon file for a small snippet like ours and it will be called default.inc.php. The English version of the file would be loaded with this line near the top of the snippet:

[code language=”php”]
$modx->lexicon->load(‘en:newresource:default’);
[/code]

The argument is in three parts, separated by colons. The first part is the two-letter language code. The second is the namespace, and the third is the topic to load. MODX automatically appends .inc.php to the end of the topic when it looks for the lexicon file.

The namespace tells MODX where to look for the directory containing the language files. In order for it to work, you need to create a namespace in the Manager (System -> Namespaces) and set its core path. In our case, the name of the namespace would be newresource, and the path would be {core_path}components/newresource/. MODX will translate the {core_path} part when it gets the namespace path. That means everything will still work if you decide to move the MODX core directory or even if you move the whole site to a new server. Notice that there is never a slash between {core_path} and the directory name that follows it. In MODX, all standard paths end in a slash, so {core_path} will provide the necessary slash.

Lexicon File Location

So where is MODX going to look for our lexicon file? Because we’ve specified the language, the namespace (and it has a path), and the topic, it will look in this directory (where {core_path} is the actual path to the core):

[code language=”html”]
{core_path}components/newresource/lexicon/en/default.inc.php
[/code]

The directory structure for that file will look like this:

[code language=”html”]
core
components
newresource
lexicon
en
default.inc.php
[/code]

In other words, it will always look for this file:

[code language=”html”]
<i>{namespace_core_path}</i>lexicon/<i>{language}</i>/<i>{topic}</i>.inc.php
[/code]

Dynamic Language Specification

Our multi-language version of the snippet isn’t going to do much good unless the user can specify the language to use in the snippet tag. To make that happen, we need to get the two-letter language code from the &language property and use it in the $modx->lexicon->load() call. We’ll use en as the default value:

[code language=”php”]
$language = $modx->getOption(‘language’, $scriptProperties, ‘en’, true);
$modx->lexicon->load($language . ‘:newresource:default’);
[/code]

If you have a multi-context site with a language for each context, you can create a cultureKey Context Setting for each context and do this in the snippet tag:

[code language=”html”]
&language=`[[++cultureKey]]`
[/code]

 

Getting Fancy

Here is another, somewhat complicated, way of handling the language in the snippet:

[code language=”php”]
$language = $modx->getOption(‘language’, $scriptProperties, ”);
$language = !empty($language)
? $language
: $modx->getOption(‘cultureKey’, NULL,
$modx->getOption(‘manager_language’, NULL, ‘en’));

$modx->lexicon->load($language . ‘:newresource:default’);
[/code]

In the code above, any language sent in the &language property of the snippet tag will take precedence. If it is not set, the cultureKey System Setting will be used. If that isn’t set, the manager_language System Setting will be used. Finally if none of those are set, the language will be set to 'en'.

Lexicon File Content

This couldn’t be much simpler. Every line in every lexicon file takes this basic form:

[code language=”php”]
$_lang[‘key’] = ‘Value’;
[/code]

You use the key in your lexicon call. The value is what will be displayed to the user. It’s a good practice to use a prefix with your lexicon keys so they won’t collide with those of other extras or the entries in the MODX core lexicon. Well use the prefix nr_ for our snippet.

Here is our English-language lexicon file for the snippet

[code language=”php”]
<?php
$_lang[‘nr_err_invalid_interval’] = ‘Invalid interval’;
$_lang[‘nr_show_new’] = ‘NEW!!!’;
[/code]

As we mentioned above, the lexicon file will be located here:

[code language=”html”]
core
components
newresource
lexicon
en
default.inc.php
[/code]

If we wanted to create a French language file, it might look like this (pardon my French):

[code language=”php”]
$_lang[‘nr_err_invalid_interval’] = ‘Intervalle non valide’;
$_lang[‘nr_show_new’] = ‘Nouveau!!!’;
[/code]

The French lexicon file would be located at:

[code language=”html”]
core
components
newresource
lexicon
fr
default.inc.php
[/code]

The error message is returned by the snippet with this code:

[code language=”php”]
$output = $modx->lexicon(‘nr_err_invalid_interval’);
[/code]

I like to use lexicon keys that will be understandable if something goes wrong and the value is not found. This is especially important with error messages.

That takes care of the error message, but what about the ‘NEW!!’ indicator? Here is one way to handle that:

[code language=”php”]
$output = $modx->lexicon(‘nr_show_new’);
[/code]

Notice that with this code, the &showNew property is no longer necessary in the snippet tag. The user will set the value of it in the various languages with the entries in the lexicon files. This method is not optimum, however. If we put the full HTML for our output in the page content or template with the snippet tag or the placeholder embedded in it, the outer part of the tag will be there regardless of whether the resource is new or not.

A better method is to continue to use the &showNew property with the language-specific part of it as a placeholder tag. The snippet will then replace the placeholder tag itself before returning the output.

[code language=”html”]
[[!NewResource?
&showNew=`<span class="new_resource">[[+nr_show_new_ph]]</span>`
&language=`en`
]]
[/code]

[code language=”php”]
$msg = $modx->lexicon(‘nr_show_new’);
$output = str_replace(‘[[+nr_show_new_ph]]’, $msg, $output);
[/code]

Updated Code

This method requires almost no changes to our snippet. We’ll add the placeholder tag to our default output and add a couple of lines later to replace it in the output:

[code language=”php”]
/* NewResource snippet */

$language = $modx->getOption(‘language’, $scriptProperties, ‘en’, true);
$modx->lexicon->load($language . ‘:newresource:default’);

/* Default return value */
$output = ”;

/* Return value for new resources that are published */
$newOutput = $modx->getOption(‘showNew’, $scriptProperties,
‘<span class="new_resource">[[+nr_show_new_ph]]</span>’, true);

/* Set $interval as the number of seconds in two weeks */
$interval = $modx->getOption(‘interval’, $scriptProperties, ‘2 weeks’, true);

$cutoffTime = strtotime(‘now – ‘ . $interval);

if ($cutoffTime === false) {
$output = ‘nr_err_invalid_interval’;
}

/* See if the resource is published */
$published = $modx->resource->get(‘published’);

/* See if publication date is within the last two weeks */
if ($published && $cutoffTime) {
/* Get the current time as a timestamp */
$currentTime = time();

/* Get the publishedon date and
convert it to a unix timestamp */
$ptime = strtotime($modx->resource->get(‘publishedon’));

if ($ptime > $cutoffTime) {
/* Yes, it’s recent — Set the return value */
$output = $newOutput;
/* Replace the placeholder tag */
$msg = $modx->lexicon(‘nr_show_new’);
$output = str_replace(‘[[+nr_show_new_ph]]’, $msg, $output);
}
}
}

return $output;
[/code]

Note that although we didn’t use it in the example tag above, we could still send the &ph property in the tag and use the specified placeholder at the location where we want the entire output of the snippet. It won’t conflict with the nr_show_new_ph tag (even if it has the same name, though that would be a bad practice). The tag in the snippet property will be replaced manually in the snippet rather than being set as a placeholder.

Replacing placeholder tags manually in a snippet is a common practice (Wayfinder does it, for example), because it’s significantly faster than making MODX parse the placeholder tags. It also has the advantage of insulating you from the whims of the parsing order. This is important if you’re nesting things (e.g. a snippet tag inside a chunk that’s inside another chunk). Generally speaking, anytime you can move actions into a snippet and avoid having them handled by the MODX parser, you’ll improve both performance and reliability.

It’s also worth mentioning that the value of the &language property could be a tag, typically a TV tag so that you can set the language of a particular page by putting the two-letter language code in a TV.

Another option for setting the language is to have the snippet get the language code from the URL of the page or from the current context. In the second case, you’d name the contexts with the two-letter language codes and put this line in the snippet to set the $language variable:

[code language=”php”]
&language = $modx->context->get(‘key’);
[/code]

If you prefer not to name the contexts with the language codes, you can also create a context Setting containing the context’s language code (let’s call the setting language_code), then do this in the snippet:

[code language=”php”]
&language = $modx->getOption(‘language_code’);
[/code]

 

Wrapping Up

This is the last article in this series. Over the course of these articles, we’ve seen how even a simple snippet can develop over time and we’ve explored the use of properties, time comparisons, and placeholders, among other things. We didn’t discuss the use of Tpl chunks to format snippet output — that will have to wait for another time.

In the next article, we’ll look at another way to use the MODX lexicon to create language-specific content.

 


For more information on how to use MODX to create a web site, see my web site Bob’s Guides, or
better yet, buy my book: MODX: The Official Guide.

Looking for quality MODX Web Hosting? Look no further than <a
href=”http://bit.ly/YgFGHl”>Arvixe Web Hosting!

Tags: , , | Posted under MODX, MODX | RSS 2.0

Author Spotlight

Bob Ray

Bob Ray is the author of MODX: The Official Guide and over 30 MODX add-on components. He hosts Bob's Guides, a source of valuable information for MODX users, and has been very active in the MODX Forums with over 19,000 posts.

Leave a Reply

Your email address will not be published. Required fields are marked *