Created
March 10, 2025 18:11
-
-
Save davidwolfpaw/fbe020cd282c4f6ad7ed805f5ad72a85 to your computer and use it in GitHub Desktop.
Sync attachment titles and alt text across WordPress multisite sites
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Plugin Name: Sync Attachment Meta | |
* Description: Sync attachment titles and alt text across multisite sites. Choose a source site to pull titles and alt text from, and have matching attachments updated on all other sites. | |
* Version: 1.0.0 | |
*/ | |
// Confirm that WP-CLI is available. | |
if ( defined( 'WP_CLI' ) && WP_CLI ) { | |
/** | |
* Sync attachment titles and alt text across multisite sites. | |
*/ | |
class Sync_Attachment_Meta_Command { | |
/** | |
* Sync titles and alt text based on post_title or filename match. | |
* | |
* <source_site_id> The ID of the source site to pull titles/alt text from. | |
* | |
* Example Command: wp sync-attachment-meta 1 | |
*/ | |
public function __invoke( $args ) { | |
list( $source_site_id ) = $args; | |
if ( ! is_multisite() ) { | |
WP_CLI::error( 'This script only works on multisite installs.' ); | |
} | |
$sites = get_sites(); | |
// Switch to the source site and get attachments. | |
switch_to_blog( $source_site_id ); | |
WP_CLI::log( "Switched to source site: {$source_site_id}" ); | |
// Get all attachments on the source site. | |
// Note: This will only get attachments that are in the media library. | |
$attachments = get_posts( | |
array( | |
'post_type' => 'attachment', | |
'post_status' => 'inherit', | |
'posts_per_page' => -1, | |
) | |
); | |
// Display count of attachments found. | |
WP_CLI::log( 'Found ' . count( $attachments ) . ' attachments on source site.' ); | |
// Collect source site attachment data indexed by both title and filename. | |
$attachment_data = array(); | |
foreach ( $attachments as $attachment ) { | |
$alt_text = get_post_meta( $attachment->ID, '_wp_attachment_image_alt', true ); | |
$file_path = get_post_meta( $attachment->ID, '_wp_attached_file', true ); | |
$file_name = basename( $file_path ); | |
// Add both title and filename as keys for quick lookup. | |
$attachment_data[ $attachment->post_title ] = array( | |
'title' => $attachment->post_title, | |
'caption' => $attachment->post_excerpt, | |
'alt' => $alt_text, | |
'file' => $file_name, | |
); | |
$attachment_data[ $file_name ] = array( | |
'title' => $attachment->post_title, | |
'caption' => $attachment->post_excerpt, | |
'alt' => $alt_text, | |
'file' => $file_name, | |
); | |
} | |
restore_current_blog(); | |
// Loop through all sites and update matching attachments. | |
foreach ( $sites as $site ) { | |
$site_id = (int) $site->blog_id; | |
// Skip the source site. | |
if ( $site_id === (int) $source_site_id ) { | |
continue; | |
} | |
// Display site ID being processed. | |
WP_CLI::log( "Processing site ID: {$site_id}" ); | |
switch_to_blog( $site_id ); | |
$site_attachments = get_posts( | |
array( | |
'post_type' => 'attachment', | |
'post_status' => 'inherit', | |
'posts_per_page' => -1, | |
) | |
); | |
$updated_count = 0; | |
foreach ( $site_attachments as $site_attachment ) { | |
$site_file_path = get_post_meta( $site_attachment->ID, '_wp_attached_file', true ); | |
$site_file_name = basename( $site_file_path ); | |
$site_title = $site_attachment->post_title; | |
$matched_data = null; | |
// Check if there's a match by post_title or file_name. | |
if ( isset( $attachment_data[ $site_title ] ) ) { | |
$matched_data = $attachment_data[ $site_title ]; | |
} elseif ( isset( $attachment_data[ $site_file_name ] ) ) { | |
$matched_data = $attachment_data[ $site_file_name ]; | |
} | |
if ( $matched_data ) { | |
// Update post title and caption. | |
wp_update_post( | |
array( | |
'ID' => $site_attachment->ID, | |
'post_title' => $matched_data['title'], | |
'post_excerpt' => $matched_data['caption'], | |
) | |
); | |
// Check if alt text already exists on this attachment. | |
$existing_alt_text = get_post_meta( $site_attachment->ID, '_wp_attachment_image_alt', true ); | |
if ( empty( $existing_alt_text ) ) { | |
// If there is no alt text, add it. | |
update_post_meta( $site_attachment->ID, '_wp_attachment_image_alt', $matched_data['alt'] ); | |
WP_CLI::log( "Updated attachment ID {$site_attachment->ID} on site {$site_id} (matched by title or filename: {$matched_data['file']}, alt text added)" ); | |
} else { | |
// Alt text already exists, skip updating | |
WP_CLI::log( "Skipped alt text for attachment ID {$site_attachment->ID} on site {$site_id} (alt text already present)" ); | |
} | |
++$updated_count; | |
} | |
} | |
WP_CLI::log( "Site {$site_id} complete. Updated {$updated_count} attachments." ); | |
restore_current_blog(); | |
} | |
WP_CLI::success( 'Attachment meta sync complete!' ); | |
} | |
} | |
WP_CLI::add_command( 'sync-attachment-meta', 'Sync_Attachment_Meta_Command' ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment