: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* Routines for generation of custom image sizes and deletion of these sizes.
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
if ( ! function_exists( 'themify_do_img' ) ) {
* Resize images dynamically using wp built in functions
* @param string|int $image Image URL or an attachment ID
function themify_do_img( $image, $width, $height,bool $crop = false ):array {
$attachment_id =$img_url= null;
if(!is_numeric( $width ) ){
if(!is_numeric( $height ) ){
// if an attachment ID has been sent
if( is_numeric( $image ) ) {
$post = get_post( $image );
$attachment_id = $post->ID;
$img_url = wp_get_attachment_url( $attachment_id );
if(strpos($image,'data:image/' )!==false ){
// URL has been passed to the function
$img_url = esc_url( $image );
// Check if the image is an attachment. If it's external return url, width and height.
if(strpos($img_url,themify_upload_dir('baseurl'))===false){
if($width==='' || $height===''){
$size = themify_get_image_size($img_url);
// Finally, run a custom database query to get the attachment ID from the modified attachment URL
$attachment_id = themify_get_attachment_id_from_url( $img_url);
// Fetch attachment metadata. Up to this point we know the attachment ID is valid.
$meta = $attachment_id ?wp_get_attachment_metadata( $attachment_id ):null;
// missing metadata. bail.
if (!is_array( $meta )) {
$ext=strtolower(strtok(pathinfo($img_url,PATHINFO_EXTENSION ),'?'));
if($ext==='png' || $ext==='jpg' || $ext==='jpeg' || $ext==='webp' || $ext==='gif' ||$ext==='bmp' ){//popular types
$upload_dir = themify_upload_dir();
$attached_file=str_replace($upload_dir['baseurl'],$upload_dir['basedir'],$img_url);
if(!is_file ($attached_file)){
$attached_file=$attachment_id?get_attached_file( $attachment_id ):null;
$size=themify_get_image_size($attached_file,true);
'file'=>trim(str_replace($upload_dir['basedir'],'',$attached_file),'/')
//if the meta doesn't exist it means the image large size also doesn't exist,that is why checking if the image is too large before cropping,otherwise the site will down
if($meta['width']>2560 || $meta['height']>2560){
unset($upload_dir,$ext,$size,$attached_file);
if ( ! is_array( $meta ) ) {
// Perform calculations when height or width = 0
if ( empty( $height ) ) {
// If width and height or original image are available as metadata
if ( !empty( $meta['width'] ) && !empty( $meta['height'] ) ) {
// Divide width by original image aspect ratio to obtain projected height
// The floor function is used so it returns an int and metadata can be written
$height = (int)(floor( $width / ( $meta['width'] / $meta['height'] ) ));
// Check if resized image already exists
if ( is_array( $meta ) && isset( $meta['sizes']["resized-{$width}x{$height}"] ) ) {
$size = $meta['sizes']["resized-{$width}x{$height}"];
if( isset( $size['width'],$size['height'] )) {
$split_url = explode( '/', $img_url );
if( ! isset( $size['mime-type'] ) || $size['mime-type'] !== 'image/gif' ) {
$split_url[ count( $split_url ) - 1 ] = $size['file'];
'url' => implode( '/', $split_url ),
'attachment_id' => $attachment_id
// Requested image size doesn't exists, so let's create one
add_filter( 'image_resize_dimensions', 'themify_img_resize_dimensions', 10, 5 );
// Patch meta because if we're here, there's a valid attachment ID for sure, but maybe the metadata is not ok.
$meta['sizes'] = array( 'large' => array() );
// Generate image returning an array with image url, width and height. If image can't be generated, original url, width and height are used.
$image = themify_make_image_size( $attachment_id, $width, $height, $meta, $img_url );
remove_filter( 'image_resize_dimensions', 'themify_img_resize_dimensions', 10 );
$image['attachment_id'] = $attachment_id;
if ( ! function_exists( 'themify_make_image_size' ) ) {
* Creates new image size.
* @uses get_attached_file()
* @uses image_make_intermediate_size()
* @uses wp_update_attachment_metadata()
* @uses update_post_meta()
* @param int $attachment_id
function themify_make_image_size( $attachment_id, $width, $height, $meta, $img_url ):array {
if($width!==0 || $height!==0){
$upload_dir = themify_upload_dir();
$attached_file=str_replace($upload_dir['baseurl'],$upload_dir['basedir'],$img_url);
if(!Themify_Filesystem::is_file ($attached_file)){
$attached_file=get_attached_file( $attachment_id );
$source_size = apply_filters( 'themify_image_script_source_size', themify_get( 'setting-img_php_base_size', 'large', true ) );
if ( $source_size !== 'full' && isset( $meta['sizes'][ $source_size ]['file'] ) ){
$attached_file = str_replace( $meta['file'], trailingslashit( dirname( $meta['file'] ) ) . $meta['sizes'][ $source_size ]['file'], $attached_file );
$resized = image_make_intermediate_size( $attached_file, $width, $height, true );
if ( $resized && ! is_wp_error( $resized ) ) {
// Save the new size in metadata
$key = sprintf( 'resized-%dx%d', $width, $height );
$meta['sizes'][$key] = $resized;
$img_url = str_replace( basename( $img_url ), $resized['file'], $img_url );
wp_update_attachment_metadata( $attachment_id, $meta );
// Save size in backup sizes, so it's deleted when the original attachment is deleted.
$backup_sizes = get_post_meta( $attachment_id, '_wp_attachment_backup_sizes', true );
if ( ! is_array( $backup_sizes ) ){
$backup_sizes[$key] = $resized;
update_post_meta( $attachment_id, '_wp_attachment_backup_sizes', $backup_sizes );
$img_url=esc_url($img_url);
// Return original image url, width and height.
* Disable the min commands to choose the minimum dimension, thus enabling image enlarging.
function themify_img_resize_dimensions( $default, $orig_w, $orig_h, $dest_w, $dest_h ):array {
// set portion of the original image that we can size to $dest_w x $dest_h
$aspect_ratio = $orig_w / $orig_h;
$new_w = (int)( $new_h * $aspect_ratio );
$new_h = (int)( $new_w / $aspect_ratio );
$size_ratio = max( $new_w / $orig_w, $new_h / $orig_h );
$crop_w = round( $new_w / $size_ratio );
$crop_h = round( $new_h / $size_ratio );
$s_x = floor( ( $orig_w - $crop_w ) / 2 );
$s_y = floor( ( $orig_h - $crop_h ) / 2 );
// the return array matches the parameters to imagecopyresampled()
// int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h
return array( 0, 0, (int) $s_x, (int) $s_y, (int) $new_w, (int) $new_h, (int) $crop_w, (int) $crop_h );
if( ! function_exists( 'themify_get_attachment_id_from_url' ) ) :
* Get attachment ID for image from its url.
* @param deprecated $base_url
function themify_get_attachment_id_from_url(string $url = '', $base_url = '' ):int {
/* cache IDs, for when an image is displayed multiple times on the same page */
// If this is the URL of an auto-generated thumbnail, get the URL of the original image
$url = preg_replace( '/-\d+x\d+(?=\.(jpg|jpeg|png|gif|webp|bmp)$)/i', '', $url );
if ( ! isset( $cache[ $url ] ) ) {
$cache[ $url ] = themify_get_attachment_id_cache( $url );
* Convert image URL to attachment ID, data is cached in a db for faster access
function themify_get_attachment_id_cache(string $url ):int {
$id = Themify_Storage::get($k);
if ($id==='0' || ($id>0 && get_post_type($id)==='attachment') ) {
$id = attachment_url_to_postid( $url );
Themify_Storage::set($k,$id);
* Removes protocol and www from URL and returns it
function themify_remove_protocol_from_url( $url ) {//deprecated will be removed
return preg_replace( '/https?:\/\/(www\.)?/', '', $url );
function themify_create_webp(string $url):string{//@todo move to class
if(!isset($info['extension'])){
$orig_ex = strtok($info['extension'],'?');
if($orig_ex!=='png' && $orig_ex!=='jpg' && $orig_ex!=='jpeg' && $orig_ex!=='gif'){
if(apply_filters('themify_disable_webp',false)===false){
if(class_exists('Imagick',false)){
if (in_array('WEBP', $im->queryFormats('WEBP'),true) ) {
$available['Imagick']=true;
if(!isset($available['Imagick']) &&function_exists('imagewebp') && (function_exists('imagecreatefromjpeg') || function_exists('imagecreatefrompng'))){
$upload_dir= themify_upload_dir();
$sameDomain=strpos($url,$upload_dir['baseurl'])!==false;
if($sameDomain===false && strpos($url,'http')!==0){//relative to absolute
$tmp_url = home_url($url);
$sameDomain=strpos($tmp_url,$upload_dir['baseurl'])!==false;
if(is_subdomain_install()){
$blog_name = explode('.',$_SERVER['SERVER_NAME']);
$blog_name=$blog_name[0];
if(strpos($url,$blog_name)===false){
if(!isset($_SERVER['SERVER_NAME']) || strpos($url,$_SERVER['SERVER_NAME'])===false){
$site_url = dirname(site_url());
if(strpos($url,$site_url)===false){
$blog_name =explode('/',trim(str_replace($site_url,'',$url),'/'));
$blog_name=$blog_name[0];
if(!isset($sites[$blog_name])){
$blog = get_id_from_blogname($blog_name);
$sites[$blog_name]=false;
$currentBlog=pathinfo(get_site_url(),PATHINFO_FILENAME);
$blog_upload_dir_info = wp_get_upload_dir();
$sites[$blog_name] = array('basedir'=>$blog_upload_dir_info['basedir'],'baseurl'=>str_replace('/'.$currentBlog.'/','/'.$blog_name.'/',$blog_upload_dir_info['baseurl']));// bug in WP return the current blog name url,not switched
elseif($sites[$blog_name]===false){
$upload_dir=$sites[$blog_name];
elseif($sameDomain===false){
$res=str_replace($upload_dir['baseurl'],$upload_dir['basedir'],urldecode($res));
if(strpos($res,'http')===0){
$resUrl=str_replace('.'.$orig_ex, '.webp', $res);
return str_replace($upload_dir['basedir'],$upload_dir['baseurl'],$resUrl);
$webp_quality = (int) themify_builder_get( 'setting-webp-quality', 'performance-webp_quality' );
if ( empty( $webp_quality ) ) {
if(isset($available['Imagick'])){
$lowerExt=explode('/',$im->getImageMimeType());
$lowerExt=str_replace('x-','',$lowerExt[1]);
if(($lowerExt!=='png' && $lowerExt!=='jpg' && $lowerExt!=='jpeg' && $lowerExt!=='gif') || $im->getImageWidth()>2560 || $im->getImageHeight()>2560){
if($im->setImageFormat( 'webp' ) && $im->setOption( 'webp:method', $webp_quality ) && $im->setOption('webp:lossless','false') && $im->setOption('webp:low-memory', 'true') && $im->setOption('webp:use-sharp-yuv', 'true')) {
if (($lowerExt !== 'png' || ($im->setOption('webp:alpha-compression', 1) && $im->setOption('webp:alpha-quality', 85))) && $im->stripImage()) {
$webp = $lowerExt === 'gif' ? $im->writeImages($resUrl, true) : $im->writeImage($resUrl);
if($lowerExt === 'gif') {
$im->optimizeImageLayers();
$webp = file_put_contents($resUrl, ($lowerExt==='gif'?$im->getImagesBlob():$im->getImageBlob()));
Themify_Filesystem::delete($resUrl,'f');
if(function_exists('exif_imagetype')){
$size=image_type_to_mime_type(exif_imagetype($res));
elseif(function_exists('finfo_file')){
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$size=finfo_file($finfo, $res);
if(function_exists('mime_content_type')){
$size = mime_content_type($res);
$size = getimagesize($res);
if(!isset($size['mime']) || !isset($size[0]) || !isset($size[1]) || $size[0]>2560 || $size[1]>2560){
$size=explode('/',$size);
if($lowerExt!=='png' && $lowerExt!=='jpg' && $lowerExt!=='jpeg'){
if(!function_exists('imagecreatefromjpeg')){