5

I'm using Views and Views Datasource to generate a JSON feed for my site. I've got a Video field which has both a video and a thumbnail image.

I want to include the url of the thumbnail image in my json feed. I add the Video field to my list of fields in the View and I choose the "Video thumbnail" format instead of the "Video Player" format so that it will show the thumbnail instead of the video. When I do this in a normal View it works perfectly. However, when I do it with a JSON document view, it doesn't work properly. It renders the url to the video instead of rendering the url to the thumbnail image.

I'm going to create another question which talks about how to get this to work properly, but THIS question is my backup solution.

I can rewrite the field so that it includes the fid of the thumbnail image, so my current idea is implementing a hook that will allow me to post process the rendered json or manipulate the data structure before it gets converted to json so that I can just lookup the image by its fid and then replace that piece of data in the array with the proper image url.

I have tried MANY hooks so far, but none of them provide data which represents the json data.

  • hook_views_pre_view
  • hook_views_pre_render
  • hook_views_post_render
  • hook_views_post_execute

My guess is that Views Datasource is processing the data after I've seen it in my hook implementations.

What hook can I use so manipulate the data structure before it gets converted to json or alternatively, what hook can I use to manipulate the json string after it has been converted to json?

2 Answers 2

4

I find my 1st answer informative regarding auxillery information regarding views and views_datasource. So here's 1 way I think you get the url you want.

You said:

My guess is that Views Datasource is processing the data after I've seen it in my hook implementations.

It is, look at what views_json_view_pre_render() is doing:

function views_json_views_pre_render(&$view) {
  if(isset($view->plugin_name) && $view->plugin_name == 'views_json') {
    // Support for Video field.
    if(!empty($view->result)) {
      // Process each View result.
      foreach($view->result as $row => $result) {
        // Only process the entity fields defined by the View.
        foreach($view->field as $field_name => $field) {
          if($field instanceof views_handler_field_field) {
            if($field->field_info['type'] == 'video') {

              // Get the Video URL.
              $video = $field->get_value($view->result[$row]);
              // -- See this line !!
              $url = file_create_url($video[0]['uri']);
              $render_array = array(
                '#type' => 'markup',
                '#markup' => filter_xss($url),
              );
              // Substitute embed code with URL. @todo Add support for escaped embed codes.
              // See this line !!
              $view->result[$row]->{'field_'. $field_name}[0]['rendered'] = $render_array;
            }

If its a video field views_json is taking each of the results and replacing the embed code with the URL of the video. This is what you're seeing.

So how do you fix this. You write your own hook_views_pre_render() that runs before views_json's pre render. In your pre render function you change $video[0]['uri'] to whatever url you want -- ultimately thats the value views_json will use. If you can get the FID or the full url to the image here you should be able to easily set that value.

So in your own module you'd write 2 functions:

// File: mymodule.install
function MYMODULE_install() {
// Set the weight of the mymodule.module to a value lower than views_datasource's views_json module.
  db_update('system')
   ->fields(array('weight' => -1))
   ->condition('name', 'mymodule')
   ->execute();
}


// File: mymodule.module
/**
 * Implements hook_views_pre_render().
 */
function mymodule_views_pre_render(&$view) {
  if(isset($view->plugin_name) && $view->plugin_name == 'views_json' && $view->name == 'YOUR_SPECIFIC_VIEW') {
    // Support for Video field.
    if(!empty($view->result)) {
      // Process each View result.
      foreach($view->result as $row => $result) {
        // Only process the entity fields defined by the View.
        foreach($view->field as $field_name => $field) {
          if($field instanceof views_handler_field_field) {
            if($field->field_info['type'] == 'video') {
              // Change the video uri to the image you want ...
              $view->result[$row][0]['uri'] = /* some logic here */;
            }
          }
        }
      }
    }
  }
}

Your pre render hook will run before views_datasource's. It simply alters the url to whatever you want. Then views_datasource's views_json hook runs and just uses it as its supposed to -- you just slipped in the correct value. This should work. Code is untested.

1
  • I'll test this out tonight. Commented Jan 5, 2013 at 21:50
1

See this issue queue. Currently (some people) think field formatting in Views is brittle. It will change in Drupal8 it looks like.

I haven't done this but this very complete issue post discusses how to alter a view field currently:

Currently Views Datasource is hardcoded to use the the default Field API formatters that come with each field. I've spent enough time researching this issue and talking to the likes of @merlinofchaos (he must hate me at this point) to conclude that the problem is not in Core or Views itself. Both provide the appropriate infrastructure to completely customize the Field API rendering experience from within Views. The way that Views allows us to customize the field rendering experience is via the use of Views Plugins.

The problem with Views Datasource is that it implements Views plugins strictly via OOP inheritance. While that is perfectly O.K. if no one ever wished to override this module's behavior, it doesn't work once you need to say something like: "render me all the fields, regardless if they are empty or not", or things like "allow HTML in the title field, because that's what my manager requested". To further complicate matters, if you implement your own Views plugin, there's no clear way of telling Views Datasource: "hey, use my Views plugin!". In other words, without extensive patching or forking, there seems to be no elegant way to tame Views Datasource.

TLTR: make your own field formatter that outputs the explicit URL you want. The player stuff you describes probably looks at the view mode destination (the HTML destination, page vs feed vs json from Media) and is altering the output someway as you describe.

2
  • If Views Datasource is always going to use the default formatter, then how will creating my own formatter help? Commented Jan 5, 2013 at 5:54
  • Also, I appreciate the info about the bug in Views Datasource. If you post that answer on my other question, I'll accept it as the answer to that one. This question, however, is about what hook I can use to fix the problem given that Views Datasource isn't going to work properly. Commented Jan 5, 2013 at 6:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.