2019-04-27 18:36:32 +02:00
< ? php
class Squat_Radar_Widget extends WP_Widget {
public function __construct () {
$widget_ops = array (
'classname' => 'squat-radar-widget' ,
'description' => 'Radar Events List' ,
);
$this -> connector = new Squat_Radar_Connector ();
parent :: __construct ( 'Squat_Radar' , 'Squat Radar Events' , $widget_ops );
}
/**
* Register the widget
*/
public static function register_widget () {
register_widget ( __CLASS__ );
add_action ( 'wp_ajax_squat_radar_events' , [ __CLASS__ , 'ajax_callback' ] );
add_action ( 'wp_ajax_nopriv_squat_radar_events' , [ __CLASS__ , 'ajax_callback' ] );
add_action ( 'wp_enqueue_scripts' , [ __CLASS__ , 'widget_script' ] );
add_action ( 'wp_enqueue_style' , [ __CLASS__ , 'widget_style' ] );
2019-04-29 20:07:19 +02:00
add_shortcode ( 'squat_radar_widget' , [ __CLASS__ , 'shortcode' ] );
add_action ( 'squat_radar_widget_cache_cron' , [ __CLASS__ , 'cache_cron' ] );
add_option ( 'squat_radar_widget_cron_run' , []);
2019-04-27 18:36:32 +02:00
}
static public function widget_style () {
wp_register_style ( 'squat-radar-widget' , SQUAT_RADAR_URL . '/assets/squat-radar.css' );
}
static public function widget_script () {
wp_register_script ( 'squat-radar-widget' , SQUAT_RADAR_URL . '/assets/squat-radar.js' , [ 'jquery' ] );
}
2019-04-29 20:07:19 +02:00
/**
* Output a widget using 'squat_radar_widget' shortcode .
*
* Requires the widget ID .
*
* @ example [ squat_radar_widget id = " 1 " ]
*/
static public function shortcode ( $attributes , $content = '' ) {
$defaults = [
'id' => '__i__' ,
];
$attributes = shortcode_atts ( $defaults , $attributes , 'squat_radar_widget' );
// Return early if ID is unknown.
$option = get_option ( 'widget_squat_radar' );
if ( ! isset ( $option [ $attributes [ 'id' ]] )) {
if ( current_user_can ( 'administrator' ) ) {
$content = '<span class="error">' . __ ( 'Squat Radar Widget shortcode ID not recognised. Check the suggestion at the top of the widget in the adminstration interface.' , 'squat-radar' ) . '</span>' ;
}
return $content ;
}
$instance = $option [ $attributes [ 'id' ]];
// render the widget
ob_start ();
// To allow overriding the args here? For before after etc.
the_widget ( __CLASS__ , $instance );
$content = ob_get_clean ();
return $content ;
}
public static function cache_cron () {
$now = time ();
$last_run = get_option ( 'squat_radar_widget_cron_run' , []);
foreach ( self :: cron_instances () as $number => $instance ) {
if ( ! isset ( $last_run [ $number ]) || $last_run [ $number ] + $instance [ 'cache_expire' ] < $now ) {
if ( self :: cache_refresh ( $instance )) {
$last_run [ $number ] = $now ;
}
}
}
set_option ( 'squat_radar_widget_cron_run' , $last_run );
}
protected static function cache_refresh ( $instance ) {
$connector = new Squat_Radar_Connector ();
// @todo Languages...
try {
$data = $connector -> events ( $instance [ 'url' ][ 'keys' ][ 'facets' ], $instance [ 'fields' ], $language , $instance [ 'limit' ], 0 , TRUE );
}
catch ( Squat_Radar_Connector_Exception $e ) {
return FALSE ;
}
return TRUE ;
}
2019-04-27 18:36:32 +02:00
public function widget ( $args , $instance ) {
wp_enqueue_style ( 'squat-radar-widget' );
$widget_id = 'squat_radar_widget_' . $this -> number ;
2019-04-29 20:07:19 +02:00
2019-04-27 18:36:32 +02:00
echo $args [ 'before_widget' ];
if ( ! empty ( $instance [ 'title' ] ) ) {
echo $args [ 'before_title' ] . apply_filters ( 'widget_title' , $instance [ 'title' ] ) . $args [ 'after_title' ];
}
2019-04-29 20:07:19 +02:00
if ( ! empty ( $instance [ 'use_cron' ]) ) {
try {
echo self :: instance_events_html ( $instance );
}
catch ( Squat_Radar_Connector_Exception $e ) {
if ( current_user_can ( 'administrator' ) ) {
echo $e -> getCode () . ': ' . $e -> getMessage ();
}
echo '<div id="' . $widget_id . '" class="squat-radar-widget"><a href="' . esc_url_raw ( $instance [ 'url' ][ 'value' ] ) . '">'
. esc_url ( $instance [ 'url' ][ 'value' ] )
. '</a></div>' ;
}
}
else {
wp_enqueue_script ( 'squat-radar-widget' );
wp_localize_script ( 'squat-radar-widget' , 'squat_radar_widget' , [ 'ajaxurl' => admin_url ( 'admin-ajax.php' ) ] );
wp_localize_script ( 'squat-radar-widget' , $widget_id , $instance );
echo '<div id="' . $widget_id . '" class="squat-radar-widget squat-radar-ajax"><a href="' . esc_url_raw ( $instance [ 'url' ][ 'value' ] ) . '">'
. esc_url ( $instance [ 'url' ][ 'value' ] )
. '</a></div>' ;
}
2019-04-27 18:36:32 +02:00
echo $args [ 'after_widget' ];
}
public static function ajax_callback () {
if ( ! array_key_exists ( 'instance' , $_POST ) ) {
wp_die ();
}
2019-04-29 20:07:19 +02:00
$data = [];
2019-04-27 18:36:32 +02:00
$instance = $_POST [ 'instance' ];
try {
2019-04-29 20:07:19 +02:00
$data [ 'html' ] = self :: instance_events_html ( $instance );
2019-04-27 18:36:32 +02:00
}
catch ( Squat_Radar_Connector_Exception $e ) {
$data = [ 'is_error' => TRUE ];
if ( current_user_can ( 'administrator' ) ) {
$data [ 'error' ][ 'code' ] = $e -> getCode ();
$data [ 'error' ][ 'message' ] = $e -> getMessage ();
}
}
2019-04-29 20:07:19 +02:00
wp_send_json ( $data );
}
public static function instance_events_html ( $instance ) {
$language = defined ( 'ICL_LANGUAGE_CODE' ) ? ICL_LANGUAGE_CODE : $instance [ 'url' ][ 'keys' ][ 'language' ];
$connector = new Squat_Radar_Connector ();
$data = $connector -> events ( $instance [ 'url' ][ 'keys' ][ 'facets' ], $instance [ 'fields' ], $language , $instance [ 'limit' ], $instance [ 'cache_expire' ], TRUE );
2019-04-27 18:36:32 +02:00
$html = '' ;
foreach ( $data [ 'result' ] as $id => $event ) {
2019-04-28 17:23:55 +02:00
$output = apply_filters ( 'squat_radar_format_event' , $event , $instance [ 'fields' ], [ 'instance' => $instance ] );
2019-04-29 20:07:19 +02:00
$html .= implode ( ' ' , $output );
2019-04-27 18:36:32 +02:00
}
2019-04-29 20:07:19 +02:00
return $html ;
2019-04-27 18:36:32 +02:00
}
public function form ( $instance ) {
2019-04-29 20:07:19 +02:00
2019-04-27 18:36:32 +02:00
//
// Introduction.
//
echo " <p> " ;
echo __ ( 'If you want to display this single widget in a page or post use the Shortcode:' ) . ' ' ;
if ( $this -> number == '__i__' ) {
echo '<em>' . __ ( 'Shortcode will be available once you have saved this the first time' ) . '</em>' ;
}
else {
esc_attr_e ( '[squat_radar_widget id="' . $this -> number . '"]' );
}
echo " </p> " ;
//
// Title.
//
$field_id = esc_attr ( $this -> get_field_id ( 'title' ) );
$field_name = esc_attr ( $this -> get_field_name ( 'title' ) );
$field_label = esc_attr ( 'Title:' , 'squat-radar' );
$field_value = empty ( $instance [ 'title' ] ) ? '' : esc_attr ( $instance [ 'title' ] );
$field_class = 'widefat' ;
echo " <p> " ;
echo " <label for= \" $field_id\ " > $field_label </ label > " ;
echo " <input class= \" $field_class\ " id = \ " $field_id\ " name = \ " $field_name\ " type = \ " text \" value= \" $field_value\ " > " ;
echo " </p> " ;
//
// Limit
//
$field_id = esc_attr ( $this -> get_field_id ( 'limit' ) );
$field_name = esc_attr ( $this -> get_field_name ( 'limit' ) );
$field_label = esc_attr ( 'Number of events to display:' , 'squat-radar' );
$field_value = empty ( $instance [ 'limit' ] ) ? '10' : ( int ) $instance [ 'limit' ];
$field_class = 'tiny-text' ;
echo " <p> " ;
echo " <label for= \" $field_id\ " > $field_label </ label > " ;
echo " <input class= \" $field_class\ " id = \ " $field_id\ " name = \ " $field_name\ " type = \ " number \" step= \" 1 \" min= \" 1 \" value= \" $field_value\ " size = \ " 3 \" > " ;
echo " </p> " ;
//
// URL.
//
$field_error = ! empty ( $instance [ 'url' ][ 'error' ] );
$field_id = esc_attr ( $this -> get_field_id ( 'url' ) );
$field_name = esc_attr ( $this -> get_field_name ( 'url' ) );
$field_label = esc_attr ( 'Event Search URL:' , 'squat-radar' );
$field_value = empty ( $instance [ 'url' ][ 'value' ] ) ? '' : esc_attr ( $instance [ 'url' ][ 'value' ] );
$field_class = 'widefat' . $field_error ? ' error' : '' ;
echo " <p> " ;
echo " <label for= \" $field_id\ " > $field_label </ label > " ;
echo " <input class= \" $field_class\ " id = \ " $field_id\ " name = \ " $field_name\ " type = \ " text \" value= \" $field_value\ " > " ;
echo " </p> " ;
if ( $field_error ) {
echo '<div class="description error">' . __ ( 'The URL was not recognised as a Radar Events search result. It needs to include the domain and the rest of the /events/search/path like: https://radar.squat.net/en/events/city/City_Name/group/123 Start from <a href="https://radar.squat.net/en/events" target="_blank">https://radar.squat.net/en/events</a> and use the filters in the right hand colunm there before copying the URL from your browser address bar.' , 'squat-radar' ) . '</div>' ;
}
else {
echo '<div class="description">' . __ ( 'Go to <a href="https://radar.squat.net/en/events" target="_blank">https://radar.squat.net/en/events</a> and filter for the events you want to show. Then copy the URL from your address bar into here. It will look similar to: https://radar.squat.net/en/events/city/City_Name/group/123' , 'squat-radar' ) . '</div>' ;
}
2019-04-28 17:23:55 +02:00
if ( empty ( $instance [ 'url' ][ 'error' ]) && ! empty ( $instance [ 'url' ][ 'keys' ] ) ) {
2019-04-27 18:36:32 +02:00
echo '<hr>' ;
echo '<p>' . __ ( 'Currently selecting events:' , 'squat-radar' ) . '</p>' ;
echo '<dl>' ;
echo '<dt>' . __ ( 'Default language' , 'squat-radar' ) . '</dt>' ;
echo '<dd>' . esc_html ( $instance [ 'url' ][ 'keys' ][ 'language' ]) . '</dd>' ;
foreach ( $instance [ 'url' ][ 'keys' ][ 'facets' ] as $key => $value ) {
echo '<dt>' . esc_html ( $key ) . '</dt>' ;
echo '<dd>' . esc_html ( $value ) . '</dd>' ;
}
echo '</dl>' ;
}
2019-04-29 20:07:19 +02:00
echo '<hr>' ;
echo '<fieldset>' ;
echo '<legend>' . __ ( 'Fields' , 'squat-radar' ) . '</legend>' ;
echo '<p>' ;
foreach ( $this -> preset_fields () as $api_field_name => $field_label ) {
$field_id = esc_attr ( $this -> get_field_id ( 'field-' . $api_field_name ) );
$field_name = esc_attr ( $this -> get_field_name ( 'field-' . $api_field_name ) );
$field_label = esc_attr ( $field_label );
$checked = '' ;
if ( isset ( $instance [ 'fields' ][ $api_field_name ]) ) {
unset ( $instance [ 'fields' ][ $api_field_name ]);
$checked = ' checked="checked"' ;
}
echo " <input type= \" checkbox \" class= \" checkbox \" id= \" $field_id\ " name = \ " $field_name\ " $checked /> " ;
echo " <label for= \" $field_id\ " > $field_label </ label >< br /> " ;
}
echo '</p>' ;
echo '</fieldset>' ;
2019-04-27 18:36:32 +02:00
// ADVANCED
echo '<hr>' ;
echo '<fieldset>' ;
echo '<legend>' . __ ( 'Advanced settings' , 'squat-radar' ) . '</legend>' ;
//
// Fields.
//
$field_id = esc_attr ( $this -> get_field_id ( 'fields' ) );
$field_name = esc_attr ( $this -> get_field_name ( 'fields' ) );
2019-04-29 20:07:19 +02:00
$field_label = esc_attr ( 'Additional fields:' , 'squat-radar' );
$field_value = empty ( $instance [ 'fields' ] ) ? '' : esc_attr ( implode ( ', ' , $instance [ 'fields' ] ) );
2019-04-27 18:36:32 +02:00
$field_class = 'widefat' ;
echo " <p> " ;
echo " <label for= \" $field_id\ " > $field_label </ label > " ;
echo " <input class= \" $field_class\ " id = \ " $field_id\ " name = \ " $field_name\ " type = \ " text \" value= \" $field_value\ " > " ;
echo " </p> " ;
2019-04-29 20:07:19 +02:00
echo '<div class="description">' . __ ( 'A comma seperated list of field API names. Examples: phone, price, flyer, offline:address:thoroughfare. Some fields might need an additonal filter to format them properly. Can also be used instead of checkboxes to define the order fields are displayed in.' ) . '</div>' ;
2019-04-27 18:36:32 +02:00
//
// Cache expiry.
//
$field_id = esc_attr ( $this -> get_field_id ( 'cache_expire' ) );
$field_name = esc_attr ( $this -> get_field_name ( 'cache_expire' ) );
$field_label = esc_attr ( 'Cache length:' , 'squat-radar' );
$field_value = empty ( $instance [ 'cache_expire' ] ) ? 10800 : ( int ) $instance [ 'cache_expire' ];
$field_class = 'widefat' ;
echo " <p> " ;
echo " <label for= \" $field_id\ " > $field_label </ label > " ;
echo " <select class= \" $field_class\ " id = \ " $field_id\ " name = \ " $field_name\ " > " ;
echo '<option value="3600"' . selected ( $field_value , 3600 ) . '>' . __ ( '1 hour' ) . '</option>' ;
echo '<option value="10800"' . selected ( $field_value , 10800 ) . '>' . __ ( '3 hours' ) . '</option>' ;
echo '<option value="43200"' . selected ( $field_value , 43200 ) . '>' . __ ( '12 hours' ) . '</option>' ;
echo " </select> " ;
echo " </p> " ;
echo '<div class="description">' . __ ( 'Length of time the cache of events will be kept. Longer faster, but updated less often.' ) . '</div>' ;
2019-04-29 20:07:19 +02:00
$field_id = esc_attr ( $this -> get_field_id ( 'use_cron' ) );
$field_name = esc_attr ( $this -> get_field_name ( 'use_cron' ) );
$field_label = esc_attr__ ( 'Use cron' );
$use_cron = isset ( $instance [ 'use_cron' ]) ? ( bool ) $instance [ 'use_cron' ] : false ;
$checked = checked ( $use_cron , TRUE , FALSE );
echo " <input type= \" checkbox \" class= \" checkbox \" id= \" $field_id\ " name = \ " $field_name\ " $checked /> " ;
echo " <label for= \" $field_id\ " > $field_label </ label >< br /> " ;
echo '<div class="description">' . __ ( 'Do not use AJAX, but always display the cached version of the events. Update the cache after the expiry length using cron. Works best if you have a regular external cronjob running.' ) . '</div>' ;
2019-04-27 18:36:32 +02:00
echo '</fieldset>' ;
}
public function update ( $new_instance , $old_instance ) {
$options = [];
if ( ! empty ( $new_instance [ 'title' ] ) ) {
$options [ 'title' ] = sanitize_text_field ( $new_instance [ 'title' ] );
}
else {
$options [ 'title' ] = '' ;
}
if ( ! empty ( $new_instance [ 'url' ]) ) {
$keys = $this -> connector -> decode_search_url ( $new_instance [ 'url' ]);
$options [ 'url' ][ 'keys' ] = $keys ;
$options [ 'url' ][ 'value' ] = $new_instance [ 'url' ];
if ( empty ( $keys )) {
$options [ 'url' ][ 'error' ] = 'URL not recognised' ;
}
}
else {
$options [ 'url' ] = [ 'value' => '' , 'keys' => []];
}
2019-04-29 20:07:19 +02:00
$options [ 'fields' ] = [];
foreach ( $this -> preset_fields () as $field_name => $field_label ) {
if ( ! empty ( $new_instance [ 'field-' . $field_name ]) ) {
$options [ 'fields' ][ $field_name ] = $field_name ;
}
}
2019-04-27 18:36:32 +02:00
if ( ! empty ( $new_instance [ 'fields' ]) ) {
$matches = [];
2019-04-28 17:23:55 +02:00
preg_match_all ( '/([a-zA-Z_:]+)/' , $new_instance [ 'fields' ], $matches );
2019-04-29 20:07:19 +02:00
$options [ 'fields' ] += array_combine ( $matches [ 0 ], $matches [ 0 ]);
2019-04-27 18:36:32 +02:00
}
if ( ! empty ( $new_instance [ 'limit' ] ) ) {
$options [ 'limit' ] = ( int ) $new_instance [ 'limit' ];
}
if ( ! empty ( $new_instance [ 'cache_expire' ] ) ) {
$options [ 'cache_expire' ] = ( int ) $new_instance [ 'cache_expire' ];
}
else {
$options [ 'cache_expire' ] = 10800 ;
}
2019-04-29 20:07:19 +02:00
if ( empty ( $new_instance [ 'use_cron' ] )) {
$options [ 'use_cron' ] = FALSE ;
$cron_instances = self :: cron_instances ();
unset ( $cron_instances [ $this -> number ]);
if ( empty ( $cron_instances ) && ( $timestamp = wp_next_scheduled ( 'squat_radar_widget_cache_cron' ) )) {
wp_unschedule_event ( $timestamp , 'squat_radar_widget_cache_cron' );
}
}
else {
$options [ 'use_cron' ] = TRUE ;
cache_refresh ( $options );
if ( ! wp_next_scheduled ( 'squat_radar_widget_cache_cron' ) ) {
wp_schedule_event ( time () + $options [ 'cache_expire' ], 'hourly' , 'squat_radar_widget_cache_cron' );
}
}
2019-04-27 18:36:32 +02:00
return $options ;
}
2019-04-29 20:07:19 +02:00
public function preset_fields () {
return [
'title_field' => __ ( 'Title' ),
'event_status' => __ ( 'Event status (proposed, or cancelled)' ),
'date_time' => __ ( 'Date and Time (start and optional end)' ),
'date_time:time_start' => __ ( 'Date and Time (start only)' ),
'body' => __ ( 'Body' ),
'category' => __ ( 'Categories' ),
'topic' => __ ( 'Tags' ),
'offline:address' => __ ( 'Address' ),
'offline:map' => __ ( 'Map (link)' ),
'og_group_ref' => __ ( 'Groups' ),
'price_category' => __ ( 'Price category' ),
'image:file:url' => __ ( 'Image' ),
'link' => __ ( 'Event URL (entered not Radar)' ),
'url' => __ ( 'More link (to event on Radar)' ),
];
}
public static function cron_instances () {
$cron_instances = [];
$instances = get_option ( 'widget_squat_radar' );
foreach ( $instances as $number => $instance ) {
if ( ! empty ( $instance [ 'use_cron' ]) ) {
$cron_instances [ $number ] = $instance ;
}
}
2019-04-27 18:36:32 +02:00
2019-04-29 20:07:19 +02:00
return $cron_instances ;
}
}