In my previous article, we saw how to solve the problem of creating Lexicon Strings for custom permissions without losing the non-custom permissions. This problem is specific to custom permissions (ones not included automatically during the installation of MODX), not to permissions in general. The Lexicon entries are placed in the modx_lexicon_entries
table in the MODX database, so they will survive any updates of MODX or any MODX Extra.
The process described in that article was somewhat time-consuming. In this article, we’ll see how to put code in a resolver that will create those Lexicon entries automatically.
Resolvers are optional, pieces of a Transport Package (the container for MODX Extras) that perform a wide variety of other tasks. They operate after the package has been fully installed, so they can do things like setting a System Setting or Snippet property to the ID of a Resources that’s part of the package, or changing a link or setting to the ID of the current site’s Login page.
In this case, we’re going to use a resolver to add language strings to the MODX database.
General Strategy
We’ll still create our Lexicon files as usual, even though they won’t be used by MODX. They will be used by our resolver during the installation of the Extra.
It would be possible to put all the code and all the language strings in the resolver itself, but in the long run, it’s much easier to just keep the Lexicon Strings in their separate language files (one for each language). It’s easier to find and edit strings, and translate them with a translation service (Google Translate, for example). It also makes it much easier to add a new language by simple copying a language file, translate the strings, and add the new two-letter code to the array of languages in the resolver. Finally, you really don’t want your code cluttered up with Lexicon strings and their keys for multiple languages.
The approach of the following code is to simply loop through the languages, load each language file, and create the Lexicon entries in the database.
This example is from the NewsPublisher Extra’s language files and the “newspublisher” resolver.
Here’s the full code content of a language file. The file for each language is the same except for the language of the description:
<?php
$_lang['np_allow_modx_tags_desc'] = 'Allow editing resources with MODX tags using NewsPublisher.';
Here's the code of the resolver:
/** @var modTransportPackage $transport */
/** @var modTransportPackage $object */
/** @var array $options */
/** @var array $_lang */
/* Set $modx variable */
if ($transport) {
$modx =& $transport->xpdo;
} else {
$modx =& $object->xpdo;
}
$modx->log(modX::LOG_LEVEL_INFO, 'Running newspublisher resolver');
/* Set class prefix for MODX 2 or MODX 3 */
$prefix = $modx->getVersionData()['version'] >= 3
? 'MODX\Revolution\\'
: '';
/* List of languages to process */
$languages = array('en', 'fr', 'it', 'de', 'ru');
/* Create lexicon entries for allow_modx_tags description */
switch ($options[xPDOTransport::PACKAGE_ACTION]) {
case xPDOTransport::ACTION_INSTALL:
/* This will only happen on a first install */
/* Set path to individual language file */
foreach ($languages as $language) {
$file = MODX_CORE_PATH .
'components/newspublisher/lexicon/' .
$language . '/' .
'permissions.inc.php';
/* Next line has to be inside the loop */
include($file);
/* Get the description from the file */
$value = $_lang['np_allow_modx_tags_desc'];
/* Make sure the entry doesn't exist already */
$fields = array(
'name' => 'np_allow_modx_tags_desc',
'language' => $language,
);
$entry = $modx->getObject($prefix .
'modLexiconEntry', $fields);
/* If entry doesn't exist, create it */
if (!$entry) {
$entry = $modx->newObject('modLexiconEntry');
$entry->set('name', 'np_allow_modx_tags_desc');
$entry->set('language', $language);
$entry->set('topic', 'permissions');
$entry->set('namespace', 'core');
$entry->set('value', $value);
if ($entry->save()) {
$modx->log(modX::LOG_LEVEL_INFO,
'Set ' . $language .
' lexicon strings for allow_modx_tags setting');
} else {
$modx->log(modX::LOG_LEVEL_INFO,
'Could not set lexicon strings for allow_modx_tags setting');
}
}
}
case xPDOTransport::ACTION_UPGRADE:
/* Upgrade code here */
break;
case xPDOTransport::ACTION_UNINSTALL:
/* Remove lexicon entries for allow_modx_tags description */
$modx->log(modX::LOG_LEVEL_INFO, "Attempting to remove Lexicon entries");
foreach($languages as $language) {
$fields = array(
'name' => 'np_allow_modx_tags_desc',
'language' => $language,
);
$entry = $modx->getObject($prefix . 'modLexiconEntry', $fields);
if ($entry) {
if ($entry->remove()) {
$modx->log(modX::LOG_LEVEL_INFO, 'Removed ' . $language .
' lexicon strings for allow_modx_tags setting');
} else {
$modx->log(modX::LOG_LEVEL_INFO, 'Could not remove ' .
$language . ' lexicon string for allow_modx_tags setting');
}
}
}
break;
}
The comments in the code above explain what it’s doing. Note that the namespace
is set to core
. This is critical, as we saw in the previous article. The core
namespace is where MODX will be looking for any permission descriptions.
Limitations
The code is somewhat limited because there’s only one Lexicon String in each language file. If there were multiple strings, the code would need an extra loop inside to process all the entries, that would look something like this (untested):
include($file);
foreach ($_lang as $key => $value) {
/* Make sure the entry doesn't exist already */
$fields = array(
'name' => $key,
'language' => $language,
);
$entry = $modx->getObject($prefix .
'modLexiconEntry', $fields);
/* If entry doesn't exist, create it */
if (!$entry) {
$entry = $modx->newObject('modLexiconEntry');
$entry->set('name', $key);
$entry->set('language', $language);
$entry->set('topic', 'permissions');
$entry->set('namespace', 'core');
$entry->set('value', $value);
if ($entry->save()) {
$modx->log(modX::LOG_LEVEL_INFO,
'Set ' . $language .
' lexicon strings for allow_modx_tags setting');
} else {
$modx->log(modX::LOG_LEVEL_INFO,
'Could not set lexicon strings for allow_modx_tags setting');
}
}
The uninstall section would also have to be modified to look more like the install section. It would “include” each file, loop through the $_lang
entries, set the field, find them in the DB, and if found, remove them.
Bob Ray is the author of the MODX: The Official Guide and dozens of MODX Extras including QuickEmail, NewsPublisher, SiteCheck, GoRevo, Personalize, EZfaq, MyComponent and many more. His website is Bob’s Guides. It not only includes a plethora of MODX tutorials but there are some really great bread recipes there, as well.