So in my continuing quest to display a form with Solr search results in a Ctools modal window and use a pager, I've managed to get everything to display fine after the initial search, but when I use the pager, I get a white screen with the data in json format instead of everything displayed in the modal again. Here is the relevant code:

function imgsearch_page($ajax, $id, $a, $b) {
  if ($ajax) {
    //Load the modal library and add the modal javascript.

    $form_state = array(
      'ajax' => TRUE,
      'title' => t('Image Search Form'),
      'next_field_id' => $id,

    // Use ctools to generate ajax instructions for the browser to create
    // a form in a modal popup.
    $search_form = ctools_modal_form_wrapper('imgsearch_form', $form_state);

    if (($form_state['executed'] && $form_state['ajax']) || isset($_GET['page'])) {
      // If the form has been submitted, there may be additional instructions
      // such as dismissing the modal popup.
      if (!empty($form_state['ajax_commands'])) {
        $output = $form_state['ajax_commands'];

      if ($form_state['values']['search_terms'] != '' || isset($_GET['search_terms'])) {
        $page_num = isset($_GET['page']) ? $_GET['page'] : 0;

        if ($_GET['search_terms']) {
          $form_state['values']['search_terms'] = $_GET['search_terms'];
        $results = nb_image_search_search($form_state['values'], $page_num);

        if (is_array($results['images']) && count($results['images'] > 0)) {
          $next_field_id = $form_state['next_field_id'];
          // Create object to store file and target field info. To be stored in ctools cache.
          $file_info = new stdClass();
          // Generate the field name.  field_images is a multivalue field collection, so we just need the next available option
          // in the $field_images['und'] array. The second number (for field_image) will always be 0 since it
          // is a single value field.
          $file_info->fieldname['url'] = '#edit-field-images-und-' . $next_field_id . '-field-image-und-0-imgsearch-file-url';
          $file_info->fieldname['person'] = '#edit-field-images-und-' . $next_field_id . '-field-person-und-0-value';
          $file_info->fieldname['organization'] = '#edit-field-images-und-' . $next_field_id . '-field-organization-und-0-value';
          $file_info->fieldname['year'] = '#edit-field-images-und-' . $next_field_id . '-field-year-und-0-value';

          $file_info->fids = array();

          // Theme the results as a table.
          $header = array(t('Image'), t('File Name'), t('Add to field'));
          $rows = array();
          foreach ($results['images'] as $image) {
            // Create image style derivative for each image.
            $imagestyle = array(
              'style_name' => 'thumbnail',
              'path' => $image['filepath'] . $image['filename'],
              'width' => '',
              'height' => '',
              'alt' => '',
              'title' => $image['filename'],
            $styled_image = theme('image_style', $imagestyle);
            $fid = $image['fid'];

            $rows[] = array(
              'image' => $styled_image,
              'name' => $image['filename'],
              'add' => ctools_ajax_text_button("select", "imgsearch/nojs/imgadd/" . $fid . '/' . $next_field_id, t('Select')),

            $file_info->fids[$fid] = $image['filename'];

            // Cache values for Person, Organization, and Year if they exist.
            foreach (array('person', 'organization', 'year') as $field) {
              if (isset($image[$field])) {
                $file_info->meta[$fid][$field] = $image[$field];
          //Cache image name in ctools object cache so it can be used later in nb_image_search_image_add()
          ctools_object_cache_set('imgsearch', 'imgsearch_' . $next_field_id, $file_info);

          // Create a render array ($build) which will be themed as a table with a
          // pager.
          $build['search_form'] = isset($search_form[0]) ? drupal_build_form('imgsearch_form', $form_state) : $search_form;
          $build['imgsearch_table'] = array(
            '#theme' => 'table',
            '#header' => $header,
            '#rows' => $rows,
            '#empty' => t('There were no matching results found'),

          // Attach the pager theme.
          $pager = pager_default_initialize($results['total_found'], $results['rows']);
          $build['imgsearch_pager'] = array(
            '#theme' => 'pager',
            '#parameters' => array(
              'search_terms' => $form_state['values']['search_terms'],
              //TODO: add params for Person, Organization, and Year.

          $form_state['values']['title'] = t('Search Results');
          $output = ctools_modal_form_render($form_state['values'], $build);

          print ajax_render($output);
        else {
          $build['no_results'] = array(
            'markup' => '<div class="no-results>No images found</div>',
    elseif (!isset($output)) {
      $output = ctools_modal_form_wrapper('imgsearch_form', $form_state);
      // Return the ajax instructions to the browser via ajax_render().
      print ajax_render($output);
  else {
    return drupal_get_form('imgsearch_form', $id);

The only real difference is that since form field values are removed somehow when the form is submitted via ajax, I use the #parameters element in the pager array, which puts it in $_GET[], allowing me to access it in the search function (nb_image_search_search()). The page argument is also there, put there by the pager. Since ctools_modal_form_wrapper() returns the form in rendered mode, I have to rebuild it again to pass it to ctools_modal_form_render().

Other than that, I don't see any differences. I've stepped through the code all the way to the call to drupal_json_encode() in ajax_render(), but can't get any farther than that.

What would be causing the json to just be displayed on a white screen instead of displaying in the modal, but only when I'm using the pager link?



2 Answers 2


The answer turned out to be a missing class in my pager links. Whenever you use CTools Modal, you have to add the ctools-use-modal class to the link. My first thought was to add the class as a link attribute in the link themeing functions, since the theme_pager_link() function accepts attributes (via $values['attributes']). However, the functions that actually call theme_pager_link() (e.g. theme_pager_previous(), theme_pager_next(), and theme_pager_last()) don't bother to actually pass attributes, so there's no way to get them to the link function. Sigh.

So, to work around this, I just created a quick jQuery behavior that adds the ctools-use-modal class to the pager links:

(function ($) {
    Drupal.behaviors.addCtoolsModalClass = {
        attach: function (context) {
          $('#modalContent .pagination ul li a').addClass('ctools-use-modal');

and voila!, it works as it should.


use array_chunks after pager_default_initialize.

A small example from my code, hope it will help you.

$per_page = 10;
$current_page = pager_default_initialize(count($result['node_ids']), $per_page);
$chunks = array_chunk(node_load_multiple($result['node_ids']),$per_page, TRUE);

Your Answer

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

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