Velo: Creating Data Hooks for Dynamic Pages

Visit the Velo by Wix website to onboard and continue learning.

Creating a data binding router hook allows you to intercept the process of a dynamic page's data getting bound to the page.

This article takes you through what code you have to write in order to make a data binding router work. To learn more about what a data binding router hook is and why you would want to create one, see About Data Binding Router Hooks.

Add a Data Binding Router Hook

To add a data binding router hook:

  1. Go to your dynamic page located in your site's pages.
  2. Click the Show More icon and then click Settings to open the page's settings.
  3. In the Page Info tab, scroll down to Advanced Settings, and click Add Hooks to display the Add Hooks panel.

When adding a data binding router hook, function stubs for the data binding router hooks you chose are added to the routers.js file in your site's backend code.

The data binding router hook functions are named with the following convention:

Copy
1
<dynamic page prefix>_<hook name>(params...)

So if your dynamic page has the prefix myPrefix, the code added to the routers.js file for the beforeRouter hook should look like:

Copy
1
myPrefix_beforeRouter(request) { // routing code ...}

The hooks you can register are listed here in the order they run:

  • beforeRouter
  • customizeQuery
  • afterRouter
  • afterSitemap

To learn more about the hook functions, see the Router API reference.

You can also register data hooks that run code before or after certain interactions with your site's collections. If you’ve done so, the data hooks will run between customizeQuery() and afterRouter().

beforeRouter( )

This hook is triggered before the router goes to the requested dynamic page. You can use this hook to route requests to a different page or return an error response. If you need the data that will be bound to the page to determine the correct response, use the afterRouter() hook instead.

The beforeRouter() hook receives a WixRouterRequest object that contains information about the incoming request. The object has information about the URL used to reach the router, where the request came from, and who the request came from.

Within the body of the hook you can write any code you want. The code you write there should help you determine how you want to respond to the request.

The function needs to return a WixRouterResponse object that causes the router to continue its routing, or respond with an HTTP response code.

If you want the router to continue to the same page it was originally going to with the same data, use the next() function to return the appropriate WixRouterResponse.

However, if you want the router to do something other than it was originally going to do before reaching your hook, you can use the forbidden(), notFound(), redirect(), or sendStatus() functions to return a WixRouterResponse.

Example

In this example we create a hook on the dynamic prefix that restricts certain requests from being routed to their intended target.

The following code is placed in the routers.js file in your site's backend code.

Copy
1
import {forbidden, next} from 'wix-router';
2
3
export function dynamic_beforeRouter(request) {
4
if (request.path.length > 1 && request.path[0] === "admin") {
5
if (request.user && request.user.role == "siteOwner")
6
return next();
7
else
8
return forbidden();
9
}
10
11
return next();
12
}

The functionality used to create data binding router hooks is contained in the Router API. To use some of this functionality, you need to import it. 

Here we import the forbidden() and next() functions.

Copy
1
import {forbidden, next} from 'wix-router';

If you want to use more of the functionality from the Router API, you need to add it to the import statement.


In the hook function, we start by checking if the path begins with the string "admin":

Copy
1
if (request.path.length > 1 && request.path[0] === "admin") {
2
// ...
3
}

If the path starts with anything other than "admin", the if is skipped and we tell the router to continue to where it was going before being intercepted by the hook:

Copy
1
return next();

However, if the path starts with "admin", we check to see what type of user is making the request:

Copy
1
if (request.user && request.user.role == "siteOwner") {
2
// ...
3
}

If the user is the owner of the site, we once again tell the router to continue to where it was going before being intercepted by the hook:

Copy
1
return next();

But if the user in not the owner of the site, we return a 403 response:

Copy
1
return forbidden();

customizeQuery( )

This hook is triggered before the page's data query is executed. You can use this hook to further refine or change the query that will determine what data is bound to your page's dataset.

The customizeQuery() hook receives a WixRouterRequest object that contains information about the incoming request, a string with the current route, and a WixDataQuery object containing query which is going to be used to get the data for the page being routed to.

Within the body of the hook you can write any code you want. The code you write there should help you determine if you want to continue with the initial data or if you want to change it in some way.

The function needs to return a WixDataQuery object that will be used to get the final data to be passed to the page that will be routed to.

If you want the router to continue with the same data it was originally going to bind to the page, return the object that the function received in the query parameter.

However, if you want the router use different data, you can either refine the current query using the functions of the Data API or create a new query.

Example

In this example we create a hook on the dynamic prefix that filters the query for a certain route to only find active users.

The following code is placed in the routers.js file in your site's backend code.

Copy
1
export function myRouter_customizeQuery(request, route, query) {
2
if (route === "/users/{name}")
3
return query.eq("status", "active");
4
else
5
return query;
6
}

The functionality used to create queries is contained in the Data API. To use some of this functionality, you need to import it. 


In the hook function, we start by checking if the route is going to a dynamic page that will be displaying users:

Copy
1
if (route === "/users/{name}")
2
// ...

If it is going there, we refine the query to only get "active" users:

Copy
1
return query.eq("status", "active");

Otherwise, we return the same query we received:

Copy
1
return query;

afterRouter( )

This hook is triggered after the router has bound the data, but before the page is displayed. You can use this hook to change the router's response based on the data that was retrieved. 

The afterRouter() hook receives a WixRouterRequest object that contains information about the incoming request and a WixRouterResponse object containing information about the router's response.

Within the body of the hook you can write any code you want. The code you write there should help you determine if you want to continue with the initial response or if you want to change it to another response.

The function needs to return a WixRouterResponse object that causes the router to continue its routing, or respond with an HTTP response code.

If you want the router to continue to the same page it was originally going to with the same data, return the object that the function received in the response parameter.

However, if you want the router to do something other than it was originally going to do before reaching your hook, you can use the
ok(), forbidden(), notFound(), redirect(), or sendStatus() functions to return a WixRouterResponse. To use the data from the router on a page that is different than the one the router was originally going to route to, you can use the [ok()] function to choose the page and pass it the response.data and response.header from the original response. For an example of this use case, see below.

Example

In this example we create a hook on the dynamic prefix that routes the user to one of two pages. We have two versions of a page, one for horizontal oriented images and another for vertical oriented ones. After the image is pulled from the database, we check which type of picture is to be shown and route to the page that corresponds to that image's orientation.

The following code is placed in the routers.js file in your site's backend code.

Copy
1
import {ok} from 'wix-router';
2
3
export function myRouter_afterRouter(request, response) {
4
if(response.status === 200 && response.page === "horizontal-pic") {
5
if(response.data.picture.orientation === "vertical")
6
return ok("vertical-pic", response.data, response.head);
7
else
8
return response;
9
}
10
11
return response;
12
}

The functionality used to create data binding router hooks is contained in the Router API. To use some of this functionality, you need to import it. 

Here we import the ok() function.

Copy
1
import {ok} from 'wix-router';

If you want to use more of the functionality from the Router API, you need to add it to the import statement.


In the hook function, we start by checking if the response status is the okay status and if the page the response is routing to is the page that displays pictures with a horizontal orientation:

Copy
1
if(response.status === 200 && response.page === "horizontal-pic") {
2
// ...
3
}

If we find any other status or if the page we're responding with is not the one we have two versions of, we just return the original response:

Copy
1
return response;

However, if the router is about to route to the page that displays horizontal images, we check the orientation of the image that will be displayed on the page. We do so by pulling the orientation information from the router's current response:

Copy
1
if(response.data.picture.orientation === "vertical")
2
// ...

If the picture's orientation doesn't match the page it was being sent to, we route to a different page that does match its orientation and we take the data and head information from the original response and send it to the new page as well:

Copy
1
return ok("vertical-pic", response.data, response.head);

But if the picture's orientation already matches the page it was being sent to, we send it to where it was already going.

Copy
1
return response;

afterSitemap( )

This hook is triggered after after a sitemap is created. You can use this hook to to revise the list of pages in your sitemap. 

The afterSitemap() hook receives a WixRouterSitemapRequest object that contains information about the incoming request and a WixRouterSitemapEntry array containing the sitemap's entries.

Within the body of the hook you can write any code you want. The code you write there should help you determine if you want to continue with the initial sitemap entries or if you want to change them in any way.

The function needs to return a WixRouterSitemapEntry array with all of the sitemap's entries.

If you want the router to continue with the same sitemap entries the hook received, return the object that the function received in the sitemapEntries parameter.

However, if you want the router modify the sitemap entries, you can add, remove, or modify entries of the received array using standard JavaScript array processing methods.

Example

In this example we create a hook on the dynamic prefix that adds a search page to the sitemap. Note that the sitemap function only publishes a URL for the search page. To actually implement a page at this URL you can use a beforeRouter() hook to check for the request for the search page URL and route the user to a search page.

The following code is placed in the routers.js file in your site's backend code.

Copy
1
import {WixRouterSitemapEntry} from 'wix-router';
2
3
export function myRouter_afterSitemap(sitemapRequest, sitemapEntries) {
4
let prefix = sitemapRequest.prefix;
5
let entry = new WixRouterSitemapEntry(`${prefix}/search`);
6
sitemapEntries.push(entry);
7
return sitemapEntries;
8
}

The functionality used to create sitemap entries is contained in the Router API. To use some of this functionality, you need to import it. 

Here we import WixRouterSitemapEntry.

Copy
1
import {WixRouterSitemapEntry} from 'wix-router';

In the hook function, we start by getting the prefix of the request:

Copy
1
let prefix = sitemapRequest.prefix;

Then we create a new entry for our search page:

Copy
1
let entry = new WixRouterSitemapEntry(`${prefix}/search`);

And add the new entry to the array of sitemap entries:

Copy
1
sitemapEntries.push(entry);

Finally, we wrap the array of entries in a Promise and return it:

Copy
1
return Promise.resolve(sitemapEntries);
Was this helpful?
Yes
No