diff --git a/bin/noblogs.in b/bin/noblogs.in index 05fd9a79fc8be7f4b1f5b97e136ee65e305d0b11..d7e9e411208cdf2f3ebb2d4b8ba528d90c08e46f 100755 --- a/bin/noblogs.in +++ b/bin/noblogs.in @@ -68,6 +68,10 @@ Known commands: Set read-only mode for the local noblogs installation. The argument must be either the literal 'on' or 'off'. + ngg-convert BLOG + Convert Next Gen Gallery (NGG) photo galleries to stardard Wordpress + galleries, and then notify (via email) admins of the fact. + <?php exit(1); } @@ -415,6 +419,23 @@ function do_set_readonly($args) { } +function do_ngg_convert($args) { + require_once(dirname(__FILE__) . '/ngg.php'); + foreach ($args as $arg) { + $blog = noblogs_get_blog($arg); + if (!$blog) { + echo "Blog {$arg} not found.\n"; + continue; + } + switch_to_blog($blog->blog_id); + echo "Converting blog ${arg}: \n"; + $post_ids = ngg_convert(); + ngg_alert_admin($post_ids); + restore_current_blog(); + } +} + + // Command-line parsing. $cmd = $argv[1]; if (!$cmd) { diff --git a/lib/ngg.php b/lib/ngg.php new file mode 100644 index 0000000000000000000000000000000000000000..63cf2ffc01cd9985b998503a0f868316240710e0 --- /dev/null +++ b/lib/ngg.php @@ -0,0 +1,242 @@ +<?php + +require_once(NOBLOGS_ROOT . '/wp-admin/includes/media.php'); +require_once(NOBLOGS_ROOT . '/wp-admin/includes/file.php'); +require_once(NOBLOGS_ROOT . '/wp-admin/includes/image.php'); + +function ngg_get_post_ids( $limit = -1 ) { + $args = array( + 's' => '[nggallery', + 'post_type' => array( 'post', 'page' ), + 'post_status' => 'any', + 'nopaging' => true, + 'fields' => 'ids', + 'posts_per_page' => $limit + ); + + $query = new WP_Query( $args ); + return $query->posts; +} + +function do_ngg_count($args) { + foreach ($args as $arg) { + $blog = noblogs_get_blog($arg); + if (!$blog) { + echo "Blog {$arg} not found.\n"; + continue; + } + switch_to_blog($blog->blog_id); + $post_ids = ngg_get_post_ids(); + $count = count($post_ids); + echo "${arg} : ${count} \n"; + foreach ( $post_ids as $post_id ) { + $post = get_post( $post_id ); + $gallery_count = count(ngg_find_gallery_shortcodes($post)); + echo "\t ${post_id}: ${gallery_count} \n"; + } + restore_current_blog(); + } +} + +function ngg_upload_image($post, $path, $image){ + $url = home_url( trailingslashit( $path ) . $image->filename ); + // Let's use a hash trick here to find our attachment post after it's been sideloaded. + $hash = md5( 'attachment-hash' . $url . $image->description . time() . rand( 1, 999 ) ); + $result = media_sideload_image( $url, $post->ID, $hash ); + if ( is_wp_error( $result ) ) { + echo sprintf( "Error loading %s: %s\n", $url, $result->get_error_message() ); + return; + } else { + $attachments = get_posts( array( + 'post_parent' => $post->ID, + 's' => $hash, + 'post_type' => 'attachment', + 'posts_per_page' => -1, + ) ); + + if ( ! $attachments || ! is_array( $attachments ) || count( $attachments ) != 1 ) { + echo sprintf( "Error: Could not insert attachment for %d\n", $post->ID ); + return; + } + } + return $attachments[0]; +} + +function ngg_upload_gallery($post,$gallery_id){ + global $wpdb; + $path = $wpdb->get_row( "SELECT * FROM {$wpdb->prefix}ngg_gallery WHERE gid = ". intval( $gallery_id ), ARRAY_A ); + $images = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}ngg_pictures WHERE galleryid = ". intval( $gallery_id ) . " ORDER BY sortorder, pid ASC" ); + + if ( ! $path || ! $images ) { + echo sprintf( "Warning: Could not find images for nggallery %d\n", $gallery_id ); + return; + } + $attached_images = []; + + foreach ( $images as $image ) { + $attachment = ngg_upload_image($post, $path['path'], $image); + + // Titles should fallback to the filename. + if ( ! trim( $image->alttext ) ) { + $image->alttext = $image->filename; + } + + $attachment->post_title = $image->alttext; + $attachment->post_content = $image->description; + $attachment->menu_order = $image->sortorder; + + update_post_meta( $attachment->ID, '_wp_attachment_image_alt', $image->alttext ); + + wp_update_post( $attachment ); + $attached_images[] = $attachment->ID; + echo sprintf( "Log: Added attachment %d for post %d \n", $attachment->ID, $post->ID ); + } + return array( $images, $attached_images ); +} + +// If there are existing images attached the post, +// let's remember to exclude them from our new gallery. +function ngg_exclude_existing_attachments($post_ID){ + $existing_attachments_ids = get_posts( array( + 'post_type' => 'attachment', + 'post_status' => 'inherit', + 'post_parent' => $post_ID, + 'post_mime_type' => 'image', + 'fields' => 'ids', + ) ); + + $attr = array(); + if ( $existing_attachments_ids ) + $attr['exclude'] = implode( ',', $existing_attachments_ids ); + + return $attr; +} + +function ngg_find_gallery_shortcodes($post){ + $matches = null; + preg_match_all( '/\[nggallery.*?\]/si', $post->post_content, $matches ); + return $matches[0]; +} + +function ngg_parse_shortcode($shortcode){ + $atts = shortcode_parse_atts($shortcode); + return intval( $atts['id'] ); +} + +function ngg_convert() { + global $wpdb; + $uploads = wp_upload_dir(); + $baseurl = $uploads['baseurl']; + $posts_count = 0; + $gallery_count = 0; + $images_count = 0; + $blog_id = get_current_blog_id(); + + $post_ids = ngg_get_post_ids(); + foreach ( $post_ids as $post_id ) { + $post = get_post( $post_id ); + $matches = null; + + // If there are existing images attached the post, + // let's remember to exclude them from our new gallery. + $code_attr = ngg_exclude_existing_attachments($post->ID); + + foreach ( ngg_find_gallery_shortcodes($post) as $shortcode ){ + $gallery_id = ngg_parse_shortcode($shortcode); + + list ($gallery_images, $attached_images) = ngg_upload_gallery($post, $gallery_id); + + if ( count($gallery_images) != count($attached_images) ) { + echo "Not replacing ${shortcode}. "; + echo sprintf("%d of %d images converted.\n", count($attached_images), count($gallery_images)); + continue; + } + + // Construct the [gallery] shortcode + $code_attr['ids'] = implode(',', $attached_images); + $new_shortcode = '[gallery'; + foreach ( $code_attr as $key => $value ) + $new_shortcode .= sprintf( ' %s="%s"', esc_attr( $key ), esc_attr( $value ) ); + $new_shortcode .= ']'; + + $post->post_content = str_replace( $shortcode, $new_shortcode, $post->post_content ); + echo sprintf( "Log: Blog id %d. Updated gallery id %d of post %d \n", $blog_id, $gallery_id, $post->ID ); + $images_count += count($attached_images); + $gallery_count++; + } + + // Booyaga! + wp_update_post( $post ); + $posts_count++; + } + + echo "Log: Converted ${posts_count} posts, ${gallery_count} galleries and ${images_count} images \n"; + return $post_ids; +} + +function ngg_alert_admin($post_ids = null) { + if (!$post_ids){ + $post_ids = ngg_get_post_ids(); + } + $posts_count = count($post_ids); + + $blog_id = get_current_blog_id(); + $blog_name = get_bloginfo('name'); + if (!$blog_name){ + $blog_name = home_url(); + } + $blog_url = site_url(); + $admin_email = get_bloginfo('admin_email'); + $admin_user = get_user_by( 'email', $admin_email); + $admin_name = $admin_user->user_nicename; + if (!$admin_name){ + $admin_name = $admin_email; + } + + $post_list = ""; + foreach ( $post_ids as $post_id ) { + $post_title = get_post($post_id)->post_title; + $post_url = get_permalink($post_id); + $post_list = $post_list . "${post_title}: ${post_url} \n"; + } + + $mail_body = <<<EOT +Dear ${admin_name}, +you are receiving this message because your are the admin of the blog "${blog_name}" +${blog_url} + +We are in the process of removing the NextGen Gallery Plugin and converting all existing +image galleries to the standard Wordpress media manager. + +In your blog, we have found that the following posts include NextGen Galleries that should +have been converted: +${post_list} +If everything went well, you do not have to do anything at all. +Please check that the images are showing correctly, and let us know if something went wrong. + +with love and +kaos +Autistici/Inventati +------------------- + +Caro ${admin_name}, +ricevi questa email perché sei l'amministratore del blog "${blog_name}" +${blog_url} + +Stiamo per rimuovere il plugin NextGen Gallery e abbiamo trasferito tutte le gallerie +di immagini al gestore di media di Wordpress. + +Nel tuo blog, ci sono i seguenti posts che includevano gallerie di NextGen e che sono +state convertite: +${post_list} +Se è andato tutto a buon fine, non devi fare nient'altro. +Controlla che le immagini si visualizzano correttamente, e facci sapere se c'è qualcosa +che non va. + +con amore e +kaos +Autistici/Inventati + +EOT; + echo "Sending email to ${admin_email} \n"; + wp_mail($admin_email, "[Noblogs] Removing NextGen Gallery Plugin", + $mail_body, 'From: Autistici/Inventati <info@autistici.org>' . "\r\n"); +}