A block can react to URL parameters without using $view->action()
. If
you want your block to react to the following URL:
http://www.example.com/index.php/path/to/page/custom_foo/param1/param2/param3
Just create a method named
public function action_custom_foo($param1 = null, $param2 = null, $param3 = null)
{
// Custom Logic
$this->view();
}
No need to worry about the block ID in this case. Note: All blocks on this page that have a method named action_custom_foo with the same signature will fire this action.
Blog Example
Concrete CMS's sample blog in the Elemental theme shows a good example of how multiple block types can use action. When a topic in the Topic List block is clicked, the following URL is browsed to:
http://www.example.com/index.php/blog/topic/11/projects
This means that any block on the page that responds to action_topic
with a $treeNodeID
and a $topicText
as its optional second
parameters will fire. This includes the following blocks: topic
list, page title, and page list.
Topic List
The topic list block uses the action_topic()
method to mark the
particular clicked-on topic as selected. Here is its action_topic()
method in the controller.
public function action_topic($treeNodeID = false, $topic = false)
{
$this->set('selectedTopicID', intval($treeNodeID));
$this->view();
}
The method simply sets the selected topic ID into the block view. The view then will check to see if this variable exists, and if it does, it will apply the active CSS class to the clicked-on topic.
Page Title
When the "Archives" custom template is applied to the Page Title
block, the Page Title block will listen for action_topic()
and
display the selected topic text instead of "Blog".
public function action_topic($treeNodeID = false, $topic = false)
{
if ($treeNodeID) {
$topicObj = Topic::getByID(intval($treeNodeID));
$this->set('currentTopic', $topicObj);
}
$this->view();
}
First, it uses the topic tree node ID to grab the selected topic, and sets it into the page. The archives custom template then displays it.
<?php
if (is_object($currentTopic)) {
$title = t('Topic Archives: %s', $currentTopic->getTreeNodeDisplayName());
}
?>
<h1 class="page-title"><?=$title?></h1>
Page List
Finally, the Page List block filters by the topic. First, it routes
the "topic" URL slug to the action_filter_by_topic()
method (see
below for more on how to do this). Then the action_filter_by_topic()
method filters the instance of the
\Concrete\Core\Page\PageList
object that is already instantiated within the Page List block.
public function action_filter_by_topic($treeNodeID = false, $topic = false)
{
if ($treeNodeID) {
$this->list->filterByTopic(intval($treeNodeID));
$topicObj = Topic::getByID(intval($treeNodeID));
if (is_object($topicObj)) {
$seo = Core::make('helper/seo');
$seo->addTitleSegment($topicObj->getTreeNodeDisplayName());
}
}
$this->view();
}
The method even updates the page title using the SEO service to that of the selected topic.
Advanced: Programmatically Disabling action_
URLs for Certain Block Instances
The Page List block provides a number of action_
URLs for other blocks
to use to filter the resulting pages displayed. While this is
powerful, its only meant to be used when you're displaying page lists
in an interactive capacity (e.g. as part of a blog or search results.)
If you're just listing featured pages, or recenty updated pages, you
may not want the ability to arbitrarily filter these pages via
URLs. That's why the Page List block uses a custom internal boolean to
control whether this filtering is available. Here's how that works:
Any time an action URL is checked, the
\Concrete\Core\Block\BlockController
method isValidControllerTask
is checked. This checks the class to
see if the method exists, and whether it starts with action_. The Page
List block controller overrides this method to also check if an
additional internal boolean is set to true.
public function isValidControllerTask($method, $parameters = array())
{
if (!$this->enableExternalFiltering) {
return false;
}
return parent::isValidControllerTask($method, $parameters);
}
This only enables the action_
URLs if the page list "Enable External
Filtering" option is checked in the Page List edit interface.
Advanced: Mapping a Custom URL segment to a Differently Named Action
Sometimes you might want your method to be named differently than the
standard action_*
method name. For example, the Page List block
reacts to the "tag", "topic" and "date" parameters:
http://www.example.com/index.php/path/to/page/topic/123/kittens
http://www.example.com/index.php/path/to/page/date/2015/01/01
http://www.example.com/index.php/path/to/page/tags/hats
The core team didn't want to create methods named action_tag
,
action_date
, action_topic
– just because amidst all the other
methods some of the purpose of these methods might be lost. We wanted
to name the methods
action_filter_by_tag
action_filter_by_date
action_filter_by_topic
Without losing the nice, succinct URL segments. To do this, simply override the built-in \Concrete\Core\Block\BlockController
public function getPassThruActionAndParameters($parameters)
{
if ($parameters[0] == 'topic') {
$method = 'action_filter_by_topic';
$parameters = array_slice($parameters, 1);
} elseif ($parameters[0] == 'tag') {
$method = 'action_filter_by_tag';
$parameters = array_slice($parameters, 1);
} elseif (Loader::helper("validation/numbers")->integer($parameters[0])) {
// then we're going to treat this as a year.
$method = 'action_filter_by_date';
$parameters[0] = intval($parameters[0]);
if (isset($parameters[1])) {
$parameters[1] = intval($parameters[1]);
}
}
return array($method, $parameters);
}