@@ -0,0 +1,405 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class renders the html for the event avatar.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Event
|
||||
*/
|
||||
class Ai1ec_View_Event_Avatar extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Get HTML markup for the post's "avatar" image according conditional
|
||||
* fallback model.
|
||||
*
|
||||
* Accepts an ordered array of named avatar $fallbacks. Also accepts a string
|
||||
* of space-separated classes to add to the default classes.
|
||||
* @param Ai1ec_Event $event The event to get the avatar for
|
||||
* @param array|null $fallback_order Order of fallback in searching for
|
||||
* images, or null to use default
|
||||
* @param string $classes A space-separated list of CSS classes
|
||||
* to apply to the outer <div> element.
|
||||
* @param boolean $wrap_permalink Whether to wrap the element in a link
|
||||
* to the event details page.
|
||||
*
|
||||
* @return string String of HTML if image is found
|
||||
*/
|
||||
public function get_event_avatar(
|
||||
Ai1ec_Event $event,
|
||||
$fallback_order = null,
|
||||
$classes = '',
|
||||
$wrap_permalink = true
|
||||
) {
|
||||
$source = $size = null;
|
||||
$url = $this->get_event_avatar_url(
|
||||
$event,
|
||||
$fallback_order,
|
||||
$source,
|
||||
$size
|
||||
);
|
||||
|
||||
if ( empty( $url ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$url = esc_attr( $url );
|
||||
$classes = esc_attr( $classes );
|
||||
|
||||
// Set the alt tag (helpful for SEO).
|
||||
$alt = $event->get( 'post' )->post_title;
|
||||
$location = $this->_registry->get( 'view.event.location' )->get_short_location( $event );
|
||||
if ( ! empty( $location ) ) {
|
||||
$alt .= ' @ ' . $location;
|
||||
}
|
||||
|
||||
$alt = esc_attr( $alt );
|
||||
$size_attr = $size[0] ? "width=\"$size[0]\" height=\"$size[1]\"" : "";
|
||||
$html = '<img src="' . $url . '" alt="' . $alt . '" ' .
|
||||
$size_attr . ' />';
|
||||
|
||||
if ( $wrap_permalink ) {
|
||||
$permalink = add_query_arg(
|
||||
'instance_id',
|
||||
$event->get( 'instance_id' ),
|
||||
get_permalink( $event->get( 'post_id' ) )
|
||||
);
|
||||
$html = '<a href="' . $permalink . '">' . $html . '</a>';
|
||||
}
|
||||
|
||||
$classes .= ' ai1ec-' . $source;
|
||||
$classes .= ( $size[0] > $size[1] )
|
||||
? ' ai1ec-landscape'
|
||||
: ' ai1ec-portrait';
|
||||
$html = '<div class="ai1ec-event-avatar timely ' . $classes . '">' .
|
||||
$html . '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the post's "avatar" image url according conditional fallback model.
|
||||
*
|
||||
* Accepts an ordered array of named methods for $fallback order. Returns
|
||||
* image URL or null if no image found. Also returns matching fallback in the
|
||||
* $source reference.
|
||||
*
|
||||
* @param array|null $fallback_order Order of fallbacks in search for images
|
||||
* @param null $source Fallback that returned matching image,
|
||||
* returned format is string
|
||||
* @param null $size (width, height) array of returned image
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_event_avatar_url(
|
||||
Ai1ec_Event $event,
|
||||
$fallback_order = null,
|
||||
&$source = null,
|
||||
&$size = null
|
||||
) {
|
||||
if ( empty( $fallback_order ) ) {
|
||||
$fallback_order = array(
|
||||
'post_thumbnail',
|
||||
'content_img',
|
||||
'category_avatar',
|
||||
'default_avatar',
|
||||
);
|
||||
}
|
||||
|
||||
$valid_fallbacks = $this->_get_valid_fallbacks();
|
||||
|
||||
foreach ( $fallback_order as $fallback ) {
|
||||
if ( ! isset( $valid_fallbacks[$fallback] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$function = $valid_fallbacks[$fallback];
|
||||
$url = null;
|
||||
if (
|
||||
! is_array( $function ) &&
|
||||
method_exists( $this, $function )
|
||||
) {
|
||||
$url = $this->$function( $event, $size );
|
||||
} else if ( is_callable( $function ) ) {
|
||||
$url = call_user_func_array( $function, array( $event, &$size ) );
|
||||
}
|
||||
if ( null !== $url ) {
|
||||
$source = $fallback;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $url ) ) {
|
||||
return null;
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read post meta for post-thumbnail and return its URL as a string.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event object.
|
||||
* @param null $size (width, height) array of returned image.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_post_thumbnail_url( Ai1ec_Event $event, &$size = null ) {
|
||||
return $this->_get_post_attachment_url(
|
||||
$event,
|
||||
array(
|
||||
'medium',
|
||||
'large',
|
||||
'full',
|
||||
),
|
||||
$size
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read post meta for post-image and return its URL as a string.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event object.
|
||||
* @param null $size (width, height) array of returned image.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_post_image_url( Ai1ec_Event $event, &$size = null ) {
|
||||
return $this->_get_post_attachment_url(
|
||||
$event,
|
||||
array(
|
||||
'full',
|
||||
'large',
|
||||
'medium'
|
||||
),
|
||||
$size
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read post meta for featured image and return its URL as a string.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event object.
|
||||
* @param null $size (width, height) array of returned image.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_featured_image_url( Ai1ec_Event $event, &$size = null ) {
|
||||
$featured_image = get_post_meta( $event->get( 'post_id' ) , '_featured_image', true );
|
||||
if ( empty( $featured_image ) ) {
|
||||
return $this->_get_post_attachment_url(
|
||||
$event,
|
||||
array(
|
||||
'full',
|
||||
'large',
|
||||
'medium'
|
||||
),
|
||||
$size
|
||||
);
|
||||
} else {
|
||||
$priority_order = array( 'large', 'full', 'medium', 'thumbnail' );
|
||||
$url = null;
|
||||
foreach ( $priority_order as $priority ) {
|
||||
foreach ( $featured_image as $values_arr ) {
|
||||
if ( $values_arr[0] === $priority ) {
|
||||
$url = $values_arr[1];
|
||||
$size = array( $values_arr[2], $values_arr[3] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( null !== $url ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the avatar url from the event content
|
||||
*/
|
||||
public function remove_avatar_url( $content ) {
|
||||
return preg_replace( '/<div[^<>]+class=[\'"]?ai1ec-event-avatar[^<>]*[\'"]?[^<>]+>.+<\/div>[.\s]*/'
|
||||
, ''
|
||||
, $content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple regex-parse of post_content for matches of <img src="foo" />; if
|
||||
* one is found, return its URL.
|
||||
*
|
||||
* @param Ai1ec_Event $event
|
||||
* @param null $size (width, height) array of returned image
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_content_img_url( Ai1ec_Event $event, &$size = null ) {
|
||||
$matches = $this->get_image_from_content(
|
||||
$event->get( 'post' )->post_content
|
||||
);
|
||||
// Check if we have a result, otherwise a notice is issued.
|
||||
if ( empty( $matches ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = $matches[2];
|
||||
$size = array( 0, 0 );
|
||||
|
||||
// Try to detect width and height.
|
||||
$attrs = $matches[1] . $matches[3];
|
||||
$matches = null;
|
||||
preg_match_all(
|
||||
'/(width|height)=["\']?(\d+)/i',
|
||||
$attrs,
|
||||
$matches,
|
||||
PREG_SET_ORDER
|
||||
);
|
||||
// Check if we have a result, otherwise a notice is issued.
|
||||
if ( ! empty( $matches ) ) {
|
||||
foreach ( $matches as $match ) {
|
||||
$size[ $match[1] === 'width' ? 0 : 1 ] = $match[2];
|
||||
}
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an image tag from an html string
|
||||
*
|
||||
* @param string $content
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_image_from_content( $content ) {
|
||||
preg_match(
|
||||
'/<img([^>]+)src=["\']?([^"\'\ >]+)([^>]*)>/i',
|
||||
$content,
|
||||
$matches
|
||||
);
|
||||
return $matches;
|
||||
}
|
||||
/**
|
||||
* Returns default avatar image (normally when no other ones are available).
|
||||
*
|
||||
* @param null $size (width, height) array of returned image
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_default_avatar_url( &$size = null ) {
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$file = $loader->get_file( 'default-event-avatar.png', array(), false );
|
||||
$size = array( 256, 256 );
|
||||
return $file->get_url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns avatar image for event's deepest category, if any.
|
||||
*
|
||||
* @param Ai1ec_Event $event Avatar requester.
|
||||
* @param void $size Unused argument.
|
||||
*
|
||||
* @return string|null Avatar's HTML or null if none.
|
||||
*/
|
||||
public function get_category_avatar_url( Ai1ec_Event $event, &$size = null ) {
|
||||
$db = $this->_registry->get( 'dbi.dbi' );
|
||||
|
||||
$terms = $this->_registry->get( 'model.taxonomy' )->get_post_categories(
|
||||
$event->get( 'post_id' )
|
||||
);
|
||||
if ( empty( $terms ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$terms_by_id = array();
|
||||
// Key $terms by term_id rather than arbitrary int.
|
||||
foreach ( $terms as $term ) {
|
||||
$terms_by_id[$term->term_id] = $term;
|
||||
}
|
||||
|
||||
// Array to store term depths, sorted later.
|
||||
$term_depths = array();
|
||||
foreach ( $terms_by_id as $term ) {
|
||||
$depth = 0;
|
||||
$ancestor = $term;
|
||||
while ( ! empty( $ancestor->parent ) ) {
|
||||
$depth++;
|
||||
if ( ! isset( $terms_by_id[$ancestor->parent] ) ) {
|
||||
break;
|
||||
}
|
||||
$ancestor = $terms_by_id[$ancestor->parent];
|
||||
}
|
||||
// Store negative depths for asort() to order from deepest to shallowest.
|
||||
$term_depths[$term->term_id] = -$depth;
|
||||
}
|
||||
// Order term IDs by depth.
|
||||
asort( $term_depths );
|
||||
|
||||
$url = '';
|
||||
$model = $this->_registry->get( 'model.taxonomy' );
|
||||
// Starting at deepest depth, find the first category that has an avatar.
|
||||
foreach ( $term_depths as $term_id => $depth ) {
|
||||
$term_image = $model->get_category_image( $term_id );
|
||||
if ( $term_image ) {
|
||||
$url = $term_image;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return empty( $url ) ? null : $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read post meta for post-attachment and return its URL as a string.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event object.
|
||||
* @param array $ordered_img_sizes Image sizes order.
|
||||
* @param null $size (width, height) array of returned
|
||||
* image.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function _get_post_attachment_url(
|
||||
Ai1ec_Event $event,
|
||||
array $ordered_img_sizes,
|
||||
&$size = null
|
||||
) {
|
||||
// Since WP does will return null if the wrong size is targeted,
|
||||
// we iterate over an array of sizes, breaking if a URL is found.
|
||||
foreach ( $ordered_img_sizes as $size ) {
|
||||
$attributes = wp_get_attachment_image_src(
|
||||
get_post_thumbnail_id( $event->get( 'post_id' ) ), $size
|
||||
);
|
||||
if ( $attributes ) {
|
||||
$url = array_shift( $attributes );
|
||||
$size = $attributes;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return empty( $url ) ? null : $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of valid fallbacks.
|
||||
*
|
||||
* @return array List of valid fallbacks.
|
||||
*/
|
||||
protected function _get_valid_fallbacks() {
|
||||
static $fallbacks;
|
||||
if ( null === $fallbacks ) {
|
||||
$fallbacks = apply_filters(
|
||||
'ai1ec_avatar_valid_callbacks',
|
||||
array(
|
||||
'post_image' => 'get_post_image_url',
|
||||
'post_thumbnail' => 'get_post_thumbnail_url',
|
||||
'content_img' => 'get_content_img_url',
|
||||
'category_avatar' => 'get_category_avatar_url',
|
||||
'default_avatar' => 'get_default_avatar_url',
|
||||
'featured_image' => 'get_featured_image_url'
|
||||
)
|
||||
);
|
||||
}
|
||||
return $fallbacks;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class renders the html for the event colors.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Event
|
||||
*/
|
||||
class Ai1ec_View_Event_Color extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Faded version of event category color
|
||||
*/
|
||||
protected function _get_color( Ai1ec_Event $event, $type ) {
|
||||
static $categories_cache = array(
|
||||
'rgba' => array(),
|
||||
'faded' => array(),
|
||||
);
|
||||
$methods = array(
|
||||
'rgba' => 'get_event_category_rgba_color',
|
||||
'faded' => 'get_event_category_faded_color',
|
||||
);
|
||||
$categories = $this->_registry->get( 'model.taxonomy' )
|
||||
->get_post_categories( $event->get( 'post_id' ) );
|
||||
if ( ! empty( $categories ) ) {
|
||||
if (
|
||||
! isset( $categories_cache[$type][$categories[0]->term_id] )
|
||||
) {
|
||||
$method = $methods[$type];
|
||||
$categories_cache[$type][$categories[0]->term_id] = $this
|
||||
->$method( $categories[0]->term_id );
|
||||
}
|
||||
return $categories_cache[$type][$categories[0]->term_id];
|
||||
}
|
||||
return '';
|
||||
}
|
||||
public function get_faded_color( Ai1ec_Event $event ) {
|
||||
return $this->_get_color( $event, 'faded' );
|
||||
}
|
||||
|
||||
/**
|
||||
* rgba() format of faded category color.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_rgba_color( Ai1ec_Event $event ) {
|
||||
return $this->_get_color( $event, 'rgba' );
|
||||
}
|
||||
/**
|
||||
* Returns a faded version of the event's category color in hex format.
|
||||
*
|
||||
* @param int $term_id The Event Category's term ID
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_event_category_faded_color( $term_id ) {
|
||||
$taxonomy = $this->_registry->get( 'model.taxonomy' );
|
||||
$color = $taxonomy->get_category_color( $term_id );
|
||||
if( ! is_null( $color ) && ! empty( $color ) ) {
|
||||
|
||||
$color1 = substr( $color, 1 );
|
||||
$color2 = 'ffffff';
|
||||
|
||||
$c1_p1 = hexdec( substr( $color1, 0, 2 ) );
|
||||
$c1_p2 = hexdec( substr( $color1, 2, 2 ) );
|
||||
$c1_p3 = hexdec( substr( $color1, 4, 2 ) );
|
||||
|
||||
$c2_p1 = hexdec( substr( $color2, 0, 2 ) );
|
||||
$c2_p2 = hexdec( substr( $color2, 2, 2 ) );
|
||||
$c2_p3 = hexdec( substr( $color2, 4, 2 ) );
|
||||
|
||||
$m_p1 = dechex( round( $c1_p1 * 0.5 + $c2_p1 * 0.5 ) );
|
||||
$m_p2 = dechex( round( $c1_p2 * 0.5 + $c2_p2 * 0.5 ) );
|
||||
$m_p3 = dechex( round( $c1_p3 * 0.5 + $c2_p3 * 0.5 ) );
|
||||
|
||||
return '#' . $m_p1 . $m_p2 . $m_p3;
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rgba() format of the event's category color, with '%s' in place
|
||||
* of the opacity (to be substituted by sprintf).
|
||||
*
|
||||
* @param int $term_id The Event Category's term ID
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_event_category_rgba_color( $term_id ) {
|
||||
$taxonomy = $this->_registry->get( 'model.taxonomy' );
|
||||
$color = $taxonomy->get_category_color( $term_id );
|
||||
if ( ! is_null( $color ) && ! empty( $color ) ) {
|
||||
$p1 = hexdec( substr( $color, 1, 2 ) );
|
||||
$p2 = hexdec( substr( $color, 3, 2 ) );
|
||||
$p3 = hexdec( substr( $color, 5, 2 ) );
|
||||
return "rgba($p1, $p2, $p3, %s)";
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class process event content.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Event
|
||||
*/
|
||||
class Ai1ec_View_Event_Content extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Render event excerpt header.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event to render excerpt for.
|
||||
*
|
||||
* @return void Content is not returned, just rendered.
|
||||
*/
|
||||
public function excerpt_view( Ai1ec_Event $event ) {
|
||||
$location = $this->_registry->get( 'view.event.location' );
|
||||
$location = esc_html(
|
||||
str_replace(
|
||||
"\n",
|
||||
', ',
|
||||
rtrim( $location->get_location( $event ) )
|
||||
)
|
||||
);
|
||||
$args = array(
|
||||
'event' => $event,
|
||||
'location' => $location,
|
||||
'text_when' => __( 'When:', AI1EC_PLUGIN_NAME ),
|
||||
'text_where' => __( 'Where:', AI1EC_PLUGIN_NAME ),
|
||||
);
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
echo $loader->get_file(
|
||||
'event-excerpt.twig',
|
||||
$args,
|
||||
true
|
||||
)->get_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* Format events excerpt view.
|
||||
*
|
||||
* @param string $text Content to excerpt.
|
||||
*
|
||||
* @return string Formatted event excerpt.
|
||||
*/
|
||||
public function event_excerpt( $text ) {
|
||||
if ( ! $this->_registry->get( 'acl.aco' )->is_our_post_type() ) {
|
||||
return $text;
|
||||
}
|
||||
$event = $this->_registry->get( 'model.event', get_the_ID() );
|
||||
$post = $this->_registry->get( 'view.event.post' );
|
||||
$ob = $this->_registry->get( 'compatibility.ob' );
|
||||
$ob->start();
|
||||
$this->excerpt_view( $event );
|
||||
// Re-apply any filters to the post content that normally would have
|
||||
// been applied if it weren't for our interference (below).
|
||||
echo shortcode_unautop( wpautop( $post->trim_excerpt( $event ) ) );
|
||||
return $ob->get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoid re-adding `wpautop` for Ai1EC instances.
|
||||
*
|
||||
* @param string $content Processed content.
|
||||
*
|
||||
* @return string Paragraphs enclosed text.
|
||||
*/
|
||||
public function event_excerpt_noautop( $content ) {
|
||||
if ( ! $this->_registry->get( 'acl.aco' )->is_our_post_type() ) {
|
||||
return wpautop( $content );
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
public function get_post_excerpt( Ai1ec_Event $event ) {
|
||||
$content = strip_tags(
|
||||
strip_shortcodes(
|
||||
preg_replace(
|
||||
'#<\s*script[^>]*>.+<\s*/\s*script\s*>#x',
|
||||
'',
|
||||
apply_filters(
|
||||
'ai1ec_the_content',
|
||||
apply_filters(
|
||||
'the_content',
|
||||
$event->get( 'post' )->post_content
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
$content = preg_replace( '/\s+/', ' ', $content );
|
||||
$words = explode( ' ', $content );
|
||||
if ( count( $words ) > 25 ) {
|
||||
return implode(
|
||||
' ',
|
||||
array_slice( $words, 0, 25 )
|
||||
) . ' [...]';
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the html for the "Calendar" button for this event.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_back_to_calendar_button_html() {
|
||||
$class = '';
|
||||
$data_type = '';
|
||||
$href = '';
|
||||
if ( isset( $_COOKIE['ai1ec_calendar_url'] ) ) {
|
||||
$href = json_decode(
|
||||
stripslashes( $_COOKIE['ai1ec_calendar_url'] )
|
||||
);
|
||||
setcookie( 'ai1ec_calendar_url', '', time() - 3600 );
|
||||
} else {
|
||||
$href = $this->_registry->get( 'html.element.href', array() );
|
||||
$href = $href->generate_href();
|
||||
}
|
||||
$text = esc_attr( Ai1ec_I18n::__( 'Calendar' ) );
|
||||
$tooltip = esc_attr( Ai1ec_I18n::__( 'View all events' ) );
|
||||
$html = <<<HTML
|
||||
<a class="ai1ec-calendar-link ai1ec-btn ai1ec-btn-default ai1ec-btn-sm
|
||||
ai1ec-tooltip-trigger $class"
|
||||
href="$href"
|
||||
$data_type
|
||||
data-placement="left"
|
||||
title="$tooltip">
|
||||
<i class="ai1ec-fa ai1ec-fa-calendar ai1ec-fa-fw"></i>
|
||||
<span class="ai1ec-hidden-xs">$text</span>
|
||||
</a>
|
||||
HTML;
|
||||
return apply_filters( 'ai1ec_get_back_to_calendar_html', $html, $href );
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple regex-parse of post_content for matches of <img src="foo" />; if
|
||||
* one is found, return its URL.
|
||||
*
|
||||
* @param null $size (width, height) array of returned image
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_content_img_url( Ai1ec_Event $event, &$size = null ) {
|
||||
preg_match(
|
||||
'/<img([^>]+)src=["\']?([^"\'\ >]+)([^>]*)>/i',
|
||||
$event->get( 'post' )->post_content,
|
||||
$matches
|
||||
);
|
||||
|
||||
// Check if we have a result, otherwise a notice is issued.
|
||||
if ( empty( $matches ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Mark found image.
|
||||
$event->get( 'post' )->post_content = str_replace(
|
||||
'<img' . $matches[1],
|
||||
'<img' . $matches[1] . ' data-ai1ec-hidden ',
|
||||
$event->get( 'post' )->post_content
|
||||
);
|
||||
|
||||
$url = $matches[2];
|
||||
$size = array( 0, 0 );
|
||||
|
||||
// Try to detect width and height.
|
||||
$attrs = $matches[1] . $matches[3];
|
||||
$matches = null;
|
||||
preg_match_all(
|
||||
'/(width|height)=["\']?(\d+)/i',
|
||||
$attrs,
|
||||
$matches,
|
||||
PREG_SET_ORDER
|
||||
);
|
||||
// Check if we have a result, otherwise a notice is issued.
|
||||
if ( ! empty( $matches ) ) {
|
||||
foreach ( $matches as $match ) {
|
||||
$size[ $match[1] === 'width' ? 0 : 1 ] = $match[2];
|
||||
}
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class renders the html for the event location.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Event
|
||||
*/
|
||||
class Ai1ec_View_Event_Location extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Return location details in brief format, separated by | characters.
|
||||
*
|
||||
* @return $string Short location string
|
||||
*/
|
||||
public function get_short_location( Ai1ec_Event $event ) {
|
||||
$location_items = array();
|
||||
foreach ( array( 'venue', 'city', 'province', 'country' ) as $field ) {
|
||||
if ( $event->get( $field ) !== '' ) {
|
||||
$location_items[] = $event->get( $field );
|
||||
}
|
||||
}
|
||||
return implode( ' | ', $location_items );
|
||||
}
|
||||
|
||||
/*
|
||||
* Return any available location details separated by newlines
|
||||
*/
|
||||
public function get_location( Ai1ec_Event $event ) {
|
||||
$location = '';
|
||||
$venue = $event->get( 'venue' );
|
||||
if ( $venue ) {
|
||||
$location .= $venue . "\n";
|
||||
}
|
||||
$address = $event->get( 'address' );
|
||||
if ( $address ) {
|
||||
$bits = explode( ',', $address );
|
||||
$bits = array_map( 'trim', $bits );
|
||||
|
||||
// If more than three comma-separated values, treat first value as
|
||||
// the street address, last value as the country, and everything
|
||||
// in the middle as the city, state, etc.
|
||||
if ( count( $bits ) >= 3 ) {
|
||||
// Append the street address
|
||||
$street_address = array_shift( $bits ) . "\n";
|
||||
if ( $street_address ) {
|
||||
$location .= $street_address;
|
||||
}
|
||||
// Save the country for the last line
|
||||
$country = array_pop( $bits );
|
||||
// Append the middle bit(s) (filtering out any zero-length strings)
|
||||
$bits = array_filter( $bits, 'strval' );
|
||||
if ( $bits ) {
|
||||
$location .= join( ', ', $bits ) . "\n";
|
||||
}
|
||||
if ( $country ) {
|
||||
$location .= $country . "\n";
|
||||
}
|
||||
} else {
|
||||
// There are two or less comma-separated values, so just append
|
||||
// them each on their own line (filtering out any zero-length strings)
|
||||
$bits = array_filter( $bits, 'strval' );
|
||||
$location .= join( "\n", $bits );
|
||||
}
|
||||
}
|
||||
return $location;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_map_view function
|
||||
*
|
||||
* Returns HTML markup displaying a Google map of the given event, if the event
|
||||
* has show_map set to true. Returns a zero-length string otherwise.
|
||||
*
|
||||
* @return void
|
||||
**/
|
||||
function get_map_view( Ai1ec_Event $event ) {
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
if( ! $event->get( 'show_map' ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$location = $this->get_latlng( $event );
|
||||
if ( ! $location ) {
|
||||
$location = $event->get( 'address' );
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'address' => $location,
|
||||
'gmap_url_link' => $this->get_gmap_url( $event, false ),
|
||||
'hide_maps_until_clicked' => $settings->get( 'hide_maps_until_clicked' ),
|
||||
'text_view_map' => __( 'Click to view map', AI1EC_PLUGIN_NAME ),
|
||||
'text_full_map' => __( 'View Full-Size Map', AI1EC_PLUGIN_NAME ),
|
||||
);
|
||||
return $loader->get_file( 'event-map.twig', $args, false )->get_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the latitude/longitude coordinates as a textual string
|
||||
* parsable by the Geocoder API.
|
||||
*
|
||||
* @param Ai1ec_Event &$event The event to return data from
|
||||
*
|
||||
* @return string The latitude & longitude string, or null
|
||||
*/
|
||||
public function get_latlng( Ai1ec_Event $event ) {
|
||||
// If the coordinates are set, use those, otherwise use the address.
|
||||
$location = NULL;
|
||||
// If the coordinates are set by hand use them.
|
||||
if ( $event->get( 'show_coordinates' ) ) {
|
||||
$longitude = floatval( $event->get( 'longitude' ) );
|
||||
$latitude = floatval( $event->get( 'latitude' ) );
|
||||
$location = $latitude . ',' . $longitude;
|
||||
}
|
||||
return $location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL to the Google Map for the given event object.
|
||||
*
|
||||
* @param Ai1ec_Event $event The event object to display a map for
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_gmap_url( Ai1ec_Event $event ) {
|
||||
$lang = $this->_registry->get( 'p28n.wpml' )->get_language();
|
||||
$location = $this->get_latlng( $event );
|
||||
if ( ! $location ) {
|
||||
$location = $event->get( 'address' );
|
||||
}
|
||||
return 'https://www.google.com/maps?f=q&hl=' . urlencode( $lang ) .
|
||||
'&source=embed&q=' . urlencode( $location );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class renders the html for the event colors.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Event
|
||||
*/
|
||||
class Ai1ec_View_Event_Post extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Add event-specific messages to be used when one is modified in dashboard.
|
||||
*
|
||||
* @wp_hook post_updated_messages
|
||||
*
|
||||
* @param array $messages List of messages.
|
||||
*
|
||||
* @return array Modified list of messages.
|
||||
*/
|
||||
public function post_updated_messages( $messages ) {
|
||||
global $post, $post_ID;
|
||||
|
||||
$messages[AI1EC_POST_TYPE] = array(
|
||||
0 => '', // Unused. Messages start at index 1.
|
||||
1 => sprintf(
|
||||
Ai1ec_I18n::__( 'Event updated. <a href="%s">View event</a>' ),
|
||||
esc_url( get_permalink( $post_ID ) )
|
||||
),
|
||||
2 => Ai1ec_I18n::__( 'Custom field updated.' ),
|
||||
3 => Ai1ec_I18n::__( 'Custom field deleted.' ),
|
||||
4 => Ai1ec_I18n::__( 'Event updated.' ),
|
||||
/* translators: %s: date and time of the revision */
|
||||
5 => isset( $_GET['revision'] )
|
||||
? sprintf(
|
||||
Ai1ec_I18n::__( 'Event restored to revision from %s' ),
|
||||
wp_post_revision_title( (int) $_GET['revision'], false )
|
||||
)
|
||||
: false,
|
||||
6 => sprintf(
|
||||
Ai1ec_I18n::__( 'Event published. <a href="%s">View event</a>' ),
|
||||
esc_url( get_permalink($post_ID) )
|
||||
),
|
||||
7 => Ai1ec_I18n::__( 'Event saved.' ),
|
||||
8 => sprintf(
|
||||
Ai1ec_I18n::__( 'Event submitted. <a target="_blank" href="%s">Preview event</a>' ),
|
||||
esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) )
|
||||
),
|
||||
9 => sprintf(
|
||||
Ai1ec_I18n::__( 'Event scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview event</a>' ),
|
||||
// translators: Publish box date format, see http://php.net/date
|
||||
$this->_registry->get( 'date.time', $post->post_date )->format_i18n( Ai1ec_I18n::__( 'M j, Y @ G:i' ) ),
|
||||
esc_url( get_permalink($post_ID) )
|
||||
),
|
||||
10 => sprintf(
|
||||
Ai1ec_I18n::__( 'Event draft updated. <a target="_blank" href="%s">Preview event</a>' ),
|
||||
esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) )
|
||||
),
|
||||
);
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an excerpt from the given content string.
|
||||
*
|
||||
* Adapted from WordPress's `wp_trim_excerpt' function that is not useful
|
||||
* for applying to custom content.
|
||||
*
|
||||
* @param string $text The content to trim.
|
||||
*
|
||||
* @return string The excerpt.
|
||||
*/
|
||||
public function trim_excerpt( Ai1ec_Event $event, $length = 35, $more = '[...]' ) {
|
||||
global $post;
|
||||
$original_post = $post;
|
||||
$post = $event->get( 'post' );
|
||||
$raw_excerpt = $event->get( 'post' )->post_content;
|
||||
if ( ! isset( $raw_excerpt{0} ) ) {
|
||||
$raw_excerpt = ' ';
|
||||
}
|
||||
|
||||
$text = preg_replace(
|
||||
'#<\s*script[^>]*>.+<\s*/\s*script\s*>#x',
|
||||
'',
|
||||
apply_filters(
|
||||
'the_excerpt',
|
||||
$raw_excerpt
|
||||
)
|
||||
);
|
||||
$text = strip_shortcodes( $text );
|
||||
$text = str_replace( ']]>', ']]>', $text );
|
||||
$text = strip_tags( $text );
|
||||
|
||||
$excerpt_length = apply_filters( 'excerpt_length', $length );
|
||||
$excerpt_more = apply_filters( 'excerpt_more', $more );
|
||||
$words = preg_split(
|
||||
'/\s+/',
|
||||
$text,
|
||||
$excerpt_length + 1,
|
||||
PREG_SPLIT_NO_EMPTY
|
||||
);
|
||||
if ( count( $words ) > $excerpt_length ) {
|
||||
array_pop( $words );
|
||||
$text = implode( ' ', $words );
|
||||
$text = $text . $excerpt_more;
|
||||
} else {
|
||||
$text = implode( ' ', $words );
|
||||
}
|
||||
$post = $original_post;
|
||||
return apply_filters( 'wp_trim_excerpt', $text, $raw_excerpt );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class renders the html for the single event page.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Event
|
||||
*/
|
||||
class Ai1ec_View_Event_Single extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Renders the html of the page and returns it.
|
||||
*
|
||||
* @param Ai1ec_Event $event
|
||||
*
|
||||
* @return string the html of the page
|
||||
*/
|
||||
public function get_content( Ai1ec_Event $event ) {
|
||||
$settings = $this->_registry->get( 'model.settings' );
|
||||
$rrule = $this->_registry->get( 'recurrence.rule' );
|
||||
$taxonomy = $this->_registry->get( 'view.event.taxonomy' );
|
||||
$location = $this->_registry->get( 'view.event.location' );
|
||||
$ticket = $this->_registry->get( 'view.event.ticket' );
|
||||
$content = $this->_registry->get( 'view.event.content' );
|
||||
$time = $this->_registry->get( 'view.event.time' );
|
||||
|
||||
$subscribe_url = AI1EC_EXPORT_URL . '&ai1ec_post_ids=' .
|
||||
$event->get( 'post_id' );
|
||||
|
||||
$event->set_runtime(
|
||||
'tickets_url_label',
|
||||
$ticket->get_tickets_url_label( $event, false )
|
||||
);
|
||||
$event->set_runtime(
|
||||
'content_img_url',
|
||||
$content->get_content_img_url( $event )
|
||||
);
|
||||
|
||||
$extra_buttons = apply_filters(
|
||||
'ai1ec_rendering_single_event_actions',
|
||||
'',
|
||||
$event
|
||||
);
|
||||
|
||||
$venues_html = apply_filters(
|
||||
'ai1ec_rendering_single_event_venues',
|
||||
nl2br( $location->get_location( $event ) ),
|
||||
$event
|
||||
);
|
||||
$default_tz = $this->_registry->get( 'date.timezone' )->get_default_timezone();
|
||||
$timezone_info = array(
|
||||
'show_timezone' => $this->_registry->get( 'model.settings' )->get( 'always_use_calendar_timezone' ),
|
||||
'using_calendar_tz' => $this->_registry->get( 'model.settings' )->get( 'always_use_calendar_timezone' ),
|
||||
'event_timezone' => str_replace( '_', ' ', $event->get( 'timezone_name' ) ) . ' ' . __( 'Timezone', AI1EC_PLUGIN_NAME ),
|
||||
'calendar_timezone' => str_replace( '_', ' ', $default_tz ) . ' ' . __( 'Timezone', AI1EC_PLUGIN_NAME ),
|
||||
);
|
||||
|
||||
$banner_image_meta = get_post_meta( $event->get( 'post_id' ), 'ai1ec_banner_image' );
|
||||
$banner_image = $banner_image_meta ? $banner_image_meta[0] : '';
|
||||
|
||||
// objects are passed by reference so an action is ok
|
||||
do_action( 'ai1ec_single_event_page_before_render', $event );
|
||||
|
||||
$filter_groups_html = apply_filters( 'ai1ec_get_filter_groups_html', $event );
|
||||
|
||||
$args = array(
|
||||
'event' => $event,
|
||||
'recurrence' => $rrule->rrule_to_text( $event->get( 'recurrence_rules' ) ),
|
||||
'exclude' => $time->get_exclude_html( $event, $rrule ),
|
||||
'categories' => $taxonomy->get_categories_html( $event ),
|
||||
'tags' => $taxonomy->get_tags_html( $event ),
|
||||
'location' => html_entity_decode( $venues_html ),
|
||||
'filter_groups' => $filter_groups_html,
|
||||
'map' => $location->get_map_view( $event ),
|
||||
'contact' => $ticket->get_contact_html( $event ),
|
||||
'back_to_calendar' => $content->get_back_to_calendar_button_html(),
|
||||
'subscribe_url' => $subscribe_url,
|
||||
'subscribe_url_no_html' => $subscribe_url . '&no_html=true',
|
||||
'edit_instance_url' => null,
|
||||
'edit_instance_text' => null,
|
||||
'google_url' => 'https://www.google.com/calendar/render?cid=' . urlencode( $subscribe_url ),
|
||||
'show_subscribe_buttons' => ! $settings->get( 'turn_off_subscription_buttons' ),
|
||||
'hide_featured_image' => $settings->get( 'hide_featured_image' ),
|
||||
'extra_buttons' => $extra_buttons,
|
||||
'show_get_calendar' => ! $settings->get( 'disable_get_calendar_button' ),
|
||||
'text_add_calendar' => __( 'Add to Calendar', AI1EC_PLUGIN_NAME ),
|
||||
'subscribe_buttons_text' => $this->_registry
|
||||
->get( 'view.calendar.subscribe-button' )
|
||||
->get_labels(),
|
||||
'text_get_calendar' => Ai1ec_I18n::__( 'Get a Timely Calendar' ),
|
||||
'text_when' => __( 'When:', AI1EC_PLUGIN_NAME ),
|
||||
'text_where' => __( 'Where:', AI1EC_PLUGIN_NAME ),
|
||||
'text_cost' => __( 'Cost:', AI1EC_PLUGIN_NAME ),
|
||||
'text_contact' => __( 'Contact:', AI1EC_PLUGIN_NAME ),
|
||||
'text_tickets' => __( 'Tickets:', AI1EC_PLUGIN_NAME ),
|
||||
'text_free' => __( 'Free', AI1EC_PLUGIN_NAME ),
|
||||
'text_categories' => __( 'Categories', AI1EC_PLUGIN_NAME ),
|
||||
'text_tags' => __( 'Tags', AI1EC_PLUGIN_NAME ),
|
||||
'buy_tickets_text' => __( 'Buy Tickets', AI1EC_PLUGIN_NAME ),
|
||||
'timezone_info' => $timezone_info,
|
||||
'banner_image' => $banner_image,
|
||||
'content_img_url' => $event->get_runtime( 'content_img_url' ),
|
||||
'post_id' => $event->get( 'post_id' ),
|
||||
'ticket_url' => $event->get( 'ticket_url' ),
|
||||
'tickets_url_label' => $event->get_runtime( 'tickets_url_label' ),
|
||||
'start' => $event->get( 'start' ),
|
||||
'end' => $event->get( 'end' ),
|
||||
'cost' => $event->get( 'cost' ),
|
||||
'instance_id' => $event->get( 'instance_id' ),
|
||||
);
|
||||
|
||||
if (
|
||||
! empty( $args['recurrence'] ) &&
|
||||
$event->get( 'instance_id' ) &&
|
||||
current_user_can( 'edit_ai1ec_events' )
|
||||
) {
|
||||
$args['edit_instance_url'] = ai1ec_admin_url(
|
||||
'post.php?post=' . $event->get( 'post_id' ) .
|
||||
'&action=edit&instance=' . $event->get( 'instance_id' )
|
||||
);
|
||||
$args['edit_instance_text'] = sprintf(
|
||||
Ai1ec_I18n::__( 'Edit this occurrence (%s)' ),
|
||||
$event->get( 'start' )->format_i18n( 'M j' )
|
||||
);
|
||||
}
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$api = $this->_registry->get( 'model.api.api-ticketing' );
|
||||
if ( false === ai1ec_is_blank( $event->get( 'ical_feed_url' ) ) ) {
|
||||
$ticket_url = $api->get_api_event_buy_ticket_url( $event->get( 'post_id' ) );
|
||||
if ( ! empty ( $ticket_url ) ) {
|
||||
$args['ticket_url'] = $ticket_url;
|
||||
}
|
||||
} else {
|
||||
$api_event_id = $api->get_api_event_id( $event->get( 'post_id' ) );
|
||||
if ( $api_event_id ) {
|
||||
$api = $this->_registry->get( 'model.api.api-ticketing' );
|
||||
$ticket_types = json_decode( $api->get_ticket_types( $event->get( 'post_id' ), false ) );
|
||||
$args['has_tickets'] = true;
|
||||
$args['API_URL'] = AI1EC_API_URL;
|
||||
$args['tickets_block'] = $loader->get_file(
|
||||
'tickets.twig',
|
||||
array(
|
||||
'tickets_checkout_url' => $api->get_api_event_buy_ticket_url( $event->get( 'post_id' ) ),
|
||||
'tickets' => $ticket_types->data,
|
||||
'text_tickets' => $args['text_tickets'],
|
||||
'buy_tickets_text' => $args['buy_tickets_text'],
|
||||
'api_event_id' => $api_event_id
|
||||
), false
|
||||
)->get_content();
|
||||
}
|
||||
}
|
||||
|
||||
return $loader->get_file( 'event-single.twig', $args, false )
|
||||
->get_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add meta OG tags to the event details page
|
||||
*/
|
||||
public function add_meta_tags() {
|
||||
// Add tags only on Event Details page
|
||||
$aco = $this->_registry->get( 'acl.aco' );
|
||||
if ( ! $aco->is_our_post_type() ) return;
|
||||
|
||||
// Get Event and process description
|
||||
$instance_id = ( isset( $_GET[ 'instance_id' ] ) ) ? $_GET[ 'instance_id' ] : null;
|
||||
|
||||
if ( !is_null( $instance_id ) ) {
|
||||
$instance_id = preg_replace( '/\D/', '', $instance_id );
|
||||
}
|
||||
$event = $this->_registry->get( 'model.event', get_the_ID(), $instance_id );
|
||||
$avatar = $this->_registry->get( 'view.event.avatar' );
|
||||
$content = $this->_registry->get( 'view.event.content' );
|
||||
$desc = $event->get( 'post' )->post_content;
|
||||
$desc = apply_filters( 'the_excerpt', $desc );
|
||||
$desc = strip_shortcodes( $desc );
|
||||
$desc = str_replace( ']]>', ']]>', $desc );
|
||||
$desc = strip_tags( $desc );
|
||||
$desc = preg_replace( '/\n+/', ' ', $desc);
|
||||
$desc = substr( $desc, 0, 300 );
|
||||
// Get featured image
|
||||
$image = $avatar->get_post_thumbnail_url( $event );
|
||||
if ( ! $image ) {
|
||||
$image = $content->get_content_img_url( $event );
|
||||
}
|
||||
|
||||
$og = array(
|
||||
'url' => home_url( esc_url( add_query_arg( null, null ) ) ),
|
||||
'title' => htmlspecialchars(
|
||||
$event->get( 'post' )->post_title .
|
||||
' (' . substr( $event->get( 'start' ) , 0, 10 ) . ')'
|
||||
),
|
||||
'type' => 'article',
|
||||
'description' => htmlspecialchars( $desc ),
|
||||
'image' => $image,
|
||||
);
|
||||
foreach ( $og as $key => $val ) {
|
||||
echo "<meta property=\"og:$key\" content=\"$val\" />\n";
|
||||
}
|
||||
// Twitter meta tags
|
||||
$twitter = array(
|
||||
'card' => 'summary',
|
||||
'title' => htmlspecialchars(
|
||||
$event->get( 'post' )->post_title .
|
||||
' (' . substr( $event->get( 'start' ) , 0, 10 ) . ')'
|
||||
),
|
||||
'description' => htmlspecialchars( $desc ),
|
||||
'image' => $image,
|
||||
);
|
||||
foreach ( $twitter as $key => $val ) {
|
||||
if ( empty( $val ) && 'image' !== $key ) {
|
||||
$val = Ai1ec_I18n::__( 'No data' );
|
||||
}
|
||||
echo "<meta name=\"twitter:$key\" content=\"$val\" />\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Ai1ec_Event $event
|
||||
*
|
||||
* @return The html of the footer
|
||||
*/
|
||||
public function get_footer( Ai1ec_Event $event ) {
|
||||
|
||||
$text_calendar_feed = null;
|
||||
|
||||
$feed_url = trim( strtolower( $event->get( 'ical_feed_url' ) ) );
|
||||
|
||||
if ( strpos( $feed_url, 'http' ) === 0 ) {
|
||||
$text_calendar_feed = Ai1ec_I18n::__(
|
||||
'This post was replicated from another site\'s <a href="%s" title="iCalendar feed"><i class="ai1ec-fa ai1ec-fa-calendar"></i> calendar feed</a>.'
|
||||
);
|
||||
} else {
|
||||
$text_calendar_feed = Ai1ec_I18n::__(
|
||||
'This post was imported from a CSV/ICS file.'
|
||||
);
|
||||
}
|
||||
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
$text_calendar_feed = sprintf(
|
||||
$text_calendar_feed,
|
||||
esc_attr( str_replace( 'http://', 'webcal://', $event->get( 'ical_feed_url' ) ) )
|
||||
);
|
||||
$args = array(
|
||||
'event' => $event,
|
||||
'text_calendar_feed' => $text_calendar_feed,
|
||||
'text_view_post' => Ai1ec_I18n::__( 'View original' ),
|
||||
);
|
||||
return $loader->get_file( 'event-single-footer.twig', $args, false )
|
||||
->get_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the full article for the event – title, content, and footer.
|
||||
*
|
||||
* @param Ai1ec_Event $event
|
||||
* @param string $footer Footer HTML to append to event
|
||||
*/
|
||||
public function get_full_article( Ai1ec_Event $event, $footer = '' ) {
|
||||
$title = apply_filters(
|
||||
'the_title',
|
||||
$event->get( 'post' )->post_title,
|
||||
$event->get( 'post_id' )
|
||||
);
|
||||
$event_details = $this->get_content( $event );
|
||||
$content = wpautop(
|
||||
apply_filters(
|
||||
'ai1ec_the_content',
|
||||
apply_filters(
|
||||
'the_content',
|
||||
$event->get( 'post' )->post_content
|
||||
)
|
||||
)
|
||||
);
|
||||
$args = compact( 'title', 'event_details', 'content', 'footer' );
|
||||
$loader = $this->_registry->get( 'theme.loader' );
|
||||
return $loader->get_file( 'event-single-full.twig', $args, false )
|
||||
->get_content();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,398 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class renders the html for the event taxonomy.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Event
|
||||
*/
|
||||
class Ai1ec_View_Event_Taxonomy extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* @var Ai1ec_Taxonomy Taxonomy abstraction layer.
|
||||
*/
|
||||
protected $_taxonomy_model = null;
|
||||
|
||||
/**
|
||||
* @var array Caches the color evaluated for each event.
|
||||
*/
|
||||
protected $_event_color_map = array();
|
||||
|
||||
/**
|
||||
* @var array Caches the color squares HTML evaluated for each event.
|
||||
*/
|
||||
protected $_event_color_squares_map = array();
|
||||
|
||||
/**
|
||||
* Returns style attribute for events rendered in Month, Week, or Day view.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event object.
|
||||
*
|
||||
* @return string Color style attribute.
|
||||
*/
|
||||
public function get_color_style( Ai1ec_Event $event ) {
|
||||
$color = $this->get_color_for_event( $event );
|
||||
|
||||
// Convert to style attribute.
|
||||
if ( $color ) {
|
||||
$color = $event->is_allday() || $event->is_multiday()
|
||||
? 'background-color: ' . $color . ';'
|
||||
: 'color: ' . $color . ' !important;';
|
||||
} else {
|
||||
$color = '';
|
||||
}
|
||||
|
||||
return $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HTML of category color swatches for this event.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event object.
|
||||
*
|
||||
* @return string HTML of the event's category color swatches.
|
||||
*/
|
||||
public function get_category_colors( Ai1ec_Event $event ) {
|
||||
$post_id = $event->get( 'post_id' );
|
||||
|
||||
if ( ! isset( $this->_event_color_squares_map[$post_id] ) ) {
|
||||
$squares = '';
|
||||
$categories = $this->_taxonomy_model->get_post_categories( $post_id );
|
||||
|
||||
if ( false !== $categories ) {
|
||||
$squares = $this->get_event_category_colors( $categories );
|
||||
}
|
||||
|
||||
// Allow add-ons to modify/add to category color swatch HTML.
|
||||
$squares = apply_filters(
|
||||
'ai1ec_event_color_squares',
|
||||
$squares,
|
||||
$event
|
||||
);
|
||||
|
||||
$this->_event_color_squares_map[$post_id] = $squares;
|
||||
}
|
||||
|
||||
return $this->_event_color_squares_map[$post_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTML markup for the category color square.
|
||||
*
|
||||
* @param int $term_id The term ID of event category
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_category_color_square( $term_id ) {
|
||||
$color = $this->_taxonomy_model->get_category_color( $term_id );
|
||||
$event_taxonomy = $this->_registry->get( 'model.event.taxonomy' );
|
||||
if ( null !== $color ) {
|
||||
$taxonomy = $event_taxonomy->get_taxonomy_for_term_id( $term_id );
|
||||
$cat = get_term( $term_id, $taxonomy->taxonomy );
|
||||
return '<span class="ai1ec-color-swatch ai1ec-tooltip-trigger" ' .
|
||||
'style="background:' . $color . '" title="' .
|
||||
esc_attr( $cat->name ) . '"></span>';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the HTML markup for the category image square.
|
||||
*
|
||||
* @param int $term_id The term ID of event category.
|
||||
*
|
||||
* @return string HTML snippet to use for category image.
|
||||
*/
|
||||
public function get_category_image_square( $term_id ) {
|
||||
$image = $this->_taxonomy_model->get_category_image( $term_id );
|
||||
if ( null !== $image ) {
|
||||
return '<img src="' . $image . '" alt="' .
|
||||
Ai1ec_I18n::__( 'Category image' ) .
|
||||
'" class="ai1ec_category_small_image_preview" />';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns category color squares for the list of Event Category objects.
|
||||
*
|
||||
* @param array $cats The Event Category objects as returned by get_terms()
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_event_category_colors( array $cats ) {
|
||||
$sqrs = '';
|
||||
foreach ( $cats as $cat ) {
|
||||
$tmp = $this->get_category_color_square( $cat->term_id );
|
||||
if ( ! empty( $tmp ) ) {
|
||||
$sqrs .= $tmp;
|
||||
}
|
||||
}
|
||||
return $sqrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Style attribute for event background color.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event object.
|
||||
*
|
||||
* @return string Color to assign to event background.
|
||||
*/
|
||||
public function get_category_bg_color( Ai1ec_Event $event ) {
|
||||
$color = $this->get_color_for_event( $event );
|
||||
|
||||
// Convert to HTML attribute.
|
||||
if ( $color ) {
|
||||
$color = 'style="background-color: ' . $color . ';"';
|
||||
} else {
|
||||
$color = '';
|
||||
}
|
||||
|
||||
return $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Style attribute for event multi-date divider color.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event object.
|
||||
*
|
||||
* @return string Color to assign to event background.
|
||||
*/
|
||||
public function get_category_divider_color( Ai1ec_Event $event ) {
|
||||
$color = $this->get_color_for_event( $event );
|
||||
|
||||
// Convert to HTML attribute.
|
||||
if ( $color ) {
|
||||
$color = 'style="border-color: ' . $color . ' transparent transparent transparent;"';
|
||||
} else {
|
||||
$color = '';
|
||||
}
|
||||
|
||||
return $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Style attribute for event text color.
|
||||
*
|
||||
* @param Ai1ec_Event $event Event object.
|
||||
*
|
||||
* @return string Color to assign to event text (foreground).
|
||||
*/
|
||||
public function get_category_text_color( Ai1ec_Event $event ) {
|
||||
$color = $this->get_color_for_event( $event );
|
||||
|
||||
// Convert to HTML attribute.
|
||||
if ( $color ) {
|
||||
$color = 'style="color: ' . $color . ';"';
|
||||
} else {
|
||||
$color = '';
|
||||
}
|
||||
|
||||
return $color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches color for event having the given post ID.
|
||||
*
|
||||
* @param int $post_id Event's post ID.
|
||||
*
|
||||
* @return string Color associated with event.
|
||||
*/
|
||||
public function get_color_for_event( $event ) {
|
||||
$post_id = $event->get( 'post_id' );
|
||||
|
||||
// If color for this event is uncached, populate cache.
|
||||
if ( ! isset( $this->_event_color_map[$post_id] ) ) {
|
||||
// Find out if an add-on has provided its own color for the event.
|
||||
$color = apply_filters( 'ai1ec_event_color', '', $event );
|
||||
|
||||
// If none provided, fall back to event categories.
|
||||
if ( empty( $color ) ) {
|
||||
$categories = $this->_taxonomy_model->get_post_categories( $post_id );
|
||||
// Find the first category of this post that defines a color.
|
||||
foreach ( $categories as $category ) {
|
||||
$color = $this->_taxonomy_model->get_category_color(
|
||||
$category->term_id
|
||||
);
|
||||
if ( $color ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->_event_color_map[$post_id] = $color;
|
||||
}
|
||||
|
||||
return $this->_event_color_map[$post_id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Categories as HTML, either as blocks or inline.
|
||||
*
|
||||
* @param Ai1ec_Event $event Rendered Event.
|
||||
* @param string $format Return 'blocks' or 'inline' formatted result.
|
||||
*
|
||||
* @return string String of HTML for category blocks.
|
||||
*/
|
||||
public function get_categories_html(
|
||||
Ai1ec_Event $event,
|
||||
$format = 'blocks'
|
||||
) {
|
||||
$categories = $this->_taxonomy_model->get_post_categories(
|
||||
$event->get( 'post_id' )
|
||||
);
|
||||
foreach ( $categories as &$category ) {
|
||||
$href = $this->_registry->get(
|
||||
'html.element.href',
|
||||
array( 'cat_ids' => $category->term_id )
|
||||
);
|
||||
|
||||
$class = $data_type = $title = '';
|
||||
if ( $category->description ) {
|
||||
$title = 'title="' .
|
||||
esc_attr( $category->description ) . '" ';
|
||||
}
|
||||
|
||||
$html = '';
|
||||
$class .= ' ai1ec-category';
|
||||
$color_style = '';
|
||||
if ( $format === 'inline' ) {
|
||||
$taxonomy = $this->_registry->get( 'model.taxonomy' );
|
||||
$color_style = $taxonomy->get_category_color(
|
||||
$category->term_id
|
||||
);
|
||||
if ( $color_style !== '' ) {
|
||||
$color_style = 'style="color: ' . $color_style . ';" ';
|
||||
}
|
||||
$class .= '-inline';
|
||||
}
|
||||
|
||||
$html .= '<a ' . $data_type . ' class="' . $class .
|
||||
' ai1ec-term-id-' . $category->term_id . ' p-category" ' .
|
||||
$title . $color_style . 'href="' . $href->generate_href() . '">';
|
||||
|
||||
if ( $format === 'blocks' ) {
|
||||
$html .= $this->get_category_color_square(
|
||||
$category->term_id
|
||||
) . ' ';
|
||||
} else {
|
||||
$html .=
|
||||
'<i ' . $color_style .
|
||||
'class="ai1ec-fa ai1ec-fa-folder-open"></i>';
|
||||
}
|
||||
|
||||
$html .= esc_html( $category->name ) . '</a>';
|
||||
$category = $html;
|
||||
}
|
||||
return implode( ' ', $categories );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags as HTML
|
||||
*/
|
||||
public function get_tags_html( Ai1ec_Event $event ) {
|
||||
$tags = $this->_taxonomy_model->get_post_tags(
|
||||
$event->get( 'post_id' )
|
||||
);
|
||||
if ( ! $tags ) {
|
||||
$tags = array();
|
||||
}
|
||||
foreach ( $tags as &$tag ) {
|
||||
$href = $this->_registry->get(
|
||||
'html.element.href',
|
||||
array( 'tag_ids' => $tag->term_id )
|
||||
);
|
||||
$class = '';
|
||||
$data_type = '';
|
||||
$title = '';
|
||||
if ( $tag->description ) {
|
||||
$title = 'title="' . esc_attr( $tag->description ) . '" ';
|
||||
}
|
||||
$tag = '<a ' . $data_type . ' class="ai1ec-tag ' . $class .
|
||||
' ai1ec-term-id-' . $tag->term_id . '" ' . $title .
|
||||
'href="' . $href->generate_href() . '">' .
|
||||
'<i class="ai1ec-fa ai1ec-fa-tag"></i>' .
|
||||
esc_html( $tag->name ) . '</a>';
|
||||
}
|
||||
return implode( ' ', $tags );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter Groups as HTML, either as blocks or inline.
|
||||
*
|
||||
* @param Ai1ec_Event $event Rendered Event.
|
||||
* @param array $filter_group Filter Group (Option Model)
|
||||
* @param string $format Return 'blocks' or 'inline' formatted result.
|
||||
*
|
||||
* @return string String of HTML for filter group blocks.
|
||||
*/
|
||||
public function get_filter_group_html(
|
||||
Ai1ec_Event $event,
|
||||
$filter_group,
|
||||
$format = 'blocks'
|
||||
) {
|
||||
|
||||
$filter_groups = $this->_taxonomy_model->get_post_taxonomy(
|
||||
$event->get( 'post_id' ), $filter_group['taxonomy_name']
|
||||
);
|
||||
|
||||
$icon_name = '';
|
||||
if ( 'ai1eccfgi-null' !== $filter_group['icon'] ) {
|
||||
$icon_name = $filter_group['icon'];
|
||||
} else {
|
||||
$icon_name = 'ai1ec-icon-timely';
|
||||
}
|
||||
|
||||
foreach ( $filter_groups as &$group ) {
|
||||
$href = $this->_registry->get(
|
||||
'html.element.href',
|
||||
array( $filter_group['taxonomy_name'] . '_ids' => $group->term_id )
|
||||
);
|
||||
|
||||
$class = $data_type = $title = '';
|
||||
if ( $group->description ) {
|
||||
$title = 'title="' .
|
||||
esc_attr( $group->description ) . '" ';
|
||||
}
|
||||
|
||||
$html = '';
|
||||
$class .= ' ai1ec-category';
|
||||
$color_style = '';
|
||||
if ( 'inline' === $format ) {
|
||||
$taxonomy = $this->_registry->get( 'model.taxonomy' );
|
||||
$color_style = $taxonomy->get_category_color(
|
||||
$group->term_id
|
||||
);
|
||||
if ( $color_style !== '' ) {
|
||||
$color_style = 'style="color: ' . $color_style . ';" ';
|
||||
}
|
||||
$class .= '-inline';
|
||||
}
|
||||
|
||||
$html .= '<a ' . $data_type . ' class="' . $class .
|
||||
' ai1ec-term-id-' . $group->term_id . ' p-category" ' .
|
||||
$title . $color_style . 'href="' . $href->generate_href() . '">';
|
||||
|
||||
if ( 'blocks' === $format ) {
|
||||
$html .= $this->get_category_color_square($group->term_id) . ' ';
|
||||
} else {
|
||||
$html = $html
|
||||
. '<i ' . $color_style . ' class="ai1ec-fa '
|
||||
. $icon_name . '"></i>';
|
||||
}
|
||||
|
||||
$html .= esc_html( $group->name ) . '</a>';
|
||||
$group = $html;
|
||||
}
|
||||
|
||||
return implode( ' ', $filter_groups );
|
||||
}
|
||||
|
||||
public function __construct( Ai1ec_Registry_Object $registry ) {
|
||||
parent::__construct( $registry );
|
||||
$this->_taxonomy_model = $this->_registry->get( 'model.taxonomy' );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class renders the html for the event ticket.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Event
|
||||
*/
|
||||
class Ai1ec_View_Event_Ticket {
|
||||
|
||||
/**
|
||||
* Create readable content for buy tickets/register link
|
||||
*
|
||||
* @param bool $long Set to false to use short message version
|
||||
*
|
||||
* @return string Message to be rendered on buy tickets link
|
||||
*/
|
||||
public function get_tickets_url_label( Ai1ec_Event $event, $long = true ) {
|
||||
if ( $event->is_free() ) {
|
||||
return ( $long )
|
||||
? __( 'Register Now', AI1EC_PLUGIN_NAME )
|
||||
: __( 'Register', AI1EC_PLUGIN_NAME );
|
||||
}
|
||||
$output = '';
|
||||
if ( $long ) {
|
||||
$output = apply_filters(
|
||||
'ai1ec_buy_tickets_url_icon',
|
||||
'<i class="ai1ec-fa ai1ec-fa-shopping-cart"></i>'
|
||||
);
|
||||
if ( ! empty( $output ) ) {
|
||||
$output .= ' ';
|
||||
}
|
||||
}
|
||||
$output .= ( $long )
|
||||
? __( 'Buy Tickets', AI1EC_PLUGIN_NAME )
|
||||
: __( 'Tickets', AI1EC_PLUGIN_NAME );
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contact info as HTML
|
||||
*/
|
||||
public function get_contact_html( Ai1ec_Event $event ) {
|
||||
$contact = '<div class="h-card">';
|
||||
$has_contents = false;
|
||||
if ( $event->get( 'contact_name' ) ) {
|
||||
$contact .=
|
||||
'<div class="ai1ec-contact-name p-name">' .
|
||||
'<i class="ai1ec-fa ai1ec-fa-fw ai1ec-fa-user"></i> ' .
|
||||
esc_html( $event->get( 'contact_name' ) ) .
|
||||
'</div> ';
|
||||
$has_contents = true;
|
||||
}
|
||||
if ( $event->get( 'contact_phone' ) ) {
|
||||
$contact .=
|
||||
'<div class="ai1ec-contact-phone p-tel">' .
|
||||
'<i class="ai1ec-fa ai1ec-fa-fw ai1ec-fa-phone"></i> ' .
|
||||
esc_html( $event->get( 'contact_phone' ) ) .
|
||||
'</div> ';
|
||||
$has_contents = true;
|
||||
}
|
||||
if ( $event->get( 'contact_email' ) ) {
|
||||
$contact .=
|
||||
'<div class="ai1ec-contact-email">' .
|
||||
'<a class="u-email" href="mailto:' .
|
||||
esc_attr( $event->get( 'contact_email' ) ) . '">' .
|
||||
'<i class="ai1ec-fa ai1ec-fa-fw ai1ec-fa-envelope-o"></i> ' .
|
||||
__( 'Email', AI1EC_PLUGIN_NAME ) . '</a></div> ';
|
||||
$has_contents = true;
|
||||
}
|
||||
if ( $event->get( 'contact_url' ) ) {
|
||||
$contact .=
|
||||
'<div class="ai1ec-contact-url">' .
|
||||
'<a class="u-url" target="_blank" href="' .
|
||||
esc_attr( $event->get( 'contact_url' ) ) .
|
||||
'"><i class="ai1ec-fa ai1ec-fa-fw ai1ec-fa-link"></i> ' .
|
||||
apply_filters(
|
||||
'ai1ec_contact_url',
|
||||
__( 'Event website', AI1EC_PLUGIN_NAME )
|
||||
) .
|
||||
' <i class="ai1ec-fa ai1ec-fa-external-link"></i></a></div>';
|
||||
$has_contents = true;
|
||||
}
|
||||
$contact .= '</div>';
|
||||
return $has_contents ? $contact : '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This class renders the html for the event time.
|
||||
*
|
||||
* @author Time.ly Network Inc.
|
||||
* @since 2.0
|
||||
*
|
||||
* @package AI1EC
|
||||
* @subpackage AI1EC.View.Event
|
||||
*/
|
||||
class Ai1ec_View_Event_Time extends Ai1ec_Base {
|
||||
|
||||
/**
|
||||
* Returns timespan expression for the event.
|
||||
*
|
||||
* Properly handles:
|
||||
* - instantaneous events
|
||||
* - all-day events
|
||||
* - multi-day events
|
||||
* Display of start date can be hidden (non-all-day events only) or full
|
||||
* date. All-day status, if any, is enclosed in a span.ai1ec-allday-badge
|
||||
* element.
|
||||
*
|
||||
* @param Ai1ec_Event $event Rendered event.
|
||||
* @param string $start_date_display Can be one of 'hidden', 'short',
|
||||
* or 'long'.
|
||||
*
|
||||
* @return string Formatted timespan HTML element.
|
||||
*/
|
||||
public function get_timespan_html(
|
||||
Ai1ec_Event $event,
|
||||
$start_date_display = 'long'
|
||||
) {
|
||||
// Makes no sense to hide start date for all-day events, so fix argument
|
||||
if ( 'hidden' === $start_date_display && $event->is_allday() ) {
|
||||
$start_date_display = 'short';
|
||||
}
|
||||
|
||||
// Localize time.
|
||||
$start = $this->_registry->get( 'date.time', $event->get( 'start' ) );
|
||||
$end = $this->_registry->get( 'date.time', $event->get( 'end' ) );
|
||||
|
||||
// All-day events need to have their end time shifted by 1 second less
|
||||
// to land on the correct day.
|
||||
$end_offset = 0;
|
||||
if ( $event->is_allday() ) {
|
||||
$end->set_time(
|
||||
$end->format( 'H' ),
|
||||
$end->format( 'i' ),
|
||||
$end->format( 's' ) - 1
|
||||
);
|
||||
}
|
||||
|
||||
// Get timestamps of start & end dates without time component.
|
||||
$start_ts = $this->_registry->get( 'date.time', $start )
|
||||
->set_time( 0, 0, 0 )
|
||||
->format();
|
||||
$end_ts = $this->_registry->get( 'date.time', $end )
|
||||
->set_time( 0, 0, 0 )
|
||||
->format();
|
||||
|
||||
$break_years = $start->format( 'Y' ) !== $end->format( 'Y' );
|
||||
$output = '';
|
||||
|
||||
// Display start date, depending on $start_date_display.
|
||||
switch ( $start_date_display ) {
|
||||
case 'hidden':
|
||||
break;
|
||||
case 'short':
|
||||
case 'long':
|
||||
$property = $start_date_display . '_date';
|
||||
$output .= $this->{'get_' . $property}( $start, $break_years );
|
||||
break;
|
||||
default:
|
||||
$start_date_display = 'long';
|
||||
}
|
||||
|
||||
// Output start time for non-all-day events.
|
||||
if ( ! $event->is_allday() ) {
|
||||
if ( 'hidden' !== $start_date_display ) {
|
||||
$output .= apply_filters(
|
||||
'ai1ec_get_timespan_html_time_separator',
|
||||
Ai1ec_I18n::_x( ' @ ', 'Event time separator' )
|
||||
);
|
||||
}
|
||||
$output .= $this->get_short_time( $start );
|
||||
}
|
||||
|
||||
// Find out if we need to output the end time/date. Do not output it for
|
||||
// instantaneous events and all-day events lasting only one day.
|
||||
if (
|
||||
! (
|
||||
$event->is_instant() ||
|
||||
( $event->is_allday() && $start_ts === $end_ts )
|
||||
)
|
||||
) {
|
||||
$output .= apply_filters(
|
||||
'ai1ec_get_timespan_html_date_separator',
|
||||
Ai1ec_I18n::_x( ' – ', 'Event start/end separator' )
|
||||
);
|
||||
|
||||
// If event ends on a different day, output end date.
|
||||
if ( $start_ts !== $end_ts ) {
|
||||
// for short date, use short display type
|
||||
if ( 'short' === $start_date_display ) {
|
||||
$output .= $this->get_short_date( $end, $break_years );
|
||||
} else {
|
||||
$output .= $this->get_long_date( $end );
|
||||
}
|
||||
}
|
||||
|
||||
// Output end time for non-all-day events.
|
||||
if ( ! $event->is_allday() ) {
|
||||
if ( $start_ts !== $end_ts ) {
|
||||
$output .= apply_filters(
|
||||
'ai1ec_get_timespan_html_time_separator',
|
||||
Ai1ec_I18n::_x( ' @ ', 'Event time separator' )
|
||||
);
|
||||
}
|
||||
$output .= $this->get_short_time( $end );
|
||||
}
|
||||
}
|
||||
|
||||
$output = esc_html( $output );
|
||||
|
||||
// Add all-day label.
|
||||
if ( $event->is_allday() ) {
|
||||
$output .= apply_filters(
|
||||
'ai1ec_get_timespan_html_allday_badge',
|
||||
' <span class="ai1ec-allday-badge">' .
|
||||
Ai1ec_I18n::__( 'all-day' ) .
|
||||
'</span>'
|
||||
);
|
||||
}
|
||||
return apply_filters(
|
||||
'ai1ec_get_timespan_html',
|
||||
$output,
|
||||
$event,
|
||||
$start_date_display
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the html for the exclude dates and exception rules.
|
||||
*
|
||||
* @param Ai1ec_Event $event
|
||||
* @param Ai1ec_Recurrence_Rule $rrule
|
||||
* @return string
|
||||
*/
|
||||
public function get_exclude_html(
|
||||
Ai1ec_Event $event,
|
||||
Ai1ec_Recurrence_Rule $rrule
|
||||
) {
|
||||
$excludes = array();
|
||||
$exception_rules = $event->get( 'exception_rules' );
|
||||
$exception_dates = $event->get( 'exception_dates' );
|
||||
if ( $exception_rules ) {
|
||||
$excludes[] =
|
||||
$rrule->rrule_to_text( $exception_rules );
|
||||
}
|
||||
if ( $exception_dates && 0 !== strpos( $exception_rules, 'EXDATE' ) ) {
|
||||
$excludes[] =
|
||||
$rrule->exdate_to_text( $exception_dates );
|
||||
}
|
||||
return implode( Ai1ec_I18n::__( ', and ' ), $excludes );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the short date
|
||||
*
|
||||
* @param Ai1ec_Date_Time $time
|
||||
* @param bool $add_year Whether to add year or not.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_short_date( Ai1ec_Date_Time $time, $add_year = false ) {
|
||||
$months = apply_filters( 'ai1ec_i18n_months', array() );
|
||||
$m = $time->format_i18n( 'M' );
|
||||
$m = array_key_exists( $m, $months ) ? $months[$m] : $m;
|
||||
if ( $add_year ) {
|
||||
return $m . ' ' . $time->format_i18n( 'j Y' );
|
||||
}
|
||||
return $m . ' ' . $time->format_i18n( 'j' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a long-length date for use in other views (e.g., single event).
|
||||
*
|
||||
* @param Ai1ec_Date_Time $time Object to format.
|
||||
*
|
||||
* @return string Formatted date time [default: `l, M j, Y`].
|
||||
*/
|
||||
public function get_long_date( Ai1ec_Date_Time $time ) {
|
||||
$date_format = $this->_registry->get( 'model.option' )->get(
|
||||
'date_format',
|
||||
'l, M j, Y'
|
||||
);
|
||||
return $time->format_i18n( $date_format );
|
||||
}
|
||||
|
||||
/**
|
||||
* Format a short-form time for use in compressed (e.g. month) views.
|
||||
*
|
||||
* @param Ai1ec_Date_Time $time Object to format.
|
||||
*
|
||||
* @return string Formatted date time [default: `g:i a`].
|
||||
*/
|
||||
public function get_short_time( Ai1ec_Date_Time $time ) {
|
||||
$time_format = $this->_registry->get( 'model.option' )->get(
|
||||
'time_format',
|
||||
'g:i a'
|
||||
);
|
||||
return $time->format_i18n( $time_format );
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user