| @@ -7,10 +7,18 @@ | ||
| 7 | 7 | |
| 8 | 8 | use Automattic\Jetpack\Assets; |
| 9 | 9 | use Automattic\Jetpack\Stats\Options as Stats_Options; |
| 10 | 10 | use Automattic\Jetpack\Status; |
| 11 | +use Automattic\Jetpack\Status\Host; | |
| 12 | + | |
| 13 | +if ( ! defined( 'ABSPATH' ) ) { | |
| 14 | + exit( 0 ); | |
| 15 | +} | |
| 16 | + | |
| 11 | 17 | /** |
| 12 | 18 | * Jetpack_Carousel class. |
| 19 | + * | |
| 20 | + * @phan-constructor-used-for-side-effects | |
| 13 | 21 | */ |
| 14 | 22 | class Jetpack_Carousel { |
| 15 | 23 | /** |
| 16 | 24 | * Defines Carousel pre-built widths |
| @@ -42,9 +50,9 @@ | ||
| 42 | 50 | */ |
| 43 | 51 | public $in_gallery = false; |
| 44 | 52 | |
| 45 | 53 | /** |
| 46 | - * Determines whether the Jetpack class and method exists. Default is true. | |
| 54 | + * Determines whether the module runs in the Jetpack plugin, as opposed to WP.com Simple site environment | |
| 47 | 55 | * |
| 48 | 56 | * @var bool |
| 49 | 57 | */ |
| 50 | 58 | public $in_jetpack = true; |
| @@ -77,9 +85,9 @@ | ||
| 77 | 85 | if ( $this->maybe_disable_jp_carousel() ) { |
| 78 | 86 | return; |
| 79 | 87 | } |
| 80 | 88 | |
| 81 | - $this->in_jetpack = ( class_exists( 'Jetpack' ) && method_exists( 'Jetpack', 'enable_module_configurable' ) ) ? true : false; | |
| 89 | + $this->in_jetpack = ! ( new Host() )->is_wpcom_simple(); | |
| 82 | 90 | |
| 83 | 91 | $this->single_image_gallery_enabled = ! $this->maybe_disable_jp_carousel_single_images(); |
| 84 | 92 | $this->single_image_gallery_enabled_media_file = $this->maybe_enable_jp_carousel_single_images_media_file(); |
| 85 | 93 | |
| @@ -95,11 +103,8 @@ | ||
| 95 | 103 | add_action( 'wp_ajax_get_attachment_comments', array( $this, 'get_attachment_comments' ) ); |
| 96 | 104 | add_action( 'wp_ajax_nopriv_get_attachment_comments', array( $this, 'get_attachment_comments' ) ); |
| 97 | 105 | add_action( 'wp_ajax_post_attachment_comment', array( $this, 'post_attachment_comment' ) ); |
| 98 | 106 | add_action( 'wp_ajax_nopriv_post_attachment_comment', array( $this, 'post_attachment_comment' ) ); |
| 99 | - | |
| 100 | - // Disable core lightbox when Carousel is enabled. | |
| 101 | - add_action( 'wp_theme_json_data_theme', array( $this, 'disable_core_lightbox' ) ); | |
| 102 | 107 | } else { |
| 103 | 108 | if ( ! $this->in_jetpack ) { |
| 104 | 109 | if ( 0 === $this->test_1or0_option( get_option( 'carousel_enable_it' ), true ) ) { |
| 105 | 110 | return; // Carousel disabled, abort early. |
| @@ -125,13 +130,12 @@ | ||
| 125 | 130 | if ( $this->single_image_gallery_enabled ) { |
| 126 | 131 | add_filter( 'the_content', array( $this, 'add_data_img_tags_and_enqueue_assets' ) ); |
| 127 | 132 | } |
| 128 | 133 | |
| 134 | + add_filter( 'render_block_data', array( $this, 'remove_core_lightbox_in_gallery' ), 10, 3 ); | |
| 135 | + | |
| 129 | 136 | // `is_amp_request()` can't be called until the 'wp' filter. |
| 130 | 137 | add_action( 'wp', array( $this, 'check_amp_support' ) ); |
| 131 | - | |
| 132 | - // Disable core lightbox when Carousel is enabled. | |
| 133 | - add_action( 'wp_theme_json_data_theme', array( $this, 'disable_core_lightbox' ) ); | |
| 134 | 138 | } |
| 135 | 139 | |
| 136 | 140 | if ( $this->in_jetpack ) { |
| 137 | 141 | Jetpack::enable_module_configurable( dirname( __DIR__ ) . '/carousel.php' ); |
| @@ -212,34 +216,8 @@ | ||
| 212 | 216 | return apply_filters( 'jp_carousel_load_for_images_linked_to_file', false ); |
| 213 | 217 | } |
| 214 | 218 | |
| 215 | 219 | /** |
| 216 | - * Disable the "Lightbox" option offered in WordPress core | |
| 217 | - * whenever Jetpack's Carousel feature is enabled. | |
| 218 | - * | |
| 219 | - * @since 13.3 | |
| 220 | - * | |
| 221 | - * @param WP_Theme_JSON_Data $theme_json Class to access and update theme.json data. | |
| 222 | - */ | |
| 223 | - public function disable_core_lightbox( $theme_json ) { | |
| 224 | - return $theme_json->update_with( | |
| 225 | - array( | |
| 226 | - 'version' => 2, | |
| 227 | - 'settings' => array( | |
| 228 | - 'blocks' => array( | |
| 229 | - 'core/image' => array( | |
| 230 | - 'lightbox' => array( | |
| 231 | - 'allowEditing' => false, | |
| 232 | - 'enabled' => false, | |
| 233 | - ), | |
| 234 | - ), | |
| 235 | - ), | |
| 236 | - ), | |
| 237 | - ) | |
| 238 | - ); | |
| 239 | - } | |
| 240 | - | |
| 241 | - /** | |
| 242 | 220 | * Returns the value of the applied jp_carousel_asset_version filter |
| 243 | 221 | * |
| 244 | 222 | * @since 1.6.0 |
| 245 | 223 | * |
| @@ -366,8 +344,28 @@ | ||
| 366 | 344 | return $content; |
| 367 | 345 | } |
| 368 | 346 | |
| 369 | 347 | /** |
| 348 | + * Remove core lightbox settings from images in a gallery, if Carousel is enabled. | |
| 349 | + * | |
| 350 | + * @param array $parsed_block An associative array of the block being rendered. | |
| 351 | + * @param array $source_block An un-modified copy of `$parsed_block`, as it appeared in the source content. | |
| 352 | + * @param WP_Block|null $parent_block If this is a nested block, a reference to the parent block. | |
| 353 | + * @return array The modified block data. | |
| 354 | + */ | |
| 355 | + public function remove_core_lightbox_in_gallery( $parsed_block, $source_block, $parent_block ) { | |
| 356 | + if ( | |
| 357 | + ! empty( $parsed_block['blockName'] ) && | |
| 358 | + 'core/image' === $parsed_block['blockName'] && | |
| 359 | + ! empty( $parent_block->name ) && | |
| 360 | + 'core/gallery' === $parent_block->name | |
| 361 | + ) { | |
| 362 | + unset( $parsed_block['attrs']['lightbox'] ); | |
| 363 | + } | |
| 364 | + return $parsed_block; | |
| 365 | + } | |
| 366 | + | |
| 367 | + /** | |
| 370 | 368 | * Enrich the gallery block content using the render_block_{$this->name} filter. |
| 371 | 369 | * This function is triggered after block render to make sure we track galleries within |
| 372 | 370 | * reusable blocks. |
| 373 | 371 | * |
| @@ -387,9 +385,9 @@ | ||
| 387 | 385 | } |
| 388 | 386 | |
| 389 | 387 | $this->enqueue_assets(); |
| 390 | 388 | |
| 391 | - if ( ! isset( $post ) ) { | |
| 389 | + if ( ! $post instanceof WP_Post ) { | |
| 392 | 390 | return $block_content; |
| 393 | 391 | } |
| 394 | 392 | |
| 395 | 393 | $blog_id = (int) get_current_blog_id(); |
| @@ -420,9 +418,9 @@ | ||
| 420 | 418 | $extra_attributes = implode( |
| 421 | 419 | ' ', |
| 422 | 420 | array_map( |
| 423 | 421 | function ( $data_key, $data_values ) { |
| 424 | - return esc_attr( $data_key ) . "='" . wp_json_encode( $data_values ) . "'"; | |
| 422 | + return esc_attr( $data_key ) . "='" . esc_attr( wp_json_encode( $data_values, JSON_UNESCAPED_SLASHES | JSON_HEX_AMP ) ) . "'"; | |
| 425 | 423 | }, |
| 426 | 424 | array_keys( $extra_data ), |
| 427 | 425 | array_values( $extra_data ) |
| 428 | 426 | ) |
| @@ -453,12 +451,9 @@ | ||
| 453 | 451 | true |
| 454 | 452 | ); |
| 455 | 453 | |
| 456 | 454 | $swiper_library_path = array( |
| 457 | - 'url' => Assets::get_file_url_for_environment( | |
| 458 | - '_inc/build/carousel/swiper-bundle.min.js', | |
| 459 | - 'modules/carousel/swiper-bundle.js' | |
| 460 | - ), | |
| 455 | + 'url' => plugins_url( '_inc/blocks/swiper.js', JETPACK__PLUGIN_FILE ), | |
| 461 | 456 | ); |
| 462 | 457 | wp_localize_script( 'jetpack-carousel', 'jetpackSwiperLibraryPath', $swiper_library_path ); |
| 463 | 458 | |
| 464 | 459 | // Note: using home_url() instead of admin_url() for ajaxurl to be sure to get same domain on wpcom when using mapped domains (also works on self-hosted). |
| @@ -480,8 +475,9 @@ | ||
| 480 | 475 | 'comment' => __( 'Comment', 'jetpack' ), |
| 481 | 476 | 'post_comment' => __( 'Post Comment', 'jetpack' ), |
| 482 | 477 | 'write_comment' => __( 'Write a Comment...', 'jetpack' ), |
| 483 | 478 | 'loading_comments' => __( 'Loading Comments...', 'jetpack' ), |
| 479 | + 'image_label' => __( 'Open image in full-screen.', 'jetpack' ), | |
| 484 | 480 | 'download_original' => sprintf( |
| 485 | 481 | /* translators: %1s is the full-size image width, and %2s is the height. */ |
| 486 | 482 | __( 'View full size <span class="photo-size">%1$s<span class="photo-size-times">×</span>%2$s</span>', 'jetpack' ), |
| 487 | 483 | '{0}', |
| @@ -545,12 +541,12 @@ | ||
| 545 | 541 | */ |
| 546 | 542 | $localize_strings = apply_filters( 'jp_carousel_localize_strings', $localize_strings ); |
| 547 | 543 | wp_localize_script( 'jetpack-carousel', 'jetpackCarouselStrings', $localize_strings ); |
| 548 | 544 | wp_enqueue_style( |
| 549 | - 'jetpack-carousel-swiper-css', | |
| 550 | - plugins_url( 'swiper-bundle.css', __FILE__ ), | |
| 545 | + 'jetpack-swiper-library', | |
| 546 | + plugins_url( '_inc/blocks/swiper.css', JETPACK__PLUGIN_FILE ), | |
| 551 | 547 | array(), |
| 552 | - $this->asset_version( JETPACK__VERSION ) | |
| 548 | + JETPACK__VERSION | |
| 553 | 549 | ); |
| 554 | 550 | wp_enqueue_style( 'jetpack-carousel', plugins_url( 'jetpack-carousel.css', __FILE__ ), array(), $this->asset_version( JETPACK__VERSION ) ); |
| 555 | 551 | wp_style_add_data( 'jetpack-carousel', 'rtl', 'replace' ); |
| 556 | 552 | |
| @@ -586,12 +582,13 @@ | ||
| 586 | 582 | $current_user = wp_get_current_user(); |
| 587 | 583 | $require_name_email = (int) get_option( 'require_name_email' ); |
| 588 | 584 | /* translators: %s is replaced with a field name in the form, e.g. "Email" */ |
| 589 | 585 | $required = ( $require_name_email ) ? __( '%s (Required)', 'jetpack' ) : '%s'; |
| 586 | + require_once JETPACK__PLUGIN_DIR . '_inc/lib/class-jetpack-spinner.php'; | |
| 590 | 587 | ?> |
| 591 | - <div id="jp-carousel-loading-overlay"> | |
| 588 | + <div id="jp-carousel-loading-overlay" style="display: none;"> | |
| 592 | 589 | <div id="jp-carousel-loading-wrapper"> |
| 593 | - <span id="jp-carousel-library-loading"> </span> | |
| 590 | + <span id="jp-carousel-library-loading"><?php echo Jetpack_Spinner::render( 40 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- static SVG markup. ?></span> | |
| 594 | 591 | </div> |
| 595 | 592 | </div> |
| 596 | 593 | <div class="jp-carousel-overlay<?php echo( $is_light ? ' jp-carousel-light' : '' ); ?>" style="display: none;"> |
| 597 | 594 | |
| @@ -597,9 +594,9 @@ | ||
| 597 | 594 | |
| 598 | 595 | <div class="jp-carousel-container<?php echo( $is_light ? ' jp-carousel-light' : '' ); ?>"> |
| 599 | 596 | <!-- The Carousel Swiper --> |
| 600 | 597 | <div |
| 601 | - class="jp-carousel-wrap swiper-container jp-carousel-swiper-container jp-carousel-transitions" | |
| 598 | + class="jp-carousel-wrap swiper jp-carousel-swiper-container jp-carousel-transitions" | |
| 602 | 599 | itemscope |
| 603 | 600 | itemtype="https://schema.org/ImageGallery"> |
| 604 | 601 | <div class="jp-carousel swiper-wrapper"></div> |
| 605 | 602 | <div class="jp-swiper-button-prev swiper-button-prev"> |
| @@ -641,9 +638,9 @@ | ||
| 641 | 638 | <div class="jp-swiper-pagination swiper-pagination"></div> |
| 642 | 639 | <div class="jp-carousel-pagination"></div> |
| 643 | 640 | </div> |
| 644 | 641 | <div class="jp-carousel-photo-title-container"> |
| 645 | - <h2 class="jp-carousel-photo-caption"></h2> | |
| 642 | + <div class="jp-carousel-photo-caption"></div> | |
| 646 | 643 | </div> |
| 647 | 644 | <div class="jp-carousel-photo-icons-container"> |
| 648 | 645 | <a href="#" class="jp-carousel-icon-btn jp-carousel-icon-info" aria-label="<?php esc_attr_e( 'Toggle photo metadata visibility', 'jetpack' ); ?>"> |
| 649 | 646 | <span class="jp-carousel-icon"> |
| @@ -677,9 +674,9 @@ | ||
| 677 | 674 | </div> |
| 678 | 675 | <div class="jp-carousel-info-extra"> |
| 679 | 676 | <div class="jp-carousel-info-content-wrapper"> |
| 680 | 677 | <div class="jp-carousel-photo-title-container"> |
| 681 | - <h2 class="jp-carousel-photo-title"></h2> | |
| 678 | + <div class="jp-carousel-photo-title"></div> | |
| 682 | 679 | </div> |
| 683 | 680 | <div class="jp-carousel-comments-wrapper"> |
| 684 | 681 | <?php if ( $localize_strings['display_comments'] ) : ?> |
| 685 | 682 | <div id="jp-carousel-comments-loading"> |
| @@ -686,9 +683,9 @@ | ||
| 686 | 683 | <span><?php echo esc_html( $localize_strings['loading_comments'] ); ?></span> |
| 687 | 684 | </div> |
| 688 | 685 | <div class="jp-carousel-comments"></div> |
| 689 | 686 | <div id="jp-carousel-comment-form-container"> |
| 690 | - <span id="jp-carousel-comment-form-spinner"> </span> | |
| 687 | + <span id="jp-carousel-comment-form-spinner"><?php echo Jetpack_Spinner::render( 20 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- static SVG markup. ?></span> | |
| 691 | 688 | <div id="jp-carousel-comment-post-results"></div> |
| 692 | 689 | <?php if ( $use_local_comments ) : ?> |
| 693 | 690 | <?php if ( ! $localize_strings['is_logged_in'] && $localize_strings['comment_registration'] ) : ?> |
| 694 | 691 | <div id="jp-carousel-comment-form-commenting-as"> |
| @@ -757,15 +754,14 @@ | ||
| 757 | 754 | </div> |
| 758 | 755 | <div class="jp-carousel-image-meta"> |
| 759 | 756 | <div class="jp-carousel-title-and-caption"> |
| 760 | 757 | <div class="jp-carousel-photo-info"> |
| 761 | - <h3 class="jp-carousel-caption" itemprop="caption description"></h3> | |
| 758 | + <div class="jp-carousel-caption" itemprop="caption description"></div> | |
| 762 | 759 | </div> |
| 763 | 760 | |
| 764 | 761 | <div class="jp-carousel-photo-description"></div> |
| 765 | 762 | </div> |
| 766 | - <ul class="jp-carousel-image-exif" style="display: none;"></ul> | |
| 767 | - <a class="jp-carousel-image-download" href="#" target="_blank" style="display: none;"> | |
| 763 | + <a class="jp-carousel-image-download" href="#" aria-label="<?php esc_attr_e( 'Download image', 'jetpack' ); ?>" target="_blank" style="display: none;"> | |
| 768 | 764 | <svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| 769 | 765 | <mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="3" y="3" width="19" height="18"> |
| 770 | 766 | <path fill-rule="evenodd" clip-rule="evenodd" d="M5.84615 5V19H19.7775V12H21.7677V19C21.7677 20.1 20.8721 21 19.7775 21H5.84615C4.74159 21 3.85596 20.1 3.85596 19V5C3.85596 3.9 4.74159 3 5.84615 3H12.8118V5H5.84615ZM14.802 5V3H21.7677V10H19.7775V6.41L9.99569 16.24L8.59261 14.83L18.3744 5H14.802Z" fill="white"/> |
| 771 | 767 | </mask> |
| @@ -816,8 +812,11 @@ | ||
| 816 | 812 | * @param string $content HTML content of the post. |
| 817 | 813 | * @return string |
| 818 | 814 | */ |
| 819 | 815 | public function add_data_img_tags_and_enqueue_assets( $content ) { |
| 816 | + if ( ! is_string( $content ) || $content === '' ) { | |
| 817 | + return ''; | |
| 818 | + } | |
| 820 | 819 | if ( |
| 821 | 820 | class_exists( 'Jetpack_AMP_Support' ) |
| 822 | 821 | && Jetpack_AMP_Support::is_amp_request() |
| 823 | 822 | ) { |
| @@ -828,11 +827,19 @@ | ||
| 828 | 827 | return $content; |
| 829 | 828 | } |
| 830 | 829 | $selected_images = array(); |
| 831 | 830 | foreach ( $matches[0] as $image_html ) { |
| 831 | + // This image already carries the attributes this method adds, so adding | |
| 832 | + // them again would emit every one of them twice. Tiled Gallery output | |
| 833 | + // reaches this filter twice: once as 'jetpack_tiled_galleries_block_content' | |
| 834 | + // from inside the block's render callback, and again as 'the_content' when | |
| 835 | + // single image galleries are enabled. See JETPACK-1990. | |
| 836 | + if ( str_contains( $image_html, 'data-attachment-id=' ) ) { | |
| 837 | + continue; | |
| 838 | + } | |
| 832 | 839 | if ( |
| 833 | 840 | preg_match( '/(wp-image-|data-id=)\"?([0-9]+)\"?/i', $image_html, $class_id ) |
| 834 | - && ! preg_match( '/wp-block-jetpack-slideshow_image/', $image_html ) | |
| 841 | + && ! str_contains( $image_html, 'wp-block-jetpack-slideshow_image' ) | |
| 835 | 842 | ) { |
| 836 | 843 | /** |
| 837 | 844 | * Allow filtering the attachment ID used to fetch and populate metadata about an image in a gallery. |
| 838 | 845 | * |
| @@ -942,13 +949,14 @@ | ||
| 942 | 949 | } |
| 943 | 950 | |
| 944 | 951 | $attachment_id = (int) $attachment->ID; |
| 945 | 952 | $orig_file = wp_get_attachment_image_src( $attachment_id, 'full' ); |
| 946 | - $orig_file = isset( $orig_file[0] ) ? $orig_file[0] : wp_get_attachment_url( $attachment_id ); | |
| 953 | + $orig_file = $orig_file[0] ?? wp_get_attachment_url( $attachment_id ); | |
| 947 | 954 | $meta = wp_get_attachment_metadata( $attachment_id ); |
| 948 | 955 | $size = isset( $meta['width'] ) ? (int) $meta['width'] . ',' . (int) $meta['height'] : ''; |
| 949 | 956 | $img_meta = ( ! empty( $meta['image_meta'] ) ) ? (array) $meta['image_meta'] : array(); |
| 950 | 957 | $comments_opened = (int) comments_open( $attachment_id ); |
| 958 | + $display_exif = $this->test_1or0_option( Jetpack_Options::get_option_and_ensure_autoload( 'carousel_display_exif', true ) ); | |
| 951 | 959 | |
| 952 | 960 | /** |
| 953 | 961 | * Note: Cannot generate a filename from the width and height wp_get_attachment_image_src() returns because |
| 954 | 962 | * it takes the $content_width global variable themes can set in consideration, therefore returning sizes |
| @@ -963,38 +971,36 @@ | ||
| 963 | 971 | * EG with Twenty Ten activated: |
| 964 | 972 | * array(4) { [0]=> string(82) "http://vanillawpinstall.blah/wp-content/uploads/2012/06/IMG_3534-1024x764.jpg" [1]=> int(640) [2]=> int(477) [3]=> bool(true) } |
| 965 | 973 | */ |
| 966 | 974 | |
| 967 | - $medium_file_info = wp_get_attachment_image_src( $attachment_id, 'medium' ); | |
| 968 | - $medium_file = isset( $medium_file_info[0] ) ? $medium_file_info[0] : ''; | |
| 969 | - | |
| 970 | 975 | $large_file_info = wp_get_attachment_image_src( $attachment_id, 'large' ); |
| 971 | - $large_file = isset( $large_file_info[0] ) ? $large_file_info[0] : ''; | |
| 976 | + $large_file = $large_file_info[0] ?? ''; | |
| 972 | 977 | |
| 973 | 978 | $attachment_title = wptexturize( $attachment->post_title ); |
| 974 | 979 | $attachment_desc = wpautop( wptexturize( $attachment->post_content ) ); |
| 975 | 980 | $attachment_caption = wpautop( wptexturize( $attachment->post_excerpt ) ); |
| 976 | 981 | |
| 977 | - // See https://github.com/Automattic/jetpack/issues/2765. | |
| 978 | - if ( isset( $img_meta['keywords'] ) ) { | |
| 979 | - unset( $img_meta['keywords'] ); | |
| 980 | - } | |
| 981 | - | |
| 982 | - $img_meta = wp_json_encode( array_map( 'strval', array_filter( $img_meta, 'is_scalar' ) ) ); | |
| 983 | - | |
| 984 | 982 | $attr['data-attachment-id'] = $attachment_id; |
| 985 | 983 | $attr['data-permalink'] = esc_attr( get_permalink( $attachment_id ) ); |
| 986 | 984 | $attr['data-orig-file'] = esc_attr( $orig_file ); |
| 987 | 985 | $attr['data-orig-size'] = $size; |
| 988 | 986 | $attr['data-comments-opened'] = $comments_opened; |
| 989 | - $attr['data-image-meta'] = esc_attr( $img_meta ); | |
| 987 | + | |
| 988 | + if ( $display_exif ) { | |
| 989 | + // See https://github.com/Automattic/jetpack/issues/2765. | |
| 990 | + if ( isset( $img_meta['keywords'] ) ) { | |
| 991 | + unset( $img_meta['keywords'] ); | |
| 992 | + } | |
| 993 | + | |
| 994 | + $img_meta = wp_json_encode( array_map( 'strval', array_filter( $img_meta, 'is_scalar' ) ), JSON_UNESCAPED_SLASHES | JSON_HEX_AMP ); | |
| 995 | + $attr['data-image-meta'] = esc_attr( $img_meta ); | |
| 996 | + } | |
| 997 | + | |
| 990 | 998 | // The lines below use `esc_attr( htmlspecialchars( ) )` because esc_attr tries to be too smart and won't double-encode, and we need that here. |
| 991 | 999 | $attr['data-image-title'] = esc_attr( htmlspecialchars( $attachment_title, ENT_COMPAT ) ); |
| 992 | 1000 | $attr['data-image-description'] = esc_attr( htmlspecialchars( $attachment_desc, ENT_COMPAT ) ); |
| 993 | 1001 | $attr['data-image-caption'] = esc_attr( htmlspecialchars( $attachment_caption, ENT_COMPAT ) ); |
| 994 | - $attr['data-medium-file'] = esc_attr( $medium_file ); | |
| 995 | 1002 | $attr['data-large-file'] = esc_attr( $large_file ); |
| 996 | - | |
| 997 | 1003 | return $attr; |
| 998 | 1004 | } |
| 999 | 1005 | |
| 1000 | 1006 | /** |
| @@ -1033,12 +1039,12 @@ | ||
| 1033 | 1039 | * @param array $extra_data Array of data about the site and the post. |
| 1034 | 1040 | */ |
| 1035 | 1041 | $extra_data = apply_filters( 'jp_carousel_add_data_to_container', $extra_data ); |
| 1036 | 1042 | foreach ( (array) $extra_data as $data_key => $data_values ) { |
| 1037 | - $html = str_replace( '<div ', '<div ' . esc_attr( $data_key ) . "='" . wp_json_encode( $data_values ) . "' ", $html ); | |
| 1038 | - $html = str_replace( '<ul class="wp-block-gallery', '<ul ' . esc_attr( $data_key ) . "='" . wp_json_encode( $data_values ) . "' class=\"wp-block-gallery", $html ); | |
| 1039 | - $html = str_replace( '<ul class="blocks-gallery-grid', '<ul ' . esc_attr( $data_key ) . "='" . wp_json_encode( $data_values ) . "' class=\"blocks-gallery-grid", $html ); | |
| 1040 | - $html = preg_replace( '/\<figure([^>]*)class="(wp-block-gallery[^"]*?has-nested-images.*?)"/', '<figure ' . esc_attr( $data_key ) . "='" . wp_json_encode( $data_values ) . "' $1 class=\"$2\"", $html ); | |
| 1043 | + $html = str_replace( '<div ', '<div ' . esc_attr( $data_key ) . "='" . esc_attr( wp_json_encode( $data_values, JSON_HEX_AMP | JSON_UNESCAPED_SLASHES ) ) . "' ", $html ); | |
| 1044 | + $html = str_replace( '<ul class="wp-block-gallery', '<ul ' . esc_attr( $data_key ) . "='" . esc_attr( wp_json_encode( $data_values, JSON_HEX_AMP | JSON_UNESCAPED_SLASHES ) ) . "' class=\"wp-block-gallery", $html ); | |
| 1045 | + $html = str_replace( '<ul class="blocks-gallery-grid', '<ul ' . esc_attr( $data_key ) . "='" . esc_attr( wp_json_encode( $data_values, JSON_HEX_AMP | JSON_UNESCAPED_SLASHES ) ) . "' class=\"blocks-gallery-grid", $html ); | |
| 1046 | + $html = preg_replace( '/\<figure([^>]*)class="(wp-block-gallery[^"]*?has-nested-images.*?)"/', '<figure ' . esc_attr( $data_key ) . "='" . esc_attr( wp_json_encode( $data_values, JSON_HEX_AMP | JSON_UNESCAPED_SLASHES ) ) . "' $1 class=\"$2\"", $html ); | |
| 1041 | 1047 | } |
| 1042 | 1048 | } |
| 1043 | 1049 | |
| 1044 | 1050 | return $html; |
| @@ -1083,9 +1089,9 @@ | ||
| 1083 | 1089 | |
| 1084 | 1090 | /** |
| 1085 | 1091 | * Retrieves comment information |
| 1086 | 1092 | * |
| 1087 | - * @return string | |
| 1093 | + * @return never | |
| 1088 | 1094 | */ |
| 1089 | 1095 | public function get_attachment_comments() { |
| 1090 | 1096 | if ( ! headers_sent() ) { |
| 1091 | 1097 | header( 'Content-type: text/javascript' ); |
| @@ -1109,11 +1115,11 @@ | ||
| 1109 | 1115 | |
| 1110 | 1116 | if ( ! $attachment_id ) { |
| 1111 | 1117 | wp_send_json_error( |
| 1112 | 1118 | __( 'Missing attachment ID.', 'jetpack' ), |
| 1113 | - 403 | |
| 1119 | + 403, | |
| 1120 | + JSON_UNESCAPED_SLASHES | |
| 1114 | 1121 | ); |
| 1115 | - return; | |
| 1116 | 1122 | } |
| 1117 | 1123 | |
| 1118 | 1124 | $attachment_post = get_post( $attachment_id ); |
| 1119 | 1125 | // If we have no info about that attachment, bail. |
| @@ -1119,11 +1125,11 @@ | ||
| 1119 | 1125 | // If we have no info about that attachment, bail. |
| 1120 | 1126 | if ( ! ( $attachment_post instanceof WP_Post ) ) { |
| 1121 | 1127 | wp_send_json_error( |
| 1122 | 1128 | __( 'Missing attachment info.', 'jetpack' ), |
| 1123 | - 403 | |
| 1129 | + 403, | |
| 1130 | + JSON_UNESCAPED_SLASHES | |
| 1124 | 1131 | ); |
| 1125 | - return; | |
| 1126 | 1132 | } |
| 1127 | 1133 | |
| 1128 | 1134 | // This AJAX call should only be used to fetch comments of attachments. |
| 1129 | 1135 | if ( 'attachment' !== $attachment_post->post_type ) { |
| @@ -1128,11 +1134,11 @@ | ||
| 1128 | 1134 | // This AJAX call should only be used to fetch comments of attachments. |
| 1129 | 1135 | if ( 'attachment' !== $attachment_post->post_type ) { |
| 1130 | 1136 | wp_send_json_error( |
| 1131 | 1137 | __( 'You aren’t authorized to do that.', 'jetpack' ), |
| 1132 | - 403 | |
| 1138 | + 403, | |
| 1139 | + JSON_UNESCAPED_SLASHES | |
| 1133 | 1140 | ); |
| 1134 | - return; | |
| 1135 | 1141 | } |
| 1136 | 1142 | |
| 1137 | 1143 | $parent_post = get_post_parent( $attachment_id ); |
| 1138 | 1144 | |
| @@ -1150,11 +1156,11 @@ | ||
| 1150 | 1156 | $current_user = wp_get_current_user(); |
| 1151 | 1157 | if ( ! ( $current_user instanceof WP_User ) ) { |
| 1152 | 1158 | wp_send_json_error( |
| 1153 | 1159 | __( 'Missing user info.', 'jetpack' ), |
| 1154 | - 403 | |
| 1160 | + 403, | |
| 1161 | + JSON_UNESCAPED_SLASHES | |
| 1155 | 1162 | ); |
| 1156 | - return; | |
| 1157 | 1163 | } |
| 1158 | 1164 | |
| 1159 | 1165 | /* |
| 1160 | 1166 | * If a post is private / draft |
| @@ -1166,11 +1172,11 @@ | ||
| 1166 | 1172 | && ! current_user_can( 'read_post', $parent_post->ID ) |
| 1167 | 1173 | ) { |
| 1168 | 1174 | wp_send_json_error( |
| 1169 | 1175 | __( 'You aren’t authorized to do that.', 'jetpack' ), |
| 1170 | - 403 | |
| 1176 | + 403, | |
| 1177 | + JSON_UNESCAPED_SLASHES | |
| 1171 | 1178 | ); |
| 1172 | - return; | |
| 1173 | 1179 | } |
| 1174 | 1180 | } |
| 1175 | 1181 | |
| 1176 | 1182 | if ( $offset < 1 ) { |
| @@ -1204,9 +1210,9 @@ | ||
| 1204 | 1210 | 'content' => wpautop( $comment->comment_content ), |
| 1205 | 1211 | ); |
| 1206 | 1212 | } |
| 1207 | 1213 | |
| 1208 | - die( wp_json_encode( $out ) ); | |
| 1214 | + wp_send_json( $out, null, JSON_UNESCAPED_SLASHES ); | |
| 1209 | 1215 | } |
| 1210 | 1216 | |
| 1211 | 1217 | /** |
| 1212 | 1218 | * Adds a new comment to the database |
| @@ -1218,9 +1224,9 @@ | ||
| 1218 | 1224 | header( 'Content-type: text/javascript' ); |
| 1219 | 1225 | } |
| 1220 | 1226 | |
| 1221 | 1227 | if ( empty( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'carousel_nonce' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- WP Core doesn't unslash or sanitize nonces either |
| 1222 | - die( wp_json_encode( array( 'error' => __( 'Nonce verification failed.', 'jetpack' ) ) ) ); | |
| 1228 | + die( wp_json_encode( array( 'error' => __( 'Nonce verification failed.', 'jetpack' ) ), JSON_UNESCAPED_SLASHES ) ); | |
| 1223 | 1229 | } |
| 1224 | 1230 | |
| 1225 | 1231 | $_blog_id = isset( $_POST['blog_id'] ) ? (int) $_POST['blog_id'] : 0; |
| 1226 | 1232 | $_post_id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0; |
| @@ -1226,17 +1232,17 @@ | ||
| 1226 | 1232 | $_post_id = isset( $_POST['id'] ) ? (int) $_POST['id'] : 0; |
| 1227 | 1233 | $comment = isset( $_POST['comment'] ) ? filter_var( wp_unslash( $_POST['comment'] ) ) : null; |
| 1228 | 1234 | |
| 1229 | 1235 | if ( empty( $_blog_id ) ) { |
| 1230 | - die( wp_json_encode( array( 'error' => __( 'Missing target blog ID.', 'jetpack' ) ) ) ); | |
| 1236 | + die( wp_json_encode( array( 'error' => __( 'Missing target blog ID.', 'jetpack' ) ), JSON_UNESCAPED_SLASHES ) ); | |
| 1231 | 1237 | } |
| 1232 | 1238 | |
| 1233 | 1239 | if ( empty( $_post_id ) ) { |
| 1234 | - die( wp_json_encode( array( 'error' => __( 'Missing target post ID.', 'jetpack' ) ) ) ); | |
| 1240 | + die( wp_json_encode( array( 'error' => __( 'Missing target post ID.', 'jetpack' ) ), JSON_UNESCAPED_SLASHES ) ); | |
| 1235 | 1241 | } |
| 1236 | 1242 | |
| 1237 | 1243 | if ( empty( $comment ) ) { |
| 1238 | - die( wp_json_encode( array( 'error' => __( 'No comment text was submitted.', 'jetpack' ) ) ) ); | |
| 1244 | + die( wp_json_encode( array( 'error' => __( 'No comment text was submitted.', 'jetpack' ) ), JSON_UNESCAPED_SLASHES ) ); | |
| 1239 | 1245 | } |
| 1240 | 1246 | |
| 1241 | 1247 | // Used in context like NewDash. |
| 1242 | 1248 | $switched = false; |
| @@ -1251,9 +1257,9 @@ | ||
| 1251 | 1257 | if ( ! comments_open( $_post_id ) ) { |
| 1252 | 1258 | if ( $switched ) { |
| 1253 | 1259 | restore_current_blog(); |
| 1254 | 1260 | } |
| 1255 | - die( wp_json_encode( array( 'error' => __( 'Comments on this post are closed.', 'jetpack' ) ) ) ); | |
| 1261 | + die( wp_json_encode( array( 'error' => __( 'Comments on this post are closed.', 'jetpack' ) ), JSON_UNESCAPED_SLASHES ) ); | |
| 1256 | 1262 | } |
| 1257 | 1263 | |
| 1258 | 1264 | if ( is_user_logged_in() ) { |
| 1259 | 1265 | $user = wp_get_current_user(); |
| @@ -1265,15 +1271,18 @@ | ||
| 1265 | 1271 | if ( empty( $user_id ) ) { |
| 1266 | 1272 | if ( $switched ) { |
| 1267 | 1273 | restore_current_blog(); |
| 1268 | 1274 | } |
| 1269 | - die( wp_json_encode( array( 'error' => __( 'Sorry, but we could not authenticate your request.', 'jetpack' ) ) ) ); | |
| 1275 | + die( wp_json_encode( array( 'error' => __( 'Sorry, but we could not authenticate your request.', 'jetpack' ) ), JSON_UNESCAPED_SLASHES ) ); | |
| 1270 | 1276 | } |
| 1271 | 1277 | } else { |
| 1272 | 1278 | $user_id = 0; |
| 1273 | 1279 | $display_name = isset( $_POST['author'] ) ? sanitize_text_field( wp_unslash( $_POST['author'] ) ) : null; |
| 1274 | - $email = isset( $_POST['email'] ) ? wp_unslash( $_POST['email'] ) : null; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Checked or sanitized below. | |
| 1275 | - $url = isset( $_POST['url'] ) ? esc_url_raw( wp_unslash( $_POST['url'] ) ) : null; | |
| 1280 | + $email = null; | |
| 1281 | + if ( isset( $_POST['email'] ) && is_string( $_POST['email'] ) ) { | |
| 1282 | + $email = wp_unslash( $_POST['email'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Checked or sanitized below. | |
| 1283 | + } | |
| 1284 | + $url = isset( $_POST['url'] ) && is_string( $_POST['url'] ) ? esc_url_raw( wp_unslash( $_POST['url'] ) ) : null; | |
| 1276 | 1285 | |
| 1277 | 1286 | if ( get_option( 'require_name_email' ) ) { |
| 1278 | 1287 | if ( empty( $display_name ) ) { |
| 1279 | 1288 | if ( $switched ) { |
| @@ -1278,9 +1287,9 @@ | ||
| 1278 | 1287 | if ( empty( $display_name ) ) { |
| 1279 | 1288 | if ( $switched ) { |
| 1280 | 1289 | restore_current_blog(); |
| 1281 | 1290 | } |
| 1282 | - die( wp_json_encode( array( 'error' => __( 'Please provide your name.', 'jetpack' ) ) ) ); | |
| 1291 | + die( wp_json_encode( array( 'error' => __( 'Please provide your name.', 'jetpack' ) ), JSON_UNESCAPED_SLASHES ) ); | |
| 1283 | 1292 | } |
| 1284 | 1293 | |
| 1285 | 1294 | if ( empty( $email ) ) { |
| 1286 | 1295 | if ( $switched ) { |
| @@ -1285,9 +1294,9 @@ | ||
| 1285 | 1294 | if ( empty( $email ) ) { |
| 1286 | 1295 | if ( $switched ) { |
| 1287 | 1296 | restore_current_blog(); |
| 1288 | 1297 | } |
| 1289 | - die( wp_json_encode( array( 'error' => __( 'Please provide an email address.', 'jetpack' ) ) ) ); | |
| 1298 | + die( wp_json_encode( array( 'error' => __( 'Please provide an email address.', 'jetpack' ) ), JSON_UNESCAPED_SLASHES ) ); | |
| 1290 | 1299 | } |
| 1291 | 1300 | |
| 1292 | 1301 | if ( ! is_email( $email ) ) { |
| 1293 | 1302 | if ( $switched ) { |
| @@ -1292,9 +1301,9 @@ | ||
| 1292 | 1301 | if ( ! is_email( $email ) ) { |
| 1293 | 1302 | if ( $switched ) { |
| 1294 | 1303 | restore_current_blog(); |
| 1295 | 1304 | } |
| 1296 | - die( wp_json_encode( array( 'error' => __( 'Please provide a valid email address.', 'jetpack' ) ) ) ); | |
| 1305 | + die( wp_json_encode( array( 'error' => __( 'Please provide a valid email address.', 'jetpack' ) ), JSON_UNESCAPED_SLASHES ) ); | |
| 1297 | 1306 | } |
| 1298 | 1307 | } else { |
| 1299 | 1308 | $email = $email !== null ? sanitize_email( $email ) : null; |
| 1300 | 1309 | } |
| @@ -1335,9 +1344,10 @@ | ||
| 1335 | 1344 | wp_json_encode( |
| 1336 | 1345 | array( |
| 1337 | 1346 | 'comment_id' => $comment_id, |
| 1338 | 1347 | 'comment_status' => $comment_status, |
| 1339 | - ) | |
| 1348 | + ), | |
| 1349 | + JSON_UNESCAPED_SLASHES | |
| 1340 | 1350 | ) |
| 1341 | 1351 | ); |
| 1342 | 1352 | } |
| 1343 | 1353 | |