Skip to content
intermediate Phase 69 · Cache Advanced

Private Content — Customer Sections and Dynamic Blocks

Handling private content in Magento 2: customer sections, section API, dynamic blocks, and private content loading patterns

45m
1 problems
Topic Progress 0%

What is Private Content?

Private Content Definition

Private content is user-specific data that cannot be cached globally:

  • Shopping cart contents
  • Wishlist items
  • Recently viewed products
  • Customer account data
  • Compare products list

How Private Content Works

1. Page served from FPC (cached HTML)
2. JavaScript detects private sections needed
3. AJAX request to /customer/section/load/
4. Response contains user-specific HTML
5. JavaScript replaces placeholders in DOM

Sections Configuration

// customer-data.js manages sections
var sections = ['cart', 'wishlist', 'compare', 'recently-viewed'];

Section Loading

// /customer/section/load/?sections=cart,wishlist
// Returns JSON with HTML for each section
{
    "cart": {
        "html": "<div class='minicart'>...</div>",
        "summary_count": 5,
        "subtotal": 100.00
    },
    "wishlist": {
        "html": "<div class='wishlist'>...</div>",
        "counter": 3
    }
}

Customer Sections Implementation

Section Provider Interface

namespace Vendor\Module\CustomerData;

use Magento\Customer\CustomerData\SectionInterface;

class CustomSection implements SectionInterface
{
    public function __construct(
        private \Magento\Customer\Model\Session $session
    ) {}

    public function getSectionData(): array
    {
        return [
            'custom_data' => $this->getCustomData(),
            'counter' => $this->getCounter()
        ];
    }
}

Register Section

<!-- etc/frontend/sections.xml -->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Customer:etc/sections.xsd">
    <section id="custom"
             label="Custom Section"
             instance="Vendor\Module\CustomerData\CustomSection"/>
</config>

JavaScript Section Loading

// customer-data.js
require(['Magento_Customer/js/customer-data'], function(customerData) {
    // Load specific sections
    customerData.reload(['cart', 'custom'], true);
    
    // Get section data
    var cart = customerData.get('cart');
    console.log(cart().summary_count);
});

Section Invalidation

// Invalidate section after action
$this->sectionPool->getSection('cart')->invalidate();

Section API

REST API Endpoint

GET /rest/V1/customers/section/load?sections=cart

Response:
{
    "cart": {
        "items_qty": 5,
        "subtotal": 100.00,
        "items": [...]
    }
}

GraphQL Sections

query {
  cart(cart_id: "...") {
    items {
      product { name }
      quantity
    }
    prices { grand_total { value } }
  }
}

Section Data Flow

// 1. Action triggers section update
$this->cart->addProduct($product);

// 2. Section marked as invalid
$this->sectionPool->getSection('cart')->invalidate();

// 3. AJAX request fetches updated section
// GET /customer/section/load/?sections=cart

// 4. Response contains fresh HTML
{
    "cart": { "html": "...", "summary_count": 6 }
}

Section Expiration

// Section data TTL
'customer' => [
    'ttl' => 3600  // 1 hour
]

Dynamic Blocks with FPC

Making Blocks Dynamic

// In block constructor
public function __construct(
    // ...
    array $data = []
) {
    $data['cacheable'] = false;
    parent::__construct($context, $data);
}

AJAX-Based Dynamic Blocks

<!-- Template -->
<div id="dynamic-content" data-mage-init='{"Magento_Ui/js/view/messages": {}}'>
    <span class="loading">Loading...</span>
</div>

<script type="text/x-magento-init">
{
    "#dynamic-content": {
        "Magento_Ui/js/view/messages": {
            "messageContainer": "<?php echo $block->getMessageContainer(); ?>"
        }
    }
}
</script>

Section-Based Dynamic Content

// Block that loads via section API
class MiniCart extends Template
{
    public function getSectionData(): string
    {
        return $this->json->serialize([
            'cart' => $this->cartData->getSummarySectionData()
        ]);
    }
}

Best Practices

  1. Use section API for customer-specific data
  2. Minimize non-cacheable blocks
  3. Prefer AJAX over ESI for simplicity
  4. Cache section responses with short TTL
  5. Invalidate sections on relevant actions

Practice Problems

0 / 1 solved
Private Content Design

Design a private content solution for a product page with dynamic add-to-cart, wishlist, and review form.

Quiz

1. What is private content in Magento?

Question 1 options

2. How does Magento load private content?

Question 2 options

3. What interface do section providers implement?

Question 3 options

4. How do you register a custom section?

Question 4 options

Flashcards

Question

What is private content?

Answer

User-specific data like cart, wishlist, and customer sections

Question

How does Magento load private content?

Answer

AJAX to /customer/section/load/?sections=cart,wishlist

Question

What interface do sections implement?

Answer

Magento\Customer\CustomerData\SectionInterface

Question

How to register a custom section?

Answer

Define in etc/frontend/sections.xml

Question

How to invalidate a section?

Answer

$this->sectionPool->getSection('cart')->invalidate()

Revision Notes

Key Takeaways

  • 1. Private content is user-specific data that cannot be cached globally
  • 2. Magento loads private content via AJAX to /customer/section/load/
  • 3. Sections implement SectionInterface with getSectionData() method
  • 4. Register sections in etc/frontend/sections.xml
  • 5. Set cacheable=false for dynamic blocks within FPC
  • 6. Invalidate sections after relevant user actions

Interview Tips

  • Explain the private content loading flow with FPC
  • Describe how to create custom customer sections
  • Discuss AJAX vs ESI for loading private content
  • Know the section API endpoint and response format

Cheat Sheet

Private Content Cheat Sheet

Flow:

  1. FPC serves cached HTML
  2. JS detects private sections
  3. AJAX to /customer/section/load/
  4. Response with user-specific HTML
  5. JS replaces DOM placeholders

Section:

implements SectionInterface {
    getSectionData(): array
}

Register:
etc/frontend/sections.xml

Invalidate:
$sectionPool->getSection('cart')->invalidate()

Dynamic block:
$data['cacheable'] = false