I'd like users to be able to select an image using Media Browser and insert it into the body of a node using WYSIWYG. (That works ok)

But I'd also like the image to be linked back to the node that owns it, so a reader can click the image to visit the node and see comments and other information about that photo.

There's a module http://drupal.org/project/file_entity_link that looks related to this issue. I've tried installing it and enabling "Link file to referencing entity" for the "Large" file type, but the end result is an image inserted in the text without any link.

I'm still working out how this all fits together - hopefully I'm missing some simple step?

Thanks for your help,

David

Background: I'm working on how to upgrade our D6 site, which used the Image and Image Assist modules to achieve what I described above (eg http://gwulo.com/node/12395).

Comments

damienmckenna’s picture

Files aren't "owned" by nodes, you'd have to do some custom code to customize the display and wrap the image in a link to the node after you did a lookup against the various file fields to see which ones contained that file's fid.

tsvenson’s picture

FYI http://drupal.org/project/workbench_files has a column listing what nodes a file is used on so the information is there.

However, for now this is only possible for files added to fields. Any files embedded using the media wysiwyg plugin is neither counted nor tracked yet.

davidhk’s picture

Thanks for the replies.

Just to clarify, I'll only need to know about files added to fields, not files embedded via wysiwyg.

After migrating D6 + Image module to D7 + image entity, I now have several thousand image nodes, each with one image field. So any image entity has an image node that owns / contains it.

Now I'd like that when I insert an image into a wysiwyg text area, the image is inserted, but with anchor tags linking it back to its node. Views already knows how to do that - I can make a view that shows a grid of thumbnails, choose the Views option to "Link image to: content", then if I click the thumbnail I go to the node that contains that image.

I've read that the media browser uses views to generate the grid of images we choose from.

But I'm not sure how / if there's a way to pass those anchor tags back from the view to the code that is generating the [[ ]] tags that are inserted into the wysiwyg text.

Taking a step back, does the [[ ]] markup support links?

davidhk’s picture

I've dug around a bit more, and I can't find any examples of the [[ ]] markup supporting links.

How I'd like it to work is that on the second screen of the Media Browser (where the user chooses the format), there would also be an option to choose the destination link, similar to the options in Image Assist:

Link:
- Not a link : the current behaviour.
- Link to media: eg for a local PDF, links to the file on the local server. eg for a Flickr photo, links to the page on Flickr for that photo.
- Link to referencing entity: This is my use-case - links to the Node that contains the Media entity. For an image, that could be a page with additional information and comments about the photo, and a high-resolution copy of the embedded image.
- Link to URL: User can specify the link.

But a simpler start could be to allow a file type display to pass a url to the code that's building the [[]] markup, and then alter the code that processes the markup to wrap the anchor tags for that url around the media.

There are several issues about inserting links to PDF files, eg http://drupal.org/node/1568474. A reply there points to related issues:
http://drupal.org/node/1451316
http://drupal.org/node/1283844
http://drupal.org/node/1016376

I'll try and understand those better.

davidhk’s picture

Initial requirement is to replicate current D6 Image Assist behaviour. So every image embedded into a WYSIWYG text area using the D7 Media Browser should be linked back to the node it belongs to. For the way our site is configured we can assume that there is a one-to-one mapping between an image entity and a node.

To identify the image entity's node, a couple of ideas:

  • Modify the Media Browser to send additional information about the selected image (ie the nid of its node, which Views knows about), and include the nid as an extra parameter in the '[[]]' macro.
  • Or just store the fid in the macro, and work back from the fid at runtime to work out which node contains this entity

Once we know the node, at some point during generating the html we need to add the anchor tags around the image)to give a link back to the node. How do we insert the change into the Drupal flow of building a page?

  • 'File Entity Link' implements a 'hook_theme, so that's one option
  • There look to be other hooks available too.
  • Not sure which is best way yet

How is this packaged up and presented to the administrator?

  • create a new formatter? Could be a quick way to get it working. Eg I currently need to use the 'Image' display. Could I create a new display (I think 'display' and 'formatter' have the same meaning here?) called 'Image linked to node'. It would call the existing 'Image' display to generate the current html, then wrap the extra anchor tags around it.
  • Another way is to provide an option independent of the choice of formatter. This is how the 'File Entity Link' appears, displaying a "Link file to referencing entity" checkbox. That could work too.
davidhk’s picture

Here's what I ended up doing, in case anyone else has a similar requirement. Looking back it does what Damien suggested in #1 - thanks for the tips.

It's my first code for media (and first for D7), so if you can see any better ways to do this, please let me know.

Regards, David

/**
* Implements hook_media_token_to_markup_alter. It wraps the <a> tag around 
* the image, to link it to the node.
*
* This is called near the end of media_token_to_markup(). 
* media_token_to_markup() takes the media token (ie the "[[]]" string 
* that represents an embedded media file) and passes the information
* to the correct file displays (aka formatters) so they can build a 
* render array. This function is called just before the render array 
* is rendered into HTML.
*
* On our site, all media entities (ie photos) are stored as part of a 
* node (the result of upgrading D6 Image module's nodes). Whenever a photo is 
* inserted into text via Media Browser, we want that photo linked back to
* its node, so a reader can click the photo and visit the node to learn 
* more about the photo.
*
* @param $element
*   Contains the render array, which we modify.
*
* @param $tag_info
* @param $settings
*   not used.
*   
*/
function YOURMODULENAME_media_token_to_markup_alter( &$element, $tag_info, $settings) {
	// The token-to-markup happens in two cases:
	//  1. When the WYSIWYG editor displays the text for editing
	//  2. When the saved text is displayed. 
	// Only add the link in case #2.
	if ($file->override['wysiwyg']) {
		return;
	} ;

  // Find which node is using this file. (There should always be one and 
  // only one node / file combination on our site.)
  $file = $element['#file'] ;
  $usage = file_usage_list( $file ) ;
	foreach ($usage as $module => $entity_types) {
    foreach ($entity_types as $entity_type => $entities) {
			foreach ($entities as $entity_id => $count) {
				if (($entity_type == 'node') && (!isset($nid))) {
					$nid = $entity_id ;
				}
			}
		}
  }
  if (!isset($nid)) {
		return;
	} ;

	// It would be better if the render array for a media object
	// had a '#path' field to specify a target url, the same way that
	// core image fields do (see http://data.agaric.com/wrapping-link-around-renderable-array-images-drupal-7)
	// But I don't think '#path' is supported, at least I couldn't make 
	// it work. The following way probably isn't the best, but seems to 
	// work ok.
	// We push the original render array down a level, and add the 
	// <a> tags like this:
	$new_element = array(
		'#prefix' => '<a href="/node/' . $nid. '">',
		'#suffix' => '</a>',
		'media' => $element,
	)	;
	$element = $new_element ;		
}
davidhk’s picture

Status: Active » Closed (fixed)
StuartDH’s picture

This looks just like the sort of thing that I need to add thumbnail images to textareas that link to 'content' content/node, rather than the 'file' content/node

Could anyone give some pointers on how to implement this. I've tried creating a module in sites/all/modules/custom/imagine with an imagine.info file that includes:

name = Imagine 
description = Make Media selected thumbnails link to content rather than files
package = Custom
core = 7.x

dependencies[] = file_entity
dependencies[] = image
dependencies[] = views
dependencies[] = media

and an imagine.module file with the code from #6, but imagine replacing YOURMODULENAME

function YOURMODULENAME_media_token_to_markup_alter( &$element, $tag_info, $settings)

So the imagine.module includes:

<?php

/**
* Implements hook_media_token_to_markup_alter. It wraps the <a> tag around
* the image, to link it to the node.
*
* This is called near the end of media_token_to_markup().
* media_token_to_markup() takes the media token (ie the "[[]]" string
* that represents an embedded media file) and passes the information
* to the correct file displays (aka formatters) so they can build a
* render array. This function is called just before the render array
* is rendered into HTML.
*
* On our site, all media entities (ie photos) are stored as part of a
* node (the result of upgrading D6 Image module's nodes). Whenever a photo is
* inserted into text via Media Browser, we want that photo linked back to
* its node, so a reader can click the photo and visit the node to learn
* more about the photo.
*
* @param $element
*   Contains the render array, which we modify.
*
* @param $tag_info
* @param $settings
*   not used.
*
*/
function imagine_media_token_to_markup_alter( &$element, $tag_info, $settings) {
	// The token-to-markup happens in two cases:
	//  1. When the WYSIWYG editor displays the text for editing
	//  2. When the saved text is displayed.
	// Only add the link in case #2.
	if ($file->override['wysiwyg']) {
		return;
	} ;
  // Find which node is using this file. (There should always be one and
  // only one node / file combination on our site.)
  $file = $element['#file'] ;
  $usage = file_usage_list( $file ) ;
	foreach ($usage as $module => $entity_types) {
    foreach ($entity_types as $entity_type => $entities) {
			foreach ($entities as $entity_id => $count) {
				if (($entity_type == 'node') && (!isset($nid))) {
					$nid = $entity_id ;
				}
			}
		}
  }
  if (!isset($nid)) {
		return;
	} ;
	// It would be better if the render array for a media object
	// had a '#path' field to specify a target url, the same way that
	// core image fields do (see http://data.agaric.com/wrapping-link-around-renderable-array-images-drupal-7)
	// But I don't think '#path' is supported, at least I couldn't make
	// it work. The following way probably isn't the best, but seems to
	// work ok.
	// We push the original render array down a level, and add the
	// <a> tags like this:
	$new_element = array(
		'#prefix' => '<a href="/node/' . $nid. '">',
		'#suffix' => '</a>',
		'media' => $element,
	)	;
	$element = $new_element ;
}

Is this the right thing to do? Unfortunately, after enabling the module, I can't seem to get it to work, but not sure if I'm completely barking up the wrong tree. Am I doing the right thing with the wrong code above, or is it because of a change in more recent devs of Media or wysiwyg etc.

Any help would be really appreciated

I'm using the latest Media 7.x-2.x-dev, Drupal 7.23 and Wysiwyg 7.x-2.x-dev with CKeditor 3.6.6.1

Stu

StuartDH’s picture

I've also installed the workbench_files module, but trying to embed thumbnails from the Media browser produces errors like

Notice: Undefined variable: file in imagine_media_token_to_markup_alter() (line 33 of /mysite/public_html/sites/all/modules/custom/imagine/imagine.module)

Notice: Trying to get property of non-object in imagine_media_token_to_markup_alter() (line 33 of /mysite/public_html/sites/all/modules/custom/imagine/imagine.module)

Notice: Undefined index: #file in imagine_media_token_to_markup_alter() (line 38 of mysite/sites/all/modules/custom/imagine/imagine.module)

Recoverable fatal error: Argument 1 passed to file_usage_list() must be an instance of stdClass, null given, called in line 39 of mysite/sites/all/modules/custom/imagine/imagine.module) and defined in file_usage_list() (line 607 of /mysite/public_html/includes/file.inc)

Line 33 is:

if ($file->override['wysiwyg']) {

and line 38 is:

$file = $element['#file'] ;

I guess it's because Media module has changed since this code was first posted in #6