You are here

function acquia_lift_personalize_campaign_wizard_targeting_alter in Acquia Lift Connector 7.2

Alter hook for the targeting portion of the campaign wizard.

Acquia Lift Target agents allow for audience designation to be used across the agent.

File

./acquia_lift.admin.wizard.inc, line 776
acquia_lift.admin.wizard.inc Functions specific to the Acquia Lift alteration of the campaign creation wizard.

Code

function acquia_lift_personalize_campaign_wizard_targeting_alter(&$form, &$form_state, $agent_data, $editable) {

  // If targeting was already found to be unsupported, then do not add.
  if (isset($form['unsupported'])) {
    return;
  }

  // Explicit targeting is not allowed for multivariate tests.
  $variation_set_handling = isset($agent_data->data['variation_set_handlng']) ? $agent_data->data['variation_set_handling'] : ACQUIA_LIFT_DECISION_LOCKSTEP;
  if ($variation_set_handling == ACQUIA_LIFT_DECISION_MULTIVARIATE) {
    unset($form['targeting'], $form['actions']);
    $form['main'] = array(
      '#markup' => t('Targeting is not supported for multivariate tests.'),
    );
    return;
  }
  if (!$editable) {
    $form['targeting']['#disabled'] = TRUE;
  }
  $option_set = acquia_lift_get_option_set_for_targeting($agent_data->machine_name);
  if (empty($option_set)) {
    return;
  }

  // Take over the form validation and submit handling.
  $form['#validate'] = array(
    'acquia_lift_personalize_campaign_wizard_validate',
  );
  $form['#submit'] = array(
    'acquia_lift_personalize_campaign_wizard_submit',
  );
  unset($form['targeting']['option_sets']);
  $variation_options = $saved_targeting = array();
  $option_sets = personalize_option_set_load_by_agent($agent_data->machine_name);
  $all_variations = _acquia_lift_personalize_campaign_wizard_variation_displays($option_sets, $variation_set_handling, FALSE);

  // Convert the variations into an associative array of displays keyed by
  // targeting option id that can be used as select input options.
  $display_attributes = array();
  $has_multiple = count($option_sets) > 1;
  if ($has_multiple && $variation_set_handling == ACQUIA_LIFT_DECISION_LOCKSTEP) {
    $display_attributes['class'] = array(
      'acquia-lift-variations-lockstep',
    );
  }
  foreach ($all_variations as $displays) {
    $variation_displays = array();
    $targeting_option_id = '';
    foreach ($displays as $option) {
      if (is_string($option)) {
        $variation_displays[] = $option;
      }
      else {
        $display_vars['option'] = $option['option_label'];
        if (isset($option['option_set_label'])) {
          $display_vars['option_set'] = $option['option_set_label'];
        }
        $variation_displays[] = theme('acquia_lift_single_variation', $display_vars);
      }
      if (!$has_multiple || !empty($option['targeting'])) {
        $targeting_option_id = $option['option_id'];
      }
    }

    // The targeting option id could remain empty if there are invalid
    // combinations of options resulting in a smaller number of variations in
    // the option set used for targeting.
    if (!empty($targeting_option_id)) {
      $variation_options[$targeting_option_id] = '<div ' . drupal_attributes($display_attributes) . '>' . implode('<br />', $variation_displays) . '</div>';
    }
  }

  // Load the targeting that is currently in use for a campaign.
  $existing_targeting = acquia_lift_get_structure_from_targeting($option_set);

  // Track whether an option to revert targeting changes should be shown.
  $show_revert = FALSE;
  $status = personalize_agent_get_status($agent_data->machine_name);

  // The settings reflected in the form will either be what is currently running
  // or any saved overrides from when this form was last submitted (if the
  // review step was never completed to apply them.)
  if (!empty($agent_data->data['lift_targeting'])) {

    // Get the current state of targeting work within the UI that has not
    // yet been saved to the agent.
    $saved_targeting = $agent_data->data['lift_targeting'];
    if ($editable && $saved_targeting != $existing_targeting && $status != PERSONALIZE_STATUS_NOT_STARTED) {
      drupal_set_message(t('The targeting settings shown here do not match what is currently implemented for this personalization.'), 'warning');
      $show_revert = TRUE;
    }
  }
  else {
    if ($editable && $status != PERSONALIZE_STATUS_NOT_STARTED) {

      // The current agent is running and there have been no UI changes made
      // since it was started.
      drupal_set_message(t('The targeting settings shown here represent what is currently implemented for this personalization.'));
    }

    // Set the saved targeting to be the same as existing targeting for
    // presentation within this form.
    $saved_targeting = $existing_targeting;
  }

  // Begin the audience form.
  $form['targeting']['audiences'] = array(
    '#type' => 'container',
    '#tree' => TRUE,
    '#attributes' => array(
      'id' => 'acquia-lift-targeting-audiences',
      'class' => array(
        'personalize-wizard-column',
      ),
    ),
  );

  // Add a new audience rule.
  $new_audiences_id = 'acquia-lift-targeting-audiences-new';
  $form['targeting']['audiences']['new'] = array(
    '#type' => 'container',
    '#attributes' => array(
      'id' => $new_audiences_id,
    ),
  );
  $form['targeting']['audiences']['new']['add'] = array(
    '#type' => 'submit',
    '#value' => t('Add target audience'),
    '#theme_wrappers' => array(
      'acquia_lift_add_card_button',
    ),
    '#access' => $editable,
    '#submit' => array(
      'acquia_lift_personalize_campaign_wizard_targeting_audience_add',
    ),
    '#limit_validation_errors' => array(),
    '#ajax' => array(
      'callback' => 'acquia_lift_personalize_campaign_wizard_targeting_audience_ajax',
      'wrapper' => $new_audiences_id,
      'effect' => 'fade',
    ),
  );
  if (isset($form_state['new_audiences'])) {
    foreach ($form_state['new_audiences'] as $delta => $details) {
      $form['targeting']['audiences']['new'][$delta] = array(
        '#type' => 'container',
        '#theme' => 'acquia_lift_card',
        '#collapsible' => TRUE,
        '#collapsed' => !isset($form_state['expanded_audience']) || $form_state['expanded_audience'] != $delta,
        '#title' => t('New target audience #@num', array(
          '@num' => $delta + 1,
        )),
        '#attributes' => array(
          'class' => array(
            'acquia-lift-campaign-add',
          ),
        ),
        '#access' => $editable,
      );
      $form['targeting']['audiences']['new'][$delta]['details'] = _acquia_lift_personalize_campaign_wizard_targeting_audience($form, $form_state, $agent_data, 'new', $delta);

      // TRICKY: Name must be specified or else it will default to "op" and
      // conflict with the main process bar save button.
      $form['targeting']['audiences']['new'][$delta]['save_audience'] = array(
        '#name' => 'save_new_audience_' . $delta,
        '#type' => 'submit',
        '#value' => t('Save'),
      );
      $form['targeting']['audiences']['new'][$delta]['cancel'] = array(
        '#type' => 'submit',
        '#name' => 'cancel_audience_' . $delta,
        '#value' => t('Cancel'),
        '#limit_validation_errors' => array(),
        '#submit' => array(
          'acquia_lift_personalize_campaign_wizard_targeting_audience_cancel',
        ),
        '#ajax' => array(
          'callback' => 'acquia_lift_personalize_campaign_wizard_targeting_audience_ajax',
          'wrapper' => $new_audiences_id,
          'effect' => 'fade',
        ),
      );
    }
  }

  // Load all existing audiences for the agent.
  if (isset($option_set->targeting)) {

    // Sort the audiences by weight for display.
    uasort($option_set->targeting, function ($a, $b) {
      if ($a['weight'] === $b['weight']) {
        return 0;
      }
      else {
        return $a['weight'] < $b['weight'] ? -1 : 1;
      }
    });
    $form['targeting']['audiences']['existing'] = array(
      '#type' => 'container',
    );
    if (count($option_set->targeting) > 2 && $editable) {

      // Show instructions regarding re-ordering audiences.  This only applies
      // when there are at least two audiences beyond the "Everyone" audience.
      $form['targeting']['audiences']['existing']['priority'] = array(
        '#markup' => '<div class="acquia-lift-audience-priority"><h4>' . t('Audience Priority') . '</h4><p>' . t('Drag and drop audiences to change the order in which they are targeted.  Audiences at the top of the list will be targeted before audiences below them.') . '</p></div>',
      );
    }
    $fallback_audience = acquia_lift_get_fallback_audience_name(array_keys($option_set->targeting));
    foreach ($option_set->targeting as $audience_id => $audience) {
      $form['targeting']['audiences']['existing'][$audience_id] = array(
        '#type' => 'container',
        '#theme' => 'acquia_lift_card',
        '#title' => isset($audience['label']) ? $audience['label'] : 'Audience: ' . $audience_id,
        '#collapsible' => FALSE,
        '#sortable' => $audience_id !== $fallback_audience && count($option_set->targeting) > 2,
        '#flag' => t('Test'),
        '#flag_visible' => isset($saved_targeting[$audience_id]) && count($saved_targeting[$audience_id]) > 1,
      );
      $form['targeting']['audiences']['existing'][$audience_id]['header'] = array(
        '#type' => 'container',
      );
      if ($editable) {
        if ($audience_id === $fallback_audience) {
          if (count($option_set->targeting) == 1) {
            $help = t('This audience is composed of all visitors who have not been selected to view a specific variation. Create a new audience above to assign specific variations to groups of visitors.');
          }
          else {
            $help = t('This audience is composed of all visitors who have not been selected to view a specific variation. Variations in the Everyone else audience will be shown to any person that does not match the audiences you have listed here.');
          }
          $form['targeting']['audiences']['existing'][$audience_id]['#title_attributes']['data-help-tooltip'] = $help;
        }
        else {
          $form['targeting']['audiences']['existing'][$audience_id]['header']['edit'] = array(
            '#type' => 'checkbox',
            '#title' => t('Edit'),
            '#attributes' => array(
              'class' => array(
                'acquia-lift-edit',
              ),
            ),
          );
          $form['targeting']['audiences']['existing'][$audience_id]['header']['delete'] = array(
            '#markup' => l(t('Delete'), 'admin/structure/personalize/manage/' . $agent_data->machine_name . '/audience/' . $audience_id . '/delete', array(
              'attributes' => array(
                'class' => array(
                  'acquia-lift-delete',
                ),
              ),
            )),
          );

          // Show the form to edit the audience segment when edit is selected.
          $form['targeting']['audiences']['existing'][$audience_id]['details'] = _acquia_lift_personalize_campaign_wizard_targeting_audience($form, $form_state, $agent_data, 'existing', $audience_id, $audience);
          $form['targeting']['audiences']['existing'][$audience_id]['details']['#states'] = array(
            'visible' => array(
              ':input[name="audiences[existing][' . $audience_id . '][header][edit]"]' => array(
                'checked' => TRUE,
              ),
            ),
          );
        }
      }

      // Show the form to assign variations when not in edit mode.
      $classes = array(
        'acquia-lift-targeting-assignment',
      );
      if ($audience_id === $fallback_audience) {
        $classes[] = 'acquia-lift-targeting-everyone-else';
      }

      // This message will only be shown when there two or more variations
      // assigned to an audience.
      $form['targeting']['audiences']['existing'][$audience_id]['message'] = array(
        '#type' => 'container',
        '#attributes' => array(
          'class' => array(
            'acquia-lift-test-message',
          ),
        ),
        'tests' => array(
          '#markup' => t('These variations will be displayed as a test, with the first variation in the list as the control.'),
        ),
      );
      $form['targeting']['audiences']['existing'][$audience_id]['assignment'] = array(
        '#type' => 'select',
        '#title' => t('Add display option'),
        '#multiple' => TRUE,
        '#options' => $variation_options,
        '#default_value' => isset($saved_targeting[$audience_id]) ? $saved_targeting[$audience_id] : '',
        '#empty_option' => t('Select...'),
        '#states' => array(
          'visible' => array(
            ':input[name="audiences[existing][' . $audience_id . '][header][edit]"]' => array(
              'checked' => FALSE,
            ),
          ),
        ),
        '#attributes' => array(
          'class' => $classes,
          'data-acquia-lift-targeting-droppable' => TRUE,
          'data-acquia-lift-targeting-allow-move' => TRUE,
          'data-acquia-lift-targeting-allow-remove' => TRUE,
        ),
      );

      // Keep track of the assignment order of options within the audience.
      $form['targeting']['audiences']['existing'][$audience_id]['assignment_order'] = array(
        '#type' => 'textfield',
        '#maxlength' => NULL,
        '#title' => t('Assignment order'),
        '#default_value' => isset($saved_targeting[$audience_id]) ? implode(',', $saved_targeting[$audience_id]) : '',
        '#attributes' => array(
          'class' => array(
            'acquia-lift-targeting-assignment-order',
          ),
        ),
      );

      // Show the ability to select a winner for an audience if:
      // - the campaign has run
      // - the campaign is not completed
      // - the audience was used in targeting
      // - the audience has a test currently implemented in Lift
      // - the audience contents has not changed from what was implemented
      $status = personalize_agent_get_status($agent_data->machine_name);
      if (!empty($agent_data->started) && $status != PERSONALIZE_STATUS_COMPLETED && isset($existing_targeting[$audience_id]) && count($existing_targeting[$audience_id]) > 1 && isset($saved_targeting[$audience_id]) && $existing_targeting[$audience_id] == $saved_targeting[$audience_id]) {

        // Add this button to the footer so that it can still be available
        // even when the card is disabled.  This allows availability even
        // when the campaign is running.
        $form['targeting']['audiences']['existing'][$audience_id]['footer'] = array(
          '#type' => 'container',
        );
        $form['targeting']['audiences']['existing'][$audience_id]['footer']['complete_url'] = array(
          '#type' => 'hidden',
          // Per ctools modals the class name is the #id of the triggering
          // ajax button with "-url" suffix.
          '#attributes' => array(
            'class' => array(
              'acquia-lift-complete-' . $audience_id . '-url',
            ),
          ),
          '#value' => url('admin/structure/personalize/manage/' . $agent_data->machine_name . '/audience/' . $audience_id . '/complete'),
        );
        $form['targeting']['audiences']['existing'][$audience_id]['footer']['complete'] = array(
          '#type' => 'button',
          '#value' => t('End test and choose winner'),
          '#attributes' => array(
            'id' => 'acquia-lift-complete-' . $audience_id,
            'class' => array(
              'ctools-use-modal',
              'ctools-modal-acquia-lift-style',
              'action-item-primary-active',
              'acquia-lift-submit-button',
              'acquia-lift-complete-audience',
            ),
            'data-acquia-lift-audience-id' => $audience_id,
          ),
          '#disabled' => FALSE,
        );
      }
    }

    // Show advanced settings for personalization.
    // These only apply when tests exist, but these are created on the client
    // so the mark-up needs to be here to show/hide dynamically.
    $form['targeting']['audiences']['advanced'] = array(
      '#type' => 'container',
      '#theme' => 'acquia_lift_card',
      '#title' => t('Test settings'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
      '#tree' => FALSE,
      '#attributes' => array(
        'class' => array(
          'acquia-lift-test-options',
        ),
      ),
      '#disabled' => !$editable,
    );
    $form['targeting']['audiences']['advanced']['options'] = _acquia_lift_personalize_campaign_wizard_settings_tests($agent_data, array());
  }

  // Add ability to revert changes to targeting.
  if ($show_revert) {
    $form['actions']['revert'] = array(
      '#type' => 'submit',
      '#value' => t('Revert changes'),
      '#attributes' => array(
        'class' => array(
          'acquia-lift-submit-button',
        ),
      ),
    );
  }

  // Show all variations so that even if there are unassigned variations they
  // can be dragged into appropriate audiences.
  $form['targeting']['variations'] = array(
    '#type' => 'container',
    '#attributes' => array(
      'class' => array(
        'personalize-wizard-column',
      ),
      'id' => 'acquia-lift-targeting-variations',
    ),
    '#tree' => TRUE,
  );
  $form['targeting']['variations']['options'] = array(
    '#type' => 'container',
    '#theme' => 'acquia_lift_card',
    '#title' => t('All variations'),
    '#collapsible' => FALSE,
    '#attributes' => array(
      'class' => array(
        'acquia-lift-informational',
      ),
    ),
  );
  $form['targeting']['variations']['options']['instructions'] = array(
    '#markup' => t('To display a variation to a specific audience, drag the variation to the audience.'),
  );
  $form['targeting']['variations']['options']['assignment'] = array(
    '#type' => 'select',
    '#title' => t('Drag variations to the desired audiences.'),
    '#multiple' => TRUE,
    '#options' => $variation_options,
    '#default_value' => array_keys($variation_options),
    '#attributes' => array(
      'class' => array(
        'acquia-lift-targeting-assignment',
      ),
      'data-acquia-lift-targeting-allow-copy' => TRUE,
      'data-acquia-lift-targeting-allow-move' => FALSE,
      'data-acquia-lift-targeting-allow-remove' => FALSE,
    ),
  );
}