Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: enhancement

Tiled Gallery: add a `jetpack_skip_photon_domain` filter to serve images from the origin host (keeping the resizing query args) instead of routing them through the Photon domain, for platforms with a built-in image service such as WordPress VIP.
2 changes: 2 additions & 0 deletions projects/plugins/jetpack/class.jetpack-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,8 @@ public static function enqueue_block_editor_assets() {
'jetpack_plan' => array(
'data' => $jetpack_plan['product_slug'],
),
/** This filter is documented in modules/tiled-gallery/tiled-gallery/tiled-gallery-item.php */
'skip_photon_domain' => (bool) apply_filters( 'jetpack_skip_photon_domain', false ),
/**
* Enable the RePublicize UI in the block editor context.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ public static function render( $attr, $content ) {
$jetpack_plan = Jetpack_Plan::get();
wp_localize_script( 'jetpack-gallery-settings', 'jetpack_plan', array( 'data' => $jetpack_plan['product_slug'] ) );

/** This filter is documented in modules/tiled-gallery/tiled-gallery/tiled-gallery-item.php */
$skip_photon_domain = (bool) apply_filters( 'jetpack_skip_photon_domain', false );
// Expose the opt-out flag to the block's save-time JS (see photonizedImgProps() in utils/index.js).
wp_localize_script( 'jetpack-gallery-settings', 'jetpack_tiled_gallery_settings', array( 'skip_photon_domain' => $skip_photon_domain ) );

if ( preg_match_all( '/<img [^>]+>/', $content, $images ) ) {
/**
* This block processes all of the images that are found and builds $find and $replace.
Expand Down Expand Up @@ -103,6 +108,13 @@ public static function render( $attr, $content ) {
continue;
}

// When the site opts out of the Photon domain, rewrite any already-baked-in
// i0.wp.com URLs back to their origin host so the srcset (and main src, below)
// serve from origin.
if ( $skip_photon_domain ) {
$orig_src = self::dephotonize_url( $orig_src, $is_ssl );
}

$srcset_parts = array();
if ( $is_squareish_layout ) {
$min_width = min( self::IMG_SRCSET_WIDTH_MIN, $orig_width, $orig_height );
Expand All @@ -116,7 +128,8 @@ public static function render( $attr, $content ) {
),
$orig_src
);
if ( $is_ssl ) {
// `ssl` is a Photon-only signal; skip it on origin URLs when opting out of the Photon domain.
if ( $is_ssl && ! $skip_photon_domain ) {
$srcset_src = add_query_arg( 'ssl', '1', $srcset_src );
}
$srcset_parts[] = esc_url( $srcset_src ) . ' ' . $w . 'w';
Expand All @@ -136,7 +149,8 @@ public static function render( $attr, $content ) {
),
$orig_src
);
if ( $is_ssl ) {
// `ssl` is a Photon-only signal; skip it on origin URLs when opting out of the Photon domain.
if ( $is_ssl && ! $skip_photon_domain ) {
$srcset_src = add_query_arg( 'ssl', '1', $srcset_src );
}
$srcset_parts[] = esc_url( $srcset_src ) . ' ' . $w . 'w';
Expand All @@ -151,8 +165,20 @@ public static function render( $attr, $content ) {
if ( ! empty( $srcset_parts ) ) {
$srcset = 'srcset="' . esc_attr( implode( ',', $srcset_parts ) ) . '"';

$replacement = str_replace( '<img', $img_element . $srcset, $image_html );

// Also rewrite the main src attribute off i0.wp.com when opting out of the
// Photon domain so pre-existing content serves the image itself from origin.
if ( $skip_photon_domain ) {
$replacement = str_replace(
$img_src[1],
self::dephotonize_url( $img_src[1], $is_ssl ),
$replacement
);
}

$find[] = $image_html;
$replace[] = str_replace( '<img', $img_element . $srcset, $image_html );
$replace[] = $replacement;
}
}
}
Expand Down Expand Up @@ -218,6 +244,29 @@ private static function is_squareish_layout( $attr ) {
);
}

/**
* Rewrite a Photon (i0/i1/i2.wp.com) image URL back to its origin host.
*
* Photon URLs take the form https://i0.wp.com/<origin-host>/<path>?<args>. This restores
* the origin URL (<scheme>://<origin-host>/<path>?<args>) so that, when a site opts out of
* the Photon domain via the `jetpack_skip_photon_domain` filter, tiled gallery images are served
* from the origin host while keeping their resizing query args. The Photon-specific `ssl`
* argument is dropped. URLs that are not Photon URLs are returned unchanged.
*
* @param string $url The (possibly Photon) image URL.
* @param bool $is_ssl Whether the origin URL should use https (detected from the Photon ssl arg).
* @return string The origin URL, or the original URL if it was not a Photon URL.
*/
private static function dephotonize_url( $url, $is_ssl = true ) {
if ( ! preg_match( '#^(?:https?:)?//i[0-2]\.wp\.com/(.+)$#', $url, $matches ) ) {
return $url;
}

$origin = ( $is_ssl ? 'https://' : 'http://' ) . $matches[1];

return remove_query_arg( 'ssl', $origin );
}

/**
* Render tiled gallery block for email.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ export function photonizedImgProps( img, galleryAtts = {} ) {
const { height, width } = img;
const { layoutStyle } = galleryAtts;

const photonImplementation = true === isVIP() || isSimpleSite() ? photonWpcomImage : photon;
// When a site opts out of the Photon domain (e.g. VIP with a platform image service), keep the
// origin host and just append the resizing query args — the behavior `photonWpcomImage` provides.
const photonImplementation =
skipPhotonDomain() || true === isVIP() || isSimpleSite() ? photonWpcomImage : photon;

/**
* Build the `src`
Expand Down Expand Up @@ -129,6 +132,25 @@ function isVIP() {
return jetpackPlan && jetpackPlan?.data === 'vip';
}

/**
* Whether the site has opted out of routing tiled gallery images through the Photon domain via the
* `jetpack_skip_photon_domain` PHP filter. The value is exposed to the editor through the Jetpack
* block editor initial state, with a localized `jetpack_tiled_gallery_settings` fallback (both set
* in tiled-gallery.php / class.jetpack-gutenberg.php).
*
* @return {boolean} True if the Photon domain should be skipped in favor of origin URLs.
*/
function skipPhotonDomain() {
/*global jetpack_tiled_gallery_settings*/
if ( typeof window?.Jetpack_Editor_Initial_State?.jetpack?.skip_photon_domain !== 'undefined' ) {
return !! window.Jetpack_Editor_Initial_State.jetpack.skip_photon_domain;
}
if ( typeof jetpack_tiled_gallery_settings !== 'undefined' ) {
return !! jetpack_tiled_gallery_settings?.skip_photon_domain;
}
return false;
}

/**
* Apply photon arguments to *.files.wordpress.com images
* or images on mapped domains on private simple sites.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,12 @@ public function gallery_shortcode( $val, $atts ) {

if ( $gallery_html && class_exists( 'Jetpack' ) && class_exists( Image_CDN::class ) ) {
// Tiled Galleries in Jetpack require that Photon be active.
// If it's not active, run it just on the gallery output.
if ( ! Image_CDN::is_enabled() && ! ( new Status() )->is_offline_mode() ) {
// If it's not active, run it just on the gallery output — unless the site has
// opted out of Photon for tiled galleries (e.g. VIP with a built-in image service),
// in which case we must not rewrite the origin URLs back onto i0.wp.com.
/** This filter is documented in modules/tiled-gallery/tiled-gallery/tiled-gallery-item.php */
if ( ! apply_filters( 'jetpack_skip_photon_domain', false )
&& ! Image_CDN::is_enabled() && ! ( new Status() )->is_offline_mode() ) {
$gallery_html = Image_CDN::filter_the_content( $gallery_html );
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,33 @@ public function __construct( $attachment_image, $needs_attachment_link, $graysca
if ( $this->image->height === $this->image->width ) {
$img_args['crop'] = true;
}
// The function will always photonoize the URL (even if Photon is
// not active). We need to photonize the URL to set the width/height.
$this->img_src = Image_CDN_Core::cdn_url( $this->orig_file, $img_args );
/**
* Allow sites to opt out of routing Tiled Gallery images through the Photon domain (the
* Jetpack Image CDN / i0.wp.com), while still appending the same resizing query args the
* tiled layout needs (w, h, crop, resize, strip).
*
* This is primarily intended for platforms such as WordPress VIP where a Photon-equivalent
* image service is built in and already understands those query args on the origin host, so
* rewriting URLs onto i0.wp.com is redundant or undesirable.
*
* When this returns true, image URLs keep their original domain and the args are simply
* added as query parameters instead of being sent through Image_CDN_Core::cdn_url().
*
* @module tiled-gallery
*
* @since $$next-version$$
*
* @param bool false Whether to skip the Photon domain and keep origin image URLs. Default false.
*/
if ( apply_filters( 'jetpack_skip_photon_domain', false ) ) {
// Keep the origin URL, but append the same query args Photon would have used so a
// platform-level image service (e.g. VIP) can resize/crop from the same parameters.
$this->img_src = add_query_arg( $img_args, $this->orig_file );
} else {
// The function will always photonoize the URL (even if Photon is
// not active). We need to photonize the URL to set the width/height.
$this->img_src = Image_CDN_Core::cdn_url( $this->orig_file, $img_args );
}

$image_meta = wp_get_attachment_metadata( $attachment_image->ID );
$size_array = array( absint( $this->image->width ), absint( $this->image->height ) );
Expand Down
Loading