diff --git a/includes/squat-radar-connector.php b/includes/squat-radar-connector.php index 2183fc0..54e5510 100644 --- a/includes/squat-radar-connector.php +++ b/includes/squat-radar-connector.php @@ -57,11 +57,11 @@ class Squat_Radar_Connector { } function events( $facets, $fields = [], $language = NULL, $limit = 10, $expiration = 10800, $reset = FALSE ) { + $fields = array_merge($fields, ['uuid', 'url']); $transient_key = 'squat_radar_events_' . sha1(implode($facets) . implode($fields) . $language . $limit); if (! $reset && $data = get_transient( $transient_key )) { return $data; } - $query = $this->encode_api_query( $facets, $fields, $language, $limit ); $events = $this->get_events($query); diff --git a/includes/squat-radar-formatter.php b/includes/squat-radar-formatter.php index b2ced4f..43e87c1 100644 --- a/includes/squat-radar-formatter.php +++ b/includes/squat-radar-formatter.php @@ -2,50 +2,318 @@ class Squat_Radar_Formatter { - static public function format_event($event, $fields) { - foreach ($fields as $field) { - $value = self::getValue($event, explode(':', $field)); - } + static public function register() { + // Filter to go through fields and then call filters to turn these into HTML. + add_filter('squat_radar_format_event', [__CLASS__, 'format_event'], 10, 3); + + // Filters to turn each individual field into HTML. + // + // $value is the data from the field and can be an array or string. + // These filters extract data from arrays based on the field structure. + add_filter('squat_radar_field_html', [__CLASS__, 'field_date_html'], 5, 4); + add_filter('squat_radar_field_html', [__CLASS__, 'field_location_html'], 5, 4); + add_filter('squat_radar_field_html', [__CLASS__, 'field_link_html'], 5, 4); + // field 'url' was turned into a more link, example of an override with more specificity. + add_filter('squat_radar_field_html', [__CLASS__, 'field_image_html'], 7, 4); + // If $value is an array it is flattened into a string here. + // If $value != $original it will _not_ be sanitized, assumption is that it has been already. + add_filter('squat_radar_field_html', [__CLASS__, 'field_html'], 10, 4); + // $value is always a string. These filters just add additional wrapper markup. + add_filter('squat_radar_field_html', [__CLASS__, 'field_title_html'], 15, 4); } + static public function format_event($event, $fields, $context) { + + $context['event'] = $event; + $output = []; + $output[] = '
'; + foreach ($fields as $field) { + $field_tree = explode(':', $field); + $value = self::getValue($event, $field_tree); + $field_tree = array_reverse($field_tree); + $output[] = apply_filters('squat_radar_field_html', $value, $value, $field_tree, $context); + } + $output[] = '
'; + return $output; + + } + + /** + * Date field formatting implementation of 'squat_radar_field_html' filter. + */ + static public function field_date_html($value, $original, $field, $context) { + + switch ($field[0]) { + case 'created': + case 'updated': + $output = ''; + if ($value) { + $output = date_i18n( get_option( 'date_format' ), $value ); + $placeholder = ($field[0] == 'created') ? __('Created: %s', 'squat-radar') : __('Updated: %s', 'squat-radar'); + $output = '' . sprintf($placeholder, $output) . ''; + } + return $output; + + // "date_time": [ + // { + // "value": "1556442000", + // "value2": "1556442000", + // "duration": 0, + // "time_start": "2019-04-28T11:00:00+02:00", + // "time_end": "2019-04-28T11:00:00+02:00", + // "rrule": null + // } + // ], + case 'date_time': + + $output = ''; + // There can only be one date. With repeat etc. but just one. + // Repeating events will appear as a new item for each repeat in the feed. + $value = $value[0]; + $output = ''; + $output .= self::field_date_format($value['time_start'], 'start'); + if ($value['time_start'] != $value['time_end']) { + $output .= self::field_date_format($value['time_end'], 'end'); + } + $output .= ''; + return $output; + + case 'time_start': + + $output = ''; + $output .= self::field_date_format($value, 'start'); + $output .= ''; + return $output; + + case 'time_end': + + $output = ''; + $output .= self::field_date_format($value, 'start'); + $output .= ''; + return $output; + + } + + return $value; + } + + private static function field_date_format($time, $start_end) { + + $date_format = get_option('squat_radar_date_format', 'j M Y'); + $time_format = get_option('squat_radar_time_format', 'H:i'); + + $output = ''; + $output .= ''; + $output .= date_i18n($date_format, strtotime($time)); + $output .= ' '; + $output .= date_i18n($time_format, strtotime($time)); + $output .= ''; + + return $output; + } + + /** + * Location field implementation of 'squat_radar_field_html' filter. + * + * "offline": [ + * { + * "uri": "https://radar.squat.net/api/1.2/location/b5786379-da49-4026-8c4e-bcc1a1563284", + * "id": "b5786379-da49-4026-8c4e-bcc1a1563284", + * "resource": "location", + * "title": "Yorck-Kino Yorckstr. 86 Berlin Deutschland", + * "map": { + * "geom": "POINT (13.3853499 52.4930248)", + * "geo_type": "point", + * "lat": "52.493024800000", + * "lon": "13.385349900000", + * "left": "13.385349900000", + * "top": "52.493024800000", + * "right": "13.385349900000", + * "bottom": "52.493024800000", + * "srid": null, + * "latlon": "52.493024800000,13.385349900000", + * "schemaorg_shape": "" + * } + * } + * ] + */ + function field_location_html($value, $original, $field, $context) { + switch ($field[0]) { + case 'map': + $output = []; + foreach ($value as $map) { + if ( is_array($value) && $value['lat'] !== NULL && $value['lon'] !== NULL ) { + $this_output = ''; + $lat = $value['lat']; + $lon = $value['lon']; + $this_output .= ""; + $this_output .= __('[Map]', 'squat-radar'); + $this_output .= ''; + $output[] = $this_output; + } + } + return implode(', ', $output); + + case 'address': + $output = []; + foreach ($value as $address) { + if ( is_array($value) ) { + $this_address = []; + foreach (['name_line', 'thoroughfare', 'locality', 'postal_code', 'country'] as $field_name) { + if (! empty($value[$field_name])) { + $this_line = ''; + $this_line .= sanitize_text_field($value[$field_name]); + $this_line .= ''; + $this_address[] = $this_line; + } + } + + $this_output = ''; + $this_output .= implode(' ,', $this_address); + $this_output .= ''; + $output[] = $this_output; + } + } + return implode('; ', $output); + } + + return $value; + } + + /** + * Item Radar links implementation of 'squat_radar_field_html' filter. + */ + function field_link_html($value, $original, $field, $context) { + if ($field[0] == 'title' && ! empty($context['event']['url'])) { + return '' . sanitize_text_field( $value ) . ''; + } + + if ($field[0] == 'url' && count($field) == 1) { + return '' . __('moreā€¦', 'squat-radar') . ''; + } + + if ($field[0] == 'url') { + array_shift($field); + $field_tree = array_reverse($field); + $sibling_fields = self::getValue($event, $field_tree); + $title = esc_url($value); + $class = 'squat-radar-url-link'; + if (! empty($sibling_fields['title']) ) { + $title = sanitize_text_field( $sibling_fields['title']); + $class = 'squat-radar-url-title'; + } + elseif ( ! empty($sibling_fields['name']) ) { + $title = sanitize_text_field( $sibling_fields['name']); + $class = 'squat-radar-url-name'; + } + return '' . $title . ''; + } + + if ($field[0] == 'link') { + return '' . esc_url($value['url']) . ''; + } + + return $value; + } + + /** + * Format image implementation of 'squat_radar_field_html' filter. + * + * Deliberatly run after field_link_html. Showing how to override an existing filter. + * image:file:url + */ + function field_image_html($value, $original, $field, $context) { + if ($field[0] == 'url' && $field[1] == 'file' && $field[2] == 'image') { + return ''; + } + + return $value; + } + + /** + * Basic implementation of 'squat_radar_field_html' filter. + * + * Put the output into HTML. + * + * @param array|string $value + * The field value being manipulated to become HTML to be displayed. + * @param array|string $original + * The original value of the field before any changes by filters. + * @param array $field + * The field tree. $field[0] being the name of the present field. $field[1] + * being any parent etc. + * @param array $context + * + * @return string + * Flattend array with additional default classes. + */ + function field_html($value, $original, $field, $context) { + if ($value != $original) { + return $value; + } + + if (is_array($value)) { + if ( ! empty($value['value']) ) { + $value = $value['value']; + } + elseif ( ! empty($value['title']) ) { + $value = $value['title']; + } + elseif ( ! empty($value['name']) ) { + $value = $value['name']; + } + elseif ( ! empty($value[0]['value']) ) { + foreach ($value as $row) { + $values[] = $row['value']; + } + $value = $values; + } + elseif ( ! empty($value[0]['title']) ) { + foreach ($value as $row) { + $titles[] = $row['title']; + } + $value = $titles; + } + elseif ( ! empty($value[0]['name']) ) { + foreach ($value as $row) { + $names[] = $row['name']; + } + $value = $names; + } + } + + if (is_array($value)) { + $output = ''; + + return $output; + } + else { + $value = '' . $value . ''; + } + + return $value; + } + + /** + * Title field HTML implentation of 'squat_radar_field_html' filter. + */ + function field_title_html($value, $original, $field, $context) { + if ($field[0] == 'title' && count($field) == 1) { + $value = '

' . $value . '

'; + } + + return $value; + } + /** * Retrieves a value from a nested array with variable depth. * - * This helper function should be used when the depth of the array element - * being retrieved may vary (that is, the number of parent keys is variable). - * It is primarily used for form structures and renderable arrays. - * - * Without this helper function the only way to get a nested array value with - * variable depth in one line would be using eval(), which should be avoided: - * @code - * // Do not do this! Avoid eval(). - * // May also throw a PHP notice, if the variable array keys do not exist. - * eval('$value = $array[\'' . implode("']['", $parents) . "'];"); - * @endcode - * - * Instead, use this helper function: - * @code - * $value = NestedArray::getValue($form, $parents); - * @endcode - * - * A return value of NULL is ambiguous, and can mean either that the requested - * key does not exist, or that the actual value is NULL. If it is required to - * know whether the nested array key actually exists, pass a third argument - * that is altered by reference: - * @code - * $key_exists = NULL; - * $value = NestedArray::getValue($form, $parents, $key_exists); - * if ($key_exists) { - * // Do something with $value. - * } - * @endcode - * - * However if the number of array parent keys is static, the value should - * always be retrieved directly rather than calling this function. - * For instance: - * @code - * $value = $form['signature_settings']['signature']; - * @endcode + * Handles on level of multiple[] values on a key. + * It will work for deeper multiples, but return the top match. * * @param array $array * The array from which to get the value. @@ -61,15 +329,28 @@ class Squat_Radar_Formatter { * Boolean that indicates whether all nested parent keys exist (TRUE) or not * (FALSE). This allows to distinguish between the two possibilities when * NULL is returned. - * - * @author drupal.org contributors */ public static function &getValue(array &$array, array $parents, &$key_exists = NULL) { $ref =& $array; - foreach ($parents as $parent) { + while ($parent = array_shift($parents)) { if (is_array($ref) && array_key_exists($parent, $ref)) { $ref =& $ref[$parent]; } + elseif (is_array($ref) && isset($ref[0])) { + $multiple = []; + array_unshift($parents, $parent); + foreach ($ref as &$value) { + $multiple[] = self::getValue($value, $parents, $key_exists); + } + if (!empty($multiple) ) { + return $multiple; + } + else { + $key_exists = FALSE; + $null = NULL; + return $null; + } + } else { $key_exists = FALSE; $null = NULL; diff --git a/includes/squat-radar-widget.php b/includes/squat-radar-widget.php index 17d7c69..6d8657b 100644 --- a/includes/squat-radar-widget.php +++ b/includes/squat-radar-widget.php @@ -76,46 +76,12 @@ class Squat_Radar_Widget extends WP_Widget { $html = ''; foreach ($data['result'] as $id => $event) { - $html .= Squat_Radar_Formatter::format_event($event); + $output = apply_filters( 'squat_radar_format_event', $event, $instance['fields'], ['instance' => $instance] ); + $html .= implode($output); } $data['html'] = $html; wp_send_json($data); - - $print.="
  • "; - - if ($r->title) { - $print.="

    "; - $print.=strip_tags($r->title); - $print.="

    "; - } - - if ($r->date_time[0]) { - $print.=""; - $print.=verwerk_datum($r->date_time[0]); - $print.=""; - } - - if ($r->body and $r->body->value) { - $print.="

    ".limit_text(strip_tags($r->body->value), 40) . "

    "; - } - - if ($r->title and $r->date_time[0]) { - - $radar_link = "https://radar.squat.net/en/node/$r_id"; - - if ( $squat_lang == "nl") { - $nog_meer = "zie alles"; - $meer = "meer"; - } else { - $nog_meer = "see all"; - $meer = "more"; - } - - $print.= "$meer"; - } - - $print.="
  • "; } public function form( $instance ) { @@ -179,7 +145,7 @@ class Squat_Radar_Widget extends WP_Widget { echo '
    ' . __('Go to https://radar.squat.net/en/events 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') . '
    '; } - if ( ! $instance['url']['error'] && ! empty( $instance['url']['keys'] ) ) { + if ( empty($instance['url']['error']) && ! empty( $instance['url']['keys'] ) ) { echo '
    '; echo '

    ' . __('Currently selecting events:', 'squat-radar') . '

    '; echo '
    '; @@ -259,7 +225,7 @@ class Squat_Radar_Widget extends WP_Widget { if ( ! empty($new_instance['fields']) ) { $matches = []; - preg_match_all('/([a-zA-Z:]+)/', $new_instance['fields'], $matches); + preg_match_all('/([a-zA-Z_:]+)/', $new_instance['fields'], $matches); $options['fields'] = $matches[0]; } else {