<?php
if (!defined('ABSPATH')) {
die('No direct access.');
}
/**
* Utility class to handle various image tasks
*/
class MetaSlider_Image
{
/**
* Theme instance
*
* @var object
* @see get_instance()
*/
protected static $instance = null;
/**
* Used to access the instance
*/
public static function instance()
{
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Method to import an image (or more than one). If nothing passed in it will load in a random one from
* the theme directory. A theme can also be defined.
*
* @param array $images - Images to upload, if any
* @param string $theme_id - The folder name of a theme
* @return WP_Error|array - The array of ids that were uploaded
*/
public function import($images, $theme_id = null)
{
/*
If we are provided images, they should be formatted already
It should look like this, possibly without the meta data
$image[$url] = array(
'source' => $tmp_name,
'caption' => '',
'title' => '',
'description' => '',
'alt' => ''
);
*/
if (empty($images)) {
$images = $this->get_theme_images($theme_id);
}
// Get an array or sucessful image ids
return $this->upload_multiple($images);
}
/**
* Method to import images from a theme
*
* @param array $images - The full path to the local image or an array that includes the path
*/
public function upload_multiple($images)
{
$successful_uploads = array();
foreach ($images as $filename => $image) {
if ($image_id = $this->upload($filename, $image['source'], $image)) {
array_push($successful_uploads, $image_id);
}
}
return $successful_uploads;
}
/**
* Method to upload a single image, you should provide a local location on the server
*
* @param string $filename - The preferred name of the file
* @param string $source - The current location of the file without the file name
* @param array $meta_data - Extra data like caption, description, etc
* @return int|boolean - returns the ID of the new image, or false
*/
public function upload($filename, $source, $meta_data = array())
{
if (!function_exists('media_handle_upload')) {
require_once(ABSPATH . 'wp-admin/includes/image.php');
require_once(ABSPATH . 'wp-admin/includes/file.php');
require_once(ABSPATH . 'wp-admin/includes/media.php');
}
if (file_exists($source)) {
$wp_upload_dir = wp_upload_dir();
// Create a new filename if needed
$filename = wp_unique_filename(trailingslashit($wp_upload_dir['path']), $filename);
// Get the file path of the target destination
$destination = trailingslashit($wp_upload_dir['path']) . $filename;
// We want these both to return true
if (copy($source, $destination)) {
if ((bool) $image_id = $this->attach_image_to_media_library($destination, $meta_data)) {
return $image_id;
}
}
// TODO: we might want to provide a specific error message if an image
// fails to upload.
return false;
}
// If we make it this far then the file doesn't exit
return false;
}
/**
* Adds the type and image id to an array
*
* @param int $image_id Image ID
* @return array
*/
public function make_layer_slide_data($image_id)
{
return array(
'type' => 'layer',
'id' => absint($image_id)
);
}
/**
* Method to import images from a theme
*
* @param array|null $theme_id - The name of a theme
* @param int $count - How many images? (4 for legacy reasons)
* @return array - a formatted image array
*/
public function get_theme_images($theme_id, $count = 4)
{
// To use local images, the folder must exist
if (!file_exists($theme_image_directory = METASLIDER_THEMES_PATH . 'images/')) {
return new WP_Error('images_not_found', __('We could not find any images to import.', 'ml-slider'), array('status' => 404));
}
if (is_multisite() && $settings = get_site_option('metaslider_global_settings')) {
$global_settings = $settings;
}
if ($settings = get_option('metaslider_global_settings')) {
$global_settings = $settings;
}
$new_install = get_option('metaslider_new_user');
if (
(isset($global_settings['legacy']) && true == $global_settings['legacy']) ||
(isset($new_install) && 'new' == $new_install)
) {
$manifest_file = 'manifest.php';
} else {
$manifest_file = 'manifest-legacy.php';
}
// Check for the manifest, and load theme specific images for a theme (if a theme is set)
if (!is_null($theme_id) && file_exists(METASLIDER_THEMES_PATH . $manifest_file)) {
$themes = (include METASLIDER_THEMES_PATH . $manifest_file);
// Check if the theme is available and has images set
foreach ($themes as $theme) {
if (!empty($theme['images']) && $theme_id === $theme['folder']) {
$images = $theme['images'];
}
}
}
// Get list of images in the folder
$all_images = array_filter(scandir($theme_image_directory), array($this, 'filter_images'));
// If images are specified, make sure they exist and use them. if not, use 4 at random
$images = !empty($images) ? $this->pluck_images($images, $all_images) : array_rand(array_flip($all_images), $count);
$images_formatted = array();
foreach ((array) $images as $filedata) {
$data = array();
// Only process strings or arrays
if (!is_string($filedata) && !is_array($filedata)) {
continue;
}
// If a string, convert it to an array with the string as the key (filename)
if (is_string($filedata)) {
$data[$filedata] = array();
$filename = $filedata;
}
// If it was an array, the filename needs to become the key
if (!empty($filedata['filename'])) {
$filename = $filedata['filename'];
unset($filedata['filename']);
$data = $filedata;
}
// Set the local images dir as the source
$data['source'] = trailingslashit($theme_image_directory) . $filename;
/*
It should look like this, possibly without the meta data
$images_formatted[$filename] = array(
'source' => $tmp_name,
'caption' => '',
'title' => '',
'description' => '',
'alt' => ''
);
*/
$images_formatted[$filename] = $data;
}
return $images_formatted;
}
/**
* Method to use filter out non-images
* TODO: possible extract this into static method on a utility class
*
* @param string $string - a filename scanned from the images dir
* @return boolean
*/
private function filter_images($string)
{
// TODO: allow all image types (this is currently used in the themes folder only)
return preg_match('/jpg$/i', $string);
}
/**
* Method to use filter out images that might not exist
* TODO: possible extract this into static method on a utility class
*
* @param array $images_to_use - Images defined in the manifest
* @param array $images - Images from the images folder
* @return array
*/
private function pluck_images($images_to_use, $images)
{
// For the filename/caption scenario
if (!empty($images_to_use[0]) && is_array($images_to_use[0])) {
// Just return the multi-dimentional array and handle the filecheck later
return $images_to_use;
}
// Return the images specified by the filename or four random
$images_that_exist = array_intersect($images_to_use, $images);
return (!empty($images_that_exist)) ? $images_that_exist : array_rand(array_flip($images), 4);
}
/**
* Method to add a file to the media library
* TODO: possible extract this into static method on a utility class
*
* @param string $filename - The full path to the image dir in the media library
* @param array $image_data - Optional data to attach / override to the image
* @return int
*/
private function attach_image_to_media_library($filename, $image_data = array())
{
$filetype = wp_check_filetype(basename($filename), null);
$wp_upload_dir = wp_upload_dir();
$attachment = array(
'guid' => $wp_upload_dir['url'] . '/' . basename($filename),
'post_mime_type' => $filetype['type'],
'post_title' => preg_replace('/\.[^.]+$/', '', basename($filename)),
'post_content' => '',
'post_excerpt' => '',
'post_status' => 'publish'
);
// Add the caption, title and description if set. This used human-friendly words
// instead of WP specific to make it more simple for theme developers
if (!empty($image_data['caption'])) {
$image_data['post_excerpt'] = $image_data['caption'];
unset($image_data['caption']);
}
if (!empty($image_data['title'])) {
$image_data['post_title'] = $image_data['title'];
unset($image_data['title']);
}
if (!empty($image_data['description'])) {
$image_data['post_content'] = $image_data['description'];
unset($image_data['description']);
}
// Merge the theme data with the defaults
$data = array_merge($attachment, $image_data);
// Insert the attachment
$attach_id = wp_insert_attachment($data, $filename);
// Double check it was an image, delete if not.
if (!wp_attachment_is_image($attach_id)) {
wp_delete_post($attach_id, true);
return false;
}
// Generate the metadata for the attachment, and update the database record
$attach_data = wp_generate_attachment_metadata($attach_id, $filename);
wp_update_attachment_metadata($attach_id, $attach_data);
// The theme can set the alt tag too if needed
if ($attach_id && !empty($image_data['alt'])) {
update_post_meta($attach_id, '_wp_attachment_image_alt', $image_data['alt']);
}
return $attach_id;
}
/**
* Method to get image id from the filename
*
* @param array $filenames - It should be the the post_name
* @return array
*/
public static function get_image_ids_from_file_name($filenames)
{
$images = array();
foreach ($filenames as $filename) {
$image = get_posts(array(
'post_type' => 'attachment',
'name' => $filename,
'posts_per_page' => 1,
'post_status' => 'inherit',
));
$image = $image ? array_pop($image) : null;
if (is_null($image)) {
$images[$filename] = null;
continue;
}
$images[$filename] = array(
'url' => wp_get_attachment_url($image->ID),
'thumbnail' => wp_get_attachment_thumb_url($image->ID),
'id' => $image->ID
);
}
return $images;
}
}