netgen/layouts-remote-media
Netgen Layouts Remote Media adds remote media support to Netgen Layouts, letting editors fetch, manage, and render externally hosted media within layout blocks. A PHP package for flexible, reusable media content in Layouts-powered sites.
What it is. netgen/layouts-remote-media is a thin bridge bundle that plugs a remote media source into Netgen Layouts. In practice that means one or both of:
remote_media) you can drop onto a layout zone in the Layouts admin UI, whose parameter is an asset picked from the remote library;ItemInterface object so it can be stored as a block item, a collection query result, or a target of a custom block parameter.Before writing any code, read three things in vendor/netgen/layouts-remote-media/:
src/ — the Item/, Block/BlockDefinition/Handler/ and Item/ValueType/ namespaces tell you exactly what the package exposes.src/Resources/config/ — services.yaml (tags like netgen_layouts.block_definition.handler, netgen_layouts.item.value_type) and any layouts.yaml with default block definition config.composer.json — the netgen/layouts-* version constraint. This is the single most important compatibility signal (see Gotchas).Minimal setup.
composer require netgen/layouts-remote-media
// config/bundles.php
return [
// ...
Netgen\Layouts\Bundle\NetgenLayoutsBundle::class => ['all' => true],
Netgen\Layouts\RemoteMedia\NetgenLayoutsRemoteMediaBundle::class => ['all' => true],
];
# .env.local — whatever the package's Configuration.php expects
REMOTE_MEDIA_BASE_URI=https://media.example.com
REMOTE_MEDIA_TOKEN=xxxxxxxx
# config/packages/netgen_layouts_remote_media.yaml
# Check the bundle's Configuration.php for the real key; it is usually
# a single-node root config, not nested under netgen_layouts.
Then clear cache and check the wiring rather than guessing:
bin/console cache:clear
bin/console debug:container --tag=netgen_layouts.block_definition.handler | grep -i media
bin/console debug:config netgen_layouts_remote_media
First use case to prove it works. Open a layout in the Layouts admin UI, add the "Remote media" block to a zone, pick one asset from the remote library, publish the layout, and confirm the front end renders it. If that round-trip works, the HTTP client, credentials, item provider and template override path are all correct — and everything else is variation on that.
Render through theme templates, not the vendor template. Layouts resolves block templates per theme and view type. Override rather than edit vendor files:
templates/themes/<theme>/blocks/remote_media/<view_type>.html.twig
Typical render — item values are exposed as block.item.<valueIdentifier>:
{% if block.item is not null %}
<figure>
<img
src="{{ netgen_layouts_image(block.item, 'large') }}"
alt="{{ block.item.value('alt_text') }}"
loading="lazy"
>
<figcaption>{{ block.item.name }}</figcaption>
</figure>
{% endif %}
Reuse the item in your own blocks. The highest-value pattern is not the shipped block but using the remote item as a parameter on a block you already own. Register a value type and a parameter definition in your bundle's config/services.yaml:
App\Layouts\Block\Parameter\RemoteMediaParameter:
tags:
- { name: netgen_layouts.block_definition.parameter_type, alias: remote_media }
You then get the remote media picker UI for free on existing blocks (hero, teaser, gallery) instead of forcing editors into a dedicated block.
Custom block definitions that only borrow rendering. Keep netgen_layouts.block_definitions declarative where you can, and fall back to a PHP BlockDefinition + Handler\Plugin when you need extra parameters (crop, aspect ratio, focal point):
final class RemoteMediaPlugin implements PluginInterface
{
public static function getDefaultConfig(): array
{
return [
'aspect_ratio' => ['type' => 'string', 'default' => '16:9'],
'crop' => ['type' => 'string', 'default' => 'fill'],
];
}
}
Batch the HTTP calls. If the remote item is fetched lazily when the item is hydrated, a grid of twelve blocks means twelve round-trips. Two mitigations:
Item\ItemResolver-style service keyed by remote identifier, and have the value types read from that per-request map.final class PerRequestRemoteCache
{
/** @var array<string, array> */
private array $resolved = [];
public function get(string $id, callable $fetch): array
{
return $this->resolved[$id] ??= $fetch($id);
}
}
Make values cacheable and siteaccess-aware. Remote assets rarely change, so tag your items and blocks with a TTL and, if available, the remote identifier. Configure per-siteaccess where the block is available:
netgen_layouts:
system:
default:
block_definitions:
remote_media:
enabled: true
block_types:
remote_media:
name: 'Remote media'
Test without the network. Symfony HttpClient's MockHttpClient plus KernelBrowser is enough to cover the item provider end to end; assert on the rendered block HTML rather than on internal service calls, since the package's internals are not a stable contract.
netgen/layouts-* packages in lockstep with the core. A ~1.x remote-media bundle against netgen/layouts-core ^2.0 will autoload and then explode on moved classes. Always check with composer why-not netgen/layouts-core before debugging anything else.NetgenLayoutsBundle; a few CompilerPass decorators assume the core services are already registered.netgen_layouts. Read DependencyInjection/Configuration.php and use debug:config <root_key> — guessing the node name costs more time than reading twenty lines of PHP.updated_at folded into the item's cache key, or an explicit admin "clear layout cache" workflow after remote edits.null for a missing/403 asset and Twig prints nothing. Wrap output in {% if block.item %} and log misses at the provider level; otherwise "the page is broken" tickets are hard to trace.Resources/config/ for the admin-side service tag and confirm the bundle's JS/CSS is published (assets:install / webpack copy step).debug:container --tag=netgen_layouts.block_definition.handler, debug:config, and the Layouts admin "Preview" mode will resolve 90% of "block doesn't appear" issues faster than reading the bundle source.BlockDefinition\Handler\Plugin for extra parameters, a custom ValueType for fields the package doesn't map, and a decorated item provider for different remote endpoints. Only patch vendor code as a last resort.composer.json, budget for maintaining a fork, and put a one-page internal README next to your integration describing the credentials, endpoints, and template overrides — future-you will not remember which theme template is load-bearing.How can I help you explore Laravel packages today?