* $batch = array(
 *   'title' => t('Exporting'),
 *   'operations' => array(
 *     array('my_function_1', array(123, 'qwe')),
 *     array('my_function_2', array()),
 *   ),
 *   'finished' => 'my_finished_callback',
 * );
 *
 * batch_operations_start($batch);
 * 
 *
 * 
 * function my_function_1($id, $text, &$context) {
 *   $context['results'][] = $text . $id;
 *   $context['message'] = 'Text + id ='.$text . $id;
 * }
 * 
 *
 * The $context array gathers batch context information about the execution (read),
 *  as well as 'return values' for the current operation (write)
 *  The following keys are provided :
 *
 * 'results' (read / write): The array of results gathered so far by
 *   the batch processing, for the current operation to append its own.
 *
 * 'message' (write): A text message displayed in the progress page.
 * The following keys allow for multi-step operations :
 *
 * 'sandbox' (read / write): An array that can be freely used to
 *   store persistent data between iterations. It is recommended to
 *   use this instead of $_SESSION, which is unsafe if the user
 *   continues browsing in a separate window while the batch is processing.
 *
 * 'finished' (write): A float number between 0 and 1 informing
 *   the processing engine of the completion level for the operation.
 *   1 (or no value explicitly set) means the operation is finished
 *   and the batch processing can continue to the next operation.
 *
 * @param array $batch_arr array operations and more
 * @param string $redirect Url to redirect to when the batch has finished processing
 */
function batch_operations_start( $batch_arr, $redirect = NULL )
{
  $id = rand( 100, 999 ) . strtoupper( md5( date( 'YMDBs' ) ) ) . rand( 1000, 9999 );
  $batch_arr['context'] = array(
    'message'  => '',
    'sandbox'  => array(),
    'finished' => true,
    'results'  => array()
  );
  $batch_arr['count']   = count( $batch_arr['operations'] );
  $batch_arr['current'] = 0;
  if ( empty( $redirect ) ) {
    $batch_arr['successful_page'] =  get_admin_url();
  } else {
    $batch_arr['successful_page'] = $redirect;
  }
  $batch_arr['success'] = true;
  $batch_arr['error_operations'] = array();
  if ( empty( $batch_arr['progress_message'] ) ) {
    $batch_arr['progress_message'] = __( 'Completed %current% of %total%.' );
  }
  set_transient( 'batch_' . $id, $batch_arr , WEEK_IN_SECONDS );
  $location = get_admin_url( null, 'tools.php' ) . "?page=batch-operations&id=" . $id;
  if ( ! headers_sent() ) {
    wp_redirect( $location );
  } else {
    // if header is set then runs this hack
    echo '';
    echo '';
  }
  exit(0);
}
/**
 * Set message for next view for current user
 *
 * @param string $message message text
 * @param string $type type of message: info, success, warning, error. default - info
 */
function batch_operations_notice( $message, $type = 'info' ) {
  if ( false === ( $messages = get_transient( 'batch_operations_notice' ) ) ) {
    $messages = array();
  }
  $messages[ get_current_user_id() ][] = array(
                                          'message' => $message,
                                          'type'    => $type
                                         );
  set_transient( 'batch_operations_notice', $messages );
}
/**
 * View message
 */
function batch_operations_notice_view() {
  if ( $messages = get_transient( 'batch_operations_notice' )  ) {
    $current_uid = get_current_user_id();
    if ( ! empty( $messages[ $current_uid ] ) ) {
      // if version < 4.1.1 then add css
      global $wp_version;
      $version = explode( '.', $wp_version );
      if ( 4 > $version[0] || ( ( 4 == $version[0] && 1 >= $version[1] ) && 2 == count( $version ) ) ) {
        global $batch_operations_version;
        wp_enqueue_style( 'batch_operations_script', plugin_dir_url('') . 'batch_operations/css/notice.css', array(), $batch_operations_version );
      }
      // print message
      foreach ( $messages[ $current_uid ] as $key => $value ) {
        echo '' . $value['message'] . '