attributes = $attributes; $this->settings = $settings; $this->active_year = ''; } /** * Renders the timeline Single Story. * * @param int $index Index value of current post. * @param object $post Current Post object. * * @since 0.0.1 */ public function ctl_render( $index, $post ) { $output = ''; $post_id = absint( is_object( $post ) && isset( $post->ID ) ? $post->ID : get_the_ID() ); if ( $post_id <= 0 ) { return ''; } $classes = array( 'ctl-story' ); $attributes = $this->attributes; $layout = $attributes['layout']; $animation = 'horizontal' === $layout ? 'none' : $attributes['config']['animation']; $icons_disabled = isset( $attributes['icons'] ) && 'no' === strtolower( $attributes['icons'] ); if ( $icons_disabled ) { $classes[] = 'ctl-story-dot-icon'; } else { $classes[] = 'ctl-story-icon'; }; if ( 'horizontal' === $layout ) { $classes[] = 'swiper-slide'; $classes[] = 0 === $index % 2 ? 'even' : 'odd'; } else { // dynamic alternate class. $condition = 0 === $index % 2; $classes[] = $condition ? 'even' : 'odd'; if ( isset( $this->settings['first_story_position'] ) && 'left' === $this->settings['first_story_position'] ) { $condition = 0 !== $index % 2; } if ( $condition ) { $classes[] = 'one-side' !== $this->attributes['layout'] ? 'ctl-story-left' : 'ctl-story-right'; } else { $classes[] = 'ctl-story-right'; } } // Get Year label. if ( $this->settings['year_label'] && ( 'one-side' === $layout || 'default' === $layout ) ) { $output .= $this->ctl_get_year_label( $post_id ); } $output .= '
'; if ( 'compact' !== $layout ) { $output .= $this->ctl_get_date( $post_id, $attributes['date-format'] ); } if ( $icons_disabled ) { $output .= '
'; } else { $output .= '' . $this->ctl_get_icon( $post_id ); } if ( 'compact' === $layout || 'horizontal' === $layout || 'clean' !== $attributes['skin'] ) { $output .= '
'; } $output .= '
'; $output .= $this->ctl_get_title( $post_id ); // Grabing story content based upon content type. if ( 'horizontal' !== $layout ) { $output .= $this->ctl_get_featured_image( $post_id ); } if ( 'compact' === $layout ) { $output .= $this->ctl_get_date( $post_id, $attributes['date-format'] ); } if ( 'horizontal' !== $layout ) { $output .= $this->ctl_get_content(); } $output .= '
'; if ( 'horizontal' === $layout ) { $output .= $this->ctl_minimal_content(); } $output .= '
'; return $output; } /** * Get Story Title * * @param int $post_id Current Post ID. */ public function ctl_get_title( $post_id ) { $output = ''; if ( ! empty( get_the_title() ) ) { $layout = $this->attributes['layout']; $title_class = 'story-' . $post_id; $re_more = ( ( isset( $this->settings['display_readmore'] ) && 'yes' === $this->settings['display_readmore'] ) || 'horizontal' === $layout ); $output .= '
'; $output .= $re_more ? $this->get_story_link( $post_id ) : ''; $output .= esc_html( get_the_title( $post_id ) ); $output .= $re_more ? '' : ''; if ( ( isset( $this->settings['display_readmore'] ) && 'yes' === $this->settings['display_readmore'] ) && 'horizontal' === $layout ) { $output .= $re_more ? $this->get_story_link( $post_id ) : ''; $output .= '

' . __( 'Read More', 'cool-timeline' ) . '

'; $output .= $re_more ? '' : ''; } $output .= '
'; } return $output; } /** * Get Timeline Story links * * @param int $post_id Current Post ID. */ public function get_story_link( $post_id ) { $attributes = $this->attributes; $story_link = ''; $url = ''; // Get custom link settings. if ( 'horizontal' === $attributes['layout'] ) { $story_link = ''; } else { $target = ! empty( $this->settings['story_link_target'] ) ? $this->settings['story_link_target'] : '_self'; $url = get_the_permalink( $post_id ); $story_link = ''; } return $story_link; } /** * Get Story Date * * @param int $post_id Current Post ID. * @param string $date_formats Timeline date format. * @return string Formatted date HTML output. */ public function ctl_get_date( $post_id, $date_formats ) { $ctl_story_type = get_post_meta( $post_id, 'story_type', true ); $ctl_story_date = ''; if ( is_array( $ctl_story_type ) && isset( $ctl_story_type['ctl_story_date'] ) ) { $ctl_story_date = $ctl_story_type['ctl_story_date']; } $layout = $this->attributes['layout']; $re_more = ( ( isset( $this->settings['display_readmore'] ) && 'yes' === $this->settings['display_readmore'] ) && 'horizontal' === $layout ); $output = ''; $posted_date = ''; if ( $ctl_story_date ) { if ( strtotime( $ctl_story_date ) !== false ) { $posted_date = date_i18n( $date_formats, strtotime( $ctl_story_date ) ); } else { $ctl_story_date = trim( str_ireplace( array( 'am', 'pm' ), '', $ctl_story_date ) ); $dateobj = DateTime::createFromFormat( 'm/d/Y H:i', $ctl_story_date, wp_timezone() ); if ( $dateobj ) { $posted_date = $dateobj->format( $date_formats ); } } if ( ! empty( $posted_date ) ) { $output .= '
'; $output .= '
'; $output .= $re_more ? $this->get_story_link( $post_id ) : ''; $output .= esc_html( $posted_date ); // Escape date output $output .= $re_more ? '' : ''; $output .= '
'; $output .= '
'; } } return $output; } /** * Get stories content */ public function ctl_get_content() { $attributes = $this->attributes; $output = ''; $content = ''; if ( 'full' === $attributes['story-content'] ) { global $post; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound $content .= apply_filters( 'the_content', $post->post_content ); } else { $content .= CTL_Helpers::ctl_get_excerpt( $this->settings ); } if ( ! empty( $content ) ) { // Remove non-http/https iframe src URLs. $content = preg_replace_callback( '#]+src=["\']([^"\']+)["\']#i', function( $matches ) { $src = esc_url_raw( $matches[1], array( 'http', 'https' ) ); if ( empty( $src ) ) { return ''; } return str_replace( $matches[1], esc_url( $src ), $matches[0] ); }, $content ); $allowed_tags = wp_kses_allowed_html( 'post' ); $allowed_tags['iframe'] = array( 'src' => true, 'width' => true, 'height' => true, 'frameborder' => true, 'allow' => true, 'allowfullscreen' => true, 'loading' => true, 'referrerpolicy' => true, ); $output .= ''; $output .= '
' . wp_kses( $content, $allowed_tags ) . '
'; } return $output; } /** * Get Story Featured Image * * @param int $post_id Current Post ID. */ public function ctl_get_featured_image( $post_id ) { $attributes = $this->attributes; global $post; $post_id = ! empty( $post_id ) ? absint( $post_id ) : ( isset( $post->ID ) ? absint( $post->ID ) : 0 ); if ( ! $post_id ) { return; } if ( ! get_the_post_thumbnail_url( $post_id ) ) { return; } // Get story media and image container size. $ctl_story_media = get_post_meta( $post_id, 'story_media', true ); $img_cont_size = isset( $ctl_story_media['img_cont_size'] ) ? $ctl_story_media['img_cont_size'] : ''; $img_html = ''; // Get alternative text for the image. $img_alt = get_post_meta( get_post_thumbnail_id( $post_id ), '_wp_attachment_image_alt', true ); $alt_text = $img_alt ? $img_alt : get_the_title( $post_id ); // Generate image link based on stories images link setting. $story_img_link = ''; $img_f_url = wp_get_attachment_url( get_post_thumbnail_id( $post_id ) ); $story_img_link = ''; $image_size = ''; $image_wrapper_cls = ''; if ( 'small' === $img_cont_size ) { $image_size = 'medium'; $image_wrapper_cls = 'small'; } else { $image_size = 'large'; $image_wrapper_cls = 'full'; } if ( 'horizontal' === $attributes['layout'] ) { $img_html .= '
'; } else { // Generate image HTML based on image container size. if ( get_the_post_thumbnail_url( $post_id ) ) { $img_html .= '
'; $img_html .= $story_img_link; $img_html .= get_the_post_thumbnail( $post_id, apply_filters( 'cool_timeline_story_img_size', $image_size ), array( 'class' => 'story-img', 'alt' => esc_html( $alt_text ), ) ); $img_html .= ''; $img_html .= '
'; } } return $img_html; } /** * Get Story Icon * * @param int $post_id Current Post ID. * @param string $default_icon default icon. */ public function ctl_get_icon( $post_id ) { $output = ''; $icon = ''; $extra_class = ''; if ( get_post_type( $post_id ) === 'cool_timeline' ) { // Story Icon. $story_icon = get_post_meta( $post_id, 'story_icon', true ); $ctl_fontawesome_icon = isset( $story_icon['fa_field_icon'] ) ? $story_icon['fa_field_icon'] : ''; $extra_class = ''; if ( '' !== $ctl_fontawesome_icon ) { if ( strpos( $ctl_fontawesome_icon, 'fab' ) === false ) { $extra_class = 'fa'; } $icon = ''; } else { $icon = ''; } } $output .= '
' . $icon . '
'; return $output; } /** * Get Story Year and create highlighted Year section in timeline * * @param int $post_id Current Post ID. * @return string Output HTML. */ public function ctl_get_year_label( $post_id ) { $attributes = $this->attributes; $output = ''; $wrp_cls = 'vertical'; $design = 'light'; // Get story date. $ctl_story_type = get_post_meta( $post_id, 'story_type', true ); $ctl_story_date = ( is_array( $ctl_story_type ) && isset( $ctl_story_type['ctl_story_date'] ) ) ? sanitize_text_field( $ctl_story_type['ctl_story_date'] ) : ''; $pattern = "/\b\d{4}\b/"; // Regular expression pattern to match a four-digit number. preg_match( $pattern, $ctl_story_date, $matches ); // Get Year value. if ( isset( $matches[0] ) ) { $story_year = $matches[0]; // Display the year label if it is different from the previous year. if ( $story_year !== $this->active_year ) { $story_year_label = sprintf( '
%s
', esc_html( $story_year ) ); $this->active_year = $story_year; if ( 'compact' === $attributes['layout'] ) { $output .= ''; } else { $output .= sprintf( '
%s
', esc_attr( $design ), esc_attr( $wrp_cls ), esc_attr( $design ), esc_attr( $story_year ), esc_attr( $story_year ), // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound apply_filters( 'ctl_story_year', $story_year_label ) ); } } } return $output; } /** * Minimal Popup Content */ public function ctl_minimal_content() { $post_id = get_the_ID(); $output = ''; $attributes = $this->attributes; $output .= '
'; $output .= $this->ctl_get_date( $post_id, $attributes['date-format'] ); $output .= '

'; $output .= esc_html( get_the_title() ); $output .= '

'; $output .= $this->ctl_get_featured_image( $post_id ); $output .= '
'; $output .= $this->ctl_get_content(); $output .= '
'; return $output; } } }