AMP Optimizer PHP library

Overview
AMP logo

AMP Toolbox for PHP

Build Status Coverage

A collection of AMP tools making it easier to publish and host AMP pages with PHP.

The following tools are part of this library:

AMP Optimizer for PHP

AMP Optimizer is a library for doing server-side optimization to AMP markup by automatically applying AMP performance best practices and enabling AMP server-side-rendering.

Table of Contents (click to expand)

Conceptual Overview

The AMP Optimizer is a AmpProject\Optimizer\TransformationEngine object that sets up a pipeline of consecutive AmpProject\Optimizer\Transformer objects. The engine takes unoptimized input in the form of either a HTML markup string or an AmpProject\Dom\Document object and turns it into an optimized HTML markup string.

During the process, errors might occur that make parts of the optimization impossible. These are collected within an AmpProject\Optimizer\ErrorCollection object that you can then iterate over to find out more and provide feedback as needed.

Diagram showing the conceptual parts of the AMP Optimizer

Installation

The AMP Optimizer is part of the AMP Toolbox for PHP library that you can pull into your project via the Composer PHP package manager:

composer require ampproject/amp-toolbox

Basic Usage

The following code snippet shows the most basic way of using the AMP Optimizer:

use AmpProject\Optimizer\ErrorCollection;
use AmpProject\Optimizer\TransformationEngine;

$transformationEngine = new TransformationEngine();    // 1.
$errorCollection      = new ErrorCollection;           // 2.

$optimizedHtml = $transformationEngine->optimizeHtml(  // 3.
    $unoptimizedHtml,                                  // 4.
    $errorCollection                                   // 5.
);
  1. First we instantiate the transformation engine itself.
  2. Then we instantiate an AmpProject\Optimizer\ErrorCollection object as we need a "bag" to collect the errors in and pass them around.
  3. As a final step, we store the result of calling the transformation engine's optimizeHtml() method, which requires...
  4. ... the unoptimized input HTML markup as a string and ...
  5. ... the empty error collection we've already instantiated. After the transformation engine ran, this collection will contain all errors that were encountered during the transformation.

Usage with a DOM Representation

If you already have a DOM representation, there's no need to save it as HTML first to use it with the transformation engine. The transformation engine accepts an AmpProject\Dom\Document object[^1] directly via its optimizeDom() method.

If you have a regular PHP built-in DOMDocument instead, you can turn it into an AmpProject\Dom\Document using AmpProject\Dom\Document::fromNode().

use AmpProject\Dom\Document;
use AmpProject\Optimizer\ErrorCollection;
use AmpProject\Optimizer\TransformationEngine;

if (! $dom instanceof Document) {
    $dom = Document::fromNode($dom);
}

$transformationEngine = new TransformationEngine();
$errorCollection      = new ErrorCollection;
$transformationEngine->optimizeDom($dom, $errorCollection);

Do note that the optimizeDom() doesn't have a return value, as it changes the provided AmpProject\Dom\Document in-place.

Working with Errors

The AmpProject\Optimizer\ErrorCollection that you pass into the transformation engine's optimizeHtml() or optimizeDom() method should ideally stay empty after the optimization pass.

To check whether errors were found, you can iterate over the collection, which will provide you with 0 or more AmpProject\Optimizer\Error objects.

$errorCollection = new ErrorCollection;

// Do the transformation here, while passing in the $errorCollection object.

foreach ($errorCollection as $error) {
	printf(
	    "Error code: %s\nError Message: %s\n",
	    $error->getCode(),
	    $error->getMessage()
	);
}

A quick count of the errors can be done for early returns as needed:

if ($errorCollection->count() > 0) {
	$this->log('The AMP serverside optimization process produced one or more errors.');
}

You can check whether the collection of errors contains an error with a specific code as well. The current convention is that all errors have their class shortname (the class name without the namespace) as the error code.

if ($errorCollection->has('CannotRemoveBoilerplate')) {
	$this->log('The boilerplate was not removed by the Optimizer.');
}

Note that this only lets you check whether an error "category" popped up. It can be one or more errors with that same code. If you need a more detailed check, you should iterate over the collection instead.

Included Transformers

Class (short name) Description
AmpBoilerplate Transformer that removes AMP boilerplate <style> and <noscript> tags in <head>, keeping only the amp-custom style tag. It then (re-)inserts the amp-boilerplate unless the document is marked with the i-amphtml-no-boilerplate attribute.
AmpRuntimeCss Transformer adding https://cdn.ampproject.org/v0.css if server-side-rendering is applied (known by the presence of the <style amp-runtime> tag). AMP runtime css (v0.css) will always be inlined as it'll get automatically updated to the latest version once the AMP runtime has loaded.
PreloadHeroImage Transformer that optimizes image rendering times for hero images by adding preload and serverside-rendered <img> tags when possible. Viable hero images are <amp-img> tags, <amp-video> tags with a poster attribute as well as <amp-iframe> and <amnp-video-iframe> tags with a placeholder attribute. The first viable image that is encountered is used by default, but this behavior can be overridden by adding the data-hero attribute to a maximum of two images. The preloads only work work images that don't use srcset, as that is not supported as a preload in most browsers. The serverside-rendered image will not be created for <amp-video> tags.
ReorderHead Transformer applying the head reordering transformations to the HTML input. ReorderHead reorders the children of <head>. Specifically, it orders the <head> like so:
(0) <meta charset> tag
(1) <style amp-runtime> (inserted by AmpRuntimeCss)
(2) remaining <meta> tags (those other than <meta charset>)
(3) AMP runtime .js <script> tag
(4) AMP viewer runtime .js <script>
(5) <script> tags that are render delaying
(6) <script> tags for remaining extensions
(7) <link> tag for favicons
(8) <link> tag for resource hints
(9) <link rel=stylesheet> tags before <style amp-custom>
(10) <style amp-custom>
(11) any other tags allowed in <head>
(12) AMP boilerplate (first <style> boilerplate, then <noscript>)
RewriteAmpUrls Transformer that rewrites AMP runtime URLs to decide what version of the runtime to use. This allows you to do such things as switching to the LTS version or disabling ES modules.
ServerSideRendering Transformer applying the server-side rendering transformations to the HTML input. This does immediately on the server what would normally be done on the client after the runtime was downloaded and executed to process the DOM. As such, it allows for the removal of the boilerplate CSS that hides the page while it has not yet been processed on the client, drastically improving time it takes for the First Contentful Paint (FCP).
TransformedIdentifier Transformer applying the transformed identifier transformations to the HTML input. This is what marks an AMP document as "already optimized", so that the AMP runtime does not need to process it anymore.

Configuring the Transformers

You can inject a configuration object into the AmpProject\Optimizer\TransformationEngine to override the default configuration.

The AmpProject\Optimizer\Configuration interface and its default implementation AmpProject\Optimizer\DefaultConfiguration will provide the list of transformers to use, as well as give access to child objects they store that are Transformer-specific configuration objects.

To override the list of transformers to use, you can provide an array containing the AmpProject\Optimizer\Configuration::KEY_TRANSFORMERS key.

use AmpProject\Optimizer\Configuration;
use AmpProject\Optimizer\DefaultConfiguration;
use AmpProject\Optimizer\TransformationEngine;
use AmpProject\Optimizer\Transformer;

$configurationData = [
	Configuration::KEY_TRANSFORMERS => [
		Transformer\ServerSideRendering::class,
		Transformer\AmpRuntimeCss::class,
		Transformer\TransformedIdentifier::class,
	],
];

$transformationEngine = new TransformationEngine(
	new DefaultConfiguration($configurationData)
);

Configuration values for the transformers can be stored under the fully qualified class name of these transformers. This can be easily done by using their ::class constant.

They will also usually provide publicly accessible constants for the known configuration keys as well.

In the following example, we configure the AmpProject\Optimizer\Transformer\AmpRuntimeCss transformer by setting its 'canary' option to true (which would default to false).

use AmpProject\Optimizer\Configuration;
use AmpProject\Optimizer\DefaultConfiguration;
use AmpProject\Optimizer\TransformationEngine;
use AmpProject\Optimizer\Transformer;

$configurationData = [
	Transformer\AmpRuntimeCss::class => [
		Configuration\AmpRuntimeCssConfiguration::CANARY => true,
	],
];

$transformationEngine = new TransformationEngine(
	new DefaultConfiguration($configurationData)
);

Creating a Custom Transformer

A custom transformer is at the most basic level an object that implements the AmpProject\Optimizer\Transformer interface.

This means it needs to have at the very least the following method:

public function transform(Document $document, ErrorCollection $errors)
{
	// Apply transformations to the provided $document and ...

	// ... add any encountered errors to the $errors collection.
}

To make this transformer then known to the transformation engine, you add it to the AmpProject\Optimizer\Configuration::KEY_TRANSFORMERS key of the AmpProject\Optimizer\Configuration object you pass into it.

use AmpProject\Optimizer\Configuration;
use AmpProject\Optimizer\DefaultConfiguration;
use AmpProject\Optimizer\TransformationEngine;
use MyProject\MyCustomTransformer;

$configurationData = [
	Configuration::KEY_TRANSFORMERS => array_merge(
		Configuration::DEFAULT_TRANSFORMERS,
		[
			MyCustomTransformer::class
		],
	),
];

$transformationEngine = new TransformationEngine(
	new DefaultConfiguration($configurationData)
);

Making a Custom Transformer Configurable

Configuration objects for the individual transformers need to be registered with the main AmpProject\Optimizer\Configuration object using its registerConfigurationClass() method, which takes a fully qualified class name of the transformer as well as a fully qualified class name of the corresponding configuration object as its two arguments.

The configuration objects for the transformers that ship with this library are already registered by default. But if you add third-party or custom transformers, you'll need to register whatever configuration objects they might need with the main AmpProject\Optimizer\Configuration object first.

In the following example, we add a new MyProject\MyCustomTransformer transformer in addition to the default set and configure it with a default value, and then we register its corresponding configuration object to make sure the configuration can be properly validated and passed around.

use AmpProject\Optimizer\Configuration;
use AmpProject\Optimizer\DefaultConfiguration;
use AmpProject\Optimizer\TransformationEngine;
use MyProject\MyCustomTransformer;
use MyProject\MyCustomTransformerConfiguration;

$configurationData = [
	Configuration::KEY_TRANSFORMERS => array_merge(
		Configuration::DEFAULT_TRANSFORMERS,
		[
			MyCustomTransformer::class
		],
	),
	MyCustomTransformer::class => [
		MyCustomTransformerConfiguration::SOME_CONFIG_KEY => 'some value',
	],
];

$configuration = new DefaultConfiguration($configurationData);

$configuration->registerConfigurationClass(
	MyCustomTransformer::class,
	MyCustomTransformerConfiguration::class
);

$transformationEngine = new TransformationEngine($configuration);

For the wiring to work correctly, the MyProject\MyCustomTransformer class needs to accept within its constructor an object implementing the AmpProject\Optimizer\TransformerConfiguration interface. The transformation engine will then inject the appropriate implementation at runtime when the transformer is being instantiated.

The MyProject\MyCustomTransformerConfiguration class should then implement that same AmpProject\Optimizer\TransformerConfiguration interface. For convenience, it can do so easily by extending the abstract AmpProject\Optimizer\Configuration\BaseTransformerConfiguration base class.

The configuration object will then be automatically injected into the transformer's constructor as needed.

Here's an example configuration class for our custom MyProject\MyCustomTransformer transformer:

namespace MyProject;

use AmpProject\Optimizer\Configuration\BaseTransformerConfiguration;

final class MyCustomTransformerConfiguration extends BaseTransformerConfiguration
{
	const SOME_CONFIG_KEY = 'some_config_key';

	protected function getAllowedKeys()
	{
		return [
			self::SOME_CONFIG_KEY => 'default value',
		];
	}

	protected function validate($key, $value)
	{
		switch ($key) {
			case self::SOME_CONFIG_KEY:
				// Validate configuration value here.
		}

		return $value;
	}
}

Here's how the transformer itself can accept and make use of the configuration object:

namespace MyProject;

use AmpProject\Dom\Document;
use AmpProject\Optimizer\Configurable;
use AmpProject\Optimizer\ErrorCollection;
use AmpProject\Optimizer\TransformerConfiguration;
use AmpProject\Optimizer\Transformer;

final class MyCustomTransformer implements Transformer
{
	private $configuration;

	public function __construct(TransformerConfiguration $configuration)
	{
		$this->configuration = $configuration;
	}

	public function transform(Document $document, ErrorCollection $errors)
	{
		// Bogus transformer logic that adds the configuration value as a body attribute.
		$document->body->setAttribute(
			'data-my-custom-transformer-body-attribute,
			$this->configuration->get(
				MyCustomTransformerConfiguration::SOME_CONFIG_KEY
			)
		);
	}
}

Transformers Requesting External Data

In case your transformer needs to make remote requests to fetch external data (like the AmpProject\Optimizer\Transformer\AmpRuntimeCss does for fetching the latest version of the CSS to inline), you need to accept an AmpProject\RemoteGetRequest object as an argument in your constructor. The transformation engine will then inject the appropriate implementation at runtime when the transformer is being instantiated.

This layer of abstraction allows code outside of the transformation engine to control the specific conditions and limits that govern these remote request, like for example throttling them or integrating them with the caching subsystem of the framework in use.

namespace MyProject;

use AmpProject\Dom\Document;
use AmpProject\RemoteGetRequest;
use AmpProject\Optimizer\ErrorCollection;
use AmpProject\Optimizer\Transformer;
use Throwable;

final class MyCustomTransformer implements Transformer
{
	const END_POINT = 'https://example.com/some_endpoint/';

	private $remoteRequest;

	public function __construct(RemoteGetRequest $remoteRequest)
	{
		$this->remoteRequest = $remoteRequest;
	}

	public function transform(Document $document, ErrorCollection $errors)
	{
		try {
			$response = $this->remoteRequest->get(self::END_POINT);
		} catch (Throwable $exception) {
			// Add error handling here.
		}

		$statusCode = $response->getStatusCode();

		if (200 < $statusCode || $statusCode >= 300) {
			// Add error handling here.
		}

		$content = $response->getBody();
		
		// Make use of the $content you've just retrieved from an external source.
	}
}

Adapting the Handling of Remote Requests

The implementation to use for fulfilling requests made via the AmpProject\RemoteGetRequest interface can be injected into the AmpProject\Optimizer\TransformationEngine via its second, optional argument:

use AmpProject\Optimizer\DefaultConfiguration;
use AmpProject\Optimizer\TransformationEngine;

$transformationEngine = new TransformationEngine(
	new DefaultConfiguration(),

	// A custom implementation that lets you control how remote requests are handled.
	new MyCustomRemoteGetRequestImplementation()
);

If this optional second argument is not provided when instancing the transformation engine, the default AmpProject\RemoteRequest\CurlRemoteGetRequest implementation is used.

There are other implementations already provided that can be useful:

Class (short name) Description
CurlRemoteGetRequest Remote request transport using cURL. This is the default implementation that will be used if you don't provide one explicitly.

It has the following configuration settings as constructor arguments:
$sslVerify - Whether to verify SSL certificates. Defaults to true.
$timeout - Timeout value to use in seconds. Defaults to 10.
$retries - Number of retry attempts to do if an error code was thrown that is worth retrying. Defaults to 2.
FallbackRemoteGetRequest Fallback pipeline implementation to go through a series of fallback requests until a request succeeds. The request will be tried with the first instance provided, and follow the instance series from one to the next until a successful response was returned.

It has the following configuration settings as constructor arguments:
...$pipeline - Variadic array of RemoteGetRequest instances to use as consecutive fallbacks.
FilesystemRemoteGetRequest Fetch the response for a remote request from the local filesystem instead. This can be used to provide offline fallbacks.

It has the following configuration settings as constructor arguments:
$argumentMap - Associative array of data for mapping between provided URLs and the filepaths they should map to.
StubbedRemoteGetRequest Stub for simulating remote requests. This is mainly used for writing tests.

It has the following configuration settings as constructor arguments:
$argumentMap - Associative array of data for mapping between provided URLs and the body content they should return.

The following code shows an example of how to use a remote request via cURL while falling back to files stored on the disk when an external request fails (probably due to network issues).

use AmpProject\Optimizer\DefaultConfiguration;
use AmpProject\Optimizer\TransformationEngine;
use AmpProject\RemoteRequest\CurlRemoteGetRequest;
use AmpProject\RemoteRequest\FallbackRemoteGetRequest;
use AmpProject\RemoteRequest\FilesystemRemoteGetRequest;

const FALLBACK_MAPPING = [
	'https://example.com/some_endpoint/' => __DIR__ . '/../fallback_files/some_endpoint.json',
];

$remoteRequest = new FallbackRemoteGetRequest(
	new CurlRemoteGetRequest(true, 5, 0),                  // 5 second timeout with no retries, and ...
	new FilesystemRemoteGetRequest(self::FALLBACK_MAPPING) // ... fall back to shipped files.
);

$transformationEngine = new TransformationEngine(new DefaultConfiguration(), $remoteRequest);

To build your own transport, you'll need to implement the AmpProject\RemoteGetRequest interface. For a more involved example of a custom transport or for integrating with your stack of choice, see the two implementations provided by the Amp for WordPress WordPress plugin:

Comments
  • ampersand sign converted into unicode when added to analytics config.

    ampersand sign converted into unicode when added to analytics config.

    Bug Description

    A user reported on support forums that the & is being converted to Unicode character \u0026 when being added to the analytics config.

    After disabling optimizer it did output correctly add_filter( 'amp_enable_optimizer', '__return_false' );

    Steps to reproduce You can reproduce using the AMP plugin for WordPress, steps assuming that you have WordPress site with AMP plugin installed

    Step 1 : Login as Admin Step 2: Goto AMP->Settings->Analytics Step 3: Enter the type as "test" (you can add anything as type was unknow from support topics) Step 4: add JSON config as below

    {
      "requests": {
        "custom_params": "cp1=test&cp2=test"
      },
      "vars": {
        "env": "-preproduction"
      },
      "triggers": {
        "trackConsent": {
          "on": "visible",
          "request": "impression"
        }
      }
    }
    

    Expected Output Same output as entered in config.

    Current Behaviour

    {
      "requests": {
        "custom_params": "cp1=test\u0026cp2=test"
      },
      "vars": {
        "env": "-preproduction"
      },
      "triggers": {
        "trackConsent": {
          "on": "visible",
          "request": "impression"
        }
      }
    }
    

    Screenshot | Input | Output | | ------------- | ------------- | | image | image |

    opened by milindmore22 1
  • `<link preload>` is not inserted when using OptimizeHeroImages(PHP 5.6)

    `` is not inserted when using OptimizeHeroImages(PHP 5.6)

    amp-toolbox-version : 0.11.0, 0.10.0, 0.6.0
    PHP version : 5.6
    

    <link preload> may not be inserted when using Transformer\OptimizeHeroImages with <amp-img data-hero>. I also use Transformer\ServerSideRendering.

    Could you check this problem?

    opened by saywo 3
  • Server side rendering breaks validation (amp4ads)

    Server side rendering breaks validation (amp4ads)

    SSR is breaking the page validation due !important declaration included in amp-ad-0.1.js:

    <style amp-runtime="" i-amphtml-version="012202042210001">html{overflow-x:hidden!important}html.i-amphtml-fie{height:100%!important;width:100%!important}html:not([amp4ads]),html:not([amp4ads]) body{height:auto!important}html:not([amp4ads]) body{margin:0!important}body{-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;-ms-text-size-adjust:100%;text-size-adjust:100%}html.i-amphtml-singledoc.i-amphtml-embedded{-ms-touch-action:pan-y ... </style>

    I've tried removing AmpRuntimeCss:

    $configurationData = [
                Configuration::KEY_TRANSFORMERS => [
                    Transformer\AmpBoilerplate::class,
                    Transformer\ServerSideRendering::class,
                    Transformer\ReorderHead::class,
                    Transformer\OptimizeHeroImages::class,
                    Transformer\TransformedIdentifier::class,
                ],
            ];
    
    $transformationEngine = new TransformationEngine(new DefaultConfiguration($configurationData), $cachedRemoteRequest);
    
    

    But empty tag was generated:

    <style amp-runtime=""></style>

    And it breaks the validation again.

    Regards.

    Blocked 
    opened by jcastilloa 7
  • Latest version concept was deprecated upstream

    Latest version concept was deprecated upstream

    The AMP project has deprecated the concept of latestVersion and -latest binaries: https://github.com/ampproject/amphtml/issues/36749

    Right now, we use that data for the AutoExtensions transformer to figure out which version of a component to pull in.

    Instead of relying on the latestVersion, we'll have to pick the most appropriate one from the list of "available" versions. We need to figure out what that means for experimental versions, as we want to default to stable versions unless otherwise requested.

    opened by schlessera 2
  • CLI options parsing is order-dependent

    CLI options parsing is order-dependent

    The parsing of the CLI options is dependent on an arbitrary ordering where associative arguments (flags like --json) need to come first before positional arguments. If these associative arguments are provided after a positional argument, they are currently being silently ignored.

    Bug CLI 
    opened by schlessera 0
Releases(0.11.2)
  • 0.11.2(Jun 13, 2022)

    Changes

    • Implement SSR for amp-audio by @ediamin in https://github.com/ampproject/amp-toolbox-php/pull/523

    Bugfixes

    • Fix SSR sizer responsiveness issue by @ediamin in https://github.com/ampproject/amp-toolbox-php/pull/521
    • Fix error when source is missing closing head tag by @ediamin in https://github.com/ampproject/amp-toolbox-php/pull/524

    Meta

    • Sync spec test suite by @github-actions in https://github.com/ampproject/amp-toolbox-php/pull/520

    Full Changelog: https://github.com/ampproject/amp-toolbox-php/compare/0.11.1...0.11.2

    Source code(tar.gz)
    Source code(zip)
  • 0.11.1(Apr 8, 2022)

    Bugfixes

    • Harden hero image optimization when noscript > img fallbacks are present [#516]

    Meta

    • Sync local fallback files [#515]

    Full Changelog: https://github.com/ampproject/amp-toolbox-php/compare/0.11.0...0.11.1

    Source code(tar.gz)
    Source code(zip)
  • 0.11.0(Apr 1, 2022)

    Changes

    • Add a new simplified table formatter API [#476]

    Bugfixes

    • Prevent SelfClosingSVGElements document filter from erroneously self-closing tags [#513]
    • Fix bad casing in Amp class name [#500]
    • Avoid overriding $iterationArray property from inherited classes [#504]

    Meta

    • Allow Composer plugins to run [#480]
    • Update action to sync local fallback files [#493]
    • Remove test ignores that are not needed anymore [#481]

    Full Changelog: https://github.com/ampproject/amp-toolbox-php/compare/0.10.0...0.11.0

    Source code(tar.gz)
    Source code(zip)
  • 0.10.0(Jan 7, 2022)

  • 0.9.3(Dec 14, 2021)

  • 0.9.2(Dec 7, 2021)

  • 0.9.1(Dec 2, 2021)

  • 0.9.0(Dec 2, 2021)

    Changes

    • Add TemporaryFileCachedRemoteGetRequest to cache cURL request [#414]

    Bugfixes

    • Disable whitespace collapsing by default in MinifyHtml transformer [#429]
    • Use Str helper class to normalize whitespace in MinifyHtml transformer [#421]

    Meta

    • Sync spec test suite [#426]

    Work-in-progress

    • [WIP] Add AMP Validator [#312]

    Note: The AMP Validator is not fully working yet, but parts of its code improvements are needed for other PRs in other repositories.

    Source code(tar.gz)
    Source code(zip)
  • 0.8.2(Oct 27, 2021)

  • 0.8.1(Oct 26, 2021)

  • 0.8.0(Oct 23, 2021)

    Changes

    • Add AutoExtensions transformer [#210], [#381]
    • Add OptimizeViewport transformer [#373]
    • Add ProtectEsiTags Document filter [#343], [#369]
    • Turn TagWithExtensionSpec into an abstract class [#358] (⚠breaking change)
    • Add $headers argument to RemoteGetRequest::get() [#356]
    • Add Attribute::DEFER [#366]
    • Refactor CLI option retrieval to improve typing [#357] (⚠breaking change)
    • Update documentation for OptimizeHeroImages [#337]

    Bugfixes

    • Only merge CSS rules for display:none [#335]
    • Fix PHP 8.1 compatibility issues [#374]

    Dependencies

    • Regenerate validator specs and update SpecGenerator and Dumper classes [#384]

    Meta

    • Fix outdated PHPStan version in GHA workflow [#368]
    • Sync spec test suite [#375]
    Source code(tar.gz)
    Source code(zip)
  • 0.7.0(Aug 27, 2021)

    Changes

    • Add MinifyHtml transformer [#251]
    • Add MinifyHtml to list of default transformers [#330]
    • Add amp-script minification [#281]
    • Optimize mustache template detection logic in MinifyHtml transformer [#309]
    • Refactor Dom\Document class using filters [#271] (⚠breaking change)
    • Consume bundles.config.extensions.json to amend TagWithExtensionSpec classes with extension version meta [#297]
    • Apply slot="i-amphtml-svc" to i-amphtml-sizer elements. [#316]
    • Allow CSS max byte count enforcement in TransformedIdentifier transformer to be configured [#319]

    Bugfixes

    • Preserve mustache tag wrapped in comment inside template element [#305]
    • Add LIBXML_SCHEMA_CREATE flag in Dom\Document filter [#322]
    • Fix missing amp binary in the distribution package [#310]

    Dependencies

    • Update validator spec - 2021-07-29 [#296]
    • Regenerate validator spec with new Extension constants [#298]
    • Update sirbrillig/phpcs-variable-analysis requirement from 2.11.1 to 2.11.2 [#273]

    Meta

    • Migrate PHPUnit configuration file over to latest schema [#332]
    • Prepare tests for running in process isolation [#329]
    • Add randomly-ordered unit test run to GHA workflow [#328]
    • Disable the Codecov annotations check [#307]
    • Sync spec test suite [#266, #278, #287]
    Source code(tar.gz)
    Source code(zip)
  • 0.6.0(Oct 27, 2021)

    Changes

    • Add validator spec via code generation [#100, #221]
    • Add option to detect malformed byte sequences [#200]
    • Add comment about mb_detect_encoding() performance [#186]
    • Add SSR support for fluid layout [#181]
    • Add resource hints transformers [#179]
    • Deprecate PreloadHeroImage for OptimizeHeroImages [#262]
    • Disable AMP runtime preloading by default [#261]
    • Add support for amp-onerror on transformed pages (with ESM scripts) [#211, #218]

    Bugfixes

    • Correct sort of transformers to fix preload hero images [#209]
    • Skip broken boilerplate error handler spec test [#229]
    • Use maxBytes from Spec instead of hard-coding it [#231]
    • Point OptimizeAmpBind spec tests to valid instead of experimental [#174]

    Dependencies

    • Update validator spec - 2021-06-24 [#258]
    • Sync local fallback files [#216]
    • Sync spec test suite [#166, #206, #215, #235, #240, #244, #257]
    • Update sirbrillig/phpcs-variable-analysis requirement from 2.11.0 to 2.11.1 [#250]
    • Update yoast/phpunit-polyfills requirement from ^0.2.0 to ^0.2.0 || ^1.0.0 [#249]

    Meta

    • Upgrade to GitHub-native Dependabot [#172]
    • Add codecov token [#230]
    • Add WPCS for inline doc and comments [#254]
    Source code(tar.gz)
    Source code(zip)
  • 0.5.2(May 6, 2021)

  • 0.5.1(May 4, 2021)

  • 0.5.0(Apr 29, 2021)

    Changes

    • Add OptimizeAmpBind transformer [#162]
    • Add toArray() to transformer configuration [#154]
    • Add missing constants for AMP-WP #6112 [#169]

    Meta

    • Replace Codecov bash uploader with GHA counterpart [#158]
    • Fix covers annotation for CLI exceptions and improve overall coverage [#167]
    Source code(tar.gz)
    Source code(zip)
  • 0.4.0(Apr 13, 2021)

    Changes

    • Add RewriteAmpUrls transformer [#119]
    • Add AmpBoilerplateErrorHandler transformer [#148]
    • Make Configuration extensible [#150] (⚠breaking change)
    • Include candidate hero images after paragraphs and persist loading attribute on noscript > img fallback [#149]
    • Add more dynamic logging behavior [#146]
    • Add crossorigin=anonymous to nomodule scripts [#140]
    • Prevent SSR for amp-img occurring after second paragraph [#141]

    Bugfixes

    • Fix SSR for nested AMP components [#122]
    • Fix tiny image detection inside responsive parent [#144]
    • Check hero image media attribute before srcset [#136]
    • Only construct preload if it is needed [#135]
    • Fix deduplication of AMP scripts and improve ReorderHead transformer [#130]
    • Calling curl_errno() before closing the connection throws an error [#128]

    Dependencies

    Meta

    • Add autoloader scenario for package as dependency [#145]
    • Replace PHPCS exclude-pattern with explicit file includes [#133]
    • Add amp binary to Composer "bin" directive [#139]
    Source code(tar.gz)
    Source code(zip)
  • 0.3.0(Mar 29, 2021)

    Changes

    • Add CLI tool [#92]

    Bugfixes

    • Remove hard-coded isTiny() result for intrinsic layout [#115]
    • Prevent loading=lazy attribute from being removed from amp-story-player poster img [#106]

    Dependencies

    Source code(tar.gz)
    Source code(zip)
  • 0.2.0(Mar 18, 2021)

    Changes

    • Add support for a data-hero-candidate attribute [#86]
    • Enforce CSS byte count limit across all inline style additions and inline object-* attributes [#29]
    • Support dimensions with units [#49]
    • Use magic $html property in normalizeHtmlAttributes() [#30]

    Bugfixes

    • Fix wrongly URL-encoded src attributes in Mustache templates [#104]
    • Fix broken encoding when using document fragments [#99]
    • Parse document correctly when AMP emoji is used [#79]
    • Secure HTML entities within template text [#54]
    • Fix @covers annotations [#46]
    • Fix broken spec test for converting intrinsic layout [#39]
    • Change padding calculation from round() to number_format() [#38]
    • Skip escaped slashes when normalizing self-closing tags [#36]

    Dependencies

    • Sync local fallback files [#35, #66, #70, #77, #80, #81, #88, #93, #94, #95, #97]
    • Sync spec test suite [#45, #56, #71, #76#85]
    • Update composer command in docs [#23]
    • Update civicrm/composer-downloads-plugin requirement from ^2.1 to ^2.1 || ^3.0 [#3]
    • Update dealerdirect/phpcodesniffer-composer-installer requirement from 0.7.0 to 0.7.1 [#43]
    • Update phpcompatibility/phpcompatibility-wp requirement from 2.1.0 to 2.1.1 [#72]
    • Update sirbrillig/phpcs-variable-analysis requirement from 2.9.0 to 2.11.0 [#44, #52, #101]

    Meta

    • Add automerge workflow [#96]
    • Add code coverage collection [#50]
    • Add GHA workflow to sync test suite and create PR [#58]
    • Avoid running sync on composer update [#64]
    • Improve PHPUnit integration [#40]
    • Raise PHPStan level to 5 [#42]
    • Run tests on all pushes [#78]
    Source code(tar.gz)
    Source code(zip)
  • 0.1.1(Dec 11, 2020)

  • 0.1.0(Nov 6, 2020)

Owner
AMP
AMP
Artax is an asynchronous HTTP client for PHP based on Amp

Artax is an asynchronous HTTP client for PHP based on Amp. Its API simplifies standards-compliant HTTP resource traversal and RESTful web service consumption without obscuring the underlying protocol. The library manually implements HTTP over TCP sockets; as such it has no dependency on ext/curl.

AMPHP 21 Dec 14, 2022
An async process dispatcher for Amp.

process This package provides an asynchronous process dispatcher that works on all major platforms (including Windows). As Windows pipes are file hand

AMPHP 204 Jan 8, 2023
Dobren Dragojević 6 Jun 11, 2023
Easy to use utility functions for everyday PHP projects. This is a port of the Lodash JS library to PHP

Lodash-PHP Lodash-PHP is a port of the Lodash JS library to PHP. It is a set of easy to use utility functions for everyday PHP projects. Lodash-PHP tr

Lodash PHP 474 Dec 31, 2022
PHP Text Analysis is a library for performing Information Retrieval (IR) and Natural Language Processing (NLP) tasks using the PHP language

php-text-analysis PHP Text Analysis is a library for performing Information Retrieval (IR) and Natural Language Processing (NLP) tasks using the PHP l

null 464 Dec 28, 2022
php-echarts is a php library for the echarts 5.0.

php-echarts 一款支持Apache EChart5.0+图表的php开发库 优先ThinkPHP5/6的开发及测试。 Apache EChart5.0已经最新发布,在视觉效果、动画效果和大数据展示方面已经远超之前的版本; 故不考虑EChart5.0之前版本的兼容问题;建议直接尝试5.0+

youyiio 5 Aug 15, 2022
Minimalist PHP frame for Core-Library, for Developing PHP application that gives you the full control of your application.

LazyPHP lightweight Pre-Made Frame for Core-library Install Run the below command in your terminal $ composer create-project ryzen/lazyphp my-first-pr

Ry-Zen 7 Aug 21, 2022
Gettext is a PHP (^7.2) library to import/export/edit gettext from PO, MO, PHP, JS files, etc.

Gettext Note: this is the documentation of the new 5.x version. Go to 4.x branch if you're looking for the old 4.x version Created by Oscar Otero http

Gettext 651 Dec 29, 2022
Columnar analytics for PHP - a pure PHP library to read and write simple columnar files in a performant way.

Columnar Analytics (in pure PHP) On GitHub: https://github.com/envoymediagroup/columna About the project What does it do? This library allows you to w

Envoy Media Group 2 Sep 26, 2022
:date: The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects

sabre/vobject The VObject library allows you to easily parse and manipulate iCalendar and vCard objects using PHP. The goal of the VObject library is

sabre.io 532 Dec 25, 2022
Small convention based CQRS library for PHP

LiteCQRS for PHP Small naming-convention based CQRS library for PHP (loosely based on LiteCQRS for C#) that relies on the MessageBus, Command, EventSo

Benjamin Eberlei 560 Nov 20, 2022
Experimental library for forking PHP

Spork: PHP on a Fork <?php $manager = new Spork\ProcessManager(); $manager->fork(function() { // do something in another process! return 'Hel

Kris Wallsmith 588 Nov 20, 2022
Collection pipeline library for PHP

Knapsack Collection pipeline library for PHP Knapsack is a collection library for PHP >= 5.6 that implements most of the sequence operations proposed

Dušan Kasan 540 Dec 17, 2022
A PHP library to play with the Raspberry PI's GPIO pins

php-gpio php-gpio is a simple PHP library to play with the Raspberry PI's GPIO pins. It provides simple tools such as reading & writing to pins. [UPDA

Ronan Guilloux 266 Oct 17, 2022
PHP library for dealing with European VAT

ibericode/vat This is a simple PHP library to help you deal with Europe's VAT rules. Fetch VAT rates for any EU member state using ibericode/vat-rates

ibericode 389 Dec 31, 2022
iOS passbook library for PHP 5.4+

PHP PASSBOOK LIBRARY What is Passbook? Passbook is an application in iOS that allows users to store coupons, boarding passes, event tickets, store car

Eymen Gunay 256 Nov 17, 2022
Sslurp is a simple library which aims to make properly dealing with SSL in PHP suck less.

Sslurp v1.0 by Evan Coury Introduction Dealing with SSL properly in PHP is a pain in the ass and completely insecure by default. Sslurp aims to make i

Evan Coury 65 Oct 14, 2022
A framework agnostic PHP library to build chat bots

BotMan If you want to learn how to create reusable PHP packages yourself, take a look at my upcoming PHP Package Development video course. About BotMa

BotMan 5.8k Jan 1, 2023