Completed
Push — develop ( 507546...65eb42 )
by Zack
05:37
created

includes/class-gvlogic-shortcode.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/**
4
 * Shortcode to handle showing/hiding content in merge tags. Works great with GravityView Custom Content fields
5
 */
6
class GVLogic_Shortcode {
7
8
	private static $SUPPORTED_SCALAR_OPERATORS = array( 'is', 'isnot', 'contains', 'starts_with', 'ends_with' );
9
10
	private static $SUPPORTED_NUMERIC_OPERATORS = array( 'greater_than', 'less_than' );
11
12
	private static $SUPPORTED_ARRAY_OPERATORS = array( 'in', 'not_in', 'isnot', 'contains' );
13
14
	private static $SUPPORTED_CUSTOM_OPERATORS = array( 'equals', 'greater_than_or_is', 'greater_than_or_equals', 'less_than_or_is', 'less_than_or_equals', 'not_contains' );
15
16
	/**
17
	 * Attributes passed to the shortcode
18
	 * @var array
19
	 */
20
	var $passed_atts;
21
22
	/**
23
	 * Content inside the shortcode, displayed if matched
24
	 * @var string
25
	 */
26
	var $passed_content;
27
28
	/**
29
	 * Parsed attributes
30
	 * @var array
31
	 */
32
	var $atts = array();
33
34
	/**
35
	 * Parsed content, shown if matched
36
	 * @var string
37
	 */
38
	var $content = '';
39
40
	/**
41
	 * Content shown if not matched
42
	 * This is set by having `[else]` inside the $content block
43
	 * @var string
44
	 */
45
	var $else_content = '';
46
47
	/**
48
	 * The current shortcode name being processed
49
	 * @var string
50
	 */
51
	var $shortcode = 'gvlogic';
52
53
	/**
54
	 * The left side of the comparison
55
	 * @var string
56
	 */
57
	var $if = '';
58
59
	/**
60
	 * The right side of the comparison
61
	 * @var string
62
	 */
63
	var $comparison = '';
64
65
	/**
66
	 * The comparison operator
67
	 * @var string
68
	 */
69
	var $operation = 'is';
70
71
	/**
72
	 * Does the comparison pass?
73
	 * @var bool
74
	 */
75
	var $is_match = false;
76
77
	/**
78
	 * @var GVLogic_Shortcode
79
	 */
80
	private static $instance;
81
82
	/**
83
	 * Instantiate!
84
	 * @return GVLogic_Shortcode
85
	 */
86
	public static function get_instance() {
87
88
		if( empty( self::$instance ) ) {
89
			self::$instance = new self;
90
		}
91
92
		return self::$instance;
93
	}
94
95
	/**
96
	 * Add the WordPress hooks
97
	 * @return void
98
	 */
99
	private function __construct() {
100
		$this->add_hooks();
101
	}
102
103
	/**
104
	 * Register the shortcode
105
	 * @return void
106
	 */
107
	function add_hooks() {
108
		add_shortcode( 'gvlogic', array( $this, 'shortcode' ) );
109
	}
110
111
	/**
112
	 * Get array of supported operators
113
	 * @param bool $with_values
114
	 *
115
	 * @return array
116
	 */
117
	function get_operators( $with_values = false ) {
118
119
		$operators = array_merge( self::$SUPPORTED_ARRAY_OPERATORS, self::$SUPPORTED_NUMERIC_OPERATORS, self::$SUPPORTED_SCALAR_OPERATORS, self::$SUPPORTED_CUSTOM_OPERATORS );
120
121
		if( $with_values ) {
122
			$operators_with_values = array();
123
			foreach( $operators as $key ) {
124
				$operators_with_values[ $key ] = '';
125
			}
126
			return $operators_with_values;
127
		} else {
128
			return $operators;
129
		}
130
	}
131
132
	/**
133
	 * Set the operation for the shortcode.
134
	 * @param string $operation
135
	 *
136
	 * @return bool True: it's an allowed operation type and was added. False: invalid operation type
137
	 */
138
	function set_operation( $operation = '' ) {
139
140
		if( empty( $operation ) ) {
141
			return false;
142
		}
143
144
		$operators = $this->get_operators( false );
145
146
		if( !in_array( $operation, $operators ) ) {
147
			do_action( 'gravityview_log_debug', __METHOD__ .' Attempted to add invalid operation type.', $operation );
148
			return false;
149
		}
150
151
		$this->operation = $operation;
152
		return true;
153
	}
154
155
	/**
156
	 * Set the operation and comparison for the shortcode
157
	 *
158
	 * Loop through each attribute passed to the shortcode and see if it's a valid operator. If so, set it.
159
	 * Example: [gvlogic if="{example}" greater_than="5"]
160
	 * `greater_than` will be set as the operator
161
	 * `5` will be set as the comparison value
162
	 *
163
	 * @return bool True: we've got an operation and comparison value; False: no, we don't
164
	 */
165
	private function setup_operation_and_comparison() {
166
167
		foreach( $this->atts as $key => $value ) {
168
169
			$valid = $this->set_operation( $key );
170
171
			if( $valid ) {
172
				$this->comparison = $value;
173
				return true;
174
			}
175
		}
176
177
		return false;
178
	}
179
180
	/**
181
	 * @param array $atts User defined attributes in shortcode tag.
182
	 * @param null $content
183
	 * @param string $shortcode_tag
184
	 *
185
	 * @return string|null
186
	 */
187
	public function shortcode( $atts = array(), $content = NULL, $shortcode_tag = '' ) {
188
189
		// Don't process except on frontend
190
		if ( function_exists( 'gravityview' ) && gravityview()->request->is_admin() ) {
191
			return null;
192
			/** Deprecated in favor of gravityview()->request->is_admin(). */
193
		} else if ( GravityView_Plugin::is_admin() ) {
0 ignored issues
show
Deprecated Code introduced by
The method GravityView_Plugin::is_admin() has been deprecated.

This method has been deprecated.

Loading history...
194
			return null;
195
		}
196
197
		if( empty( $atts ) ) {
198
			do_action( 'gravityview_log_error', __METHOD__.' $atts are empty.', $atts );
199
			return null;
200
		}
201
202
		$this->passed_atts = $atts;
203
		$this->passed_content = $content;
204
		$this->shortcode = $shortcode_tag;
205
206
		$this->parse_atts();
207
208
		// We need an "if"
209
		if( false === $this->if ) {
210
			do_action( 'gravityview_log_error', __METHOD__.' $atts->if is empty.', $this->passed_atts );
211
			return null;
212
		}
213
214
		$setup = $this->setup_operation_and_comparison();
215
216
		// We need an operation and comparison value
217
		if( ! $setup ) {
218
			do_action( 'gravityview_log_error', __METHOD__.' No valid operators were passed.', $this->atts );
219
			return null;
220
		}
221
222
		// Set the content and else_content
223
		$this->set_content_and_else_content();
224
225
		// Check if it's a match
226
		$this->set_is_match();
227
228
		// Return the value!
229
		$output = $this->get_output();
230
231
		return $output;
232
	}
233
234
	/**
235
	 * Does the if and the comparison match?
236
	 * @uses GVCommon::matches_operation
237
	 *
238
	 * @return boolean True: yep; false: nope
239
	 */
240
	private function set_is_match() {
241
		$this->is_match = GVCommon::matches_operation( $this->if, $this->comparison, $this->operation );
242
	}
243
244
	/**
245
	 * Get the output for the shortcode, based on whether there's a matched value
246
	 *
247
	 * @return string HTML/Text output of the shortcode
248
	 */
249
	private function get_output() {
250
251
		if( $this->is_match ) {
252
			$output = $this->content;
253
		} else {
254
			$output = $this->else_content;
255
		}
256
257
		// Get recursive!
258
		$output = do_shortcode( $output );
259
260
		/**
261
		 * @filter `gravityview/gvlogic/output` Modify the [gvlogic] output
262
		 * @param string $output HTML/text output
263
		 * @param GVLogic_Shortcode $this This class
264
		 */
265
		$output = apply_filters('gravityview/gvlogic/output', $output, $this );
266
267
		do_action( 'gravityview_log_debug', __METHOD__ .' Output: ', $output );
268
269
		return $output;
270
	}
271
272
	/**
273
	 * Check for `[else]` tag inside the shortcode content. If exists, set the else_content variable.
274
	 * If not, use the `else` attribute passed by the shortcode, if exists.
275
	 *
276
	 * @todo allow for chains of [else if="{another field:123}" is="example"] - requires registering [else] shortcode...
277
	 * @return void
278
	 */
279
	private function set_content_and_else_content() {
280
281
		$content = explode( '[else]', $this->passed_content );
282
283
		$this->content = $content[0];
284
285
		$else_attr = isset( $this->atts['else'] ) ? $this->atts['else'] : NULL;
286
287
		$this->else_content = isset( $content[1] ) ? $content[1] : $else_attr;
288
	}
289
290
	/**
291
	 * Process the attributes passed to the shortcode. Make sure they're valid
292
	 * @return void
293
	 */
294
	private function parse_atts() {
295
296
		$supported = array(
297
			'if' => false,
298
			'else' => false,
299
		);
300
301
		$supported_args = $supported + $this->get_operators( true );
302
303
		// Whittle down the attributes to only valid pairs
304
		$this->atts = shortcode_atts( $supported_args, $this->passed_atts, $this->shortcode );
305
306
		// Only keep the passed attributes after making sure that they're valid pairs
307
		$this->atts = function_exists( 'array_intersect_key' ) ? array_intersect_key( $this->passed_atts, $this->atts ) : $this->atts;
308
309
		// Strip whitespace if it's not default false
310
		$this->if = ( isset( $this->atts['if'] ) && is_string( $this->atts['if'] ) ) ? trim( $this->atts['if'] ) : false;
311
312
		// Make sure the "if" isn't processed in self::setup_operation_and_comparison()
313
		unset( $this->atts['if'] );
314
	}
315
}
316
317
GVLogic_Shortcode::get_instance();
318