Multi-channel content visibility for TYPO3. Define contexts based on various
conditions (IP address, domain, query parameters, HTTP headers, sessions, etc.)
and control content visibility across your entire TYPO3 installation.
The Contexts extension provides a flexible system for defining contextual
conditions that control content visibility throughout your TYPO3 installation.
Instead of duplicating pages for different scenarios (mobile vs. desktop,
different countries, logged-in vs. anonymous users), you can define contexts
that automatically show or hide content based on various conditions.
Key Features
Multi-channel content management
Define contexts based on IP addresses, domains, query parameters, HTTP headers,
session data, and more. Content visibility is automatically controlled based
on the active context.
Page and content element visibility
Apply contexts to pages, content elements, and records. Elements are
automatically shown or hidden based on context matching.
Extensible architecture
Create custom context types through a clean API. The extension provides
built-in types and allows easy extension for project-specific needs.
Performance optimized
Context matching is cached and optimized for production environments.
Minimal overhead on page rendering.
Use Cases
Geographic content: Show different content based on visitor location (IP-based)
Device-specific content: Different layouts for mobile/desktop (via domain or parameter)
A/B testing: Show different content variants based on session or cookie
Environment-specific: Different behavior in staging vs. production
User-based: Content visibility based on frontend user properties
Requirements
TYPO3 v12.4 LTS or v13.4 LTS
PHP 8.2 or higher
Tip
For TYPO3 v11 support, use version 3.x of this extension.
Related Extensions
Additional context types are available through companion extensions by Netresearch:
Enable debug output in the frontend. When enabled, an HTML comment
<!-- Contexts Extension Debug Mode Active --> is added to the
page header. Use in development only.
contexts.matchMode
contexts.matchMode
type
string
Default
all
How multiple contexts are evaluated when checking visibility:
all: All assigned contexts must match (AND logic)
any: At least one context must match (OR logic)
contexts.cacheLifetimeModifier
contexts.cacheLifetimeModifier
type
integer
Default
Modify cache lifetime when contexts are active (in seconds).
0 means no modification.
Page and Content Element Settings
Context visibility is configured directly on page and content element
records via the Contexts tab in the TYPO3 backend.
Each context record appears with two options:
Visible: yes — record is only shown when the context is active
Visible: no — record is hidden when the context is active
The extension adds two database columns to controlled tables:
tx_contexts_enable
Comma-separated list of context UIDs that must be active for the
record to be visible.
tx_contexts_disable
Comma-separated list of context UIDs that hide the record when
active.
Caching Considerations
Context-dependent content affects page caching. The extension handles
this through several mechanisms:
Query restriction: The ContextRestriction class
automatically adds WHERE clauses to database queries, filtering
records based on active contexts.
Cache hash modification: When query parameter contexts are
active, the extension adds context identifiers to the page cache
hash, ensuring separate cache entries per context combination.
Menu filtering: Menu items are filtered based on context
visibility settings, so navigation reflects the current context.
Tip
For pages that depend heavily on context state, consider using
config.no_cache = 1 in TypoScript or use context-aware
cache tags to ensure correct content delivery.
Context Types
The extension provides several built-in context types. Each type evaluates
different conditions to determine if a context is active.
Match visitors by their IP address or IP range. Supports both IPv4 and IPv6.
Configuration
IP/Range
IP/Range
type
string
required
true
Single IP address, CIDR notation, range, or comma-separated list.
Examples:
Single IP: 192.168.1.100
CIDR notation: 10.0.0.0/8, FE80::/16
Range: 192.168.1.1-192.168.1.255
Wildcards: 80.76.201.*, 80.76.*.37
Multiple: 192.168.1.0/24,10.0.0.0/8
Use Cases
Internal network detection (show admin tools for office IPs)
Geographic content (by IP geolocation with contexts_geolocation)
Office vs. external visitor differentiation
Development/staging environment detection
Domain Context
Match based on the accessed domain name (HTTP_HOST).
Configuration
Domain
Domain
type
string
required
true
Domain name(s) to match. One domain per line.
Matching Rules:
Without leading dot: Exact match only
www.example.org will not match example.org
With leading dot: Matches all subdomains
.example.org matches www.example.org, shop.example.org, etc.
Examples:
Single: www.example.com
Multiple (one per line):
example.com
www.example.com
Copied!
Subdomain wildcard: .example.com
Use Cases
Multi-domain setups (different content per domain)
Staging vs. production detection
Brand-specific content on shared installations
Language-specific domains
Query Parameter Context
Match based on URL query parameters (GET parameters).
Configuration
Parameter Name
Parameter Name
type
string
required
true
The GET parameter name to check.
Expected Value
Expected Value
type
string
required
false
Value to match. Supports regular expressions. If empty, any non-empty
value activates the context.
Store in Session
Store in Session
type
boolean
default
false
When enabled, the context state is stored in the user session, persisting
across page navigations even after the parameter is removed from the URL.
Examples:
?debug=1 with parameter debug and value 1
?variant=a for A/B testing
?affID=partner for affiliate tracking
Use Cases
A/B testing variants
Debug mode activation
Campaign and affiliate tracking
Feature flags via URL
HTTP Header Context
New in version 3.0.0
HTTP Header context for matching request headers.
Match based on HTTP request headers sent by the browser or proxy.
Configuration
Header Name
Header Name
type
string
required
true
The HTTP header name to check (case-insensitive).
Expected Value
Expected Value
type
string
required
false
Value(s) to match against the header. One value per line.
Matching uses case-insensitive substring comparison: if any
configured value appears anywhere in the actual header value,
the context matches. If empty, any non-empty header value
activates the context.
Store in Session
Store in Session
type
boolean
default
false
When enabled, the context state persists in the user session.
New in version 4.0.0
PSR-7 header support and case-insensitive substring matching.
Header Name Resolution
The extension supports both standard HTTP header names and
$_SERVER parameter keys:
The extension registers four PSR-14 event listeners that handle
context-based behavior in the frontend and backend. These listeners
are registered via PHP attributes and cannot be removed, but you
can register your own listeners on the same events.
Page Access Control
PageAccessEventListener listens to
AfterPageAndLanguageIsResolvedEvent and checks whether the
current page is accessible based on its context restrictions
(tx_contexts_enable / tx_contexts_disable). If access
is denied, it throws an ImmediateResponseException with a
403 response.
The current page is always checked for its own context
restrictions. Parent pages only propagate restrictions when
extendToSubpages is enabled.
Menu Item Filtering
MenuItemFilterEventListener listens to
FilterMenuItemsEvent and removes menu items that should
not be visible in the current context. This ensures navigation
menus reflect context-based visibility.
Icon Overlay Modification
IconOverlayEventListener listens to
ModifyRecordOverlayIconIdentifierEvent and modifies icon
overlays for records that have context-based visibility
settings, providing visual feedback in the backend.
Cache Lifetime Modification
CacheHashEventListener listens to
ModifyCacheLifetimeForPageEvent and can adjust cache
lifetime based on active contexts.
Architecture
Request Lifecycle
The ContainerInitialization PSR-15 middleware initializes
context matching on every frontend request. It:
Sets the PSR-7 request on the Container singleton
Triggers Container::initMatching() which loads all context
records from the database and runs match() on each
Only matched contexts are retained in the container
This middleware runs before the page resolver, ensuring contexts
are available throughout the rendering pipeline.
Query Restrictions
The ContextRestriction class implements
EnforceableQueryRestrictionInterface and automatically adds
WHERE clauses to all database queries on context-controlled
tables. It uses FIND_IN_SET() to check whether active
context UIDs appear in the tx_contexts_enable or
tx_contexts_disable columns.
This means records with context restrictions are automatically
filtered in all frontend queries without additional code.
Context API
Checking Contexts Programmatically
The Container class provides access to all matched contexts.
It uses a singleton pattern and extends ArrayObject.
<?phpdeclare(strict_types=1);
useNetresearch\Contexts\Context\Container;
// Get the container instance (singleton)
$container = Container::get();
// Find a specific context by alias or UID
$context = $container->find('my-context-alias');
if ($context !== null) {
// Context exists and is active (matched)
}
// Iterate over all active (matched) contextsforeach (Container::get() as $uid => $context) {
echo $context->getAlias() . ' is active';
}
Copied!
Using the ContextMatcher API
For simple matching checks, use the ContextMatcher API:
<?phpdeclare(strict_types=1);
useNetresearch\Contexts\Api\ContextMatcher;
if (ContextMatcher::getInstance()->matches('mobile')) {
// Mobile context is active
}
Copied!
Configuration API
Enable context settings on custom tables using the
Configuration API:
This registers the tx_contexts_settings column, adds flat
columns (tx_contexts_enable, tx_contexts_disable), and
integrates context visibility into the record editing form.
Record API
Check if a record is enabled for the current contexts:
<?phpdeclare(strict_types=1);
useNetresearch\Contexts\Api\Record;
// Check if a record is visible in current context
$row = ['uid' => 42, 'tx_contexts_enable' => '3,5'];
if (Record::isEnabled('tt_content', $row)) {
// Record is visible
}
// Check a specific settingif (Record::isSettingEnabled('my_table', 'my_setting', $row)) {
// Setting is enabled for this record
}
Copied!
TypoScript Conditions
Use the contextMatch() function in TypoScript conditions:
# Show content only when mobile context is active[contextMatch('mobile')]
page.10.wrap = <div class="mobile-wrapper">|</div>
[END]# Combine with other conditions[contextMatch('internal') && tree.level > 2]
lib.breadcrumb.show = 1
[END]
Copied!
The contextMatch() function is provided via TYPO3's
ExpressionLanguage and works in all condition contexts
(TypoScript, TSconfig, etc.).
Fluid ViewHelpers
The extension provides a ViewHelper for context matching in Fluid
templates.
Check if a context is active using the matches ViewHelper:
<f:ifcondition="{contexts:matches(alias: 'mobile')}"><f:then><p>Mobile context is active</p></f:then><f:else><p>Mobile context is not active</p></f:else></f:if>
Copied!
The ViewHelper returns 1 when the context matches and 0
otherwise, making it compatible with Fluid's condition evaluation.
Practical Examples
Conditional rendering based on context:
<f:ifcondition="{contexts:matches(alias: 'internal')}"><divclass="admin-toolbar"><!-- Only shown for internal network --></div></f:if>
Copied!
Combining with other conditions:
<f:ifcondition="{contexts:matches(alias: 'premium')} && {user}"><divclass="premium-content"><!-- Premium user content --></div></f:if>
Copied!
Testing
Running Tests
Tests can be run via Composer scripts or the Docker-based
runTests.sh script.
# Unit tests (default suite)
./Build/Scripts/runTests.sh -s unit
# Unit tests with coverage
./Build/Scripts/runTests.sh -s unitCoverage
# Functional tests with SQLite
./Build/Scripts/runTests.sh -s functional -d sqlite
# PHPStan
./Build/Scripts/runTests.sh -s phpstan
# With specific PHP version
./Build/Scripts/runTests.sh -s unit -p 8.4
# Show all options
./Build/Scripts/runTests.sh -h
Copied!
The Docker-based script uses ghcr.io/typo3/core-testing-php*
images and requires Docker or Podman.
Writing Tests for Custom Contexts
<?phpdeclare(strict_types=1);
namespaceVendor\MyExtension\Tests\Unit\Context\Type;
usePHPUnit\Framework\Attributes\Test;
useTYPO3\TestingFramework\Core\Unit\UnitTestCase;
useVendor\MyExtension\Context\Type\MyCustomContext;
finalclassMyCustomContextTestextendsUnitTestCase{
#[Test]publicfunctionmatchReturnsTrueForValidCondition(): void{
$context = new MyCustomContext();
// Setup test conditionsself::assertTrue($context->match());
}
}
Copied!
Debugging
Enable context debugging via the Site Set setting:
config/sites/<identifier>/config.yaml
settings:contexts:debug:true
Copied!
This adds an HTML comment to the page header indicating that
debug mode is active. For detailed context matching inspection,
use the TYPO3 Admin Panel or check the tx_contexts_contexts
table for context configuration and the tx_contexts_enable /
tx_contexts_disable columns on your records.
Migration Guide
This guide covers migrating from previous versions of the Contexts extension.
Migrating from v3.x to v4.0
Version 4.0 introduces significant changes for TYPO3 v12/v13 compatibility.
Breaking Changes
PHP Version
Before: PHP 7.4 - 8.1
After: PHP 8.2+
Update your deployment and CI pipelines accordingly.
TYPO3 Version
Before: TYPO3 v11
After: TYPO3 v12.4 LTS and v13.4 LTS only
TYPO3 v11 and earlier are no longer supported. Use version 3.x for older
TYPO3 installations.
Hook Migration
All SC_OPTIONS hooks have been replaced with PSR-14 events.