image_replace.module in Image Replace 7
Same filename and directory in other branches
Provides an image style effect replacing the whole image with another one.
File
image_replace.moduleView source
<?php
/**
* @file
* Provides an image style effect replacing the whole image with another one.
*/
/**
* Determine replacement image uri for the given original filename.
*
* @param string $target_style
* The target image style name.
* @param string $target_uri
* The uri of the image for which to find a replacement.
*
* @return string|null
* The replacement uri when a mapping for the given uri/style combination
* exists.
*/
function image_replace_get($target_style, $target_uri) {
return db_select('image_replace')
->fields('image_replace', array(
'replacement_uri',
))
->condition('target_style', $target_style)
->condition('target_uri', $target_uri)
->execute()
->fetchField();
}
/**
* Add an image replacement mapping.
*
* @param string $target_style
* The target image style name.
* @param string $target_uri
* The uri of the image for which to set a replacement.
* @param string $replacement_uri
* The replacement uri to set for the given uri/style combination.
*/
function image_replace_add($target_style, $target_uri, $replacement_uri) {
return db_insert('image_replace')
->fields(array(
'target_style' => $target_style,
'target_uri' => $target_uri,
'replacement_uri' => $replacement_uri,
))
->execute();
}
/**
* Remove the given image replacement mapping if it exists.
*
* @param string $target_style
* The target image style name.
* @param string $target_uri
* The uri of the image for which to remove the replacement.
*/
function image_replace_remove($target_style, $target_uri) {
return db_delete('image_replace')
->condition('target_style', $target_style)
->condition('target_uri', $target_uri)
->execute();
}
/**
* Implements hook_form_FORM_ID_alter().
*
* Add per image-field instance settings for image style replacement.
*/
function image_replace_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
if ($form['#field']['type'] == 'image') {
$instance = $form['#instance'];
$form['instance']['settings']['image_replace'] = array(
'#type' => 'fieldset',
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#title' => t('Image replace'),
'#description' => t('Use another image when rendered with certain image styles.'),
'#weight' => 99,
'#tree' => TRUE,
'#element_validate' => array(
'image_replace_form_field_ui_field_edit_form_element_validate',
),
);
$image_field_options = array();
foreach (_image_replace_image_instances($instance['entity_type'], $instance['bundle']) as $field_name => $info) {
$image_field_options[$field_name] = check_plain($info['label']);
}
unset($image_field_options[$form['#field']['field_name']]);
foreach (_image_replace_style_options() as $image_style => $label) {
$default_value = _image_replace_instance_setting($instance, 'source_field', $image_style);
$form['instance']['settings']['image_replace'][$image_style]['source_field'] = array(
'#type' => 'select',
'#title' => $label,
'#description' => t('The image field to use as a source when rendered with the %style image style.', array(
'%style' => $label,
)),
'#options' => $image_field_options,
'#default_value' => $default_value,
'#empty_value' => FALSE,
);
if ($default_value) {
$form['instance']['settings']['image_replace']['#collapsed'] = FALSE;
}
}
}
}
/**
* Form element validation callback.
*
* Displays a warning when replacement mapping is changed for fields with
* existing content.
*/
function image_replace_form_field_ui_field_edit_form_element_validate($element, &$form_state, $form) {
if (field_has_data($form['#field'])) {
$changed = FALSE;
foreach (_image_replace_style_options() as $image_style => $label) {
$current_value = $element[$image_style]['source_field']['#default_value'];
$new_value = $element[$image_style]['source_field']['#value'];
if (!(empty($current_value) && empty($new_value)) && $current_value != $new_value) {
$changed = TRUE;
break;
}
}
if ($changed) {
$replacements = array(
'@vbo_project_url' => 'https://drupal.org/project/views_bulk_operations',
'@rules_project_url' => 'https://drupal.org/project/rules',
'@admin_url' => url('admin/config/media/image-replace-rebuild-node', array(
'query' => array(
'type_op' => 'in',
'type[]' => $form['#instance']['bundle'],
),
)),
'@media_url' => url('admin/config/media'),
);
$non_node_hint = t('If it is too cumbersome to track down all existing entities and resave them, it is suggested to build an administrative View using <a href="@vbo_project_url">Views Bulk Operations</a> and <a href="@rules_project_url">Rules</a>. Image Replace comes with such a View for content entities, which can serve as an example for other entity types.', $replacements);
$hint_matrix[0][0] = $non_node_hint;
$hint_matrix[0][1] = $non_node_hint;
$hint_matrix[1][0] = t('If it is too cumbersome to track down all existing entities and resave them, it is suggested to install <a href="@vbo_project_url">Views Bulk Operations</a> and <a href="@rules_project_url">Rules</a>. Image Replace comes with an administrative View, which can be used to rebuild the image replacement mapping for existing content.', $replacements);
$hint_matrix[1][1] = t('An <a href="@admin_url">administrative interface</a> capable of rebuilding the replacement mapping is part of the <a href="@media_url">Media configuration</a>', $replacements);
$is_node = $form['#instance']['entity_type'] === 'node';
$has_vbo = module_exists('views_bulk_operations') && module_exists('rules');
$message = t('The image replacement settings have been modified. As a result, it is necessary to rebuild the image replacement mapping for existing content. Note: The replacement mapping is updated automatically when saving an entity.');
$message .= '<br>';
$message .= $hint_matrix[$is_node][$has_vbo];
$message .= '<br>';
$message .= t('Also note that images already might be cached in the browser or by any intermediate HTTP cache. On live sites the only way to force browsers to redownload a cached image is to reupload the image with a different name.');
drupal_set_message($message, 'warning');
}
}
}
/**
* Implements hook_field_attach_presave().
*
* Insert image mappings into the image replace table when entities are saved.
*/
function image_replace_field_attach_presave($entity_type, $entity) {
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
// Collect involved image fields and target mapping from image instance
// settings.
$involved_fields = array();
$target_map = array();
foreach (_image_replace_image_instances($entity_type, $bundle) as $target_field => $instance) {
$source_map = _image_replace_instance_setting($instance, 'source_field');
if (!empty($source_map)) {
$involved_fields[$target_field] = $target_field;
foreach ($source_map as $target_style => $source_field) {
$target_map[$target_field][$target_style] = $source_field;
$involved_fields[$source_field] = $source_field;
}
}
}
// Extract all uris from all involved image fields.
$uri_map = array();
foreach ($involved_fields as $field_name) {
$uri_map[$field_name] = array();
$items = field_get_items($entity_type, $entity, $field_name);
if ($items) {
foreach ($items as $item) {
$file = file_load($item['fid']);
$uri_map[$field_name][] = $file->uri;
}
}
}
// Synchronize image replacement entries.
foreach ($target_map as $target_field => $source_map) {
foreach ($source_map as $target_style => $source_field) {
foreach ($uri_map[$target_field] as $delta => $target_uri) {
image_replace_remove($target_style, $target_uri);
if (isset($uri_map[$source_field][$delta])) {
image_replace_add($target_style, $target_uri, $uri_map[$source_field][$delta]);
}
}
}
}
// Flush derived images.
foreach ($uri_map as $uris) {
foreach ($uris as $uri) {
image_path_flush($uri);
}
}
}
/**
* Implements hook_image_effect_info().
*/
function image_replace_image_effect_info() {
$effects = array();
// The array is keyed on the machine-readable effect name.
$effects['image_replace'] = array(
'label' => t('Replace image'),
'help' => t('Swap the original image if a replacement image was configured.'),
'effect callback' => 'image_replace_effect',
'dimensions passthrough' => TRUE,
);
return $effects;
}
/**
* Image effect callback: Change the image if a replacement is available.
*/
function image_replace_effect(&$image, $data) {
$replacement_file = image_replace_get($data['image_style'], $image->source);
if ($replacement_file) {
$replacement_image = image_load($replacement_file);
if ($replacement_image) {
foreach ($image as $key => $value) {
unset($image->{$key});
}
foreach ($replacement_image as $key => $value) {
$image->{$key} = $value;
}
}
}
}
/**
* Implements hook_image_styles_alter().
*
* Save image style name into replace effect settings in order to make the style
* name available from within image_replace_effect callback.
*/
function image_replace_image_styles_alter(&$styles) {
foreach ($styles as $image_style => $style) {
foreach ($style['effects'] as $ieid => $effect) {
if ($effect['name'] == 'image_replace') {
$styles[$image_style]['effects'][$ieid]['data']['image_style'] = $image_style;
}
}
}
}
/**
* Implements hook_views_api().
*/
function image_replace_views_api() {
return array(
'api' => 3,
);
}
/**
* Collect info for all image field instances on a given entity_type/bundle.
*
* @param string $entity_type
* The entity type, e.g. node, for which the info shall be returned.
* @param string $bundle
* The bundle name for which to return instances.
*
* @return array
* An associative array of instance arrays keyed by the field name.
*/
function _image_replace_image_instances($entity_type, $bundle) {
$image_instances = array();
foreach (field_info_field_map() as $field_name => $info) {
if ($info['type'] == 'image' && !empty($info['bundles'][$entity_type]) && in_array($bundle, $info['bundles'][$entity_type])) {
$instance_info = field_info_instance($entity_type, $field_name, $bundle);
$image_instances[$field_name] = $instance_info;
}
}
return $image_instances;
}
/**
* Return image replace settings for the given field instance.
*
* @param array $instance
* An array defining the field instance.
* @param string $key
* (Optional) The key of the setting to return. If $image_style is omitted,
* an associative array will be returned indexed with the image style name.
* If $image_style is given, the value of the setting for the given image
* style is returned.
* @param string $image_style
* (Optional) The name of the image style for which to retrieve the settings.
* If $key is omitted, all settings for the given image style will be
* returned. If $key is given, only the value for the given setting key is
* returned.
*
* @return any
* When a setting is defined matching the parameters, the setting value,
* otherwise NULL.
*/
function _image_replace_instance_setting(array $instance, $key = NULL, $image_style = NULL) {
$settings = isset($instance['settings']['image_replace']) ? $instance['settings']['image_replace'] : array();
$result = $settings;
if (isset($key) && isset($image_style)) {
$result = isset($settings[$image_style][$key]) ? $settings[$image_style][$key] : NULL;
}
elseif (isset($image_style)) {
$result = isset($settings[$image_style]) ? $settings[$image_style] : array();
}
elseif (isset($key)) {
$result = array();
foreach ($settings as $image_style => $values) {
if (!empty($values[$key])) {
$result[$image_style] = $values[$key];
}
}
}
return $result;
}
/**
* Return a list of image replace enabled style => label map.
*
* @return array
* A key-value list where keys are style names and values are style labels of
* image styles having a replace effect configured.
*/
function _image_replace_style_options() {
$styles = image_styles();
$result = array();
foreach ($styles as $style_name => $style) {
foreach ($style['effects'] as $effect) {
if ($effect['name'] == 'image_replace') {
$result[$style_name] = check_plain($style['label']);
}
}
}
return $result;
}
Functions
Name | Description |
---|---|
image_replace_add | Add an image replacement mapping. |
image_replace_effect | Image effect callback: Change the image if a replacement is available. |
image_replace_field_attach_presave | Implements hook_field_attach_presave(). |
image_replace_form_field_ui_field_edit_form_alter | Implements hook_form_FORM_ID_alter(). |
image_replace_form_field_ui_field_edit_form_element_validate | Form element validation callback. |
image_replace_get | Determine replacement image uri for the given original filename. |
image_replace_image_effect_info | Implements hook_image_effect_info(). |
image_replace_image_styles_alter | Implements hook_image_styles_alter(). |
image_replace_remove | Remove the given image replacement mapping if it exists. |
image_replace_views_api | Implements hook_views_api(). |
_image_replace_image_instances | Collect info for all image field instances on a given entity_type/bundle. |
_image_replace_instance_setting | Return image replace settings for the given field instance. |
_image_replace_style_options | Return a list of image replace enabled style => label map. |