@@ -383,15 +383,100 @@ private static function replace_custom_emoji( $text, $activity ) {
383383
384384 foreach ( $ activity ['tag ' ] as $ tag ) {
385385 if ( isset ( $ tag ['type ' ] ) && 'Emoji ' === $ tag ['type ' ] && ! empty ( $ tag ['name ' ] ) && ! empty ( $ tag ['icon ' ]['url ' ] ) ) {
386- $ text = str_replace (
387- $ tag ['name ' ],
388- sprintf (
389- '<img src="%s" alt="%s" class="emoji" /> ' ,
390- \esc_url ( $ tag ['icon ' ]['url ' ] ),
391- \esc_attr ( $ tag ['name ' ] )
392- ),
393- $ text
386+ $ emoji_url = $ tag ['icon ' ]['url ' ];
387+ $ emoji_name = $ tag ['name ' ];
388+
389+ // Check for existing emoji by URL or placeholder.
390+ $ existing_attachments = \get_posts (
391+ array (
392+ 'post_type ' => 'attachment ' ,
393+ 'posts_per_page ' => -1 ,
394+ 'fields ' => 'ids ' ,
395+
396+ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
397+ 'meta_query ' => array (
398+ 'relation ' => 'OR ' ,
399+ array (
400+ 'key ' => 'activitypub_emoji_source_url ' ,
401+ 'value ' => $ emoji_url ,
402+ ),
403+ array (
404+ 'key ' => 'activitypub_emoji_placeholder ' ,
405+ 'value ' => $ emoji_name ,
406+ ),
407+ ),
408+ )
394409 );
410+
411+ $ attachment_id = 0 ;
412+ $ existing_attachment = 0 ;
413+ $ existing_placeholder = 0 ;
414+
415+ // Sort through results to identify URL and placeholder matches.
416+ foreach ( $ existing_attachments as $ post_id ) {
417+ if ( \get_post_meta ( $ post_id , 'activitypub_emoji_source_url ' , true ) === $ emoji_url ) {
418+ $ existing_attachment = $ post_id ;
419+ } elseif ( \get_post_meta ( $ post_id , 'activitypub_emoji_placeholder ' , true ) === $ emoji_name ) {
420+ $ existing_placeholder = $ post_id ;
421+ }
422+ }
423+
424+ // If we have a different image for this placeholder, or no existing image, download the new one.
425+ if ( empty ( $ existing_attachment ) || ! empty ( $ existing_placeholder ) ) {
426+ if ( ! function_exists ( '\download_url ' ) ) {
427+ require_once \ABSPATH . 'wp-admin/includes/file.php ' ;
428+ }
429+
430+ $ temp_file = \download_url ( $ emoji_url );
431+ if ( ! \is_wp_error ( $ temp_file ) ) {
432+ $ file_array = array (
433+ 'name ' => \wp_basename ( $ emoji_url ),
434+ 'tmp_name ' => $ temp_file ,
435+ );
436+
437+ if ( ! function_exists ( '\media_handle_sideload ' ) ) {
438+ require_once \ABSPATH . 'wp-admin/includes/media.php ' ;
439+ require_once \ABSPATH . 'wp-admin/includes/image.php ' ;
440+ }
441+
442+ $ attachment_id = \media_handle_sideload ( $ file_array , 0 , $ emoji_name );
443+
444+ if ( ! \is_wp_error ( $ attachment_id ) ) {
445+ \update_post_meta ( $ attachment_id , 'activitypub_emoji_source_url ' , $ emoji_url );
446+ \update_post_meta ( $ attachment_id , 'activitypub_emoji_placeholder ' , $ emoji_name );
447+ }
448+ }
449+
450+ if ( \is_file ( $ temp_file ) ) {
451+ \wp_delete_file ( $ temp_file );
452+ }
453+ } else {
454+ $ attachment_id = $ existing_attachment ;
455+ }
456+
457+ if ( $ attachment_id ) {
458+ $ image_url = \wp_get_attachment_url ( $ attachment_id );
459+ $ text = str_replace (
460+ $ emoji_name ,
461+ sprintf (
462+ '<img src="%s" alt="%s" class="emoji" /> ' ,
463+ \esc_url ( $ image_url ),
464+ \esc_attr ( $ emoji_name )
465+ ),
466+ $ text
467+ );
468+ } else {
469+ // Fallback to the original remote URL if something went wrong.
470+ $ text = str_replace (
471+ $ emoji_name ,
472+ sprintf (
473+ '<img src="%s" alt="%s" class="emoji" /> ' ,
474+ \esc_url ( $ emoji_url ),
475+ \esc_attr ( $ emoji_name )
476+ ),
477+ $ text
478+ );
479+ }
395480 }
396481 }
397482
0 commit comments