Disclaimer: This website requires Please enable JavaScript in your browser settings for the best experience.

Dev guideRecipesAPI ReferenceChangelog
Dev guideRecipesUser GuidesNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev guide

Recent articles by category

How to retrieve and display recent articles by category using Optimizely Graph.

You can use Optimizely Graph queries to retrieve and display recent articles based on category filters. These examples let you build dynamic content experiences and suggest related articles to your users.

Basic category-based article query

Use this query to fetch the most recent articles from a specific category. This is ideal for showing topic-based content or suggesting related articles.

The following query retrieves up to 10 articles from a specified category and filters for published content, and sorts results by publish date, showing the newest first:

# This query retrieves up to 10 articles from a specified category.
# It filters for published content and sorts results by publish date (newest first).

query GetRecentArticlesByCategory($category: String, $limit: Int = 10) {
  ArticlePage(
    where: {
      Category: { Name: { eq: $category } }
      StartPublish: { lte: "2025-09-14T23:59:59Z" }
    }
    orderBy: { StartPublish: DESC }
    limit: $limit
  ) {
    total
    items {
      Name
      RelativePath
      TeaserText
      MainBody
      StartPublish
      PageImage {
        Url
      }
      Category {
        Name
      }
    }
  }
}

Advanced category filtering with time ranges

Use the following query to filter articles by multiple categories within a specific date range, making it ideal for time-sensitive content or analytics:

# This query retrieves articles from selected categories within a defined time range.
# It returns article details and category facets for filtering and analysis.

query GetArticlesByCategoryAndTimeRange(
  $categories: [String!],
  $startDate: Date!,
  $endDate: Date!,
  $limit: Int = 20
) {
  ArticlePage(
    where: {
      _and: [
        { StartPublish: { gte: $startDate, lte: $endDate } }
      ]
    }
    orderBy: { StartPublish: DESC }
    limit: $limit
  ) {
    total
    facets {
      Category {
        Name(filters: $categories) {
          name
          count
        }
      }
    }
    items {
      Name
      RelativePath
      TeaserText
      MainBody
      StartPublish
      PageImage {
        Url
      }
      Category {
        Name
        Description
      }
    }
  }
}

React implementation

Use the following query to filter articles by multiple categories within a specific date range, making it ideal for time-sensitive content or analytics:

// This component fetches and displays articles based on the selected category.
// It includes loading and error states, and lets users to change category and article count.

import { gql, useQuery } from '@apollo/client';
import { useState } from 'react';

const GET_ARTICLES_BY_CATEGORY = gql`
  query GetRecentArticlesByCategory($category: String, $limit: Int = 10) {
    ArticlePage(
      where: {
        Category: { Name: { eq: $category } }
        StartPublish: { lte: "2025-09-14T23:59:59Z" }
      }
      orderBy: { StartPublish: DESC }
      limit: $limit
    ) {
      total
      items {
        Name
        RelativePath
        TeaserText
        MainBody
        StartPublish
        PageImage {
          Url
        }
        Category {
          Name
        }
      }
    }
  }
`;

interface Article {
  Name: string;
  RelativePath: string;
  TeaserText?: string;
  MainBody?: string;
  StartPublish: string;
  PageImage?: {
    Url: string;
  };
  Category?: {
    Name: string;
  };
}

export function ArticlesByCategory() {
  const [selectedCategory, setSelectedCategory] = useState<string>('technology');
  const [limit, setLimit] = useState(10);

  const { loading, error, data, refetch } = useQuery(GET_ARTICLES_BY_CATEGORY, {
    variables: { category: selectedCategory, limit },
    errorPolicy: 'partial'
  });

  const handleCategoryChange = (category: string) => {
    setSelectedCategory(category);
  };

  if (loading) return (
    <div className="loading-state">
      <div className="spinner"></div>
      <p>Loading articles...</p>
    </div>
  );

  if (error) return (
    <div className="error-state">
      <h3>Unable to load articles</h3>
      <p>{error.message}</p>
      <button onClick={() => refetch()}>Try Again</button>
    </div>
  );

  const articles: Article[] = data?.ArticlePage?.items || [];

  return (
    <div className="articles-by-category">
      <div className="filter-controls">
        <h2>Articles by Category</h2>
        <div className="category-filters">
          {['technology', 'innovation', 'development', 'design', 'business'].map(category => (
            <label key={category} className="category-filter">
              <input
                type="radio"
                name="category"
                value={category}
                checked={selectedCategory === category}
                onChange={(e) => handleCategoryChange(e.target.value)}
              />
              {category}
            </label>
          ))}
        </div>

        <div className="limit-control">
          <label>
            Show:
            <select value={limit} onChange={(e) => setLimit(Number(e.target.value))}>
              <option value={5}>5 articles</option>
              <option value={10}>10 articles</option>
              <option value={20}>20 articles</option>
            </select>
          </label>
        </div>

        <p className="results-count">
          Found {data?.ArticlePage?.total || 0} articles
        </p>
      </div>

      <div className="articles-grid">
        {articles.map((article) => (
          <article key={article.RelativePath} className="article-card">
            {article.PageImage && (
              <div className="article-image">
                <img 
                  src={article.PageImage.Url} 
                  alt={article.Name}
                />
              </div>
            )}

            <div className="article-content">
              <h3>
                <a href={article.RelativePath}>{article.Name}</a>
              </h3>

              {article.TeaserText && (
                <p className="teaser">{article.TeaserText}</p>
              )}

              <div className="article-meta">
                <time dateTime={article.StartPublish}>
                  {new Date(article.StartPublish).toLocaleDateString()}
                </time>

                {article.Category && (
                  <span className="category">{article.Category.Name}</span>
                )}
              </div>
            </div>
          </article>
        ))}
      </div>
    </div>
  );
}
``