GravityView  2.17
The best, easiest way to display Gravity Forms entries on your website.
class-gv-shortcode-gvlogic.php
Go to the documentation of this file.
1 <?php
2 namespace GV\Shortcodes;
3 
4 /** If this file is called directly, abort. */
5 if ( ! defined( 'GRAVITYVIEW_DIR' ) ) {
6  die();
7 }
8 
9 /**
10  * The [gvlogic] shortcode.
11  */
12 class gvlogic extends \GV\Shortcode {
13  /**
14  * {@inheritDoc}
15  */
16  public $name = 'gvlogic';
17 
18  /**
19  * {@inheritDoc}
20  */
21  public static function add( $name = null ) {
22  parent::add(); // Me, myself and...
23 
24  /**
25  * ...some aliases.
26  */
27  parent::add( 'gvlogic2' );
28  parent::add( 'gvlogic3' ); // This level of nesting is not supported by GravityView support...but go for it!
29  parent::add( 'gvlogicelse' );
30  }
31 
32  /**
33  * Process and output the [gvfield] shortcode.
34  *
35  * @param array $atts The attributes passed.
36  * @param string $content The content inside the shortcode.
37  * @param string $tag The tag.
38  *
39  * @return string The output.
40  */
41  public function callback( $atts, $content = '', $tag = '' ) {
42  $request = gravityview()->request;
43 
44  if ( $request->is_admin() ) {
45  return apply_filters( 'gravityview/shortcodes/gvlogic/output', '', $atts );
46  }
47 
48  $atts = $this->parse_atts( $atts, $content, $tag );
49 
51  $atts = gv_map_deep( $atts, array( '\GravityView_Merge_Tags', 'replace_get_variables' ) );
52 
53  $content = \GFCommon::replace_variables_prepopulate( $content );
54  $atts = gv_map_deep( $atts, array( '\GFCommon', 'replace_variables_prepopulate' ) );
55 
56  // An invalid operation
57  if ( is_null( \GV\Utils::get( $atts, 'logged_in', null ) ) && false === \GV\Utils::get( $atts, 'if', false ) ) {
58  gravityview()->log->error( '$atts->if/logged_in is empty.', array( 'data' => $atts ) );
59  return apply_filters( 'gravityview/shortcodes/gvlogic/output', '', $atts );
60  }
61 
62  $authed = $this->authorized( $atts );
63  $operator = $this->get_operator( $atts );
64  $value = $this->get_value( $atts );
65 
66  if ( false === $operator && is_null( $value ) ) {
67  if ( false !== $atts['if'] ) { // Only-if test
68  $match = $authed && ! in_array( strtolower( $atts['if'] ), array( '', '0', 'false', 'no' ) );
69  } else {
70  $match = $authed; // Just login test
71  }
72 
73  $output = $this->get_output( $match, $atts, $content );
74  } else { // Regular test
75 
76  $output = $content;
77 
78  // Allow checking against multiple values at once
79  $and_values = explode( '&&', $value );
80  $or_values = explode( '||', $value );
81 
82  // Cannot combine AND and OR
83  if ( sizeof( $and_values ) > 1 ) {
84 
85  // Need to match all AND
86  foreach ( $and_values as $and_value ) {
87  $match = $authed && \GVCommon::matches_operation( $atts['if'], $and_value, $operator );
88  if ( ! $match ) {
89  break;
90  }
91  }
92 
93  } elseif ( sizeof( $or_values ) > 1 ) {
94 
95  // Only need to match a single OR
96  foreach ( $or_values as $or_value ) {
97 
98  $match = \GVCommon::matches_operation( $atts['if'], $or_value, $operator );
99 
100  // Negate the negative operators
101  if ( ( $authed && $match ) || ( $authed && ( ! $match && in_array( $operator, array( 'isnot', 'not_contains', 'not_in' ) ) ) ) ) {
102  break;
103  }
104  }
105 
106  } else {
107  $match = $authed && \GVCommon::matches_operation( $atts['if'], $value, $operator );
108  }
109 
110  $output = $this->get_output( $match, $atts, $output );
111  }
112 
113 
114  // Output and get recursive!
115  $output = do_shortcode( $output );
116  $output = \GFCommon::replace_variables( $output, array(), array(), false, true, false );
117 
118  return apply_filters( 'gravityview/shortcodes/gvlogic/output', $output, $atts );
119  }
120 
121  /**
122  * Are we authorized to follow the if path?
123  *
124  * @param array $atts The attributes.
125  *
126  * @return bool Yes, or no.
127  */
128  private function authorized( $atts ) {
129 
130  $needs_login = \GV\Utils::get( $atts, 'logged_in', null );
131 
132  if ( is_null( $needs_login ) ) {
133  return true; // No auth requirements have been set
134  }
135 
136  return ! $needs_login ^ is_user_logged_in(); // XNOR
137  }
138 
139  /**
140  * Fetch the operator.
141  *
142  * @param array $atts The attributes.
143  *
144  * @return bool|string The operator.
145  */
146  private function get_operator( $atts ) {
147  $valid_ops = $this->get_operators( false );
148 
149  foreach ( $atts as $op => $value ) {
150  if ( in_array( $op, array( 'if', 'else' ) ) ) {
151  continue;
152  }
153 
154  if ( in_array( $op, $valid_ops, true ) ) {
155  return $op;
156  }
157  }
158 
159  return false;
160  }
161 
162  /**
163  * Fetch the value.
164  *
165  * @param array $atts The attributes.
166  *
167  * @return null|string The value.
168  */
169  private function get_value( $atts ) {
170  $valid_ops = $this->get_operators( false );
171 
172  foreach ( $atts as $op => $value ) {
173  if ( in_array( $op, array( 'if', 'else' ) ) ) {
174  continue;
175  }
176 
177  if ( in_array( $op, $valid_ops, true ) ) {
178  return $value;
179  }
180  }
181 
182  return null;
183  }
184 
185  /**
186  * Get the output content.
187  *
188  * @param bool $match if or else?
189  * @param array $atts The attributes.
190  * @param string $content The content.
191  *
192  * @return string The output.
193  */
194  private function get_output( $match, $atts, $content ) {
195  if ( ! $match && ! empty( $atts['else'] ) ) {
196  return $atts['else']; // Attributized else is easy :)
197  }
198 
199  $if = '';
200  $else = '';
201 
202  $opens = 0; // inner opens
203  $found = false; // found split position
204 
205  while ( $content ) { // scan
206 
207  if ( ! preg_match( '#(.*?)(\[\/?(gvlogic|else).*?])(.*)#s', $content, $matches ) ) {
208  if ( ! $found ) { // We're still iffing.
209  $if .= $content;
210  } else { // We are elsing
211  $else .= $content;
212  }
213  break; // No more shortcodes
214  }
215 
216  list( $_, $before_shortcode, $shortcode, $_, $after_shortcode ) = $matches;
217 
218  if ( ! $found ) { // We're still iffing.
219  $if .= $before_shortcode;
220  } else { // We are elsing
221  $else .= $before_shortcode;
222  }
223 
224  if ( 0 === strpos( $shortcode, '[else]' ) && 0 === $opens ) {
225  // This is the else we need!
226  $found = true;
227  if ( $match ) {
228  break; // We just need the if on a match, no need to analyze further
229  }
230  } else if ( $match && 0 === strpos( $shortcode, '[else if' ) && 0 === $opens ) {
231  $found = true; // We found a match, do not process further
232  break;
233  } else {
234  // Increment inner tracking counters
235  if ( 0 === strpos( $shortcode, '[gvlogic' ) ) {
236  $opens++;
237  }
238 
239  if ( 0 === strpos( $shortcode, '[/gvlogic' ) ) {
240  $opens--;
241  }
242 
243  // Tack on the shortcode
244  if ( ! $found ) { // We're still iffing.
245  $if .= $shortcode;
246  } else { // We are elsing
247  $else .= $shortcode;
248  }
249  }
250 
251  $content = $after_shortcode;
252  }
253 
254  gravityview()->log->debug( '[gvlogic] output parsing:', array(
255  'data' => array(
256  'if' => $if,
257  'else' => $else,
258  ),
259  ) );
260 
261  if ( ! $match ) {
262  while ( ( $position = strpos( $if, '[else if=' ) ) !== false ) {
263  // Try to match one of the elseif's
264  $sentinel = wp_generate_password( 32, false );
265  $if = substr( $if, $position ); // ...by replacing it with a gvlogic shortcode
266  // ..and executing it!
267  $result = do_shortcode( preg_replace( '#\[else if#', '[gvlogic if', $if, 1 ) . "[else]{$sentinel}[/gvlogic]" );
268  if ( $result !== $sentinel ) {
269  // We have an elseif match!
270  return $result;
271  }
272  $if = substr( $if, 1 ); // Move over to get the next elseif match.. and repeat
273  }
274  }
275 
276  return $match ? $if : $else;
277  }
278 
279  /**
280  * Get array of supported operators
281  * @param bool $with_values
282  *
283  * @return array
284  */
285  private function get_operators( $with_values = false ) {
286 
287  $operators = array(
288  'is', 'isnot', 'contains', 'starts_with', 'ends_with',
289  'greater_than', 'less_than', 'in', 'not_in',
290  'contains', 'equals', 'greater_than_or_is', 'greater_than_or_equals',
291  'less_than_or_is', 'less_than_or_equals', 'not_contains',
292  );
293 
294  if ( $with_values ) {
295  return array_combine(
296  $operators,
297  array_fill( 0, count( $operators ), '' )
298  );
299  }
300 
301  return $operators;
302  }
303 
304  /**
305  * Process the attributes passed to the shortcode. Make sure they're valid
306  *
307  * @return array Array of attributes parsed for the shortcode
308  */
309  private function parse_atts( $atts, $content, $tag ) {
310 
311  $supplied_atts = ! empty( $atts ) ? $atts : array();
312 
313  $atts = shortcode_atts( array(
314  'if' => null,
315  'else' => null,
316  'logged_in' => null,
317  ) + $this->get_operators( true ), $atts, $tag );
318 
319  // Only keep the passed attributes after making sure that they're valid pairs
320  $atts = array_intersect_key( $supplied_atts, $atts );
321 
322  // Strip whitespace if it's not default false
323  if ( isset( $atts['if'] ) && is_string( $atts['if'] ) ) {
324  $atts['if'] = trim( $atts['if'] );
325  } else {
326  $atts['if'] = false;
327  }
328 
329  if ( isset( $atts['logged_in'] ) ) {
330  // Truthy
331  if ( in_array( strtolower( $atts['logged_in'] ), array( '0', 'false', 'no' ) ) ) {
332  $atts['logged_in'] = false;
333  } else {
334  $atts['logged_in'] = true;
335  }
336  }
337 
338  /**
339  * @filter `gravityview/gvlogic/atts` The logic attributes.
340  *
341  * @since 2.5
342  *
343  * @param array $atts The logic attributes.
344  */
345  return apply_filters( 'gravityview/gvlogic/atts', $atts );
346  }
347 }
callback( $atts, $content='', $tag='')
Process and output the [gvfield] shortcode.
authorized( $atts)
Are we authorized to follow the if path?
static replace_get_variables( $text, $form=array(), $entry=array(), $url_encode=false)
Allow passing variables via URL to be displayed in Merge Tags.
If this file is called directly, abort.
static matches_operation( $val1, $val2, $operation)
Wrapper for the GFFormsModel::matches_operation() method that adds additional comparisons, including: &#39;equals&#39;, &#39;greater_than_or_is&#39;, &#39;greater_than_or_equals&#39;, &#39;less_than_or_is&#39;, &#39;less_than_or_equals&#39;, &#39;not_contains&#39;, &#39;in&#39;, and &#39;not_in&#39;.
get_operators( $with_values=false)
Get array of supported operators.
get_value( $atts)
Fetch the value.
gv_map_deep( $value, $callback)
Maps a function to all non-iterable elements of an array or an object.
If this file is called directly, abort.
get_operator( $atts)
Fetch the operator.
static get( $array, $key, $default=null)
Grab a value from an array or an object or default.
get_output( $match, $atts, $content)
Get the output content.
gravityview()
The main GravityView wrapper function.
parse_atts( $atts, $content, $tag)
Process the attributes passed to the shortcode.