Looking to create routes containing some UI and content? This is the article for you!
Differences from Gdn_Controller
A PageDispatchController
serves a different purpose to a Gdn_Controller
.
PageDispatchController
- Core static master view only.
- Primary views expected to be rendered in React.
- Server side rendering only of SEO-critical content using Twig.
- Offers utilities for preloading data into a frontend store.
- Uses the new dispatching rules.
- Hands off to the frontend for future routing.
- Return based result content.
Gdn_Controller
- Uses a master view from any enabled theme.
- Views rendered primarily server side with Twig, Smarty, and PHP.
- Controllers holds Gdn_Assets & Gdn_Modules.
- Additional page contents are outputted using
echo
in 100s of events. - Exclusively server-side routing.
- Data often pulled from models and not the API. Using
Gdn_Form
instead of API submission and must handle post-backs directly.
How does the routing work?
Pages are routed using ResourceRoute
which means all of the rules in our Dispatcher documentation apply. In practice the only HTTP verbs used for pages like this are going to be GET
and INDEX
though.
Using POST, PATCH, PUT, and DELETE verbs is strongly discouraged. Prefer to use ApiControllers for those types of actions.
Registering a Route With the Dispatcher
The first step to creating a Page for your addon is register some rule with the dispatcher.
This registration should be done through \Garden\Container
.
youraddon/settings/bootstrap.php
$container = \Gdn::getContainer();
$container
->rule(\Garden\Web\Dispatcher::class)
->addCall('addRoute', ['route' => new \Garden\Container\Callback(function () {
$route = new \Garden\Web\ResourceRoute('/my-prefix', '*\\%sMyPrefixController');
$route->setMeta('CONTENT_TYPE', 'text/html; charset=utf-8');
})]);
This example assumes we want page to be served from the prefix /my-prefix
and our controllers should be in a pattern of Some\Namespace\ResourceMyPrefixController
. In this case that controller would serve /my-prefix/resource
.
Creating the Controller
We're going to start with a very simple controller setup and gradually build it out.
youraddon/Controllers/ResourceMyPrefixController.php
namespace MyAddon\Controllers;
use Vanilla\Web\PageDispatchController;
class ResourceMyPrefixController extends PageDispatchController {
/**
* Render out the /my-prefix/resource/{id}/editor page.
*
* @param int $id
*/
public function get_editor(int $id) {
return $this
->useSimplePage(\Gdn::translate('Resource Editor'))
->blockRobots()
->requiresSession("/my-prefix/resource/$id/editor")
->render()
;
}
/**
* Render out the /my-prefix/resource/add page.
*/
public function get_add() {
return $this
->useSimplePage(\Gdn::translate('New Resource'))
->blockRobots()
->requiresSession("/my-prefix/resource/add")
->render()
;
}
}
What did we do?
Here we've made 2 simple page containers for client rendered views. It would be expected that the primary page content will be rendered using React, as all that these pages will render are a search engine information and an empty body.
- 2 pages, 1 for add and 1 for edit of the resource.
- These pages require the user to be signed in. Signed out users will be sent to the sign in page and then redirected back after a successful login.
- Search engines are blocked from crawling these pages.
SimplePage
Simple pages are ideal for when we want the server to deal with search engines (Either by providing some SEO info, like title and description, or blocking them), then handing things off to ReactJS.
When should you use a simple page instead of a custom one?
Simple pages generally best for when the server doesn't have any data to preload, and just wants to render a shell, before the frontend router takes over. The following metadata can be configured after creating the simple page.
- Set the page title - Part of the constructor.
- Blocking Search engines -
blockRobots()
. - Require users to be signed in
requiresSession()
. - Set any information from
PageHeadInterface
.- Meta tags
- Title
- Description
Custom simple pages
By default PageDispatchController
uses SimpleTitlePage
for creating simple pages, but it is encouraged to create your own and configure it for your PageDispatchController
. This way you can configure common metadata or add custom configuration methods.
To set a custom simple page, create a subclass of Vanilla\Web\Page
and assign it in your controller.
// If targetting forum or KB use ThemedPage instead.
class MyCustomPageClass extends Page {
/**
* @return string
*/
public function getAssetSection(): string {
return "admin"; // forum, admin, or knowledge
}
/**
* @inheritdoc
*/
public function initialize(string $title = "") {
$this->setSeoRequired(false);
$this->setSeoTitle($title);
}
}
class ResourceMyPrefixController extends PageDispatchController {
protected $simplePageClass = MyCustomPageClass::class;
}
Defining an Asset Section
In our previous example we implemented getAssetSection()
. This is a method of Page
that must be implemented in order to tell the controller what scripts to add to the page.
Custom assets can be created, but generally you want to define either "forum", "admin" or "knowledge".
See the build documentation on asset sections.
Custom Pages
This section is under construction.