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 = '
';
if ( $wrap_permalink ) {
$permalink = add_query_arg(
'instance_id',
$event->get( 'instance_id' ),
get_permalink( $event->get( 'post_id' ) )
);
$html = '' . $html . '';
}
$classes .= ' ai1ec-' . $source;
$classes .= ( $size[0] > $size[1] )
? ' ai1ec-landscape'
: ' ai1ec-portrait';
$html = '
' .
$html . '
';
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
);
}
/**
* Simple regex-parse of post_content for matches of
; 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(
'/
]+)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',
)
);
}
return $fallbacks;
}
}