Adding Blog Page to another page without using Summary Block

Description: adding blog page to another page without using Summary Block

#1. First, use this code to Page Header Injection (page where you want to place Blog Page)

<!-- @tuanphan - Blog page to another page -->
<style>
.blog-basic-grid.preFade {
  opacity: 0;
}

.blog-basic-grid.fadeIn {
  opacity: 1;
  transition: opacity 0.5s ease;
}

.load-more-btn {
  display: block;
  margin: 40px auto;
  padding: 12px 30px;
  background: #000;
  color: #fff;
  border: none;
  cursor: pointer;
  font-size: 1rem;
  transition: background 0.3s ease;
}

.load-more-btn:hover {
  background: #333;
}

.load-more-btn:disabled {
  background: #ccc;
  cursor: not-allowed;
}
</style>

<script>
document.addEventListener('DOMContentLoaded', function() {
  const container = document.querySelector('[data-showcase-blog]');
  if (!container) return;

  const BLOG_URL = container.getAttribute('data-showcase-blog');
  if (!BLOG_URL) return;

  const CATEGORY = container.getAttribute('data-category');
  const LIMIT = parseInt(container.getAttribute('data-limit')) || 40;
  const LOAD_MORE = container.getAttribute('data-load-more') === 'true';

  let allItems = [];
  let displayedCount = 0;
  let blogWrapper = null;
  const ITEMS_PER_LOAD = 10;

  // Fetch HTML structure từ blog page
  fetch(BLOG_URL).then(response => response.text()).then(html => {
    const parser = new DOMParser();
    const doc = parser.parseFromString(html, 'text/html');
    const originalWrapper = doc.querySelector('.blog-basic-grid.collection-content-wrapper');
    
    if (!originalWrapper) return;

    // Clone wrapper và xóa hết nội dung bên trong
    blogWrapper = document.createElement('div');
    blogWrapper.className = originalWrapper.className;
    blogWrapper.classList.add('preFade');
    
    // Copy data attributes
    Array.from(originalWrapper.attributes).forEach(attr => {
      if (attr.name.startsWith('data-')) {
        blogWrapper.setAttribute(attr.name, attr.value);
      }
    });
    
    // Fetch all blog data
    fetchAllBlogPages(BLOG_URL);
  });

  async function fetchAllBlogPages(baseUrl, offset = null) {
    const url = offset ? `${baseUrl}?offset=${offset}&format=json` : `${baseUrl}?format=json`;
    
    try {
      const response = await fetch(url);
      const data = await response.json();
      
      let items = data.items || [];
      
      if (CATEGORY) {
        items = items.filter(item => {
          const categories = item.categories || [];
          return categories.some(cat => cat.toLowerCase().includes(CATEGORY.toLowerCase()));
        });
      }

      allItems = allItems.concat(items);

      if (data.pagination && data.pagination.nextPage && data.pagination.nextPageUrl) {
        const nextOffset = data.pagination.nextPageOffset;
        await fetchAllBlogPages(baseUrl, nextOffset);
      } else {
        // Hoàn thành fetch, bắt đầu render
        allItems = allItems.slice(0, LIMIT);
        initializeDisplay();
      }
    } catch (error) {
      console.error('Error fetching blog data:', error);
    }
  }

  function initializeDisplay() {
    // Thêm wrapper vào container trước
    container.innerHTML = '';
    container.appendChild(blogWrapper);
    
    if (LOAD_MORE) {
      const initialItems = allItems.slice(0, ITEMS_PER_LOAD);
      renderItems(initialItems);
      displayedCount = initialItems.length;
      
      if (displayedCount < allItems.length) {
        createLoadMoreButton();
      }
    } else {
      renderItems(allItems);
      displayedCount = allItems.length;
    }
    
    setTimeout(() => {
      blogWrapper.classList.remove('preFade');
      blogWrapper.classList.add('fadeIn');
    }, 100);
  }

  function renderItems(itemsToRender) {
    itemsToRender.forEach(item => {
      const article = createBlogArticle(item);
      blogWrapper.appendChild(article);
    });
  }

  function createBlogArticle(item) {
    const article = document.createElement('article');
    article.className = 'blog-basic-grid--container entry blog-item is-loaded';
    
    // Image wrapper div
    const imageOuterDiv = document.createElement('div');
    const imageLink = document.createElement('a');
    imageLink.href = item.fullUrl;
    imageLink.className = 'image-wrapper';
    imageLink.setAttribute('data-animation-role', 'image');
    
    const img = document.createElement('img');
    img.setAttribute('data-src', item.assetUrl);
    img.setAttribute('data-image', item.assetUrl);
    img.setAttribute('data-image-dimensions', item.originalSize || '1280x853');
    img.setAttribute('data-image-focal-point', '0.5,0.5');
    img.alt = item.title;
    img.setAttribute('data-load', 'false');
    img.src = item.assetUrl;
    img.className = 'image';
    img.style.cssText = 'display:block;position: absolute; height: 100%; width: 100%; object-fit: cover; object-position: 50% 50%;';
    img.loading = 'lazy';
    img.decoding = 'async';
    img.setAttribute('data-loader', 'sqs');
    
    imageLink.appendChild(img);
    imageOuterDiv.appendChild(imageLink);
    
    // Spacer
    const spacer = document.createElement('div');
    spacer.className = 'blog-article-spacer';
    
    // Text content
    const textDiv = document.createElement('div');
    textDiv.className = 'blog-basic-grid--text';
    
    // Meta section
    const metaSection = createMetaSection(item);
    
    // Title
    const title = document.createElement('h1');
    title.className = 'blog-title';
    const titleLink = document.createElement('a');
    titleLink.href = item.fullUrl;
    titleLink.textContent = item.title;
    
    // Nếu có sourceUrl thì thêm passthrough-link
    if (item.sourceUrl) {
      titleLink.className = 'passthrough-link';
      titleLink.setAttribute('target', '_blank');
      titleLink.setAttribute('rel', 'noopener');
      titleLink.setAttribute('data-no-animation', '');
    }
    
    title.appendChild(titleLink);
    
    // Excerpt
    const excerpt = document.createElement('div');
    excerpt.className = 'blog-excerpt';
    if (item.excerpt) {
      const excerptWrapper = document.createElement('div');
      excerptWrapper.className = 'blog-excerpt-wrapper';
      excerptWrapper.innerHTML = item.excerpt;
      excerpt.appendChild(excerptWrapper);
    }
    
    // Read more link
    const readMore = document.createElement('a');
    readMore.className = 'blog-more-link passthrough-link';
    readMore.href = item.sourceUrl || item.fullUrl;
    readMore.setAttribute('data-animation-role', 'content');
    readMore.textContent = 'Read More';
    
    if (item.sourceUrl) {
      readMore.setAttribute('target', '_blank');
      readMore.setAttribute('rel', 'noopener');
    }
    
    textDiv.appendChild(metaSection);
    textDiv.appendChild(title);
    textDiv.appendChild(excerpt);
    textDiv.appendChild(readMore);
    
    article.appendChild(imageOuterDiv);
    article.appendChild(spacer);
    article.appendChild(textDiv);
    
    return article;
  }

  function createMetaSection(item) {
    const metaSection = document.createElement('div');
    metaSection.className = 'blog-meta-section';
    
    const metaPrimary = document.createElement('span');
    metaPrimary.className = 'blog-meta-primary';
    
    // Categories
    if (item.categories && item.categories.length > 0) {
      const categoriesSpan = document.createElement('span');
      categoriesSpan.className = 'blog-categories-list';
      
      item.categories.forEach((cat, index) => {
        const catLink = document.createElement('a');
        catLink.href = `${BLOG_URL}/category/${cat}`;
        catLink.className = 'blog-categories';
        catLink.textContent = cat;
        categoriesSpan.appendChild(catLink);
        
        if (index < item.categories.length - 1) {
          const comma = document.createElement('span');
          comma.className = 'blog-categories--comma';
          comma.textContent = ', ';
          categoriesSpan.appendChild(comma);
        }
      });
      
      metaPrimary.appendChild(categoriesSpan);
    }
    
    // Author
    if (item.author) {
      const authorSpan = document.createElement('span');
      authorSpan.className = 'blog-author';
      authorSpan.textContent = item.author.displayName;
      metaPrimary.appendChild(authorSpan);
    }
    
    // Date
    const date = new Date(item.publishOn);
    const dateTime = document.createElement('time');
    dateTime.className = 'blog-date';
    dateTime.setAttribute('pubdate', '');
    dateTime.setAttribute('data-animation-role', 'date');
    dateTime.textContent = date.toLocaleDateString('en-US', {month: 'numeric', day: 'numeric', year: '2-digit'});
    metaPrimary.appendChild(dateTime);
    
    const delimiter = document.createElement('span');
    delimiter.className = 'blog-meta-delimiter';
    
    // Meta secondary (duplicate for responsive)
    const metaSecondary = metaPrimary.cloneNode(true);
    metaSecondary.className = 'blog-meta-secondary';
    
    metaSection.appendChild(metaPrimary);
    metaSection.appendChild(delimiter);
    metaSection.appendChild(metaSecondary);
    
    return metaSection;
  }

  function showMoreItems() {
    const itemsToShow = allItems.slice(displayedCount, displayedCount + ITEMS_PER_LOAD);
    renderItems(itemsToShow);
    displayedCount += itemsToShow.length;

    if (displayedCount >= allItems.length) {
      const btn = container.querySelector('.load-more-btn');
      if (btn) btn.remove();
    }
  }

  function createLoadMoreButton() {
    const btn = document.createElement('button');
    btn.className = 'load-more-btn';
    btn.textContent = 'Load More';
    btn.onclick = showMoreItems;
    container.appendChild(btn);
  }
});
</script>

Adding blog page to another page without using summary block 1

#2. Next, edit page > Add a Code Block with this syntax

<div data-showcase-blog="/blog-01" data-category data-limit="40" data-load-more="true"></div>

Adding blog page to another page without using summary block 2

#3. Update Blog Page URL Slug

Adding blog page to another page without using summary block 3

Buy me a coffee