Skip to content
On this page

Events

A lot of customization can be done either via event listeners, or by adding custom classes.

Just go with your personal preference.

Event listeners

  • are a bit verbose.
  • you can keep them all in one file.
  • there is no need to touch the config files.
  • are not threatened by breaking changes in the base classes.

Custom classes

  • must be configured
  • look a bit cleaner
  • can benefit from inheritance (specific section -> base section holding your defaults)
  • it can be a bit tricky to avoid duplicate code (hello, multiple inheritance..)
  • can break if base classes are updated (type changes)

Modify Query

Custom modules can extend the configuration by adding keys to the custom section config array and modify the query via an event:

php
use wsydney76\contentoverview\events\ModifyContentOverviewQueryEvent;
use wsydney76\contentoverview\models\Section;


Event::on(
    Section::class,
    Section::EVENT_MODIFY_CONTENTOVERVIEW_QUERY,
    function(ModifyContentOverviewQueryEvent $event) {
        /** @var Section $sectionConfig */
        $sectionConfig = $event->sender;
        if (isset($sectionConfig->custom['tagline'])) {
            $event->query->tagline($sectionConfig->custom['tagline']);
        }
        
        // Add eager loading related elements that appear in info 
        $event->query->with(['assignedTo ...'])
    }
);

Modify Collections

Every collection of models in the chain Pages -> Tabs -> Columns -> Sections -> Actions/Filters/TableColumns can be modified.

This is especially useful if you want to apply rules based on a users role and entry content.

EventEvent ClassProperty
ContentOverviewService::EVENT_DEFINE_PAGESDefinePagesEvent$pages
Page::EVENT_DEFINE_TABSDefineTabsEvent$tab
Tab::EVENT_DEFINE_COLUMNSDefineColumnsEvent$columns
Column::EVENT_DEFINE_SECTIONSDefineSectionsEvent$sections
Section::EVENT_DEFINE_ACTIONSDefineActionsEvent$entry, $actions
Section::EVENT_DEFINE_FILTERSDefineFiltersEvent$filters
TableSection::EVENT_DEFINE_TABLECOLUMNSDefineTableColumnsEvent$table, $tableColumns

Add a handle to a model so that it can easily be identified in your event handler.

Additionally, you can add a custom setting to any model that contains arbitrary data.

All event properties are Collections, so they can be modified using all collection methods.

For convenience, all event classes have a user property containing the current user, and, where appropriate, a reference to their parent object.

For a better overview it is recommended to define all possible objects in your config files and filter out what is not needed, instead of adding stuff in your event handlers.

Examples:

php
Event::on(
    ContentOverviewService::class,
    ContentOverviewService::EVENT_DEFINE_PAGES,
    function(DefinePagesEvent $event) {
        if (!$event->user->can('yourpermission')) {
            $event->pages = $event->pages->filter(function($page) {
                return $page->handle !== 'workpage';
            });
        }
    }
);
php
Event::on(
    Section::class,
    Section::EVENT_DEFINE_ACTIONS,
    function(DefineActionsEvent $event) {
        $event->actions = $event->actions->filter(function($action) use ($event) {
            if ($action instanceof Action && $action->handle === 'publishAction') {
                return $event->entry->status !== 'live';
            }
            return true;
        });
    }
);

Support Custom Filters

Options can be set dynamically via an event:

php
use wsydney76\contentoverview\events\DefineCustomFilterOptionsEvent;
use wsydney76\contentoverview\models\Filter;
Event::on(
    Filter::class,
    Filter::EVENT_DEFINE_CUSTOM_FILTER_OPTIONS,
    function(DefineCustomFilterOptionsEvent $event) {
        if ($event->filter->handle === 'criticalreviews') {
            $event->filter->options->prepend([
                'label' => 'A new option',
                'value' => 'aNewOption'
            ]) ;
        }
    }
);

A custom module can apply filter params to the section query in an event handler, e.g.

php

use wsydney76\contentoverview\events\FilterContentOverviewQueryEvent;
use wsydney76\contentoverview\models\Section;

...

Event::on(
    Section::class,
    Section::EVENT_FILTER_CONTENTOVERVIEW_QUERY,
    function(FilterContentOverviewQueryEvent $event) {
        if ($event->handle === 'criticalreviews') {
            switch ($event->value) {
                case 'overdue':
                {
                    $event->query
                        ->workflowStatus('inReview')
                        ->dueDate('< now');
                    break;
                }
                case 'nextweek':
                {
                   // 
                }
            }
        }
          
    }
    );

Modify Settings for Current User

Sometimes it makes sense to modify plugin settings for the current user, based on their role or preferences.

Currently implemented for the replaceDashboard, showPages, enableCreateInSlideoutEditor settings.

The event contains $key and $value properties.

php
Event::on(
    Settings::class,
    Settings::EVENT_DEFINE_USER_SETTING,
    function(DefineUserSettingEvent $event) {
        $currentUser = Craft::$app->user;
        
        // Give users a custom field so that they can decide whether to see links in the main nav or in sidebar
        // depending on their screen size
        if ($event->key === 'showPages') {
            $showPages = $currentUser->identity->showContentoverviewPages->value ?? 'default';
            if ($showPages !== 'default') {
                $event->value = $showPages;
            }
        }

        // Always show dashboard for admins
        if ($event->key === 'replaceDashboard') {
            if ($currentUser->getIsAdmin()) {
                $event->value = false;
            }
        }
    }
);

Define images

Event example:

php
use wsydney76\contentoverview\models\Section;
use wsydney76\contentoverview\events\DefineImageEvent;
...
Event::on(
    Section::class,
    Section::EVENT_DEFINE_IMAGE,
    function(DefineImageEvent $event) {
        /** @var Entry $entry */
        $entry = $event->entry;
        if ($entry->section->handle === 'film') {
            // TODO: improve performance, load/cache fallback images in advance
            $event->image = $entry->featuredImage->one() ??
                $entry->series->one()->featuredImage->one() ??
                GlobalSet::find()->handle('siteInfo')->one()->featuredImage->one() ??
                null;
        }
    }
);

Define Icons

Event example:

php
// Section config
->icon('@appicons/newspaper.svg')
->iconBgColor('var(--blue-400')
php
// Custom module
use wsydney76\contentoverview\models\Section;
use wsydney76\contentoverview\events\DefineIconEvent;
...
Event::on(
    Section::class,
    Section::EVENT_DEFINE_ICON,
    function(DefineIconEvent $event) {
        if ($event->entry->type->handle === 'privacy') {
            $event->icon = '@appicons/bullhorn.svg';
            $event->iconBgColor = 'var(--red-400)';
        }
    }
);

Screenshot

Get Section Config for Ajax requests

This is only relevant if you are using a custom Page model that does not read its config from a page config file.

In order to enable ajax requests for a section, like refreshing its html, a sectionPath identifier is handled internally, in the form of pageKey-tabIndex-columnIndex-sectionIndex, e.g. page1-0-1-3.

The ajax controller then gets the section config from the corresponding page config file.

However, if a plugin uses its own page model without using a config file, this will fail.

In this case a plugin can inject the section config model via an event:

php
Event::on(
    ContentOverviewService::class,
    ContentOverviewService::EVENT_GETSECTIONBYPATH,
    function(GetSectionByPathEvent $event) {              
        if ($event->sectionPath ===  'package-0-0-0') {
            $event->section = $co->createSection(MyCustomSection::class);
        }
    }
);