Examine practical examples of content retrieval

The Training guides repository is our sample project built to accompany developer guides. This page walks through how that project applies the principles from Retrieve content in Xperience by Kentico, centralizing its content retrieval logic behind custom IContentItemRetrieverService, implemented by ContentItemRetrieverService. Even in projects with more complex architecture, such as a repository pattern, we recommend a similar service, since many domain models are likely to need similar content operations from Xperience.

Let’s take a look at the implementations in ContentItemRetrieverService, diving into the functionality of each method.

RetrieveCurrentPage<T>

This method fetches the page that matches the current request’s URL, returning it as the strongly-typed page model T. It wraps the IContentRetriever method of the same name, using optional parameters to build a RetrieveCurrentPageParameters object. The depth parameter (how many levels of linked content items to pull in) defaults to 1, includeSecuredItems (whether secured content should be returned) defaults to true, and languageName falls back to whatever the preferredLanguageRetriever determines from the current request. Whether the query runs in preview mode is decided automatically based on the website channel context.

Example scenario

The content tree-based router routes a request to the controller registered for a given web page content type. The controller utilizes this method to retrieve the current page’s data and process it for display.

Code

C#
RetrieveCurrentPage

public async Task<T?> RetrieveCurrentPage<T>(
    int depth = 1,
    bool includeSecuredItems = true,
    string? languageName = null)
    where T : IWebPageFieldsSource, new()
{
    var parameters = new RetrieveCurrentPageParameters
    {
        LinkedItemsMaxLevel = depth,
        LanguageName = languageName ?? preferredLanguageRetriever.Get(),
        IsForPreview = webSiteChannelContext.IsPreview,
        IncludeSecuredItems = includeSecuredItems
    };

    return await contentRetriever.RetrieveCurrentPage<T>(parameters);
}

RetrieveWebPageByContentItemGuid<T>

Given the content item GUID of a web page content item, this method looks up that specific page and returns it as generic type. It builds a RetrieveContentParameters object with the usual depth, language, preview, and secured-items settings, then calls IContentRetriever.RetrieveContentByGuids<T> with the single GUID wrapped in an array. Since that call returns a collection (even though only one match is expected), the method takes the first result with FirstOrDefault(), returning null if nothing was found.

This method uses the content item GUID (ContentItemGUID) instead of web page item GUID (WebPageItemGUID), as the Combined content selector (ContentItemSelector) form component utilizes the content item GUID for references.

Example scenario

An editor selects a web page content item in widget properties, or in structured content. The widget or page template uses this method to retrieve selected page’s data for display, assuming it is of content type T.

Code

C#
RetrieveWebPageByContentItemGuid

public async Task<T?> RetrieveWebPageByContentItemGuid<T>(
    Guid contentItemGuid,
    int depth = 1,
    bool includeSecuredItems = true,
    string? languageName = null)
    where T : IWebPageFieldsSource, new()
{
    var parameters = new RetrieveContentParameters
    {
        LinkedItemsMaxLevel = depth,
        LanguageName = languageName ?? preferredLanguageRetriever.Get(),
        IsForPreview = webSiteChannelContext.IsPreview,
        IncludeSecuredItems = includeSecuredItems
    };

    var pages = await contentRetriever.RetrieveContentByGuids<T>(
        [contentItemGuid],
        parameters);

    return pages.FirstOrDefault();
}

RetrieveWebPagesByContentItemGuids<T>

This is the plural counterpart to RetrieveWebPageByContentItemGuid<T>, looking up multiple web page content items by their content item GUIDs in a single call rather than one at a time. It builds the same kind of RetrieveContentParameters object with depth, language, preview, and secured-items settings, then calls IContentRetriever.RetrieveContentByGuids<T> with the full array of GUIDs, returning all matching pages instead of just the first.

Example scenario

A widget or page template needs to display several editor-selected web page content items at once, e.g., a list of featured pages selected via a Combined content selector (ContentItemSelector) form component. This method resolves all of the selected content item GUIDs to their page data in a single query.

Code

C#
RetrieveWebPagesByContentItemGuids

public async Task<IEnumerable<T?>> RetrieveWebPagesByContentItemGuids<T>(
    IEnumerable<Guid> contentItemGuids,
    int depth = 1,
    bool includeSecuredItems = true,
    string? languageName = null)
    where T : IWebPageFieldsSource, new()
{
    var parameters = new RetrieveContentParameters
    {
        LinkedItemsMaxLevel = depth,
        LanguageName = languageName ?? preferredLanguageRetriever.Get(),
        IsForPreview = webSiteChannelContext.IsPreview,
        IncludeSecuredItems = includeSecuredItems
    };

    var pages = await contentRetriever.RetrieveContentByGuids<T>(
        contentItemGuids.ToArray(),
        parameters);

    return pages;
}

RetrieveWebPageChildrenByPath<T> (with additionalQueryConfiguration)

This method finds all child pages beneath a given path and returns them as generic type T. It also lets you add extra filtering or sorting using the additionalQueryConfiguration delegate. It assembles a RetrievePagesParameters object configured to match children of the path, using the usual depth, language, and secured-items settings, and then passes that — along with the optional configuration action — to IContentRetriever.RetrievePages<T>.

Caching is disabled for this call to keep the training materials simpler. However, for production scenarios, we recommend configuring caching while taking into account the dependency requirements of page listings.

Example scenario

Editors select a parent page in a widget property. This method selects the children of the selected page with the provided content type T and meets an additional filtering condition for display in the widget.

Code

C#
RetrieveWebPageChildrenByPath (with additionalQueryConfiguration)

public async Task<IEnumerable<T>> RetrieveWebPageChildrenByPath<T>(
    string path,
    int depth = 1,
    bool includeSecuredItems = true,
    Action<RetrievePagesQueryParameters>? additionalQueryConfiguration = null,
    string? languageName = null)
    where T : IWebPageFieldsSource, new()
{
    var parameters = new RetrievePagesParameters
    {
        LinkedItemsMaxLevel = depth,
        LanguageName = languageName ?? preferredLanguageRetriever.Get(),
        IsForPreview = webSiteChannelContext.IsPreview,
        PathMatch = PathMatch.Children(path),
        IncludeSecuredItems = includeSecuredItems
    };

    return await contentRetriever.RetrievePages<T>(
        parameters,
        additionalQueryConfiguration: additionalQueryConfiguration,
        cacheSettings: RetrievalCacheSettings.CacheDisabled);
}

RetrieveWebPageChildrenByPath<T> (without additionalQueryConfiguration)

This convenience overload simplifies the common scenario where no custom query configuration is required. Instead of duplicating logic, it delegates to the fuller overload above and passes null for the additionalQueryConfiguration parameter.

Example scenario

Editors select a parent page in a widget property. This method selects the children of the selected page with the provided content type T for display in the widget.

Code

C#
RetrieveWebPageChildrenByPath

public async Task<IEnumerable<T>> RetrieveWebPageChildrenByPath<T>(
    string path,
    int depth = 1,
    bool includeSecuredItems = true,
    string? languageName = null)
    where T : IWebPageFieldsSource, new()
    => await RetrieveWebPageChildrenByPath<T>(
        path,
        depth,
        includeSecuredItems,
        null,
        languageName);

RetrieveWebPageChildrenByPathAndReference<T>

This method narrows down the children of a page to only those that reference a specific set of content items. Rather than reimplementing the query logic, it delegates to RetrieveWebPageChildrenByPath<T> and supplies an additionalQueryConfiguration delegate that calls .Linking(referenceFieldName, referenceIds), filtering results down to pages whose specified reference field points at one of the given IDs.

Example scenario

In a content model that keeps structured content in the Content hub and uses page wrappers for web-specific metadata, one method retrieves the IDs of reusable content items that meet a certain criteria, such as a specific taxonomy tag. This method retrieves pages with the provided content type T from a given section of the content tree which reference those reusable items.

Code

C#
RetrieveWebPageChildrenByPathAndReference

public async Task<IEnumerable<T>> RetrieveWebPageChildrenByPathAndReference<T>(
    string parentPagePath,
    string referenceFieldName,
    IEnumerable<int> referenceIds,
    bool includeSecuredItems,
    int depth = 1,
    string? languageName = null)
    where T : IWebPageFieldsSource, new()
 => await RetrieveWebPageChildrenByPath<T>(
        path: parentPagePath,
        includeSecuredItems: includeSecuredItems,
        depth: depth,
        additionalQueryConfiguration: config => config.Linking(referenceFieldName, referenceIds),
        languageName: languageName);

RetrieveWebPageSectionByPath<T>

This method retrieves an entire section of the content tree — the page at a given path plus all of its children — using PathMatch.Section instead of PathMatch.Children, which excludes the root page. An optional nestingLevel can limit how many levels deep the section extends; if omitted, all descendants are included regardless of depth. Like RetrieveWebPageChildrenByPath<T>, it accepts an additionalQueryConfiguration delegate for further filtering or sorting, and disables caching for the same reasons.

Example scenario

A sitemap or “section overview” feature needs to list a landing page together with everything nested beneath it (e.g., a Store landing page and all of its category and product pages) in a single query, rather than querying the parent and its children separately.

Code

C#
RetrieveWebPageSectionByPath

public async Task<IEnumerable<T>> RetrieveWebPageSectionByPath<T>(
    string path,
    int? nestingLevel = null,
    int depth = 1,
    bool includeSecuredItems = true,
    Action<RetrievePagesQueryParameters>? additionalQueryConfiguration = null,
    string? languageName = null)
    where T : IWebPageFieldsSource, new()
{
    var parameters = new RetrievePagesParameters
    {
        LinkedItemsMaxLevel = depth,
        LanguageName = languageName ?? preferredLanguageRetriever.Get(),
        IsForPreview = webSiteChannelContext.IsPreview,
        PathMatch = nestingLevel.HasValue
            ? PathMatch.Section(path, nestingLevel.Value)
            : PathMatch.Section(path),
        IncludeSecuredItems = includeSecuredItems
    };

    return await contentRetriever.RetrievePages<T>(
        parameters,
        additionalQueryConfiguration: additionalQueryConfiguration,
        cacheSettings: RetrievalCacheSettings.CacheDisabled);
}

RetrieveWebPageByPathWithoutContext<T>

Unlike most of the other retrieval methods, this one doesn’t rely on the ambient website channel context to know which channel or language to query — instead, the caller explicitly provides channelName, languageName, and forPreview. This makes it useful in scenarios where you need to look up a page outside the current request’s channel, such as cross-channel lookups. It builds a ContentItemQueryBuilder directly, scoping the query to the given website channel and matching a single exact path, then executes the query through IContentQueryExecutor.GetMappedResult<T> and returns the first matching page (or null if none exists).

Example scenario

In a content item event handler that creates pages corresponding to reusable content items, this method retrieves the parent page under which you want to create an item’s corresponding page.

Code

C#
RetrieveWebPageByPathWithoutContext

public async Task<T?> RetrieveWebPageByPathWithoutContext<T>(
    string pathToMatch,
    string languageName,
    string channelName,
    bool forPreview,
    bool includeSecuredItems)
    where T : IWebPageFieldsSource, new()
{
    var builder = new ContentItemQueryBuilder();

    builder.ForContentTypes(query =>
        {
            query.ForWebsite(channelName, PathMatch.Single(pathToMatch));
        })
        .InLanguage(languageName);

    var queryExecutorOptions = new ContentQueryExecutionOptions
    {
        ForPreview = forPreview,
        IncludeSecuredItems = includeSecuredItems
    };

    var pages = await contentQueryExecutor.GetMappedResult<T>(builder, queryExecutorOptions);

    return pages.FirstOrDefault();
}

RetrieveWebPageChildrenByPathWithoutContext

This is the “without context” counterpart to the children-by-path methods below, and it’s the most flexible of the bunch. Rather than being locked into a single content type or the ambient channel, it accepts an explicit channelName, a list of contentTypeNames to search across, and two configuration delegates — customContentTypesQueryParameters and customContentQueryParameters — that let the caller layer on additional type-level and query-level filtering. Internally, it builds a ContentItemQueryBuilder scoped to the children of parentPagePath within the given channel, applies the requested content types and linked-item depth, optionally restricts the query to a specific language, and then executes it with IContentQueryExecutor.GetMappedWebPageResult<IWebPageFieldsSource>, returning whatever pages match.

Example scenario

In a content item event handler that creates pages corresponding to reusable content items, this method checks if a corresponding page for the reusable item already exists in a given content tree section.

Code

C#
RetrieveWebPageChildrenByPathWithoutContext

public async Task<IEnumerable<IWebPageFieldsSource>> RetrieveWebPageChildrenByPathWithoutContext(
    IEnumerable<string> contentTypeNames,
    string parentPagePath,
    Func<ContentTypesQueryParameters, ContentTypesQueryParameters> customContentTypesQueryParameters,
    Func<ContentQueryParameters, ContentQueryParameters> customContentQueryParameters,
    bool forPreview,
    bool includeSecuredItems,
    string channelName,
    string? languageName = null,
    int depth = 1)
{
    Action<ContentTypesQueryParameters> contentTypesQueryParameters =
        config => customContentTypesQueryParameters(config
            .ForWebsite(channelName, PathMatch.Children(parentPagePath))
            .OfContentType(contentTypeNames.ToArray())
            .WithLinkedItems(depth)
            .WithContentTypeFields());

    var builder = new ContentItemQueryBuilder()
                        .ForContentTypes(contentTypesQueryParameters)
                        .Parameters(param => customContentQueryParameters(param));

    if (!string.IsNullOrEmpty(languageName))
    {
        builder.InLanguage(languageName);
    }

    var queryExecutorOptions = new ContentQueryExecutionOptions
    {
        ForPreview = forPreview,
        IncludeSecuredItems = includeSecuredItems
    };

    var pages = await contentQueryExecutor.GetMappedWebPageResult<IWebPageFieldsSource>(builder, queryExecutorOptions);

    return pages;
}

Since contentTypeNames is already known ahead of time here, IContentRetriever.RetrievePagesOfContentTypes would be a more direct ContentRetriever-based alternative to building this query manually.


RetrieveContentItemByGuid<T>

This method is the reusable-content-item equivalent of RetrieveWebPageByContentItemGuid<T> — instead of a web page, it looks up a reusable content item (which lives in the Content hub rather than a specific web channel) by its GUID. It builds a RetrieveContentParameters object with the standard depth, language, preview, and secured-items settings, calls IContentRetriever.RetrieveContentByGuids<T> with the single GUID, and returns the first match or null if the item wasn’t found.

Example scenario

Editors select a reusable content item in a widget’s properties. The widget uses this method to query the reusable item’s data and display it.

Code

C#
RetrieveContentItemByGuid

public async Task<T?> RetrieveContentItemByGuid<T>(
    Guid contentItemGuid,
    int depth = 1,
    bool includeSecuredItems = true,
    string? languageName = null)
    where T : IContentItemFieldsSource, new()
{
    var parameters = new RetrieveContentParameters
    {
        LinkedItemsMaxLevel = depth,
        LanguageName = languageName ?? preferredLanguageRetriever.Get(),
        IsForPreview = webSiteChannelContext.IsPreview,
        IncludeSecuredItems = includeSecuredItems
    };

    var items = await contentRetriever.RetrieveContentByGuids<T>(
        [contentItemGuid],
        parameters);

    return items.FirstOrDefault();
}

RetrieveReusableContentItemsFromSmartFolder<T>

This method pulls a page of reusable content items out of a specific smart folder, sorted by their last-published date and capped at a maximum count. After building the standard RetrieveContentParameters, it calls IContentRetriever.RetrieveContent<T> with a query that scopes results InSmartFolder(smartFolderGuid), orders them by the ContentItemCommonDataLastPublishedWhen column — descending for OrderByOption.NewestFirst or ascending otherwise — and limits the result set with TopN(topN) (20 items by default). Caching is disabled so that newly published or reordered items show up immediately.

Example scenario

Administrators configure a smart folder that dynamically collects gallery image content items meeting certain criteria. Editors select the folder in the properties of a widget, which uses this method to retrieve the contents of the smart folder.

Code

C#
RetrieveReusableContentItemsFromSmartFolder

public async Task<IEnumerable<T>> RetrieveReusableContentItemsFromSmartFolder<T>(
    Guid smartFolderGuid,
    OrderByOption orderBy,
    int topN = 20,
    int depth = 1,
    bool includeSecuredItems = true,
    string? languageName = null)
    where T : IContentItemFieldsSource, new()
{
    const string LAST_PUBLISHED_COLUMN_NAME = "ContentItemCommonDataLastPublishedWhen";

    var parameters = new RetrieveContentParameters
    {
        LinkedItemsMaxLevel = depth,
        LanguageName = languageName ?? preferredLanguageRetriever.Get(),
        IsForPreview = webSiteChannelContext.IsPreview,
        IncludeSecuredItems = includeSecuredItems
    };

    return await contentRetriever.RetrieveContent<T>(
        parameters,
        query => query
            .InSmartFolder(smartFolderGuid)
            .OrderBy(new OrderByColumn(
                LAST_PUBLISHED_COLUMN_NAME,
                orderBy.Equals(OrderByOption.NewestFirst) ? OrderDirection.Descending : OrderDirection.Ascending))
            .TopN(topN),
        RetrievalCacheSettings.CacheDisabled);
}

RetrieveContentItemsBySchemaAndTags

This method finds reusable content items belonging to a given schema that are tagged with any of a specified set of taxonomy tags — handy for building tag-filtered listings such as “all articles tagged with these topics.” It configures a RetrieveContentOfReusableSchemasParameters object with language, preview, and secured-items settings, then calls IContentRetriever.RetrieveContentOfReusableSchemas<IContentItemFieldsSource> for the single schema, adding a WhereContainsTags(taxonomyColumnName, tagGuids) filter to the query. Since the return type is the generic IContentItemFieldsSource interface rather than a specific model, this method doesn’t require a type parameter.

Example scenario

Using a widget property in an article list widget, editors select taxonomy tags whose articles they want to display in the listing. This method finds reusable items with those tags, which a subsequent query can use to locate pages that reference those items.

Code

C#
RetrieveContentItemsBySchemaAndTags

public async Task<IEnumerable<IContentItemFieldsSource>> RetrieveContentItemsBySchemaAndTags(
    string schemaName,
    string taxonomyColumnName,
    IEnumerable<Guid> tagGuids,
    bool includeSecuredItems = true,
    string? languageName = null)
{
    var parameters = new RetrieveContentOfReusableSchemasParameters
    {
        LanguageName = languageName ?? preferredLanguageRetriever.Get(),
        IsForPreview = webSiteChannelContext.IsPreview,
        IncludeSecuredItems = includeSecuredItems
    };

    return await contentRetriever.RetrieveContentOfReusableSchemas<IContentItemFieldsSource>(
        [schemaName],
        parameters,
        query => query.Where(where => where.WhereContainsTags(taxonomyColumnName, tagGuids)),
        RetrievalCacheSettings.CacheDisabled,
        configureModel: null);
}

RetrieveContentItemsByTags<T>

This method filters content items of a single, specific content type T by taxonomy tags, without requiring the taxonomy field to belong to a shared reusable field schema, unlike RetrieveContentItemsBySchemaAndTags, which requires a schemaName. It builds the standard RetrieveContentParameters and calls IContentRetriever.RetrieveContent<T>, adding a WhereContainsTags filter.

Example scenario

A content type has its own dedicated taxonomy field that isn’t shared through a reusable field schema (e.g., a BlogPost type with a BlogPostTags field). Editors select tags through a widget, and this method retrieves matching items of the specified type directly. There is no need to know or reference the schema name.

Code

C#
RetrieveContentItemsByTags

public async Task<IEnumerable<T>> RetrieveContentItemsByTags<T>(
    string taxonomyColumnName,
    IEnumerable<Guid> tagGuids,
    int depth = 1,
    bool includeSecuredItems = true,
    string? languageName = null)
    where T : IContentItemFieldsSource, new()
{
    var parameters = new RetrieveContentParameters
    {
        LinkedItemsMaxLevel = depth,
        LanguageName = languageName ?? preferredLanguageRetriever.Get(),
        IsForPreview = webSiteChannelContext.IsPreview,
        IncludeSecuredItems = includeSecuredItems
    };

    return await contentRetriever.RetrieveContent<T>(
        parameters,
        query => query.Where(where => where.WhereContainsTags(taxonomyColumnName, tagGuids)),
        RetrievalCacheSettings.CacheDisabled);
}

RetrieveContentItemsBySchemas<T>

This is a more general-purpose version of the schema-based retrieval methods: it can search across multiple reusable field schemas at once (rather than just one) and gives the caller full control over the query through the additionalQueryConfiguration delegate. After setting up the usual RetrieveContentOfReusableSchemasParameters — including LinkedItemsMaxLevel for controlling how deep linked items are resolved — it calls IContentRetriever.RetrieveContentOfReusableSchemas<T> with the list of schema names and the caller-supplied query configuration, again with caching disabled.

Example scenario

A visitor selects product attributes that correspond to taxonomy tags, which are assigned to products via multiple reusable field schemas. The back-end logic uses this method to find products which have one or more of the selected tags, which display logic can further refine with post-filtering.

Code

C#
RetrieveContentItemsBySchemas

public async Task<IEnumerable<T>> RetrieveContentItemsBySchemas<T>(
    IEnumerable<string> schemaNames,
    Action<RetrieveContentOfReusableSchemasQueryParameters> additionalQueryConfiguration,
    int depth = 1,
    bool includeSecuredItems = true,
    string? languageName = null)
{
    var parameters = new RetrieveContentOfReusableSchemasParameters
    {
        LanguageName = languageName ?? preferredLanguageRetriever.Get(),
        IsForPreview = webSiteChannelContext.IsPreview,
        IncludeSecuredItems = includeSecuredItems,
        LinkedItemsMaxLevel = depth
    };

    return await contentRetriever.RetrieveContentOfReusableSchemas<T>(
        schemaNames,
        parameters,
        additionalQueryConfiguration,
        RetrievalCacheSettings.CacheDisabled,
        configureModel: null);
}

RetrieveParentItemsOfSchema<T>

This method works in the opposite direction from the reference-based children lookup above: instead of finding pages that reference certain items, it finds reusable content items (filtered to a given schema) that reference a set of child item IDs through a specified field — effectively locating the “parents” of those children. It builds the standard RetrieveContentOfReusableSchemasParameters and calls IContentRetriever.RetrieveContentOfReusableSchemas<T> for the single schema, adding a .LinkingSchemaField(referenceFieldName, referenceIds) filter to match items whose reference field points at any of the supplied IDs.

Example scenario

A product pricing service must find a price for any product passed to it, regardless of whether the product is a parent product or a product variant, regardless of where pricing information is stored. If a variant does not have pricing information, the service uses this method to look up its parent product.

Code

C#
RetrieveParentItemsOfSchema

public async Task<IEnumerable<T>> RetrieveParentItemsOfSchema<T>(
    string schemaName,
    string referenceFieldName,
    IEnumerable<int> referenceIds,
    bool includeSecuredItems,
    int depth = 1,
    string? languageName = null)
{
    var parameters = new RetrieveContentOfReusableSchemasParameters
    {
        LinkedItemsMaxLevel = depth,
        LanguageName = languageName ?? preferredLanguageRetriever.Get(),
        IsForPreview = webSiteChannelContext.IsPreview,
        IncludeSecuredItems = includeSecuredItems
    };

    return await contentRetriever.RetrieveContentOfReusableSchemas<T>(
        [schemaName],
        parameters,
        query => query.LinkingSchemaField(referenceFieldName, referenceIds),
        RetrievalCacheSettings.CacheDisabled);
}

RetrieveWebPageByPath<T>

This method retrieves a single web page by matching its exact tree path — the kind of path visible in the administration interface’s Properties tab. It builds a RetrievePagesParameters object with PathMatch.Single(pathToMatch), along with the usual language, preview, and secured-items settings, then calls IContentRetriever.RetrievePages<T> with caching disabled and no additional query configuration. Since the underlying call can technically return more than one result, it takes the first match with FirstOrDefault().

Example scenario

A C# component like a layout or view component expects a specific page to exist in the database, and uses this method to retrieve the data of a page with the given path, stored in a constant. (This is safer than using something like a GUID because if an editor accidentally deletes the expected page and clears the recycle bin, they can create a new page at the path, and it will work despite having a different GUID.)

Code

C#
RetrieveWebPageByPath

public async Task<T?> RetrieveWebPageByPath<T>(
    string pathToMatch,
    bool includeSecuredItems = true,
    string? languageName = null)
    where T : IWebPageFieldsSource, new()
{
    var parameters = new RetrievePagesParameters
    {
        LanguageName = languageName ?? preferredLanguageRetriever.Get(),
        IsForPreview = webSiteChannelContext.IsPreview,
        PathMatch = PathMatch.Single(pathToMatch),
        IncludeSecuredItems = includeSecuredItems
    };

    var pages = await contentRetriever.RetrievePages<T>(
        parameters,
        additionalQueryConfiguration: null,
        cacheSettings: RetrievalCacheSettings.CacheDisabled);

    return pages.FirstOrDefault();
}

RetrieveWebPageByContentItemGuid

This non-generic overload looks up a web page by content item GUID when the exact web page content type isn’t known ahead of time. Since most IContentRetriever methods require a concrete type and won’t accept the IWebPageFieldsSource interface directly, this method falls back to the older, lower-level ContentItemQueryBuilder approach via the private RetrieveWebPages helper, filtering with WhereEquals(nameof(ContentItemFields.ContentItemGUID), pageContentItemGuid). It returns the first matching page, mapped generically to IWebPageFieldsSource, or null if nothing matches.

Example scenario

An editor selects a web page content item in widget properties, or in structured content, using a Combined content selector (ContentItemSelector) that allows selection from at least two types. The widget or template uses this method to retrieve selected page’s data for display, regardless of the web page content type.

Code

C#
RetrieveWebPageByContentItemGuid

public async Task<IWebPageFieldsSource?> RetrieveWebPageByContentItemGuid(
    Guid pageContentItemGuid,
    int depth = 2,
    bool includeSecuredItems = true,
    string? languageName = null)
{
    var pages = await RetrieveWebPages(parameters =>
        {
            parameters.Where(where => where.WhereEquals(nameof(ContentItemFields.ContentItemGUID), pageContentItemGuid));
        },
        depth,
        includeSecuredItems,
        languageName ?? preferredLanguageRetriever.Get());

    return pages.FirstOrDefault();
}

RetrieveWebPagesByContentItemGuids

This is the non-generic, plural counterpart to RetrieveWebPageByContentItemGuid, used when the specific web page content type isn’t known ahead of time and multiple pages need to be resolved by their content item GUIDs at once. Like the singular version, it falls back to the private RetrieveWebPages helper, filtering with WhereIn instead of WhereEquals, and returns all matching pages mapped generically to IWebPageFieldsSource.

Example scenario

An editor selects multiple web page content items in widget properties, or in structured content, using a Combined content selector (ContentItemSelector) that allows selection from at least two types. The widget or template uses this method to retrieve all of the selected pages’ data for display, regardless of their web page content type.

Code

C#
RetrieveWebPagesByContentItemGuids

public async Task<IEnumerable<IWebPageFieldsSource?>> RetrieveWebPagesByContentItemGuids(
    IEnumerable<Guid> pageContentItemGuids,
    int depth = 2,
    bool includeSecuredItems = true,
    string? languageName = null)
{
    var pages = await RetrieveWebPages(parameters =>
        {
            parameters.Where(where => where.WhereIn(nameof(ContentItemFields.ContentItemGUID), pageContentItemGuids));
        },
        depth,
        includeSecuredItems,
        languageName ?? preferredLanguageRetriever.Get());

    return pages;
}

RetrieveWebPageById

This method mirrors RetrieveWebPageByContentItemGuid above, but looks a page up by its numeric WebPageItemID instead of its GUID — again useful when the specific page type isn’t known in advance and the type-safe ContentRetriever API isn’t an option. It delegates to the same private RetrieveWebPages helper, this time filtering with WhereEquals(nameof(WebPageFields.WebPageItemID), webPageItemId), and returns the first matching page or null.

Example scenario

A custom module includes binding data between pages and a custom class, which it sends to a controller in a POST request. The controller uses this method to look up the page’s data.

Code

C#
RetrieveWebPageById

public async Task<IWebPageFieldsSource?> RetrieveWebPageById(
    int webPageItemId,
    int depth = 2,
    bool includeSecuredItems = true,
    string? languageName = null)
{
    var pages = await RetrieveWebPages(parameters =>
        {
            parameters.Where(where => where.WhereEquals(nameof(WebPageFields.WebPageItemID), webPageItemId));
        },
        depth,
        includeSecuredItems,
        languageName ?? preferredLanguageRetriever.Get());

    return pages.FirstOrDefault();
}

RetrieveWebPages (Private Helper)

This private helper centralizes the shared query logic used by both RetrieveWebPageByContentItemGuid and RetrieveWebPageById, so neither has to duplicate it. It builds a ContentItemQueryBuilder scoped to the current website channel, includes linked items up to the given depth (with web page data included), applies whatever Where filter the caller passes in through the parameters action, and restricts the query to the given (or preferred) language. It then executes the query via IContentQueryExecutor.GetMappedResult<IWebPageFieldsSource> and returns the matching pages, respecting the preview and secured-items settings along the way.

Example scenario

A component in your project needs to retrieve pages based on some kind of filtering data, but there is no way to know which content types are required. The ContentItemRetrieverService method that it utilizes calls this private method to retrieve the necessary pages.

Code

C#
RetrieveWebPages

private async Task<IEnumerable<IWebPageFieldsSource>> RetrieveWebPages(
    Action<ContentQueryParameters> parameters,
    int depth,
    bool includeSecuredItems = true,
    string? languageName = null)
{
    var builder = new ContentItemQueryBuilder()
        .ForContentTypes(query => query
        .WithLinkedItems(depth, options => options.IncludeWebPageData(true))
        .ForWebsite(webSiteChannelContext.WebsiteChannelName))
    .Parameters(parameters)
    .InLanguage(languageName ?? preferredLanguageRetriever.Get());

    var queryExecutorOptions = new ContentQueryExecutionOptions
    {
        ForPreview = webSiteChannelContext.IsPreview,
        IncludeSecuredItems = includeSecuredItems
    };

    return await contentQueryExecutor.GetMappedResult<IWebPageFieldsSource>(builder, queryExecutorOptions);
}

RetrieveWebPageAncestorsByTreePath

This method retrieves the ancestor chain of a page for use in breadcrumb navigation, given the page’s tree path (e.g., /Store/Cat_food/Purremo_Essentials_dry_cat_food). It first uses the private GetAncestorTreePaths helper to split the tree path into a list of ancestor paths — one per level, from the root down to the immediate parent (or including the page itself if includeCurrentPage is true) — then passes that list to the private RetrieveWebPages helper, filtering with WhereIn. Since ancestors can be of different content types, results are mapped generically to IWebPageFieldsSource and ordered from the root down by tree path length, ready for direct rendering as a breadcrumb trail.

Example scenario

A shared layout or view component needs to render breadcrumb navigation for the current page (e.g., Home > Store > Cat food > Purremo Essentials dry cat food), regardless of the content types of the pages along the way.

Code

C#
RetrieveWebPageAncestorsByTreePath

public async Task<IEnumerable<IWebPageFieldsSource>> RetrieveWebPageAncestorsByTreePath(
        string treePath,
        bool includeCurrentPage = false,
        int depth = 1,
        bool includeSecuredItems = true,
        string? languageName = null)
    {
        var ancestorTreePaths = GetAncestorTreePaths(treePath, includeCurrentPage);

        if (ancestorTreePaths.Count == 0)
        {
            return [];
        }

        var pages = await RetrieveWebPages(parameters =>
            {
                parameters.Where(where => where.WhereIn(nameof(WebPageFields.WebPageItemTreePath), ancestorTreePaths));
            },
            depth,
            includeSecuredItems,
            languageName ?? preferredLanguageRetriever.Get());

        return pages.OrderBy(page => page.SystemFields.WebPageItemTreePath.Length);
    }

    /// <summary>
    /// Builds the tree paths of all ancestors of the given tree path, ordered from the root down to the immediate parent (or the page itself, if <paramref name="includeCurrentPage"/> is true).
    /// </summary>
    private static List<string> GetAncestorTreePaths(string treePath, bool includeCurrentPage)
    {
        string[] segments = treePath.Split('/', StringSplitOptions.RemoveEmptyEntries);
        int segmentsToInclude = includeCurrentPage ? segments.Length : segments.Length - 1;

        var ancestorTreePaths = new List<string>();
        string currentPath = string.Empty;

        for (int i = 0; i < segmentsToInclude; i++)
        {
            currentPath += $"/{segments[i]}";
            ancestorTreePaths.Add(currentPath);
        }

        return ancestorTreePaths;
    }

What’s next

Building on top of these content retrieval techniques, explore advanced, use-case-driven ways of working with content in Xperience by Kentico. Discover how to work with reusable field schemas, filter content by taxonomies, and deliver content dynamically to editors with smart folders.