GravityView  2.17
The best, easiest way to display Gravity Forms entries on your website.
class-gv-widget.php
Go to the documentation of this file.
1 <?php
2 namespace GV;
3 
4 /** If this file is called directly, abort. */
5 if ( ! defined( 'GRAVITYVIEW_DIR' ) ) {
6  die();
7 }
8 
9 /**
10  * The \GV\Widget class.
11  *
12  * An interface that most GravityView widgets would want to adhere to and inherit from.
13  */
14 abstract class Widget {
15 
16  /**
17  * Widget admin label
18  * @var string
19  */
20  protected $widget_label = '';
21 
22  /**
23  * Widget description, shown on the "+ Add Widget" picker
24  * @var string
25  */
26  protected $widget_description = '';
27 
28  /**
29  * Widget details, shown in the widget modal
30  * @since 1.8
31  * @var string
32  */
33  protected $widget_subtitle = '';
34 
35  /**
36  * Widget admin ID
37  * @var string
38  */
39  protected $widget_id = '';
40 
41  /**
42  * Default configuration for header and footer
43  * @var array
44  */
45  protected $defaults = array();
46 
47  /**
48  * Widget admin advanced settings
49  * @var array
50  */
51  protected $settings = array();
52 
53  /**
54  * Allow class to automatically add widget_text filter for you in shortcode
55  * @var string
56  */
57  protected $shortcode_name;
58 
59  /**
60  * Hold the widget options.
61  * @var array()
62  */
63  private $widget_options = array();
64 
65  /**
66  * The position of the widget.
67  * @api
68  * @since 2.0
69  * @var string
70  */
71  public $position = '';
72 
73  /**
74  * A unique ID for this widget.
75  * @api
76  * @since 2.0
77  * @var string
78  */
79  public $UID = '';
80 
81  /**
82  * The actual configuration for this widget instance.
83  *
84  * @api
85  * @since 2.0
86  * @var \GV\Settings
87  */
89 
90  /**
91  * @var string An icon that represents the widget type in the widget picker.
92  *
93  * Supports these icon formats:
94  * - Gravity Forms icon class: The string starts with "gform-icon". Note: the site must be running GF 2.5+. No need to also pass "gform-icon".
95  * - Dashicons: The string starts with "dashicons". No need to also pass "dashicons".
96  * - Inline SVG: Starts with "data:". Note: No single quotes are allowed!
97  * - If not matching those formats, the value will be used as a CSS class in a `<i>` element.
98  *
99  * @see GravityView_Admin_View_Item::getOutput
100  */
101  public $icon;
102 
103  /**
104  * Constructor.
105  *
106  * @param string $label The Widget label as shown in the admin.
107  * @param string $id The Widget ID, make this something unique.
108  * @param array $defaults Default footer/header Widget configuration.
109  * @param array $settings Advanced Widget settings.
110  *
111  * @return \GV\Widget
112  */
113  public function __construct( $label, $id, $defaults = array(), $settings = array() ) {
114  /**
115  * The shortcode name is set to the lowercase name of the widget class, unless overridden by the class specifying a different value for $shortcode_name
116  * @var string
117  */
118  $this->shortcode_name = empty( $this->shortcode_name ) ? strtolower( get_called_class() ) : $this->shortcode_name;
119 
120  if ( $id ) {
121  $this->widget_id = $id;
122  }
123 
124  $this->widget_label = $label;
125  $this->defaults = array_merge( array( 'header' => 0, 'footer' => 0 ), $defaults );
126 
127  // Make sure every widget has a title, even if empty
128  $this->settings = wp_parse_args( $settings, $this->get_default_settings() );
129 
130  // Hook once per unique ID
131  if ( $this->is_registered() ) {
132  return;
133  }
134 
135  // widget options
136  add_filter( 'gravityview_template_widget_options', array( $this, 'assign_widget_options' ), 10, 3 );
137 
138  // frontend logic
139  add_action( sprintf( 'gravityview/widgets/%s/render', $this->get_widget_id() ), array( $this, 'render_frontend' ), 10, 3 );
140 
141  // register shortcodes
142  add_action( 'wp', array( $this, 'add_shortcode' ) );
143 
144  // Use shortcodes in text widgets.
145  add_filter( 'widget_text', array( $this, 'maybe_do_shortcode' ) );
146 
147  // register widgets to be listed in the View Configuration
148  // Important: this has to be the last filter/action added in the constructor.
149  add_filter( 'gravityview/widgets/register', array( $this, 'register_widget' ) );
150  }
151 
152  /**
153  * Define general widget settings
154  * @since 1.5.4
155  * @return array $settings Default settings
156  */
157  protected function get_default_settings() {
158  $settings = array();
159 
160  /**
161  * @filter `gravityview/widget/enable_custom_class` Enable custom CSS class settings for widgets
162  * @param boolean $enable_custom_class False by default. Return true if you want to enable.
163  * @param \GV\Widget $this Current instance of \GV\Widget.
164  */
165  $enable_custom_class = apply_filters( 'gravityview/widget/enable_custom_class', false, $this );
166 
167  if ( $enable_custom_class ) {
168  $settings['custom_class'] = array(
169  'type' => 'text',
170  'label' => __( 'Custom CSS Class:', 'gk-gravityview' ),
171  'desc' => __( 'This class will be added to the widget container', 'gk-gravityview' ),
172  'value' => '',
173  'merge_tags' => true,
174  'class' => 'widefat code',
175  );
176  }
177 
178  return $settings;
179  }
180 
181  /**
182  * Get the Widget ID.
183  *
184  * @return string The Widget ID.
185  */
186  public function get_widget_id() {
187  return $this->widget_id;
188  }
189 
190  /**
191  * Get the widget settings
192  *
193  * @return array|null Settings array; NULL if not set for some reason.
194  */
195  public function get_settings() {
196  return empty( $this->settings ) ? null : $this->settings;
197  }
198 
199  /**
200  * Get a setting by the setting key.
201  *
202  * @param string $key Key for the setting
203  *
204  * @todo Use the \GV\Settings class later. For now subclasses may still expect and array instead.
205  *
206  * @return mixed|null Value of the setting; NULL if not set
207  */
208  public function get_setting( $key ) {
209  return Utils::get( $this->settings, $key, null );
210  }
211 
212  /**
213  * Default widget areas.
214  *
215  * Usually overridden by the selected template.
216  *
217  * @return array The default areas where widgets can be rendered.
218  */
219  public static function get_default_widget_areas() {
220 
221  $default_areas = array(
222  array(
223  '1-1' => array(
224  array(
225  'areaid' => 'top',
226  'title' => __( 'Top', 'gk-gravityview' ) ,
227  'subtitle' => ''
228  ),
229  ),
230  ),
231  array(
232  '1-2' => array(
233  array(
234  'areaid' => 'left',
235  'title' => __( 'Left', 'gk-gravityview' ) ,
236  'subtitle' => ''
237  ),
238  ),
239  '2-2' => array(
240  array(
241  'areaid' => 'right',
242  'title' => __( 'Right', 'gk-gravityview' ) ,
243  'subtitle' => ''
244  ),
245  ),
246  ),
247  );
248 
249  /**
250  * @filter `gravityview_widget_active_areas` Array of zones available for widgets to be dropped into
251  * @deprecated 2.0: Use gravityview/widget/active_areas instead
252  * @param array $default_areas Definition for default widget areas
253  */
254  $default_areas = apply_filters( 'gravityview_widget_active_areas', $default_areas );
255 
256  /**
257  * @filter `gravityview/widget/active_areas` Array of zones available for widgets to be dropped into
258  * @since 2.0
259  * @param array $default_areas Definition for default widget areas
260  */
261  return apply_filters( 'gravityview/widget/active_areas', $default_areas );
262  }
263 
264  /**
265  * Register widget to become available in admin. And for lookup.
266  *
267  * @param array $widgets Usually just empty. Used to gather them all up.
268  *
269  * @return array $widgets
270  */
271  public function register_widget( $widgets ) {
272  if ( ! is_array( $widgets ) ) {
273  $widgets = array();
274  }
275 
276  $widgets[ $this->get_widget_id() ] = array(
277  'label' => $this->widget_label ,
278  'description' => $this->widget_description,
279  'subtitle' => $this->widget_subtitle,
280  'icon' => $this->icon,
281  'class' => get_called_class(),
282  );
283 
284  return $widgets;
285  }
286 
287  /**
288  * Assign template specific widget options
289  *
290  * @access protected
291  *
292  * @param array $options (default: array())
293  * @param string $template (default: '')
294  *
295  * @return array
296  */
297  public function assign_widget_options( $options = array(), $template = '', $widget = '' ) {
298  if ( $this->get_widget_id() === $widget ) {
299  if( $settings = $this->get_settings() ) {
300  $options = array_merge( $options, $settings );
301  }
302  }
303  return $options;
304  }
305 
306  /**
307  * Do shortcode if the Widget's shortcode exists.
308  *
309  * @param string $text Widget text to check
310  * @param null|\WP_Widget Empty if not called by WP_Widget, or a WP_Widget instance
311  *
312  * @return string Widget text
313  */
314  public function maybe_do_shortcode( $text, $widget = null ) {
315  if ( ! empty( $this->shortcode_name ) && has_shortcode( $text, $this->shortcode_name ) ) {
316  return do_shortcode( $text );
317  }
318  return $text;
319  }
320 
321  /**
322  * Add $this->shortcode_name shortcode to output self::render_frontend()
323  *
324  * @return void
325  */
326  public function add_shortcode() {
327  if ( empty( $this->shortcode_name ) ) {
328  return;
329  }
330 
331  if ( ! gravityview()->plugin->is_compatible() ) {
332  return;
333  }
334 
335  if ( gravityview()->request->is_admin() ) {
336  return;
337  }
338 
339  // If the widget shouldn't output on single entries, don't show it
340  if ( empty( $this->show_on_single ) && gravityview()->request->is_entry() ) {
341  gravityview()->log->debug( 'Skipping; set to not run on single entry.' );
342  add_shortcode( $this->shortcode_name, '__return_null' );
343  return;
344  }
345 
346  global $post;
347 
348  if ( ! is_object( $post ) || empty( $post->post_content ) || ! Shortcode::parse( $post->post_content ) ) {
349  add_shortcode( $this->shortcode_name, '__return_null' );
350  return;
351  }
352 
353  add_shortcode( $this->shortcode_name, array( $this, 'render_shortcode') );
354  }
355 
356  /**
357  * Frontend logic.
358  *
359  * Override in child class.
360  *
361  * @param array $widget_args The Widget shortcode args.
362  * @param string $content The content.
363  * @param string|\GV\Template_Context $context The context, if available.
364  *
365  * @return void
366  */
367  public function render_frontend( $widget_args, $content = '', $context = '' ) {
368  }
369 
370  /**
371  * General validations when rendering the widget
372  *
373  * Always call this from your `render_frontend()` override!
374  *
375  * @return boolean True: render frontend; False: don't render frontend
376  */
377  public function pre_render_frontend() {
378 
379  /**
380  * Assume shown regardless of hide_until_search setting.
381  */
382  $allowlist = array(
383  'custom_content',
384  );
385 
386  /**
387  * @deprecated 2.14 In favor of allowlist.
388  */
389  $allowlist = apply_filters_deprecated( 'gravityview/widget/hide_until_searched/whitelist', array( $allowlist ), '2.14', 'gravityview/widget/hide_until_searched/allowlist' );
390 
391  /**
392  * @filter `gravityview/widget/hide_until_searched/allowlist` Some widgets have got to stay shown.
393  * @since 2.14
394  * @param string[] $allowlist The widget IDs that have to be shown by default.
395  */
396  $allowlist = apply_filters( 'gravityview/widget/hide_until_searched/allowlist', $allowlist );
397 
398  if ( ( $view = gravityview()->views->get() ) && ! in_array( $this->get_widget_id(), $allowlist ) ) {
399  $hide_until_searched = $view->settings->get( 'hide_until_searched' );
400  } else {
401  $hide_until_searched = false;
402  }
403 
404  /**
405  * @filter `gravityview/widget/hide_until_searched` Modify whether to hide content until search
406  * @param boolean $hide_until_searched Hide until search?
407  * @param \GV\Widget $this Widget instance
408  */
409  $hide_until_searched = apply_filters( 'gravityview/widget/hide_until_searched', $hide_until_searched, $this );
410 
411  if ( $hide_until_searched && ! gravityview()->request->is_search() ) {
412  gravityview()->log->debug( 'Hide View data until search is performed' );
413  return false;
414  }
415 
416  return true;
417  }
418 
419  /**
420  * Shortcode.
421  *
422  * @param array $atts The Widget shortcode args.
423  * @param string $content The content.
424  * @param string|\GV\Template_Context $context The context, if available.
425  *
426  * @return string Whatever the widget echoed.
427  */
428  public function render_shortcode( $atts, $content = '', $context = '' ) {
429  ob_start();
430  $this->render_frontend( $atts, $content, $context );
431  return ob_get_clean();
432  }
433 
434  /**
435  * Create the needed widget from a configuration array.
436  *
437  * @param array $configuration The configuration array.
438  * @see \GV\Widget::as_configuration()
439  * @internal
440  * @since 2.0
441  *
442  * @return \GV\Widget|null The widget implementation from configuration or none.
443  */
444  public static function from_configuration( $configuration ) {
445  $registered_widgets = self::registered();
446 
447  if ( ! $id = Utils::get( $configuration, 'id' ) ) {
448  return null;
449  }
450 
451  if ( ! $widget = Utils::get( $registered_widgets, $id ) ) {
452  return null;
453  }
454 
455  if ( ! class_exists( $class = Utils::get( $widget, 'class' ) ) ) {
456  return null;
457  }
458 
459  $w = new $class( Utils::get( $widget, 'label' ), $id );
460  $w->configuration = new Settings( $configuration );
461 
462  return $w;
463  }
464 
465  /**
466  * Return an array of the old format.
467  *
468  * 'id' => string
469  * + whatever else specific fields may have
470  *
471  * @internal
472  * @since 2.0
473  *
474  * @return array
475  */
476  public function as_configuration() {
477  return array_merge( array(
478  'id' => $this->get_widget_id(),
479  ), $this->configuration->all() );
480  }
481 
482  /**
483  * Return all registered widgets.
484  *
485  * @api
486  * @since 2.0
487  *
488  * @return array
489  */
490  public static function registered() {
491  /**
492  * @filter `gravityview_register_directory_widgets` Get the list of registered widgets. Each item is used to instantiate a GravityView_Admin_View_Widget object
493  * @deprecated Use `gravityview/widgets/register`
494  * @param array $registered_widgets Empty array
495  */
496  $registered_widgets = apply_filters( 'gravityview_register_directory_widgets', array() );
497 
498  /**
499  * @filter `gravityview/widgets/register` Each item is used to instantiate a GravityView_Admin_View_Widget object
500  * @param array $registered_widgets Empty array
501  */
502  return apply_filters( 'gravityview/widgets/register', $registered_widgets );
503  }
504 
505  /**
506  * Whether this Widget's been registered already or not.
507  *
508  * @api
509  * @since 2.0
510  *
511  * @return bool
512  */
513  public function is_registered() {
514  if ( ! $widget_id = $this->get_widget_id() ) {
515  gravityview()->log->warning( 'Widget ID not set before calling Widget::is_registered', array( 'data' => $this ) );
516  return false;
517  }
518  return in_array( $widget_id, array_keys( self::registered() ), true );
519  }
520 }
If this file is called directly, abort.
static registered()
Return all registered widgets.
if(! isset( $gravityview)||empty( $gravityview->template)) $template
The entry loop for the list output.
pre_render_frontend()
General validations when rendering the widget.
$class
render_frontend( $widget_args, $content='', $context='')
Frontend logic.
get_settings()
Get the widget settings.
static get_default_widget_areas()
Default widget areas.
static from_configuration( $configuration)
Create the needed widget from a configuration array.
assign_widget_options( $options=array(), $template='', $widget='')
Assign template specific widget options.
maybe_do_shortcode( $text, $widget=null)
Do shortcode if the Widget&#39;s shortcode exists.
register_widget( $widgets)
Register widget to become available in admin.
global $post
Definition: delete-entry.php:7
If this file is called directly, abort.
add_shortcode()
Add $this->shortcode_name shortcode to output self::render_frontend()
if(empty( $field_settings['content'])) $content
Definition: custom.php:37
render_shortcode( $atts, $content='', $context='')
Shortcode.
is_registered()
Whether this Widget&#39;s been registered already or not.
get_widget_id()
Get the Widget ID.
gravityview()
The main GravityView wrapper function.
get_setting( $key)
Get a setting by the setting key.
as_configuration()
Return an array of the old format.
get_default_settings()
Define general widget settings.