diff --git a/php/class-delivery.php b/php/class-delivery.php index 1d920518f..a4eaa7452 100644 --- a/php/class-delivery.php +++ b/php/class-delivery.php @@ -541,6 +541,8 @@ public function unsync_size_relationship( $attachment_id ) { */ public function get_sized( $attachment_id ) { static $sizes = array(), $registered_sizes; + + $attachment_id = (int) $attachment_id; if ( ! $registered_sizes ) { $registered_sizes = wp_get_registered_image_subsizes(); } @@ -920,13 +922,17 @@ public function find_attachment_size_urls() { $search ); + // Cache for the current request only. Across requests, failed deliveries or syncs need to be retried, + // and the contextualized post IDs can differ (e.g. per WPML language). + static $cache = array(); + $key = md5( $sql ); - $cached = wp_cache_get( $key ); + $cached = isset( $cache[ $key ] ) ? $cache[ $key ] : false; $auto_sync = $this->sync->is_auto_sync_enabled(); if ( false === $cached ) { $cached = array(); - $results = $wpdb->get_results( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared + $results = $wpdb->get_results( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared if ( $results ) { foreach ( $results as $result ) { @@ -942,7 +948,8 @@ public function find_attachment_size_urls() { */ $post_id = apply_filters( 'cloudinary_contextualized_post_id', $result->post_id ); - if ( ! $this->is_deliverable( $post_id ) ) { + // The contextualized post can be missing, e.g. WPML returns null for an attachment without a translation. + if ( empty( $post_id ) || ! $this->is_deliverable( $post_id ) ) { continue; } // If we are here, it means that an attachment in the media library doesn't have a delivery for the url. @@ -953,11 +960,13 @@ public function find_attachment_size_urls() { $this->sync->add_to_sync( $post_id ); } $size = $this->get_sized( $post_id ); - $key = ! empty( $size['sized_url'] ) ? $size['sized_url'] : wp_get_attachment_url( $post_id ); - $cached[ $key ] = (int) $post_id; + $attachment_url = ! empty( $size['sized_url'] ) ? $size['sized_url'] : wp_get_attachment_url( $post_id ); + if ( $attachment_url ) { + $cached[ $attachment_url ] = (int) $post_id; + } } } - wp_cache_add( $key, $cached ); + $cache[ $key ] = $cached; } $this->known = array_merge( $this->known, $cached ); diff --git a/php/class-media.php b/php/class-media.php index 9948db77b..65f6daf57 100644 --- a/php/class-media.php +++ b/php/class-media.php @@ -3180,7 +3180,7 @@ public function get_cloudinary_version( $attachment_id ) { $attachment = get_post( $attachment_id ); if ( ! empty( $attachment ) && Assets::POST_TYPE_SLUG === $attachment->post_type && ! empty( $attachment->post_parent ) ) { - $version = (int) preg_replace( '/\D/', '', $this->get_post_meta( (int) $attachment->post_parent, Sync::META_KEYS['version'], true ) ); + $version = (int) preg_replace( '/\D/', '', $this->get_post_meta( (int) $attachment->post_parent, Sync::META_KEYS['version'], true, '' ) ); } } diff --git a/php/class-string-replace.php b/php/class-string-replace.php index 905fa9a27..fe13b160d 100644 --- a/php/class-string-replace.php +++ b/php/class-string-replace.php @@ -164,8 +164,31 @@ public function init() { * Stop the buffer capture and set the output callback. */ public function start_capture() { - ob_start( array( $this, 'replace_strings' ) ); - ob_start( array( $this, 'replace_strings' ) ); // Second call to catch early buffer flushing. + ob_start( array( $this, 'output_handler' ) ); + ob_start( array( $this, 'output_handler' ) ); // Second call to catch early buffer flushing. + } + + /** + * Output buffer callback to replace strings in the captured buffer. + * + * Output produced within an output handler is discarded, and doing so is deprecated as of PHP 8.4. + * Errors displayed while replacing (e.g. notices raised by hooked callbacks) would count as such output, + * so display is disabled for the duration of the handler. Errors are still logged as usual. + * This doesn't cover callbacks that echo output directly, which still trigger the deprecation. + * + * @param string $buffer The captured buffer. + * @param int $phase The output handler phase bitmask. + * + * @return string + */ + public function output_handler( $buffer, $phase ) { + $display_errors = ini_set( 'display_errors', '0' ); // phpcs:ignore WordPress.PHP.IniSet.display_errors_Disallowed + $buffer = $this->replace_strings( $buffer, $phase ); + if ( false !== $display_errors ) { + ini_set( 'display_errors', $display_errors ); // phpcs:ignore WordPress.PHP.IniSet.display_errors_Disallowed + } + + return $buffer; } /** @@ -285,7 +308,7 @@ protected function prime_replacements( $content, $context = 'view' ) { * Replace string in HTML. * * @param string|array $content The HTML. - * @param string $context The context to use. + * @param string|int $context The context to use, or the output handler phase when capturing a buffer. * * @return string */ diff --git a/php/relate/class-relationship.php b/php/relate/class-relationship.php index bedeef302..172e4ac14 100644 --- a/php/relate/class-relationship.php +++ b/php/relate/class-relationship.php @@ -270,11 +270,12 @@ public function delete_cache() { public static function get_relationship( $post_id ) { static $cache = array(); - if ( ! isset( $cache[ $post_id ] ) ) { - $cache[ $post_id ] = new self( $post_id ); + $key = (int) $post_id; + if ( ! isset( $cache[ $key ] ) ) { + $cache[ $key ] = new self( $post_id ); } - return $cache[ $post_id ]; + return $cache[ $key ]; } /** diff --git a/php/ui/class-component.php b/php/ui/class-component.php index 71b0396e1..bea5e9dac 100644 --- a/php/ui/class-component.php +++ b/php/ui/class-component.php @@ -618,7 +618,7 @@ public static function build_tag( $element, $attributes = array(), $state = 'ope /** * Get a build part to construct. * - * @param string|null $part The part name. + * @param string $part The part name. * * @return array */ diff --git a/php/ui/component/class-opt-level.php b/php/ui/component/class-opt-level.php index 5ff1eb178..8d32e5c0d 100644 --- a/php/ui/component/class-opt-level.php +++ b/php/ui/component/class-opt-level.php @@ -119,7 +119,7 @@ protected function get_setting_line( $slug ) { protected function get_badge( $status = 'active' ) { $badge = $this->get_part( 'span' ); $badge['attributes']['class'][] = "cld-optimisation-item-{$status}"; - $text = $this->get_part( null ); + $text = $this->get_part( '' ); if ( 'active' === $status ) { $text['content'] = __( 'Activated', 'cloudinary' ); $icon = $this->dashicon( $this->get_part( 'span' ) );