feat: initial ACRIB WordPress deployment
- WordPress 6.9.4 (es_ES) with Kadence theme - Homepage: Hero, La Asociación, Pilares, Beneficios, Eventos, Miembros, Hazte Miembro, Contacto - Brand identity: #13294b navy, #a12932 burgundy, #c69c48 gold - Fonts: Raleway (headings) + Source Sans 3 (body) + Lato (UI) - Plugins: Kadence Blocks, Polylang, Contact Form 7 - Custom CSS with full brand styling and responsive layout - HTTPS enforced via wp-config.php proxy detection
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
<?php declare( strict_types=1 );
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\Optimizer\Image\Contracts;
|
||||
|
||||
use KadenceWP\KadenceBlocks\Optimizer\Response\ImageAnalysis;
|
||||
use WP_HTML_Tag_Processor;
|
||||
|
||||
/**
|
||||
* Process an img tag to manipulate its markup before the HTML is send back
|
||||
* to the browser.
|
||||
*/
|
||||
interface Processor {
|
||||
|
||||
/**
|
||||
* Manipulates img tags.
|
||||
*
|
||||
* @param WP_HTML_Tag_Processor $p The HTML Tag Processor, set on the current image it's processing.
|
||||
* @param string[] $critical_images The array of critical image src's.
|
||||
* @param array<string, ImageAnalysis> $images The array of all collected images indexed by a unique key.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process( WP_HTML_Tag_Processor $p, array $critical_images, array $images ): void;
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
<?php declare( strict_types=1 );
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\Optimizer\Image;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use KadenceWP\KadenceBlocks\Optimizer\Enums\Viewport;
|
||||
use KadenceWP\KadenceBlocks\Optimizer\Image\Contracts\Processor;
|
||||
use KadenceWP\KadenceBlocks\Optimizer\Image\Traits\Image_Key_Generator_Trait;
|
||||
use KadenceWP\KadenceBlocks\Optimizer\Path\Path;
|
||||
use KadenceWP\KadenceBlocks\Optimizer\Path\Path_Factory;
|
||||
use KadenceWP\KadenceBlocks\Optimizer\Skip_Rules\Rule_Collection;
|
||||
use KadenceWP\KadenceBlocks\Optimizer\Store\Contracts\Store;
|
||||
use KadenceWP\KadenceBlocks\Psr\Log\LoggerInterface;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\SuperGlobals\SuperGlobals as SG;
|
||||
use KadenceWP\KadenceBlocks\Traits\Viewport_Trait;
|
||||
use WP_HTML_Tag_Processor;
|
||||
|
||||
/**
|
||||
* Modify HTML img tags before the HTML is sent back to the browser:
|
||||
*
|
||||
* - 1. Set correct lazy load attributes.
|
||||
* - 2. Set the optimal sizes attribute.
|
||||
*/
|
||||
final class Image_Processor {
|
||||
|
||||
use Viewport_Trait;
|
||||
use Image_Key_Generator_Trait;
|
||||
|
||||
private Store $store;
|
||||
private Rule_Collection $rules;
|
||||
private Path_Factory $path_factory;
|
||||
|
||||
/**
|
||||
* The list of image processors.
|
||||
*
|
||||
* @var Processor[]
|
||||
*/
|
||||
private array $processors;
|
||||
|
||||
/**
|
||||
* The logger.
|
||||
*
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
private LoggerInterface $logger;
|
||||
|
||||
/**
|
||||
* @param Store $store The optimization store.
|
||||
* @param Rule_Collection $rules The rule collection.
|
||||
* @param Path_Factory $path_factory The path factory.
|
||||
* @param LoggerInterface $logger The logger.
|
||||
* @param Processor[] $processors The list of image processors.
|
||||
*/
|
||||
public function __construct(
|
||||
Store $store,
|
||||
Rule_Collection $rules,
|
||||
Path_Factory $path_factory,
|
||||
LoggerInterface $logger,
|
||||
array $processors
|
||||
) {
|
||||
$this->store = $store;
|
||||
$this->rules = $rules;
|
||||
$this->path_factory = $path_factory;
|
||||
$this->logger = $logger;
|
||||
$this->processors = $processors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Begin buffering the request.
|
||||
*
|
||||
* @action template_redirect
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function start_buffering(): void {
|
||||
// Process skip rules and bypass buffering.
|
||||
foreach ( $this->rules->all() as $rule ) {
|
||||
if ( $rule->should_skip() ) {
|
||||
$this->logger->debug(
|
||||
'Skipping Image Processor Buffering: skip rule',
|
||||
[
|
||||
'rule' => get_class( $rule ),
|
||||
'request_uri' => SG::get_server_var( 'REQUEST_URI', 'unknown' ),
|
||||
]
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ob_start( [ $this, 'stop_buffering' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify each image using our collection of image processors.
|
||||
*
|
||||
* @see self::stop_buffering()
|
||||
*
|
||||
* @param string $html The HTML WordPress will render.
|
||||
* @param Path $path The current path object.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function process_images( string $html, Path $path ): string {
|
||||
$analysis = $this->store->get( $path );
|
||||
|
||||
if ( ! $analysis ) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
$device = $analysis->getDevice( Viewport::current( $this->is_mobile() ) );
|
||||
$critical_images = $device ? $device->criticalImages : [];
|
||||
$images = $analysis->images;
|
||||
|
||||
$images_by_key = [];
|
||||
|
||||
// Reshape the array so we can do O(1) lookups.
|
||||
foreach ( $images as $image ) {
|
||||
if ( isset( $image->src, $image->sizes ) ) {
|
||||
$key = $this->generate_image_key( $image->src, $image->sizes );
|
||||
|
||||
if ( $key !== null ) {
|
||||
$images_by_key[ $key ] = $image;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$p = new WP_HTML_Tag_Processor( $html );
|
||||
|
||||
// Add the kb-optimized class to the body.
|
||||
if ( $p->next_tag( 'body' ) ) {
|
||||
$p->add_class( 'kb-optimized' );
|
||||
}
|
||||
|
||||
// Run each image through all image processors.
|
||||
while ( $p->next_tag( 'img' ) ) {
|
||||
$src = $p->get_attribute( 'src' );
|
||||
$classes = $p->get_attribute( 'class' );
|
||||
|
||||
foreach ( $this->processors as $processor ) {
|
||||
|
||||
/**
|
||||
* Allow short-circuiting of processing this image for the
|
||||
* current processor.
|
||||
*
|
||||
* @param bool $should_process Whether we proceed with processing. Defaults to true.
|
||||
* @param string $src The image src.
|
||||
* @param string|null $classes The classes assigned to the img tag.
|
||||
* @param Processor $processor The current processor instance.
|
||||
* @param Path $post The current path object.
|
||||
*/
|
||||
$should_process = apply_filters(
|
||||
'kadence_blocks_optimizer_image_processor',
|
||||
true,
|
||||
$src,
|
||||
$classes,
|
||||
$processor,
|
||||
$path
|
||||
);
|
||||
|
||||
if ( $should_process ) {
|
||||
$processor->process( $p, $critical_images, $images_by_key );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $p->get_updated_html();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback that receives the buffer's contents.
|
||||
*
|
||||
* @see wp_ob_end_flush_all()
|
||||
* @action shutdown
|
||||
*
|
||||
* @param string $html The HTML WordPress will render.
|
||||
* @param int $phase The bitmask of the PHP_OUTPUT_HANDLER_* constants.
|
||||
*
|
||||
* @return string The modified HTML with lazy loaded and optimal image sizes.
|
||||
*/
|
||||
private function stop_buffering( string $html, int $phase ): string {
|
||||
if ( ! ( $phase & PHP_OUTPUT_HANDLER_FINAL ) ) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
try {
|
||||
$path = $this->path_factory->make();
|
||||
} catch ( InvalidArgumentException $e ) {
|
||||
$this->logger->error(
|
||||
'Failed to get path in image processor buffering',
|
||||
[
|
||||
'exception' => $e,
|
||||
]
|
||||
);
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
return $this->process_images( $html, $path );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php declare( strict_types=1 );
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\Optimizer\Image\Processors;
|
||||
|
||||
use KadenceWP\KadenceBlocks\Optimizer\Image\Contracts\Processor;
|
||||
use KadenceWP\KadenceBlocks\Optimizer\Response\ImageAnalysis;
|
||||
use WP_HTML_Tag_Processor;
|
||||
|
||||
final class Lazy_Load_Processor implements Processor {
|
||||
|
||||
/**
|
||||
* A queue of URLs that are above the fold.
|
||||
*
|
||||
* @var string[]|null
|
||||
*/
|
||||
private ?array $critical_image_queue = null;
|
||||
|
||||
/**
|
||||
* Add or remove the appropriate lazy loading attributes. It's important to note that WordPress
|
||||
* may have already added a loading=lazy attribute to an image that shouldn't have it.
|
||||
*
|
||||
* @param WP_HTML_Tag_Processor $p The HTML Tag Processor, set on the current image it's processing.
|
||||
* @param string[] $critical_images The list of the above the fold image URLs.
|
||||
* @param array<string, ImageAnalysis> $images The array of all collected images indexed by a unique key.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process( WP_HTML_Tag_Processor $p, array $critical_images, array $images ): void {
|
||||
$src = (string) $p->get_attribute( 'src' );
|
||||
|
||||
// Don't lazy load data URLs.
|
||||
if ( str_starts_with( $src, 'data:' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize the queue on first run.
|
||||
if ( ! isset( $this->critical_image_queue ) ) {
|
||||
$this->critical_image_queue = $critical_images;
|
||||
}
|
||||
|
||||
// Check if this image is next in our critical queue.
|
||||
if ( $this->critical_image_queue ) {
|
||||
$queue_index = array_search( $src, $this->critical_image_queue, true );
|
||||
|
||||
if ( $queue_index !== false ) {
|
||||
// Remove lazy loading for critical image.
|
||||
if ( 'lazy' === $p->get_attribute( 'loading' ) ) {
|
||||
$p->remove_attribute( 'loading' );
|
||||
}
|
||||
|
||||
// Remove this occurrence from the queue.
|
||||
unset( $this->critical_image_queue[ $queue_index ] );
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Below the fold logic (or after all critical images processed).
|
||||
$p->set_attribute( 'loading', 'lazy' );
|
||||
|
||||
// If WordPress somehow added a high fetch priority, remove it.
|
||||
if ( 'high' === $p->get_attribute( 'fetchpriority' ) ) {
|
||||
$p->remove_attribute( 'fetchpriority' );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php declare( strict_types=1 );
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\Optimizer\Image\Processors;
|
||||
|
||||
use KadenceWP\KadenceBlocks\Optimizer\Image\Contracts\Processor;
|
||||
use KadenceWP\KadenceBlocks\Optimizer\Image\Traits\Image_Key_Generator_Trait;
|
||||
use KadenceWP\KadenceBlocks\Optimizer\Response\ImageAnalysis;
|
||||
use WP_HTML_Tag_Processor;
|
||||
|
||||
final class Sizes_Attribute_Processor implements Processor {
|
||||
|
||||
use Image_Key_Generator_Trait;
|
||||
|
||||
/**
|
||||
* Set the optimal sizes attribute for the image.
|
||||
*
|
||||
* @param WP_HTML_Tag_Processor $p The HTML Tag Processor, set on the current image it's processing.
|
||||
* @param string[] $critical_images The array of critical image src's.
|
||||
* @param array<string, ImageAnalysis> $images The array of all collected images indexed by a unique key.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function process( WP_HTML_Tag_Processor $p, array $critical_images, array $images ): void {
|
||||
// The analyzer doesn't collect images without a srcset.
|
||||
$srcset = $p->get_attribute( 'srcset' );
|
||||
|
||||
if ( ! $srcset ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$src = $p->get_attribute( 'src' );
|
||||
$sizes = $p->get_attribute( 'sizes' );
|
||||
|
||||
$key = $this->generate_image_key( $src, $sizes );
|
||||
|
||||
if ( null === $key ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$image = $images[ $key ] ?? false;
|
||||
|
||||
if ( ! $image instanceof ImageAnalysis ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the sizes attribute with our optimal sizes.
|
||||
if ( $image->optimalSizes ) {
|
||||
$p->set_attribute( 'sizes', $image->optimalSizes );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php declare( strict_types=1 );
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\Optimizer\Image;
|
||||
|
||||
use KadenceWP\KadenceBlocks\Optimizer\Image\Processors\Lazy_Load_Processor;
|
||||
use KadenceWP\KadenceBlocks\Optimizer\Image\Processors\Sizes_Attribute_Processor;
|
||||
use KadenceWP\KadenceBlocks\StellarWP\ProphecyMonorepo\Container\Contracts\Provider as Provider_Contract;
|
||||
|
||||
final class Provider extends Provider_Contract {
|
||||
|
||||
public function register(): void {
|
||||
$this->container->singleton( Lazy_Load_Processor::class, Lazy_Load_Processor::class );
|
||||
$this->container->singleton( Image_Processor::class, Image_Processor::class );
|
||||
|
||||
$this->container->when( Image_Processor::class )
|
||||
->needs( '$processors' )
|
||||
->give(
|
||||
fn(): array => [
|
||||
// Add additional image processors here.
|
||||
$this->container->get( Lazy_Load_Processor::class ),
|
||||
$this->container->get( Sizes_Attribute_Processor::class ),
|
||||
]
|
||||
);
|
||||
|
||||
add_action(
|
||||
'template_redirect',
|
||||
$this->container->callback( Image_Processor::class, 'start_buffering' ),
|
||||
1,
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php declare( strict_types=1 );
|
||||
|
||||
namespace KadenceWP\KadenceBlocks\Optimizer\Image\Traits;
|
||||
|
||||
trait Image_Key_Generator_Trait {
|
||||
|
||||
/**
|
||||
* Generate a unique key for indexing image data.
|
||||
*
|
||||
* @param string|null|bool $src The image source URL.
|
||||
* @param string|null|bool $sizes The image sizes attribute.
|
||||
*
|
||||
* @return string|null A unique key or null if inputs are missing or non-string.
|
||||
*/
|
||||
private function generate_image_key( $src, $sizes ): ?string {
|
||||
// Only allow actual strings.
|
||||
if ( ! is_string( $src ) || ! is_string( $sizes ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Bypass empty attributes.
|
||||
if ( $src === '' || $sizes === '' ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return md5( $src . '|' . $sizes );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user