GravityView  2.10.1
The best, easiest way to display Gravity Forms entries on your website.
class-gravityview-field-sequence.php
Go to the documentation of this file.
1 <?php
2 /**
3  * @file class-gravityview-field-sequence.php
4  * @package GravityView
5  * @subpackage includes\fields
6  */
7 
8 /**
9  * Add a sequence field.
10  * @since 2.3.3
11  */
13 
14  var $name = 'sequence';
15 
16  var $contexts = array( 'single', 'multiple' );
17 
18  /**
19  * @var bool
20  */
21  var $is_sortable = false;
22 
23  /**
24  * @var bool
25  */
26  var $is_searchable = false;
27 
28  /**
29  * @var bool
30  */
31  var $is_numeric = true;
32 
33  var $_custom_merge_tag = 'sequence';
34 
35  var $group = 'gravityview';
36 
37  var $icon = 'dashicons-editor-ol';
38 
39  public function __construct() {
40 
41  $this->label = esc_html__( 'Number Sequence', 'gravityview' );
42  $this->description = esc_html__( 'Display a sequential result number for each entry.', 'gravityview' );
43 
44  add_filter( 'gravityview/metaboxes/tooltips', array( $this, 'field_tooltips') );
45 
46  add_filter( 'gravityview_entry_default_fields', array( $this, 'add_default_field' ), 10, 3 );
47 
48  parent::__construct();
49  }
50 
51  /**
52  * Add as a default field, outside those set in the Gravity Form form
53  *
54  * @since 2.10 Moved here from GravityView_Admin_Views::get_entry_default_fields
55  *
56  * @param array $entry_default_fields Existing fields
57  * @param string|array $form form_ID or form object
58  * @param string $zone Either 'single', 'directory', 'edit', 'header', 'footer'
59  *
60  * @return array
61  */
62  public function add_default_field( $entry_default_fields, $form = array(), $zone = '' ) {
63 
64  if ( 'edit' === $zone ) {
65  return $entry_default_fields;
66  }
67 
68  $entry_default_fields['sequence'] = array(
69  'label' => __( 'Result Number', 'gravityview' ),
70  'type' => $this->name,
71  'desc' => $this->description,
72  'icon' => $this->icon,
73  'group' => 'gravityview',
74  );
75 
76  return $entry_default_fields;
77  }
78 
79  /**
80  * Add tooltips
81  * @param array $tooltips Existing tooltips
82  * @return array Modified tooltips
83  */
84  public function field_tooltips( $tooltips ) {
85 
86  $return = $tooltips;
87 
88  $return['reverse_sequence'] = array(
89  'title' => __('Reverse the order of the result numbers', 'gravityview'),
90  'value' => __('Output the number sequence in descending order. If enabled, numbers will count down from high to low.', 'gravityview'),
91  );
92 
93  return $return;
94  }
95 
96  public function field_options( $field_options, $template_id, $field_id, $context, $input_type, $form_id ) {
97 
98  unset ( $field_options['search_filter'] );
99 
100  $new_fields = array(
101  'start' => array(
102  'type' => 'number',
103  'label' => __( 'First Number in the Sequence', 'gravityview' ),
104  'desc' => __('For each entry, the displayed number will increase by one. When displaying ten entries, the first entry will display "1", and the last entry will show "10".', 'gravityview'),
105  'value' => '1',
106  'merge_tags' => false,
107  ),
108  'reverse' => array(
109  'type' => 'checkbox',
110  'label' => __( 'Reverse the order of the number sequence (high to low)', 'gravityview' ),
111  'tooltip' => 'reverse_sequence',
112  'value' => '',
113  ),
114  );
115 
116  return $new_fields + $field_options;
117  }
118 
119  /**
120  * Replace {sequence} Merge Tags inside Custom Content fields
121  *
122  * TODO:
123  * - Find a better way to infer current View data (without using legacy code)
124  *
125  * @param array $matches
126  * @param string $text
127  * @param array $form
128  * @param array $entry
129  * @param bool $url_encode
130  * @param bool $esc_html
131  *
132  * @return string
133  */
134  public function replace_merge_tag( $matches = array(), $text = '', $form = array(), $entry = array(), $url_encode = false, $esc_html = false ) {
135  /**
136  * An internal cache for sequence tag reuse within one field.
137  * Avoids calling get_sequence over and over again, off-by-many increments, etc.
138  */
139  static $merge_tag_sequences = array();
140 
141  $view_data = gravityview_get_current_view_data(); // TODO: Don't use legacy code...
142 
143  // If we're not in a View or embed, don't replace the merge tag
144  if ( empty( $view_data ) ) {
145  gravityview()->log->error( '{sequence} Merge Tag used outside of a GravityView View.', array( 'data' => $matches ) );
146  return $text;
147  }
148 
149  $legacy_field = \GravityView_View::getInstance()->getCurrentField(); // TODO: Don't use legacy code...
150 
151  // If we're outside field context (like a GV widget), don't replace the merge tag
152  if ( ! $legacy_field ) {
153  gravityview()->log->error( '{sequence} Merge Tag was used without outside of the GravityView entry loop.', array( 'data' => $matches ) );
154  return $text;
155  }
156 
157  $return = $text;
158 
159  $context = new \GV\Template_Context();
160  $context->view = \GV\View::by_id( $view_data['view_id'] );
161  $context->entry = \GV\GF_Entry::from_entry( $entry );
162 
163  $gv_field = \GV\Internal_Field::by_id( 'sequence' );
164  $merge_tag_context = \GV\Utils::get( $legacy_field, 'UID' );
165  $merge_tag_context = $entry['id'] . "/{$merge_tag_context}";
166 
167  foreach ( $matches as $match ) {
168 
169  $full_tag = $match[0];
170  $property = $match[1];
171 
172  $gv_field->reverse = false;
173  $gv_field->start = 1;
174 
175  $modifiers = explode( ',', trim( $property ) );
176 
177  foreach ( $modifiers as $modifier ) {
178 
179  $modifier = trim( $modifier );
180 
181  if ( 'reverse' === $modifier ) {
182  $gv_field->reverse = true;
183  }
184 
185  $maybe_start = explode( ':', $modifier );
186 
187  // If there is a field with the ID of the start number, the merge tag won't work.
188  // In that case, you can use "=" instead: `{sequence start=10}`
189  if( 1 === sizeof( $maybe_start ) ) {
190  $maybe_start = explode( '=', $modifier );
191  }
192 
193  if ( 'start' === rgar( $maybe_start, 0 ) && is_numeric( rgar( $maybe_start, 1 ) ) ) {
194  $gv_field->start = (int) rgar( $maybe_start, 1 );
195  }
196  }
197 
198  /**
199  * We make sure that distinct sequence modifiers have their own
200  * output counters.
201  */
202  $merge_tag_context_modifiers = $merge_tag_context . '/' . var_export( $gv_field->reverse, true ) . '/' . $gv_field->start;
203 
204  if ( ! isset( $merge_tag_sequences[ $merge_tag_context_modifiers ] ) ) {
205  $gv_field->UID = $legacy_field['UID'] . '/' . var_export( $gv_field->reverse, true ) . '/' . $gv_field->start;
206  $context->field = $gv_field;
207  $sequence = $merge_tag_sequences[ $merge_tag_context_modifiers ] = $this->get_sequence( $context );
208  } else {
209  $sequence = $merge_tag_sequences[ $merge_tag_context_modifiers ];
210  }
211 
212  $return = str_replace( $full_tag, $sequence, $return );
213  }
214 
215  return $return;
216  }
217 
218  /**
219  * Calculate the current sequence number for the context.
220  *
221  * @param \GV\Template_Context $context The context.
222  *
223  * @return int The sequence number for the field/entry within the view results.
224  */
225  public function get_sequence( $context ) {
226  static $startlines = array();
227 
228  $context_key = md5( json_encode(
229  array(
230  $context->view->ID,
231  \GV\Utils::get( $context, 'field/UID' ),
232  )
233  ) );
234 
235  /**
236  * Figure out the starting number.
237  */
238  if ( $context->request && $entry = $context->request->is_entry() ) {
239 
240  $sql_query = array();
241 
242  add_filter( 'gform_gf_query_sql', $callback = function( $sql ) use ( &$sql_query ) {
243  $sql_query = $sql;
244  return $sql;
245  } );
246 
247  $total = $context->view->get_entries()->total();
248  remove_filter( 'gform_gf_query_sql', $callback );
249 
250  unset( $sql_query['paginate'] );
251 
252  global $wpdb;
253 
254  foreach ( $wpdb->get_results( implode( ' ', $sql_query ), ARRAY_A ) as $n => $result ) {
255  if ( in_array( $entry->ID, $result ) ) {
256  return $context->field->reverse ? ( $total - $n ) : ( $n + 1 );
257  }
258  }
259 
260  return 0;
261  } elseif ( ! isset( $startlines[ $context_key ] ) ) {
262  $pagenum = max( 0, \GV\Utils::_GET( 'pagenum', 1 ) - 1 );
263  $pagesize = $context->view->settings->get( 'page_size', 25 );
264 
265  if ( $context->field->reverse ) {
266  $startlines[ $context_key ] = $context->view->get_entries()->total() - ( $pagenum * $pagesize );
267  $startlines[ $context_key ] += $context->field->start - 1;
268  } else {
269  $startlines[ $context_key ] = ( $pagenum * $pagesize ) + $context->field->start;
270  }
271  }
272 
273  return $context->field->reverse ? $startlines[ $context_key ]-- : $startlines[ $context_key ]++;
274  }
275 }
276 
add_default_field( $entry_default_fields, $form=array(), $zone='')
Add as a default field, outside those set in the Gravity Form form.
Modify field settings by extending this class.
static getInstance( $passed_post=NULL)
replace_merge_tag( $matches=array(), $text='', $form=array(), $entry=array(), $url_encode=false, $esc_html=false)
Replace {sequence} Merge Tags inside Custom Content fields.
gravityview_get_current_view_data( $view_id=0)
Get data for a specific view.
Definition: class-api.php:1154
gravityview()
Definition: _stubs.php:26
static from_entry( $entry)
Construct a instance from a Gravity Forms entry array.
get( $key, $default=null)
Retrieve a setting.
if(gravityview() ->plugin->is_GF_25()) $form
scale description p description
$gv_field
Definition: time.php:11
static by_id( $post_id)
Construct a instance from a post ID.
$field_id
Definition: time.php:17
field_options( $field_options, $template_id, $field_id, $context, $input_type, $form_id)
static by_id( $field_id)
Get a from an internal Gravity Forms field ID.
if(empty( $created_by)) $form_id
static get( $array, $key, $default=null)
Grab a value from an array or an object or default.
$entry
Definition: notes.php:27
get_sequence( $context)
Calculate the current sequence number for the context.