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

class-gravityview-entry-link-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
 * Handle the [gv_entry_link] shortcode
5
 *
6
 * Replaces [gv_edit_entry_link] and [gv_delete_entry_link] shortcodes
7
 *
8
 * @since 1.15
9
 */
10
class GravityView_Entry_Link_Shortcode {
11
12
	/**
13
	 * @type array Entry fetched using the $atts['entry_id'] shortcode setting.
14
	 * @since 1.15
15
	 */
16
	private $entry = array();
17
18
	/**
19
	 * @type int If set, generate a link to the entry for this View ID. Required when used outside a View. Otherwise, current View ID is used.
20
	 * @since 1.15
21
	 */
22
	private $view_id = 0;
23
24
	/**
25
	 * @type array The accepted shortcode attribute pairs, with defaults set
26
	 * @since 1.15
27
	 */
28
	static private $defaults = array(
29
		'action'       => 'read',
30
		'view_id'      => 0,
31
		'entry_id'     => 0,
32
		'post_id'      => 0,
33
		'link_atts'    => '',
34
		'return'       => 'html',
35
		'field_values' => '',
36
	);
37
38
	/**
39
	 * @type array The final settings for the shortcode, after merging passed $atts with self::$defaults
40
	 * @since 1.15
41
	 */
42
	private $settings = array();
43
44
	function __construct() {
45
		$this->add_hooks();
46
	}
47
48
	/**
49
	 * Add shortcodes
50
	 *
51
	 * @since 1.15
52
	 */
53
	private function add_hooks() {
54
		add_shortcode( 'gv_entry_link', array( $this, 'read_shortcode' ) );
55
		add_shortcode( 'gv_edit_entry_link', array( $this, 'edit_shortcode' ) );
56
		add_shortcode( 'gv_delete_entry_link', array( $this, 'delete_shortcode' ) );
57
	}
58
59
	/**
60
	 * @since 1.15
61
	 * @copydoc GravityView_Entry_Link_Shortcode::shortcode
62
	 */
63
	public function read_shortcode( $atts, $content = null, $context = 'gv_entry_link' ) {
64
		return $this->shortcode( $atts, $content, $context );
65
	}
66
67
	/**
68
	 * Backward compatibility for existing `gv_edit_entry_link` shortcode
69
	 * Forces $atts['action'] to "edit"
70
	 *
71
	 * @since 1.15
72
	 * @copydoc GravityView_Entry_Link_Shortcode::shortcode
73
	 */
74
	public function edit_shortcode( $atts, $content = null, $context = 'gv_edit_entry_link' ) {
75
		$atts['action'] = 'edit';
76
77
		return $this->shortcode( $atts, $content, $context );
78
	}
79
80
	/**
81
	 * Backward compatibility for existing `gv_delete_entry_link` shortcodes
82
	 * Forces $atts['action'] to "delete"
83
	 *
84
	 * @since 1.15
85
	 * @copydoc GravityView_Entry_Link_Shortcode::shortcode
86
	 */
87
	public function delete_shortcode( $atts, $content = null, $context = 'gv_delete_entry_link' ) {
88
		$atts['action'] = 'delete';
89
90
		return $this->shortcode( $atts, $content, $context );
91
	}
92
93
	/**
94
	 * Generate a link to an entry. The link can be an edit, delete, or standard link.
95
	 *
96
	 * @since 1.15
97
	 *
98
	 * @param array $atts {
99
	 *    @type string $action What type of link to generate. Options: `read`, `edit`, and `delete`. Default: `read`
100
	 *    @type string $view_id Define the ID for the View. If not set, use current View ID, if exists.
101
	 *    @type string $entry_id ID of the entry to edit. If undefined, uses the current entry ID, if exists.
102
	 *    @type string $post_id ID of the base post or page to use for an embedded View
103
	 *    @type string $link_atts Pass anchor tag attributes (`target=_blank` to open Edit Entry link in a new window, for example)
104
	 *    @type string $return What should the shortcode return: link HTML (`html`) or the URL (`url`). Default: `html`
105
	 *    @type string $field_values Only used for `action="edit"`. Parameters to pass in to the prefill data in Edit Entry form. Uses the same format as Gravity Forms "Allow field to be populated dynamically" {@see https://www.gravityhelp.com/documentation/article/allow-field-to-be-populated-dynamically/ }
106
	 * }
107
	 *
108
	 * @param string|null $content Used as link anchor text, if specified.
109
	 * @param string $context Current shortcode being called. Not used.
110
	 *
111
	 * @return null|string If admin or an error occurred, returns null. Otherwise, returns entry link output. If `$atts['return']` is 'url', the entry link URL. Otherwise, entry link `<a>` HTML tag.
112
	 */
113
	private function shortcode( $atts, $content = null, $context = 'gv_entry_link' ) {
114
115
		// Don't process when saving post. Keep processing if it's admin-ajax.php
116
		if ( function_exists( 'gravityview' ) && gravityview()->request->is_admin() ) {
117
			return null;
118
			/** Deprecated in favor of gravityview()->request->is_admin(). */
119
		} else if ( ! class_exists( 'GravityView_Plugin' ) || 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...
120
			return null;
121
		}
122
123
		// Make sure GV is loaded
124
		if ( ! class_exists( 'GravityView_frontend' ) || ! class_exists( 'GravityView_View' ) ) {
125
			do_action( 'gravityview_log_error', __METHOD__ . ' GravityView_frontend or GravityView_View do not exist.' );
126
127
			return null;
128
		}
129
130
		$this->settings = shortcode_atts( self::$defaults, $atts, $context );
131
132
		$this->view_id = empty( $this->settings['view_id'] ) ? GravityView_View::getInstance()->getViewId() : absint( $this->settings['view_id'] );
133
134
		if ( empty( $this->view_id ) ) {
135
			do_action( 'gravityview_log_error', __METHOD__ . ' A View ID was not defined and we are not inside a View' );
136
137
			return null;
138
		}
139
140
		$this->entry = $this->get_entry( $this->settings['entry_id'] );
141
142
		do_action( 'gravityview_log_debug', __METHOD__ . ' ' . $context . ' $atts: ', $atts );
143
144
		if ( ! $this->has_cap() ) {
145
			do_action( 'gravityview_log_error', __METHOD__ . ' User does not have the capability to ' . esc_attr( $this->settings['action'] ) . ' this entry: ' . $this->entry['id'] );
146
147
			return null;
148
		}
149
150
		$url = $this->get_url();
151
152
		if ( ! $url ) {
153
			do_action( 'gravityview_log_error', __METHOD__ . ' Link returned false; View or Post may not exist.' );
154
155
			return false;
156
		}
157
158
		// Get just the URL, not the tag
159
		if ( 'url' === $this->settings['return'] ) {
160
			return $url;
161
		}
162
163
		$link_atts = $this->get_link_atts();
164
165
		$link_text = $this->get_anchor_text( $content );
166
167
		return gravityview_get_link( $url, $link_text, $link_atts );
168
	}
169
170
	/**
171
	 * Parse shortcode atts to fetch `link_atts`, which will be added to the output of the HTML anchor tag generated by shortcode
172
	 * Only used when `return` value of shortcode is not "url"
173
	 *
174
	 * @since 1.15
175
	 * @see gravityview_get_link() See acceptable attributes here
176
	 * @return array Array of attributes to be added
177
	 */
178
	private function get_link_atts() {
179
180
		wp_parse_str( $this->settings['link_atts'], $link_atts );
181
182
		if ( 'delete' === $this->settings['action'] ) {
183
			$link_atts['onclick'] = isset( $link_atts['onclick'] ) ? $link_atts['onclick'] : GravityView_Delete_Entry::get_confirm_dialog();
184
		}
185
186
		return (array) $link_atts;
187
	}
188
189
	/**
190
	 * Get the anchor text for the link. If content inside shortcode is defined, use that as the text. Otherwise, use default values.
191
	 *
192
	 * Only used when `return` value of shortcode is not "url"
193
	 *
194
	 * @since 1.15
195
	 *
196
	 * @param string|null $content Content inside shortcode, if defined
197
	 *
198
	 * @return string Text to use for HTML anchor
199
	 */
200
	private function get_anchor_text( $content = null ) {
201
202
		if ( $content ) {
203
			return $content;
204
		}
205
206
		switch ( $this->settings['action'] ) {
207
			case 'edit':
208
				$anchor_text = __( 'Edit Entry', 'gravityview' );
209
				break;
210
			case 'delete':
211
				$anchor_text = __( 'Delete Entry', 'gravityview' );
212
				break;
213
			default:
214
				$anchor_text = __( 'View Details', 'gravityview' );
215
		}
216
217
		return $anchor_text;
218
	}
219
220
	/**
221
	 * Get the URL for the entry.
222
	 *
223
	 * Uses the `post_id`, `view_id` params as defined in the shortcode attributes.
224
	 *
225
	 * @since 1.15
226
	 *
227
	 * @param string|null $content Content inside shortcode, if defined
228
	 *
229
	 * @return string|boolean If URL is fetched, the URL to the entry link. If not found, returns false.
230
	 */
231
	private function get_url() {
232
233
		// if post_id is not defined, default to view_id
234
		$post_id = empty( $this->settings['post_id'] ) ? $this->view_id : absint( $this->settings['post_id'] );
235
236
		switch ( $this->settings['action'] ) {
237
			case 'edit':
238
				$url = GravityView_Edit_Entry::get_edit_link( $this->entry, $this->view_id, $post_id );
239
				break;
240
			case 'delete':
241
				$url = GravityView_Delete_Entry::get_delete_link( $this->entry, $this->view_id, $post_id );
242
				break;
243
			case 'read':
244
			default:
245
				$url = GravityView_API::entry_link( $this->entry, $post_id );
246
		}
247
248
		$url = $this->maybe_add_field_values_query_args( $url );
249
250
		return $url;
251
	}
252
253
	/**
254
	 * Check whether the user has the capability to see the shortcode output, depending on the action ('read', 'edit', 'delete')
255
	 *
256
	 * @since 1.15
257
	 * @return bool True: has cap.
258
	 */
259
	private function has_cap() {
260
261
		switch ( $this->settings['action'] ) {
262
			case 'edit':
263
				$has_cap = GravityView_Edit_Entry::check_user_cap_edit_entry( $this->entry, $this->view_id );
264
				break;
265
			case 'delete':
266
				$has_cap = GravityView_Delete_Entry::check_user_cap_delete_entry( $this->entry, array(), $this->view_id );
267
				break;
268
			case 'read':
269
			default:
270
				$has_cap = true; // TODO: add cap check for read_gravityview
271
		}
272
273
		return $has_cap;
274
	}
275
276
	/**
277
	 * Get entry array from `entry_id` parameter. If no $entry_id
278
	 *
279
	 * @since 1.15
280
	 * @uses GVCommon::get_entry
281
	 * @uses GravityView_frontend::getSingleEntry
282
	 *
283
	 * @param int $entry_id Gravity Forms Entry ID. If not passed, current View's current entry ID will be used, if found.
284
	 *
285
	 * @return array|bool Gravity Forms array, if found. Otherwise, false.
286
	 */
287
	private function get_entry( $entry_id = 0 ) {
288
289
		$backup_entry = GravityView_frontend::getInstance()->getSingleEntry() ? GravityView_frontend::getInstance()->getEntry() : GravityView_View::getInstance()->getCurrentEntry();
290
291
		if ( empty( $entry_id ) ) {
292
			if ( ! $backup_entry ) {
293
				do_action( 'gravityview_log_error', __METHOD__ . ' No entry defined (or entry id not valid number)', $this->settings );
294
295
				return false;
296
			}
297
			$entry = $backup_entry;
298
		} else {
299
			$entry = wp_cache_get( 'gv_entry_link_entry_' . $entry_id, 'gravityview_entry_link_shortcode' );
300
			if ( false === $entry ) {
301
				$entry = GVCommon::get_entry( $entry_id, true, false );
302
				wp_cache_add( 'gv_entry_link_entry_' . $entry_id, $entry, 'gravityview_entry_link_shortcode' );
303
			}
304
		}
305
306
		// No search results
307
		if ( false === $entry ) {
308
			do_action( 'gravityview_log_error', __METHOD__ . ' No entries match the entry ID defined', $entry_id );
309
310
			return false;
311
		}
312
313
		return $entry;
314
	}
315
316
	/**
317
	 * Allow passing URL params to dynamically populate the Edit Entry form
318
	 * If `field_values` key is set, run it through `parse_str()` and add the values to $url
319
	 *
320
	 * @since 1.15
321
	 *
322
	 * @param string $href URL
323
	 */
324
	private function maybe_add_field_values_query_args( $url ) {
325
326
		if ( $url && ! empty( $this->settings['field_values'] ) ) {
327
328
			wp_parse_str( $this->settings['field_values'], $field_values );
329
330
			$url = add_query_arg( $field_values, $url );
331
		}
332
333
		return $url;
334
	}
335
}
336
337
new GravityView_Entry_Link_Shortcode;