这是另一种方法the other answer 这在使用导入器导入内容时有效,并一次性修复URL。再次强调:这不是经过战斗考验的解决方案,但这是我确定的解决方案,它确实奏效了。
我更喜欢这种方法,因为它可以一劳永逸地解决问题,如果它奏效,它也会奏效。由于您不会将损坏的东西留在数据库中并在显示器上进行修复,因此您无需担心以后的东西损坏。
/*
Plugin Name: Bugfix Ticket 31581 for WP_Importer
Plugin URI: https://wordpress.stackexchange.com/a/206992/47733
Description: Fixes image references after post WP 4.1 image scaling change in post content when using the WP_Importer (see https://core.trac.wordpress.org/ticket/31581)
Version: 0.0.1
*/
class Bugfix31581WPImporter {
protected $remaps;
/**
* Initialize class, mainly setting up hooks
*/
public function init(){
if (WP_IMPORTING === true){
$this->remaps = array();
//This hook is chosen because it is pretty close to where the actual attachment import is happening.
//TODO: May be reconsidered.
add_filter(\'wp_update_attachment_metadata\', array($this, \'collectRemaps\'), 10 , 2);
add_action(\'import_end\', array($this, \'remap\'));
add_action(\'import_end\', array($this, \'importEnded\'));
}
}
/**
* Cleans up hooks after the import has ended.
*/
public function importEnded(){
remove_filter(\'wp_update_attachment_metadata\', array($this, \'collectRemaps\'), 10);
remove_action(\'import_end\', array($this, \'remap\'), 10);
remove_action(\'import_end\', array($this, \'importEnded\'), 10);
}
/**
* When an attachment is added compare the resulting sizes with the sizes from the legacy algorithm and setup remap.
*
* @param $data
* @param $post_id
*
* @return mixed
*/
public function collectRemaps($data, $post_id ){
$intermediate_sizes = $this->getIntermediateSizes();
if(empty($data) || !array_key_exists(\'sizes\', $data)){
return $data;
}
foreach($data[\'sizes\'] as $key => $size){
$size_new_algorithm = array($size[\'width\'], $size[\'height\']);
$dest_w = $intermediate_sizes[$key][\'width\'];
$dest_h = $intermediate_sizes[$key][\'height\'];
$crop = $intermediate_sizes[$key][\'crop\'];
add_filter(\'wp_constrain_dimensions\', array($this, \'legacy_wp_constrain_dimensions\'), 10, 5);
$size_old_algorithm = image_resize_dimensions($data[\'width\'], $data[\'height\'], $dest_w, $dest_h, $crop);
//Bail out in the rare case of `image_resize_dimensions` returning false
if($size_old_algorithm===false){
continue;
}
$size_old_algorithm = array($size_old_algorithm[4], $size_old_algorithm[5]);
remove_filter(\'wp_constrain_dimensions\', array($this, \'legacy_wp_constrain_dimensions\'), 10);
// Compare the current size with the calculation of the old algorithm...
$diff = array_diff($size_new_algorithm, $size_old_algorithm);
// ...to detect any mismatches
if(!empty($diff)){
$oldFilename = $this->getOldFilename($size[\'file\'], $size_old_algorithm);
// If getting the old filename didn\'t work for some reason (probably other filename-structure) bail out.
if($oldFilename===false){
continue;
}
if(!array_key_exists($post_id, $this->remaps)){
$this->remaps[$post_id] = array();
}
$this->remaps[$post_id][$size[\'file\']] = array(
\'file\' => $oldFilename,
\'size\' => $key
);
}
}
return $data;
}
/**
* Get resize settings for all image sizes
*
* Taken from wp_generate_attachment_metadata() in includes/image.php
*
* @return array
*/
public function getIntermediateSizes(){
global $_wp_additional_image_sizes;
$sizes = array();
foreach ( get_intermediate_image_sizes() as $s ) {
$sizes[$s] = array( \'width\' => \'\', \'height\' => \'\', \'crop\' => false );
if ( isset( $_wp_additional_image_sizes[$s][\'width\'] ) )
$sizes[$s][\'width\'] = intval( $_wp_additional_image_sizes[$s][\'width\'] ); // For theme-added sizes
else
$sizes[$s][\'width\'] = get_option( "{$s}_size_w" ); // For default sizes set in options
if ( isset( $_wp_additional_image_sizes[$s][\'height\'] ) )
$sizes[$s][\'height\'] = intval( $_wp_additional_image_sizes[$s][\'height\'] ); // For theme-added sizes
else
$sizes[$s][\'height\'] = get_option( "{$s}_size_h" ); // For default sizes set in options
if ( isset( $_wp_additional_image_sizes[$s][\'crop\'] ) )
$sizes[$s][\'crop\'] = $_wp_additional_image_sizes[$s][\'crop\']; // For theme-added sizes
else
$sizes[$s][\'crop\'] = get_option( "{$s}_crop" ); // For default sizes set in options
}
return $sizes;
}
/**
* Turn the new filename into the old filename reducing the height by one
*
* @param $newFilename
* @param $size
*
* @return mixed
*/
public function getOldFilename($newFilename, $size){
$dimensions = array();
$filetypes = $this->getAllowedImageExtentions();
// TODO: This pattern can be different. See `image_make_intermediate_size` in image editor implementation.
$matchFiles = \'/([0-9]{1,5})x([0-9]{1,5}).(\' . $filetypes . \')$/\';
// Extract the dimensions
preg_match($matchFiles,$newFilename,$dimensions);
// If the file URL doesn\'t allow guessing the dimensions bail out.
if(empty($dimensions)){
return $newFilename;
}
$newStub = $dimensions[1] . \'x\' . $dimensions[2] . \'.\' . $dimensions[3];
$oldStub = $size[0] . \'x\' . $size[1] . \'.\' . $dimensions[3];
$oldFilename = str_replace($newStub,$oldStub,$newFilename);
return $oldFilename;
}
/**
* Extract all file extensions that match an image/* mime type
*
* @return string
*/
protected function getAllowedImageExtentions(){
$allowed_filetypes = get_allowed_mime_types();
$allowed_images = array();
foreach($allowed_filetypes as $extensions => $mimetype){
if( substr($mimetype,0,6) == \'image/\' ){
$allowed_images[] = $extensions;
}
}
return implode(\'|\',$allowed_images);
}
/**
* This is the heart of this class. Based on the collected remaps from earlier it does a S&R on the DB.
*/
public function remap(){
global $wpdb;
foreach($this->remaps as $attachment_id => $replaces){
foreach($replaces as $new_url => $old_data){
$to_url = wp_get_attachment_image_src($attachment_id,$old_data[\'size\']);
$to_url = $to_url[0];
$from_url = str_replace($new_url, $old_data[\'file\'], $to_url);
// remap urls in post_content
$wpdb->query( $wpdb->prepare("UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url) );
//TODO: This is disabled as enclosures can\'t be images, right?
// remap enclosure urls
//$result = $wpdb->query( $wpdb->prepare("UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key=\'enclosure\'", $from_url, $to_url) );
}
}
}
/**
* This is a copy of the legacy pre 4.1 wp_constrain_dimensions()
*
* @param $dimensions
* @param $current_width
* @param $current_height
* @param $max_width
* @param $max_height
*
* @return array
*/
public function legacy_wp_constrain_dimensions($dimensions, $current_width, $current_height, $max_width, $max_height){
if ( !$max_width and !$max_height )
return array( $current_width, $current_height );
$width_ratio = $height_ratio = 1.0;
$did_width = $did_height = false;
if ( $max_width > 0 && $current_width > 0 && $current_width > $max_width ) {
$width_ratio = $max_width / $current_width;
$did_width = true;
}
if ( $max_height > 0 && $current_height > 0 && $current_height > $max_height ) {
$height_ratio = $max_height / $current_height;
$did_height = true;
}
// Calculate the larger/smaller ratios
$smaller_ratio = min( $width_ratio, $height_ratio );
$larger_ratio = max( $width_ratio, $height_ratio );
if ( intval( $current_width * $larger_ratio ) > $max_width || intval( $current_height * $larger_ratio ) > $max_height )
// The larger ratio is too big. It would result in an overflow.
$ratio = $smaller_ratio;
else
// The larger ratio fits, and is likely to be a more "snug" fit.
$ratio = $larger_ratio;
// Very small dimensions may result in 0, 1 should be the minimum.
$w = max ( 1, intval( $current_width * $ratio ) );
$h = max ( 1, intval( $current_height * $ratio ) );
// Sometimes, due to rounding, we\'ll end up with a result like this: 465x700 in a 177x177 box is 117x176... a pixel short
// We also have issues with recursive calls resulting in an ever-changing result. Constraining to the result of a constraint should yield the original result.
// Thus we look for dimensions that are one pixel shy of the max value and bump them up
if ( $did_width && $w == $max_width - 1 )
$w = $max_width; // Round it up
if ( $did_height && $h == $max_height - 1 )
$h = $max_height; // Round it up
return array( $w, $h );
}
}
add_filter(\'import_start\',array(new Bugfix31581WPImporter(),\'init\'));