You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

187 lines
6.3 KiB
PHP

<?php
/**
* Class Optimization
*
* @link https://github.com/googleforcreators/web-stories-wp
*
* @copyright 2020 Google LLC
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
*/
/**
* Copyright 2020 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
declare(strict_types = 1);
namespace Google\Web_Stories\AMP;
use Google\Web_Stories_Dependencies\AmpProject\AmpWP\RemoteRequest\CachedRemoteGetRequest;
use Google\Web_Stories_Dependencies\AmpProject\AmpWP\RemoteRequest\WpHttpRemoteGetRequest;
use Google\Web_Stories_Dependencies\AmpProject\Dom\Document;
use Google\Web_Stories_Dependencies\AmpProject\Optimizer\Configuration;
use Google\Web_Stories_Dependencies\AmpProject\Optimizer\Configuration\AmpStoryCssOptimizerConfiguration;
use Google\Web_Stories_Dependencies\AmpProject\Optimizer\DefaultConfiguration;
use Google\Web_Stories_Dependencies\AmpProject\Optimizer\Error;
use Google\Web_Stories_Dependencies\AmpProject\Optimizer\ErrorCollection;
use Google\Web_Stories_Dependencies\AmpProject\Optimizer\LocalFallback;
use Google\Web_Stories_Dependencies\AmpProject\Optimizer\TransformationEngine;
use Google\Web_Stories_Dependencies\AmpProject\Optimizer\Transformer\AmpRuntimeCss;
use Google\Web_Stories_Dependencies\AmpProject\Optimizer\Transformer\AmpStoryCssOptimizer;
use Google\Web_Stories_Dependencies\AmpProject\Optimizer\Transformer\MinifyHtml;
use Google\Web_Stories_Dependencies\AmpProject\Optimizer\Transformer\OptimizeAmpBind;
use Google\Web_Stories_Dependencies\AmpProject\Optimizer\Transformer\OptimizeHeroImages;
use Google\Web_Stories_Dependencies\AmpProject\Optimizer\Transformer\RewriteAmpUrls;
use Google\Web_Stories_Dependencies\AmpProject\Optimizer\Transformer\ServerSideRendering;
use Google\Web_Stories_Dependencies\AmpProject\Optimizer\Transformer\TransformedIdentifier;
use Google\Web_Stories_Dependencies\AmpProject\RemoteRequest\FallbackRemoteGetRequest;
use Google\Web_Stories_Dependencies\AmpProject\RemoteRequest\FilesystemRemoteGetRequest;
/**
* Optimization class.
*
* @since 1.1.0
*/
class Optimization {
/**
* Optimizes a document.
*
* @since 1.1.0
*
* @param Document $document Document instance.
*/
public function optimize_document( Document $document ): void {
$errors = new ErrorCollection();
$this->get_optimizer()->optimizeDom( $document, $errors );
if ( \count( $errors ) > 0 ) {
/**
* Error list.
*
* @var Error[] $errors_array Error list.
*/
$errors_array = iterator_to_array( $errors );
$error_messages = array_filter(
array_map(
static function ( Error $error ) {
// Hidden because amp-story is a render-delaying extension.
if ( 'CannotRemoveBoilerplate' === $error->getCode() ) {
return '';
}
return ' - ' . $error->getCode() . ': ' . $error->getMessage();
},
$errors_array
)
);
if ( ! empty( $error_messages ) ) {
$document->head->appendChild(
$document->createComment( "\n" . __( 'AMP optimization could not be completed due to the following:', 'web-stories' ) . "\n" . implode( "\n", $error_messages ) . "\n" )
);
}
}
}
/**
* Optimizer instance to use.
*
* @since 1.1.0
*
* @link https://github.com/ampproject/amp-wp/blob/8856284d90fc8558c30acc029becd352ae26e4e1/includes/class-amp-theme-support.php#L2235-L2255
* @see AMP_Theme_Support::get_optimizer
*
* @return TransformationEngine Optimizer transformation engine to use.
*/
private function get_optimizer(): TransformationEngine {
$configuration = self::get_optimizer_configuration();
$fallback_remote_request_pipeline = new FallbackRemoteGetRequest(
new WpHttpRemoteGetRequest(),
new FilesystemRemoteGetRequest( LocalFallback::getMappings() )
);
$cached_remote_request = new CachedRemoteGetRequest( $fallback_remote_request_pipeline, WEEK_IN_SECONDS );
return new TransformationEngine(
$configuration,
$cached_remote_request
);
}
/**
* Get the AmpProject\Optimizer configuration object to use.
*
* @since 1.1.0
*
* @link https://github.com/ampproject/amp-wp/blob/5405daa38e65f0ec16ffc920014d0110b03ee773/src/Optimizer/AmpWPConfiguration.php#L43-L78
* @see AmpWPConfiguration::apply_filters()
*
* @return Configuration Optimizer configuration to use.
*/
private static function get_optimizer_configuration(): Configuration {
$transformers = Configuration::DEFAULT_TRANSFORMERS;
$transformers[] = AmpStoryCssOptimizer::class;
/**
* Filter whether the AMP Optimizer should use server-side rendering or not.
*
* @since 1.1.0
*
* @param bool $enable_ssr Whether the AMP Optimizer should use server-side rendering or not.
*/
$enable_ssr = apply_filters( 'web_stories_enable_ssr', true );
// In debugging mode, we don't use server-side rendering, as it further obfuscates the HTML markup.
if ( ! $enable_ssr ) {
$transformers = array_diff(
$transformers,
[
AmpRuntimeCss::class,
OptimizeHeroImages::class,
OptimizeAmpBind::class,
RewriteAmpUrls::class,
ServerSideRendering::class,
TransformedIdentifier::class,
AmpStoryCssOptimizer::class,
]
);
}
$configuration = [
Configuration::KEY_TRANSFORMERS => $transformers,
AmpStoryCssOptimizer::class => [
AmpStoryCssOptimizerConfiguration::OPTIMIZE_AMP_STORY => true,
],
MinifyHtml::class => [
// Prevents issues with rounding floats, relevant for things like shopping (product prices).
Configuration\MinifyHtmlConfiguration::MINIFY_JSON => false,
],
];
/**
* Filter the configuration to be used for the AMP Optimizer.
*
* @since 1.1.0
*
* @param array $configuration Associative array of configuration data.
*/
$configuration = apply_filters( 'web_stories_amp_optimizer_config', $configuration );
return new DefaultConfiguration( $configuration );
}
}