Created
March 10, 2025 21:05
-
-
Save davidwolfpaw/1af6ba483c66a7f1a2ac7be581f4b6d2 to your computer and use it in GitHub Desktop.
Update Image Alt Text in All Blocks (Multisite + Custom Blocks)
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: Update Image Alt Text in All Blocks (Multisite + Custom Blocks) | |
* Description: WP-CLI command to update alt text in all images inside blocks for all sites in a multisite network, including custom blocks. | |
*/ | |
if ( defined( 'WP_CLI' ) && WP_CLI ) { | |
class Network_Update_All_Image_Alts_Command { | |
/** | |
* Run the image alt text update across all sites in the network. | |
* | |
* ## EXAMPLES | |
* | |
* wp network-update-all-image-alts | |
* | |
* @when after_wp_load | |
*/ | |
public function __invoke() { | |
if ( ! is_multisite() ) { | |
WP_CLI::error( 'This command is for multisite installs only.' ); | |
return; | |
} | |
$sites = get_sites( array( 'number' => 0 ) ); | |
WP_CLI::log( 'Starting alt text updates on ' . count( $sites ) . ' sites...' ); | |
foreach ( $sites as $site ) { | |
switch_to_blog( $site->blog_id ); | |
$site_name = get_bloginfo( 'name' ); | |
WP_CLI::log( "Processing site: {$site_name} (ID: {$site->blog_id})" ); | |
$updated_count = $this->run_image_alt_update_on_current_site(); | |
WP_CLI::log( "Finished {$site_name}: {$updated_count} posts/pages updated.\n" ); | |
restore_current_blog(); | |
} | |
WP_CLI::success( 'All sites processed!' ); | |
} | |
/** | |
* Runs the image alt text update on the current site. | |
* | |
* @return int Number of updated posts. | |
*/ | |
private function run_image_alt_update_on_current_site() { | |
$args = array( | |
'post_type' => array( 'post', 'page' ), // Add CPTs if needed. | |
'post_status' => 'publish', | |
'posts_per_page' => -1, | |
); | |
$query = new WP_Query( $args ); | |
$updated_count = 0; | |
foreach ( $query->posts as $post ) { | |
$original_content = $post->post_content; | |
$updated_content = $this->update_image_alts_in_all_blocks( $original_content ); | |
if ( $updated_content !== $original_content ) { | |
wp_update_post( | |
array( | |
'ID' => $post->ID, | |
'post_content' => $updated_content, | |
) | |
); | |
WP_CLI::log( "Updated post ID {$post->ID} ({$post->post_title})" ); | |
++$updated_count; | |
} | |
} | |
return $updated_count; | |
} | |
/** | |
* Parses and updates alt text for images in all blocks within post content. | |
* Uses serialize_blocks() to preserve block markup. | |
* | |
* @param string $content The post content. | |
* @return string Updated content. | |
*/ | |
private function update_image_alts_in_all_blocks( $content ) { | |
$blocks = parse_blocks( $content ); | |
$updated_blocks = array(); | |
foreach ( $blocks as $block ) { | |
$updated_blocks[] = $this->process_any_block_recursive( $block ); | |
} | |
// Use serialize_blocks() to keep block markup intact. | |
return serialize_blocks( $updated_blocks ); | |
} | |
/** | |
* Recursively process blocks to update image alt text. | |
* | |
* @param array $block | |
* @return array | |
*/ | |
private function process_any_block_recursive( $block ) { | |
// === Generic Core Block Handling === | |
if ( ! empty( $block['attrs'] ) && ! empty( $block['attrs']['id'] ) ) { | |
$attachment_id = $block['attrs']['id']; | |
$media_alt = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ); | |
if ( $media_alt ) { | |
if ( empty( $block['attrs']['alt'] ) || $block['attrs']['alt'] !== $media_alt ) { | |
$block['attrs']['alt'] = $media_alt; | |
} | |
} | |
} | |
if ( ! empty( $block['attrs']['images'] ) && is_array( $block['attrs']['images'] ) ) { | |
foreach ( $block['attrs']['images'] as &$image ) { | |
if ( ! empty( $image['id'] ) ) { | |
$attachment_id = $image['id']; | |
$media_alt = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ); | |
if ( $media_alt ) { | |
if ( empty( $image['alt'] ) || $image['alt'] !== $media_alt ) { | |
$image['alt'] = $media_alt; | |
} | |
} | |
} | |
} | |
} | |
// === Custom Kirkwood Block Handling === | |
if ( $block['blockName'] === 'kirkwood/story-section-block' && ! empty( $block['attrs']['sections'] ) ) { | |
foreach ( $block['attrs']['sections'] as $section_key => &$section_data ) { | |
// Main imageID handling | |
if ( isset( $section_data['imageID'] ) && is_numeric( $section_data['imageID'] ) ) { | |
$attachment_id = $section_data['imageID']; | |
$media_alt = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ); | |
if ( $media_alt ) { | |
if ( empty( $section_data['altText'] ) || $section_data['altText'] !== $media_alt ) { | |
$section_data['altText'] = $media_alt; | |
} | |
} | |
} | |
// Optional: Mobile ImageID handling | |
if ( isset( $section_data['mobileImageID'] ) && is_numeric( $section_data['mobileImageID'] ) ) { | |
$attachment_id = $section_data['mobileImageID']; | |
$media_alt = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ); | |
if ( $media_alt ) { | |
if ( empty( $section_data['mobileAltText'] ) || $section_data['mobileAltText'] !== $media_alt ) { | |
$section_data['mobileAltText'] = $media_alt; | |
} | |
} | |
} | |
} | |
} | |
// === Recursively Process Inner Blocks === | |
if ( ! empty( $block['innerBlocks'] ) ) { | |
foreach ( $block['innerBlocks'] as &$inner_block ) { | |
$inner_block = $this->process_any_block_recursive( $inner_block ); | |
} | |
} | |
return $block; | |
} | |
} | |
// Register the WP-CLI command. | |
WP_CLI::add_command( 'network-update-all-image-alts', 'Network_Update_All_Image_Alts_Command' ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment