phpBB3 customization driven by configurable feature list

phpBB

Let’s assume you have installed phpBB3 to run forums on the web-project you are working on. It can be a Drupal-based site using phpBBforum Integration module . Anyway, the forum system was re-skinned and your project manager, seems, is pretty happy for the first. But later he requests some changes, e.g. to prevent users from sending emails to each other within the board. This one is easy; you can just direct him to ACP / General / E-mail settings, where board-wide emails can be disabled globally. However, the project manager wants only registered users not be able sending emails, when administrators and global moderators are still able to do it. Again, it is not a problem, because phpBB3 provides permissions roles which can be assigned to user groups. So, you go to ACP / PERMISSIONS / User roles and create and a new role, e.g. ProjectX Registered User Features, based on existing one (All Features). Now for this role, click on the Edit button (green one) and change the value of ‘Can send e-mails’ option of Misc tab in User permissions panel. You see, that’s the configuration for ‘ProjectX Registered User Features’ role. In order to apply this role for all the registered users, just go to ACP / USERS AND GROUPS / Groups’ permissions, select registered users and assign ProjectX Registered User Features’ role to the group.

phpBB3 user roles
phpBB3 role options

Everything is fine so far, but only until the project manager requests something like ‘user search form in UCP has to be removed for unprivileged users’. You cannot find this feature in role options and start thinking of just removing the form from the style template. But what if the project manager changes his mind? No, we need extra option for user roles.

Turning to the documentation we find that creating a new role option is not a big deal. Having new options defined, we need to access them somehow within the style templates (in our case /styles/themeName/template/ucp_header.html) . If using conditions of phpBB template language, we can have a block displayed only when the condition is true

<!-- IF TEMPLATE_CONSTANT -->
HTML...
<!-- ENDIF -->

It would suit us if we could extract those constants from our new role options. Since we are smart enough not to hardcode in the phpBB core scripts, we search for a way to plug into template parser with our new template constants assigned. phpBB is not Drupal, speaking of flexibility, but they also use hooks . So, we create in includes/hooks folder file

hook_advfeatures.php with following code:

<?php
class AdvFeatures
{
    /**
     * Predefined feature (permission option) list
     * @see language/en/mods/advfeatures.php for translations
     * @var array
     */
    private $_config = array(
        'u_advfeature_user_search_form_is_enabled',
    );
    /**
     * Plugin initialization
     * @global user $user @see session
     */
    public function  __construct()
    {
        global $user;
        $user->add_lang('mods/advfeatures');
    }
    /**
     * When permission option (feature) is not defined in the system, let's add it
     * 
     * @global dbal $db
     * @param string $feature
     * @return boolean
     */
    private function _updateFeature($feature)
    {
        global $db;
        // Delete if exists already
        $sql = "DELETE FROM " . ACL_OPTIONS_TABLE . " WHERE auth_option = '{$feature}'";
        $db->sql_query($sql);
        // Add a new value
        $data = array('auth_option' => $feature, 'is_global' => 1);
        $sql = 'INSERT INTO ' . ACL_OPTIONS_TABLE . ' ' . $db->sql_build_array('INSERT', $data);
        return $db->sql_query($sql);
    }
    /**
     * Checks the feature (permission option) list and assign the options as global
     * template constants
     * 
     * @global auth $auth
     * @return array
     */
    private function _syncFeatureList()
    {
        global $auth;
        $assignments = array();
        if (!$this->_config) {
            return null;
        }
        foreach ($this->_config as $feature) {
            $res = $auth->acl_get($feature);
            if ($res === false) {
                $this->_updateFeature($feature);
            }
            $assignments[strtoupper($feature)] = $res;
        }
        return $assignments;
    }

    /**
     * Hooks into $template->display to assign advanced features template constants
     *
     * @global template $template
     * @param phpbb_hook $handle
     * @param boolean $include_once
     */
    public function hookDisplay(phpbb_hook $handle, $include_once = true)
    {
        global $template;
        $assignments = $this->_syncFeatureList();
        $template->assign_vars($assignments);
    }
}

$_plugin = new AdvFeatures();
$phpbb_hook->register(array('template', 'display'), array($_plugin, 'hookDisplay'));

If you have read the code attentively, you would have found the request for translation file

$user->add_lang('mods/advfeatures');

Don’t we want our new role options to appear in ACP like {acl_u_advfeature_user_search_form_is_enabled} ? Ok, let’s create translation file advfeatures.php in language/en/mods folder:

<?php

if (!defined('IN_PHPBB')) {
    exit;
}

if (empty($lang) || !is_array($lang)) {
    $lang = array();
}
// Advanced feature descriptions
$lang = array_merge($lang, array(
    'acl_u_advfeature_user_search_form_is_enabled' =>
        array('lang' => 'Can access user search form', 'cat' => 'misc'),

));

Afterwards, we add the condition in the style template (/styles/themeName/template/ucp_header.html):

Here is the same role option name but typed in capital letters to adhere common constant naming convention.

Now, the feature ‘User search form’ can be enabled or disabled right through ACP by the project manager without your help. And when new requests are coming, you are just adding new role options in $_config property of AdvFeatures class and applying conditions using derived template constants.