Create a custom page
Introduction
Codex allows you to create custom pages in Codex admin through plugins. The users can use these pages to perform a specific functionality that is not provided as a feature in Codex. Users can navigate through the menu on these pages or some buttons created on other pages.
A page created through plugins can contain any type of content and can access Codex API or any third-party API for managing the data. In addition, it is integrated natively into Codex, meaning you can access all the data on that page, the user, and permissions and use Codex's existing functionality.
Before continuing with this tutorial, please make sure you have read our plugins Quick Start guide and Create your first plugin tutorial, which goes through the setup of the first plugin used during this tutorial.
Define the routes
When creating a custom page in Codex, you need to specify the route of that page. You can define the route of your pages in the manifest.json
file of the plugin under the routes field.
{
"plugin_name": "sport",
"plugin_display_name": "Sport",
"version": "1.0.0",
"routes": [
{
"path": "teams",
"name": "list_of_teams",
"title": "Teams",
"component": "pages/Teams.vue",
"meta": {
"breadcrumb": [
{
"text": "Teams",
"to": { "name": "sites" },
"active": true
}
]
}
},
{
"path": "matches",
"name": "list_of_matches",
"title": "Matches",
"component": "pages/Matches.vue",
"meta": {
"breadcrumb": [
{
"text": "Matches",
"to": { "name": "sites" },
"active": true
}
]
}
}
]
}
path
A string that represents the path of that route will be displayed in the browser URL when users visit that specific route. For example, for path matches
, the full URL will be
https://codex.gjirafa.tech/{organization}/{site}/plugins/{plugin-name}/matches
name
A string that represents the unique name of the route. For each route, the plugin name is also appended automatically to avoid any potential collision with routes from another plugin.
title
A string that represents the title of the route, for example, Matches
component
A string that represents the Vue component that will be rendered for the page, for example, Matches.vue
. In case you place components in a specific directory, you need to specify the relative path, including the directory, for example, components/Matches.vue
.
meta
An object that represents meta-information about the route, such as breadcrumbs.
breadcrumb
An array of objects that represents an array of breadcrumbs for that specific route.
Navigation
After defining the routes, you must also define navigation menu items for your routes. That can be done through the navigation
field in the manifest file. Each item of the navigation array represents a menu item that can be placed in any of the Codex module menus.
{
"plugin_name": "sport",
"plugin_display_name": "Sport",
"version": "1.0.0",
"routes": [
// routes here
],
"navigation": [
{
"name": "sport-teams",
"title": "Sport",
"route": "sport-list_of_teams",
"icon": "Target",
"insertAfter": "home-dashboard",
"children": [
{
"title": "Teams",
"route": "sport-list_of_teams"
},
{
"title": "Matches",
"route": "sport-list_of_matches"
}
]
}
]
}
name
A string that represents the name of the navigation menu item.
title
A string that represents the navigation title will also be displayed to the end users in the admin.
route
A string that represents the route to which the navigation will send the users. Since all routes automatically have the plugin name as a prefix, for each navigation item, you need to add the plugin name before the route name. For example, we have the list_of_matches
route in the plugin with the name sport
, then in navigation, we need to write sport-list_of_matches
.
icon
A string that represents the icon of the navigation menu item.
insertAfter
A string that represents where the menu item should be placed in Codex Admin, for example, content-sections
or content-module
. You can add the navigation item anywhere within Codex Admin; see the list of menu items below.
Apart from insertAfter
you can also use
insertBefore
If you want to insert the menu item before another one.
insertAt
When you want to insert a new module into Codex, you need to use the insertAt field of navigation. This field is an object and contains the index of the module too.
"insertAt": {
"parent": "assets-module",
"index": 2
}
Codex navigation tree
Below you can find the complete navigation tree of Codex. You can place your navigation items under this tree based on your plugin types and user experience.
Codex
└───Home (home-module)
│ │ Sites (home-dashboard)
└───{site} (site-module)
│ │ Entries (site-entries)
│ │ Sections (site-sections)
└───Builder (builder-module)
│ │ Models (builder-models)
│ │ Webhooks (builder-webhooks)
└───Administration (administration-module)
│ │ Sites (administration-sites)
│ │ Users (administration-users)
│ │ Authors (administration-authors)
│ │ API Keys (administration-apikeys)
│ │ Labels (administration-labels)
Develop the pages
Now that we have specified the routes and navigations, we need to set the page components to render the content displayed to the end users. These pages are native Vue component files, meaning you have complete control over what to display and what actions can be performed.
Continuing with our sports plugin, create a new directory and name it pages
in the root plugin directory. In the pages
directory, create two new files, Teams.vue
and Matches.vue
. Your plugin directory now should look like this
root-directory
│ .codexignore
│ manifest.json
└───shared
│ │ sportApi.js
│ │ MatchDetails.vue
└───pages
│ │ Teams.vue
│ │ Matches.vue
In our Teams.vue
component we are going to show a list of all teams which will be retrieved from our sportApi.js
file as created in the previous tutorial.
<template>
<div class="sport-teams">
<b-table striped hover :items="teams"></b-table>
</div>
</template>
<script>
import { getTeams } from '../shared/sportApi'
export default {
data() {
return {
teams: getTeams()
}
},
}
</script>
<style>
.sport-teams {
display: flex;
padding: 2%;
}
</style>
In our Matches.vue
component we are going to show a list of all matches which will be retrieved from our sportApi.js
file as created in the previous tutorial.
<template>
<div class="sport-matches">
<b-table striped hover :items="matchItems"></b-table>
</div>
</template>
<script>
import { getMatches } from '../shared/sportApi'
import MatchDetails from '../shared/MatchDetails'
export default {
components: {
MatchDetails
},
data() {
return {
matches: getMatches()
}
},
computed: {
matchItems() {
return this.matches.map((match) => ({
firstTeamName: match.firstTeam.name,
firstTeamScore: match.firstTeamScore,
secondTeamScore: match.secondTeamScore,
secondTeamName: match.secondTeam.name,
}))
}
}
}
</script>
<style>
.sport-matches {
display: flex;
padding: 2%;
}
</style>