File: /home/mobilech/alliancelaptoptraining.com.np/wp-content/plugins/tutor/components/DateFilter.php
<?php
/**
* Date Filter Component.
*
* @package Tutor\Components
* @author Themeum
* @link https://themeum.com
* @since 4.0.0
*/
namespace Tutor\Components;
use TUTOR\Icon;
use TUTOR\Input;
use Tutor\Components\Constants\Size;
use Tutor\Components\Popover;
defined( 'ABSPATH' ) || exit;
/**
* DateFilter Component Class.
*
* Example usage:
*
* ```php
* DateFilter::make()
* ->type( DateFilter::TYPE_RANGE )
* ->placement( DateFilter::PLACEMENT_BOTTOM_START )
* ->render();
* ```
*
* ```php
* DateFilter::make()
* ->type( DateFilter::TYPE_SINGLE )
* ->placement( DateFilter::PLACEMENT_BOTTOM_END )
* ->render();
* ```
*
* @since 4.0.0
*/
class DateFilter extends BaseComponent {
/**
* Date Filter Type Single
*/
const TYPE_SINGLE = 'single';
/**
* Date Filter Type Range
*/
const TYPE_RANGE = 'range';
/**
* Placement Bottom Start
*/
const PLACEMENT_BOTTOM_START = 'bottom-start';
/**
* Placement Bottom End
*/
const PLACEMENT_BOTTOM_END = 'bottom-end';
/**
* Component Type
*
* @var string
*/
protected $type = self::TYPE_SINGLE;
/**
* Button Label
*
* @var string
*/
protected $label = '';
/**
* Popover placement
*
* @var string
*/
protected $placement = self::PLACEMENT_BOTTOM_START;
/**
* Button size.
*
* @var string
*/
protected $size = Size::SMALL;
/**
* Icon size.
*
* @var integer
*/
protected $icon_size = Size::SIZE_16;
/**
* Whether to display the label text.
*
* @since 4.0.0
*
* @var bool
*/
protected $show_label = true;
/**
* Whether to hide the initial label when no date range is selected.
*
* @since 4.0.0
*
* @var bool
*/
protected $hide_initial_label = false;
/**
* Query params to clear when a date filter is applied or cleared (e.g. 'current_page').
*
* @since 4.0.0
*
* @var array
*/
protected $clear_params = array();
/**
* Set filter type.
*
* @param string $type Filter type (single|range).
*
* @return self
*/
public function type( string $type ): self {
$this->type = $type;
return $this;
}
/**
* Set Button Size.
*
* @since 4.0.0
*
* @param string $size the size type (x-small|small|medium|large).
*
* @return self
*/
public function trigger_size( string $size ): self {
$allowed_sizes = array( Size::X_SMALL, Size::SMALL, Size::MEDIUM, Size::LARGE );
if ( in_array( $size, $allowed_sizes, true ) ) {
$this->size = $size;
}
return $this;
}
/**
* Set the button icon size.
*
* @since 4.0.0
*
* @param integer $size the icon size.
*
* @return self
*/
public function icon_size( int $size ): self {
$this->icon_size = $size;
return $this;
}
/**
* Set button label.
*
* @param string $label Button label.
*
* @return self
*/
public function label( string $label ): self {
$this->label = $label;
return $this;
}
/**
* Set popover placement.
*
* @param string $placement Popover placement.
*
* @return self
*/
public function placement( string $placement ): self {
$this->placement = $placement;
return $this;
}
/**
* Enable or disable the display of the label text.
*
* @since 4.0.0
*
* @param bool $show_label True to show the label, false to hide it.
*
* @return $this
*/
public function show_label( bool $show_label ) {
$this->show_label = $show_label;
return $this;
}
/**
* Hide or show the initial label text before a date range is selected.
*
* @since 4.0.0
*
* @return self
*/
public function hide_initial_label(): self {
$this->hide_initial_label = true;
return $this;
}
/**
* Set query params to clear when a date filter is applied or cleared.
*
* Useful for resetting pagination (e.g. 'current_page') or other
* context-specific params whenever the date selection changes.
*
* @since 4.0.0
*
* @param array $params List of query param keys to remove on apply/clear.
*
* @return self
*/
public function clear_params( array $params ): self {
$this->clear_params = $params;
return $this;
}
/**
* Render the component.
*
* @return string
*/
public function get(): string {
$is_range = self::TYPE_RANGE === $this->type;
if ( empty( $this->label ) ) {
$this->label = $this->calculate_label();
}
// Default settings based on type.
$calendar_options = array(
'type' => 'default',
'clearParams' => $this->clear_params,
);
$button_classes = 'tutor-btn tutor-btn-outline';
if ( $this->size ) {
$button_classes .= ' tutor-btn-' . $this->size;
}
$popover_classes = 'tutor-popover';
$icon = Icon::CALENDAR_2;
if ( $is_range ) {
$calendar_options = array(
'type' => 'multiple',
'selectionDatesMode' => 'multiple-ranged',
'clearParams' => $this->clear_params,
);
$popover_classes .= ' tutor-range-calendar-popover';
}
if ( empty( $this->label ) ) {
$button_classes .= ' tutor-btn-icon';
} else {
$button_classes .= ' tutor-gap-2';
}
$options_json = wp_json_encode( $calendar_options );
$origin = Popover::TRANSFORM_ORIGIN_MAP[ $this->placement ] ?? 'center.top';
ob_start();
?>
<div x-data="tutorPopover({ placement: '<?php echo esc_attr( $this->placement ); ?>' })" <?php echo $this->get_attributes_string(); //phpcs:ignore -- Sanitization is performed inside get_attributes_string. ?>>
<button
type="button"
x-ref="trigger"
@click="toggle()"
class="<?php echo esc_attr( $button_classes ); ?>"
<?php if ( empty( $this->label ) ) : ?>
aria-label="<?php echo $is_range ? esc_attr__( 'Filter by date range', 'tutor' ) : esc_attr__( 'Filter by date', 'tutor' ); ?>"
<?php endif; ?>
>
<?php SvgIcon::make()->name( $icon )->size( $this->icon_size )->render(); ?>
<?php if ( ! empty( $this->label ) ) : ?>
<span><?php echo esc_html( $this->label ); ?></span>
<?php endif; ?>
<?php if ( $this->has_selection() ) : ?>
<span @click.stop="$dispatch('tutor-calendar:clear')" class="tutor-cursor-pointer tutor-icon-secondary tutor-flex tutor-align-center">
<?php SvgIcon::make()->name( Icon::CROSS_2 )->render(); ?>
</span>
<?php endif; ?>
</button>
<div
x-ref="content"
x-show="open"
x-cloak
x-transition.origin.<?php echo esc_attr( $origin ); ?>
@click.outside="handleClickOutside()"
class="<?php echo esc_attr( $popover_classes ); ?>"
>
<div x-data="tutorCalendar({ options: <?php echo esc_attr( $options_json ); ?>, hidePopover: () => hide() })"></div>
</div>
</div>
<?php
return ob_get_clean();
}
/**
* Check if filter has active selection.
*
* @return bool
*/
protected function has_selection(): bool {
if ( self::TYPE_SINGLE === $this->type ) {
return ! empty( Input::get( 'date' ) );
}
return ! empty( Input::get( 'start_date' ) ) && ! empty( Input::get( 'end_date' ) );
}
/**
* Calculate dynamic label based on URL parameters.
*
* @return string
*/
protected function calculate_label(): string {
if ( self::TYPE_SINGLE === $this->type ) {
return Input::get( 'date', '' );
}
if ( ! $this->show_label ) {
return '';
}
$start_date = Input::get( 'start_date' );
$end_date = Input::get( ( 'end_date' ) );
if ( ! $start_date || ! $end_date ) {
return $this->hide_initial_label ? '' : __( 'All Time', 'tutor' );
}
$presets = array(
'today' => __( 'Today', 'tutor' ),
'yesterday' => __( 'Yesterday', 'tutor' ),
'last-7' => __( 'Last 7 Days', 'tutor' ),
'last-14' => __( 'Last 14 Days', 'tutor' ),
'last-30' => __( 'Last 30 Days', 'tutor' ),
'this-month' => __( 'This Month', 'tutor' ),
'last-month' => __( 'Last Month', 'tutor' ),
'last-year' => __( 'Last Year', 'tutor' ),
);
$current_time = time();
foreach ( $presets as $key => $label ) {
$range = $this->get_preset_dates( $key, $current_time );
if ( $range && $range[0] === $start_date && $range[1] === $end_date ) {
return $label;
}
}
$start_format = date_i18n( 'M j', strtotime( $start_date ) );
$end_format = date_i18n( 'M j', strtotime( $end_date ) );
return sprintf( '%s - %s', $start_format, $end_format );
}
/**
* Get preset dates.
*
* @param string $preset Preset key.
* @param int $current_time Current timestamp.
*
* @return array|null
*/
protected function get_preset_dates( $preset, $current_time ) {
$today = gmdate( 'Y-m-d', $current_time );
switch ( $preset ) {
case 'today':
return array( $today, $today );
case 'yesterday':
$d = gmdate( 'Y-m-d', strtotime( '-1 day', $current_time ) );
return array( $d, $d );
case 'last-7':
$start = gmdate( 'Y-m-d', strtotime( '-6 days', $current_time ) );
return array( $start, $today );
case 'last-14':
$start = gmdate( 'Y-m-d', strtotime( '-13 days', $current_time ) );
return array( $start, $today );
case 'last-30':
$start = gmdate( 'Y-m-d', strtotime( '-29 days', $current_time ) );
return array( $start, $today );
case 'this-month':
$start = gmdate( 'Y-m-01', $current_time );
$end = gmdate( 'Y-m-t', $current_time );
return array( $start, $end );
case 'last-month':
$first_day_last_month = strtotime( 'first day of previous month', $current_time );
$start = gmdate( 'Y-m-d', $first_day_last_month );
$end = gmdate( 'Y-m-t', $first_day_last_month );
return array( $start, $end );
case 'last-year':
$start = gmdate( 'Y-01-01', strtotime( '-1 year', $current_time ) );
$end = gmdate( 'Y-12-31', strtotime( '-1 year', $current_time ) );
return array( $start, $end );
}
return null;
}
}