Retrieve page content

Web page content is stored in the database and edited through the administration interface using the content tree in website channel applications.

The Xperience API allows you to work with pages using:

The implementation and complexity of the retrieval and management code depend on your preferences and project requirements, and can range from simple method calls within controller actions to custom solutions utilizing repository and service patterns. Install the sample Dancing Goat project to view a reference implementation.

Retrieve page data

To retrieve web page content, use the following services from CMS.ContentEngine and CMS.Websites namespaces:

  • ContentItemQueryBuilder class with the ForWebsite query parametrization method – to create and parametrize a content item query specifically for retrieving website data. The ForWebsite query parameter has the following properties:
    • websiteChannelName – code name of the website channel from which the pages are retrieved. You can use current channel context to retrieve this value.
    • pathMatch – a parameter of type PathMatch used to limit the retrieved pages based on their positon in the website’s content tree. See Filter pages based on content tree structure for more information.
    • includeUrlPath – indicates if the URLs of pages and content item assets are fetched as well. Defaults to true.
  • IContentQueryExecutor interface and its GetMappedWebPageResult method – to execute a page query specified by the builder and map the results to the model class.
    • To retrieve correct version of pages in preview mode and Page Builder, modify the query execution by configuring the ContentQueryExecutionOptions.
Sample page retrieval


// Services obtained via dependency injection
private readonly IContentQueryExecutor executor;

public async Task PageRetrieval()
{
    // Configures the query builder
    var builder = new ContentItemQueryBuilder()
                        .ForContentType(
                            // Scopes the query to pages of the 'My.ArticlePage' content type
                            "My.ArticlePage",
                            config => config
                                // Retrieves pages only from the specified channel and path
                                .ForWebsite(
                                    "MyWebsiteChannel",
                                    PathMatch.Children("/Articles"))
                        // Retrieves only English variants of pages
                        ).InLanguage("en");

    // Executes the query and stores the data in generated 'ArticlePage' models
    IEnumerable<ArticlePage> pages = await executor.GetMappedWebPageResult<ArticlePage>(builder);

    // Displays the page data
    foreach(var page in pages)
    {
        Console.WriteLine(page.ArticleTitle);
        Console.WriteLine(page.ArticlePageSummary);
    }
}

Retrieve multilingual page data

To retrieve web page content in a specific language, use the InLanguage method and as a parameter provide the language code name as specified in the Languages application.

Sample multilingual page retrieval


// Creates a query to retrieve pages in the Spanish language
var builder = new ContentItemQueryBuilder()
                        .ForContentType(
                            // ...
                        ).InLanguage("es");

If you omit the method and don’t specify a language, the query returns results in the primary language of the website channel.

Pages in fallback language

If the desired language variant of a page doesn’t exist, the query returns the page data in the fallback language, if fallbacks are configured.

Filter pages based on content tree structure

You can set the query to only include pages from a certain section of the content tree or omit pages from a section using the PathMatch parameter of the ForWebsites query parametetrization method. PathMatch expressions can be combined to more accurately specify what pages are included in the query.

  • Single – only retrieves a single page that corresponds to the specified tree path.
    • E.g., PathMatch.Single(path: "/Articles/Coffee_processing_techniques")
  • Children – recursively retrieves all children of a specified parent page, excluding the parent page from the query. You can also specify a nesting level to limit the depth of recursion.
    • E.g., PathMatch.Children(path: "/Articles", nestingLevel: 3)
  • SkipChildren – recursively exclude all children of a specified parent page from the query, except for the parent page. You can also specify a nesting level to limit the depth of recursion.
    • E.g., PathMatch.SkipChildren(path: "/Articles/Coffee", nestingLevel: 3)
  • Section – recursively retrieves all children of a specified parent page, including the parent page in the query. You can also specify a nesting level to limit the depth of recursion.
    • E.g., PathMatch.Section(path: "/Articles", nestingLevel: 3)
  • SkipSection – recursively exclude all children and the specified parent page from the query. You can also specify a nesting level to limit the depth of recursion.
    • E.g., PathMatch.SkipSection(path: "Articles/Coffee", nestingLevel: 3)

Combine PathMatch expressions

You can combine multiple PathMatch expressions by passing an array as the argument to the ForWebsite method.

Example - Combine PathMatch expressions


var builder = new ContentItemQueryBuilder()
                    .ForContentType(
                        "My.ArticlePage",
                        config => config
                            .ForWebsite(
                                websiteChannelName: "MyWebsiteChannel",
                                pathMatches: new PathMatch[]{
                                    PathMatch.Children("/Articles"),
                                    PathMatch.SkipSection("/Articles/Coffee_processing_techniques")
                                }
                            )
                    );

Filter pages based on tags

You can limit the retrieval query to only retrieve pages with the specified tags using the WhereContainsTags content item query parametrization method.

See Retrieve content items for more information.

Page security configuration

Pages can be secured to allow access only to authenticated users. You can filter out secured pages during retrieval by passing the appropriate bool value to the IncludeSecuredItems property of the ContentQueryExecutionOptions and providing them to the query executor.

Retrieve secured pages


// Services obtained via dependency injection
private readonly IContentQueryExecutor executor;

// Information about whether to include secured items in the query execution passed from the caller
public async Task PageRetrieval(bool includeSecuredItems)
{
    // Configures the query builder
    var builder = new ContentItemQueryBuilder()...;

    // Configures the query options for the query executor
     var queryOptions = new ContentQueryExecutionOptions()
    {
         IncludeSecuredItems = includeSecuredItems
    };

    // Executes the query and stores the data in generated 'ArticlePage' models
    IEnumerable<ArticlePage> pages = await executor.GetMappedWebPageResult<ArticlePage>(
                                                builder: builder,
                                                options: queryOptions);
}

The secured state of a retrieved page is indicated by its page.SystemFields.ContentItemIsSecured property. You can use this property to display information to visitors accordingly.

For example, you can pass the page’s ContentItemIsSecured property to a model and display an appropriate message to visitors. 

Reflect page security in views


// In this case, the 'ContentItemIsSecured' is mapped to the 'IsSecured' property of this view model 
@if (model.IsSecured && !User.Identity.IsAuthenticated)
{
    <p>
        Sign in to access this page
    </p>
}

An alternative popular practice is to display a blurred teaser image overlaid with a lock to indicate elevated permission requirements.

You can check whether the current ClaimsPrincipal is authenticated via User.Identity.IsAuthenticated. If unauthenticated visitors attempt to access a secured page, the server returns HTTP 403 Forbidden. ASP.NET Identity can be configured to automatically redirect such requests to another location on the website (typically a registration or sign in page) via AccessDeniedPath.

Program.cs


builder.Services.ConfigureApplicationCookie(options =>
{
    // Responses that would otherwise return 403 are instead redirected to <domain>/account/signin
    options.AccessDeniedPath = new PathString("/account/signin");
});

Work with retrieved page data

You can access various types of data from retrieved page objects:

  • Content type fields – the data that is editable in a page’s Content view mode. The set of available fields is configurable via the field editor.
  • System fields – available under the SystemFields property of the retrieved page objects. Access WebPage* fields for web page data and ContentItem* for data of the underlying content item.
  • Page URL – see Get page URLs.
Access page data


// Retrieves a page
var page = (await executor.GetMappedWebPageResult<Article>(builder)).FirstOrDefault();

// Accesses the ID of the parent
var parentId = page.SystemFields.WebPageItemParentID;

// Accesses the code name of the page object
var pageName = page.SystemFields.WebPageItemName;

Access page field data

The fields available in a page’s Content view mode are specific to its content type. You can see the fields that each content type uses:

  • In Content types (application) → edit a content type → Fields tab
  • In the corresponding <namespace>_<content_type_name> database table

You can access specific fields of a content type directly using strongly typed properties when using generated content type classes:

Access content type fields


// Retrieves a page
var page = (await executor.GetMappedWebPageResult<Article>(builder)).FirstOrDefault();

// Accesses the 'Text' field of the page
var pageText = page.ArticlePageText;

// Accesses the 'Teaser' field of the page
var pageImage = page.ArticlePageTeaser.FirstOrDefault();

Resolving HTML tags and relative URLs

Fields which are populated by the Rich text editor form component may contain HTML tags and relative links. To ensure that the content is displayed correctly when rendered in Razor views, use the Html.Raw method, which disables HTML encoding for the values.



@Html.Raw(Model.<RichTextFieldProperty>)

Automatic URL resolving

The system provides page output filtering functionality that automatically resolves all virtual relative URLs to their absolute form. This filter ensures that links added by content editors into page content work correctly, even if you do not explicitly handle URL resolving in your code.

Get page URLs

Pages in the content tree of Xperience websites can have their live site URLs generated by the system through content tree-based routing. This allows content editors to create new pages or adjust the URLs of existing ones in the administration interface, without the need to update and redeploy the application.

You may need to get the URLs of retrieved pages in various scenarios, such as rendering navigation menus or other page links, performing redirects, etc.

To get the URL of a page in general code, use any of the Retrieve method overloads of the IWebPageUrlRetriever interface (available in the CMS.Websites namespace). The most common usages might include:

Retrieve the URL of a page


// An instance of IWebPageUrlReriever (e.g., obtained via dependency injection)
private readonly IWebPageUrlRetriever webPageUrlRetriever;

// A page retrieved using the content query
ArticlePage article;

// Id of a web page retrieved previously
int webPageItemId;

// Retrieves the relative path of a page in a specific language using the whole page and language code
string url1 = (await webPageUrlRetriever.Retrieve(article, "en")).RelativePath;

// Retrieves the relative path of a page in a specific language using the page id and language code
string url2 = (await webPageUrlRetriever.Retrieve(webPageItemId, "en")).RelativePath;

Retrieved URLs are by default cached for 24 hours. You can change the cache duration via WebPageUrlRetrieverOptions.

Program.cs


var builder = WebApplication.CreateBuilder(args);

// ...

// Sets the cache duration to 60 minutes
builder.Services.Configure<WebPageUrlRetrieverOptions>(options => options.MaximumUrlCacheDuration = TimeSpan.FromMinutes(60));

The Retrieve methods return a relative path to a page, which you can resolve to an application absolute path at runtime (for example using the UrlHelper.Content method).

Resolve relative URLs in Razor


@using Microsoft.AspNetCore.Mvc

<!-- Relative URL of the article is passed through the AricleUrl model property -->
<a href="@Url.Content(Model.ArticleUrl)">Visit the Article!</a>

Access context of the current request

Xperience by Kentico provides interfaces that help you access information about the current context.

Access context of the current channel

To retrieve information about the website channel context of the current request, use an instance of the IWebsiteChannelContext interface (e.g., obtained via dependency injection) from the CMS.Websites.Routing namespace.

Access the following properties:

  • WebsiteChannelID – the ID of the current website channel.
  • WebsiteChannelName – code name of the current website channel.
  • IsPreview – a boolean value that, if true, signifies whether the current request is made in preview (Page Builder or the preview mode in a website channel application).

Access current preferred language

To retrieve the preferred language of the current request, use the Get method of the IPreferredLanguageRetriever interface (e.g., obtained via dependency injection) .

Note that the preferred language of the request can be different from the actual language of the retrieved content. For example, if language variant of a page does not exist in the preferred language, fallback language variant is retrieved.

Retrieve currently preferred language


// An instance of  IPreferredLanguageRetriever (e.g., obtained via dependency injection)
private readonly IPreferredLanguageRetriever preferredLanguageRetriever;

// Retrieves the code name of the preferred language
string languageName = preferredLanguageRetriever.Get();

Retrieve pages for preview

Whenever you work with pages within a website channel application, the system retrieves a given page from the database. Therefore, in order for the preview mode and Page Builder to work as expected, it is crucial that the query executor retrieves the page according to the context in which the query is executed:

  • For the live site, retrieve the published versions of the page according to the validity of security claims upon page request.
  • For preview and Page Builder, retrieve the page in the latest available version regardless of the workflow state and regardless whether it is secured or not.

You can achieve this by configuring the ContentQueryExecutionOptions and providing them to the query executor.

In order to distinguish whether the query executor needs to retrieve the page for preview, you can make use of the IsPreview property of IWebsiteChannelContext described above.

Retrieve pages for preview


// Services obtained via dependency injection
private readonly IContentQueryExecutor executor;
private IWebsiteChannelContext websiteChannelContext;

// Information about whether to include secured items in the query execution passed from the caller
public async Task PageRetrieval(bool includeSecuredItems)
{
    // Configures the query builder
    var builder = new ContentItemQueryBuilder()...;

    // Configures the query options for the query executor
    var queryOptions = new ContentQueryExecutionOptions();
    {
        ForPreview = websiteChannelContext.IsPreview,
        IncludeSecuredItems = includeSecuredItems || websiteChannelContext.IsPreview
    };

    // Executes the query and stores the data in generated 'ArticlePage' models
    IEnumerable<ArticlePage> pages = await executor.GetMappedWebPageResult<ArticlePage>(
                                                builder: builder,
                                                options: queryOptions);
}

Retrieve folders

To retrieve the folders from the content tree of a website channel (e.g., to create a page under the folder), use the Retrieve method of the IWebPageFolderRetriever interface (e.g., obtained via dependency injection).

Retrieve folders


// Services obtained via dependency injection
private readonly IWebPageFolderRetriever folderRetriever;
private IWebsiteChannelContext channelContext;

// Retrieves a folder from the specified path
WebPageFolder folder = (await folderRetriever.Retrieve(channelContext.WebsiteChannelName, PathMatch.Children("/Articles"))).FirstOrDefault();

// Use the WebPageFolder object to access information about the folder
int id = folder.ContentItemID;