Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Amp Laravel Package

lullabot/amp

Lullabot AMP is a PHP library that converts standard HTML into valid Accelerated Mobile Pages markup. It handles AMP-specific transformations and validation, helping PHP and Drupal projects serve faster, compliant mobile pages.

View on GitHub
Deep Wiki
Context7

Getting Started

lullabot/amp converts an HTML string into AMP HTML and reports validation problems against a bundled snapshot of the AMP spec. It is a plain PHP library (no framework coupling), so in Laravel you install it and wrap it in your own service.

composer require lullabot/amp

The package pulls in masterminds/html5 and querypath/querypath; make sure ext-dom, ext-mbstring and ext-libxml are enabled (they normally are in a standard Laravel PHP image).

The entire public surface lives on Lullabot\AMP\AMP. A first conversion is three calls:

use Lullabot\AMP\AMP;

$amp = new AMP();
$amp->loadHtml($html);          // full document: <html><head><body>
$amp->convertToAmpHtml();
$ampHtml = $amp->getAmpHtml();

if ($amp->getInputOutputHtmlValidationErrors()) {
    // inspect error objects (code, line, column, spec_url, severity)
}

Look first at src/AMP.php for the entry points, then at src/Pass/ — every transformation (AmpImgTagTransformPass, AmpIframeTagTransformPass, YouTube/Instagram/Twitter embeds, form fixes, etc.) is a discrete pass, which is the best map of what the library will and won't do to your markup. The first realistic use case is a CMS-style blog post: render the existing Blade view, feed the full document in, store the resulting AMP HTML string, and serve it from a separate /amp/... route.

Implementation Patterns

Wrap it in a stateless service. The AMP object is mutable and does not reset cleanly between documents, so never register it as a singleton. Bind a factory or bind() (not singleton()) and return a fresh helper per conversion:

class AmpConverter
{
    public function convert(string $html, array $options = []): AmpResult
    {
        $amp = new AMP();
        $amp->setOptions($options);
        $amp->loadHtml($html);
        $amp->convertToAmpHtml();

        return new AmpResult(
            $amp->getAmpHtml(),
            $amp->getWarnings(),
            $amp->getInputOutputHtmlValidationErrors(),
            $amp->getActionTakenLines(),
        );
    }
}

Convert after rendering, not inside Blade. The library needs the final <html>/<head>/<body> document (or a body fragment in body scope). Render the view with view()->render(), then convert. For fragment-level conversion of a single article body, pass ['scope' => Scope::BODY_SCOPE] and embed the result into your own AMP shell (see remove_amp_script below).

Do it on a queue, not in the request. DOM parsing plus validation is the slow part; cache the AMP output keyed by hash('xxh128', $html . serialize($options)) and regenerate on save. This also gives you a natural place to log getActionTakenLines() for auditing what was rewritten.

Use the pass pipeline as an extension point. Subclass Lullabot\AMP\Pass\BasePass when you need domain-specific fixes (e.g. rewriting relative image URLs to absolute CDN URLs before the amp-img pass runs). Ordering matters — register custom passes after the standard fix passes so you operate on already-normalised markup, and inspect AMP::$passes in the current release for the exact hook before relying on it; it's an internal, not a documented, API.

Tighten the loop in CI. Keep a directory of representative HTML fixtures and assert on getInputOutputHtmlValidationErrors() (should be empty) plus a snapshot of getWarnings(). Error objects expose getSpecUrl(), so you can render AMP-doc links straight into your QA report.

Options worth knowing: scope (Scope::HTML_SCOPE / Scope::BODY_SCOPE), remove_amp_script (set true when injecting into a page that already loads v0.js), and amp_json_custom_data for injecting your own JSON-LD alongside the generated AMP boilerplate.

Gotchas and Tips

  • Scope mismatch is the #1 failure. Passing an HTML fragment to the default HTML_SCOPE yields a malformed or over-eagerly-fixed document. Either give it a full page or set BODY_SCOPE deliberately.
  • URLs are not absolutised for you. Relative src/href values on images, iframes and links survive into the output and trigger validator errors. Run a pass or a pre-step (Laravel url()/asset()) before conversion.
  • amp-img needs dimensions. If the original <img> has no width/height, the converter can't invent them — you get warnings and invalid markup. Enforce dimensions in your CMS/editor, or add them in a custom pass.
  • JavaScript is silently dropped. Anything relying on inline handlers, <script> tags, or JS-driven widgets will break. The pass list will rewrite known embeds (YouTube, Vimeo, Twitter, Instagram, <video>, <audio>, <iframe>), but custom widgets need a real amp-* component or must be excluded.
  • CSS is constrained. Inline style attributes and non-allowlisted <style> content are flagged or stripped; AMP only permits a single <style amp-custom> block in <head>. Expect to restructure your CSS for the AMP output.
  • The bundled validator is a snapshot. It lags the live AMP spec, and both can disagree with Google's cached validator. For anything user-facing, additionally run the official amphtml-validator in CI rather than trusting getInputOutputHtmlValidationErrors() alone.
  • Warnings are noisy. getWarnings() returns validation-warning objects, not strings — use the code/severity getters to filter, otherwise benign notices drown out real problems.
  • Encoding. loadHtml($html, $encoding) — pass the encoding explicitly if your source isn't UTF-8; otherwise non-ASCII output can be mangled.
  • QueryPath is old. The dependency chain is mature but not actively developed; pin your Composer constraints and re-run your fixture suite whenever you bump PHP minor versions.
  • Idempotency. Calling convertToAmpHtml() twice on the same object double-transforms. Build a fresh AMP instance per request/record, and use getInputHtml() to diff input vs. output while debugging.
  • Debug output. dumpAllActionsTaken() prints every transformation with a human-readable description and line reference — the fastest way to answer "why did my markup change?"
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core