Jest to inne podejście niż inna odpowiedź, która działa podczas importowania treści za pomocą importera i naprawia adresy URL raz na zawsze. Znowu: To nie jest testowany w bitwie, ale rozwiązanie, na którym się zdecydowałem i zadziałało.
Wolę to, ponieważ rozwiązuje problem raz na zawsze, a jeśli działa, działa. Ponieważ nie zostawiasz uszkodzonych elementów w bazie danych i nie naprawiasz ich na ekranie, nie musisz martwić się późniejszym uszkodzeniem elementów.
/*
Plugin Name: Bugfix Ticket 31581 for WP_Importer
Plugin URI: /wordpress//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'));
error issue of #13852
na myśli#18532
? :)