Constants
22 hours ago
Accordion.php
22 hours ago
Alert.php
22 hours ago
AttachmentCard.php
22 hours ago
Avatar.php
22 hours ago
Badge.php
22 hours ago
BaseComponent.php
22 hours ago
Button.php
22 hours ago
ConfirmationModal.php
22 hours ago
CourseFilter.php
22 hours ago
DateFilter.php
22 hours ago
DropdownFilter.php
22 hours ago
EmptyState.php
22 hours ago
FileUploader.php
22 hours ago
InputField.php
22 hours ago
Modal.php
22 hours ago
Nav.php
22 hours ago
Pagination.php
22 hours ago
Popover.php
22 hours ago
PreviewTrigger.php
22 hours ago
Progress.php
22 hours ago
SearchFilter.php
22 hours ago
Sorting.php
22 hours ago
StarRating.php
22 hours ago
StarRatingInput.php
22 hours ago
StatusSelect.php
22 hours ago
SvgIcon.php
22 hours ago
Table.php
22 hours ago
Tabs.php
22 hours ago
Tooltip.php
22 hours ago
WPEditor.php
22 hours ago
Sorting.php
257 lines
| 1 | <?php |
| 2 | /** |
| 3 | * Sorting Component Class. |
| 4 | * |
| 5 | * Responsible for rendering a sorting dropdown |
| 6 | * with ascending and descending options. |
| 7 | * |
| 8 | * @package Tutor\Components |
| 9 | * @author Themeum |
| 10 | * @link https://themeum.com |
| 11 | * @since 4.0.0 |
| 12 | */ |
| 13 | |
| 14 | namespace Tutor\Components; |
| 15 | |
| 16 | use Tutor\Helpers\QueryHelper; |
| 17 | use Tutor\Components\Constants\Positions; |
| 18 | use Tutor\Components\Constants\Color; |
| 19 | use Tutor\Components\Constants\Size; |
| 20 | use Tutor\Components\Popover; |
| 21 | use TUTOR\Icon; |
| 22 | |
| 23 | defined( 'ABSPATH' ) || exit; |
| 24 | |
| 25 | /** |
| 26 | * Class Sorting |
| 27 | * |
| 28 | * Example Usage: |
| 29 | * ``` |
| 30 | * Sorting::make() |
| 31 | * ->order( 'DESC' ) |
| 32 | * ->label_asc( 'Oldest' ) |
| 33 | * ->label_desc( 'Newest' ) |
| 34 | * ->on_change( 'changeOrder' ) |
| 35 | * ->bind_active_order( 'currentOrder' ) |
| 36 | * ->render(); |
| 37 | * ``` |
| 38 | * |
| 39 | * @since 4.0.0 |
| 40 | */ |
| 41 | class Sorting extends BaseComponent { |
| 42 | |
| 43 | /** |
| 44 | * Order param |
| 45 | * |
| 46 | * @var string |
| 47 | */ |
| 48 | protected $order = 'DESC'; |
| 49 | |
| 50 | /** |
| 51 | * Label for ascending order |
| 52 | * |
| 53 | * @var string |
| 54 | */ |
| 55 | protected $label_asc; |
| 56 | |
| 57 | /** |
| 58 | * Label for descending order |
| 59 | * |
| 60 | * @var string |
| 61 | */ |
| 62 | protected $label_desc; |
| 63 | |
| 64 | /** |
| 65 | * On change callback function name |
| 66 | * |
| 67 | * @var string |
| 68 | */ |
| 69 | protected $on_change = ''; |
| 70 | |
| 71 | /** |
| 72 | * Alpine.js variable name for active state |
| 73 | * |
| 74 | * @var string |
| 75 | */ |
| 76 | protected $active_order = ''; |
| 77 | |
| 78 | /** |
| 79 | * Base URL for building sort links (preserves other query params when set). |
| 80 | * |
| 81 | * @var string |
| 82 | */ |
| 83 | protected $base_url = ''; |
| 84 | |
| 85 | /** |
| 86 | * Component size |
| 87 | * |
| 88 | * @var string |
| 89 | */ |
| 90 | protected $size = Size::X_SMALL; |
| 91 | |
| 92 | /** |
| 93 | * Constructor |
| 94 | */ |
| 95 | public function __construct() { |
| 96 | $this->label_asc = __( 'Oldest First', 'tutor' ); |
| 97 | $this->label_desc = __( 'Newest First', 'tutor' ); |
| 98 | } |
| 99 | |
| 100 | /** |
| 101 | * Set order |
| 102 | * |
| 103 | * @param string $order order. |
| 104 | * |
| 105 | * @return self |
| 106 | */ |
| 107 | public function order( string $order ): self { |
| 108 | $this->order = QueryHelper::get_valid_sort_order( $order ); |
| 109 | return $this; |
| 110 | } |
| 111 | |
| 112 | /** |
| 113 | * Set label for ascending order |
| 114 | * |
| 115 | * @param string $label label. |
| 116 | * |
| 117 | * @return self |
| 118 | */ |
| 119 | public function label_asc( string $label ): self { |
| 120 | $this->label_asc = $label; |
| 121 | return $this; |
| 122 | } |
| 123 | |
| 124 | /** |
| 125 | * Set label for descending order |
| 126 | * |
| 127 | * @param string $label label. |
| 128 | * |
| 129 | * @return self |
| 130 | */ |
| 131 | public function label_desc( string $label ): self { |
| 132 | $this->label_desc = $label; |
| 133 | return $this; |
| 134 | } |
| 135 | |
| 136 | /** |
| 137 | * Set JS callback on change |
| 138 | * |
| 139 | * @param string $method_name JS method name. |
| 140 | * |
| 141 | * @return self |
| 142 | */ |
| 143 | public function on_change( string $method_name ): self { |
| 144 | $this->on_change = $method_name; |
| 145 | return $this; |
| 146 | } |
| 147 | |
| 148 | /** |
| 149 | * Set Alpine.js active state binding |
| 150 | * |
| 151 | * @param string $active_order Alpine variable name. |
| 152 | * @return self |
| 153 | */ |
| 154 | public function bind_active_order( string $active_order ): self { |
| 155 | $this->active_order = $active_order; |
| 156 | return $this; |
| 157 | } |
| 158 | |
| 159 | /** |
| 160 | * Set base URL for sort links so other query params are preserved (cumulative filtering). |
| 161 | * |
| 162 | * @param string $url Full current page URL including query string. |
| 163 | * |
| 164 | * @return self |
| 165 | */ |
| 166 | public function base_url( string $url ): self { |
| 167 | $this->base_url = $url; |
| 168 | return $this; |
| 169 | } |
| 170 | |
| 171 | /** |
| 172 | * Set component size |
| 173 | * |
| 174 | * @param string $size size. |
| 175 | * |
| 176 | * @return self |
| 177 | */ |
| 178 | public function size( string $size ): self { |
| 179 | $this->size = $size; |
| 180 | return $this; |
| 181 | } |
| 182 | |
| 183 | /** |
| 184 | * Get component content |
| 185 | * |
| 186 | * @return string |
| 187 | */ |
| 188 | public function get(): string { |
| 189 | $orders = array( |
| 190 | 'DESC' => $this->label_desc, |
| 191 | 'ASC' => $this->label_asc, |
| 192 | ); |
| 193 | |
| 194 | $origin = Popover::TRANSFORM_ORIGIN_MAP[ Positions::BOTTOM_END ] ?? 'right.top'; |
| 195 | |
| 196 | ob_start(); |
| 197 | ?> |
| 198 | <div |
| 199 | x-data="tutorPopover({ |
| 200 | placement: 'bottom-end', |
| 201 | offset: 4, |
| 202 | })" |
| 203 | > |
| 204 | <button |
| 205 | type="button" |
| 206 | x-ref="trigger" |
| 207 | @click="toggle()" |
| 208 | class="tutor-btn tutor-btn-outline tutor-btn-<?php echo esc_attr( $this->size ); ?> tutor-btn-icon" |
| 209 | aria-label="<?php esc_attr_e( 'Open sorting options', 'tutor' ); ?>" |
| 210 | > |
| 211 | <?php |
| 212 | $sorting_icon = 'DESC' === $this->order ? Icon::ASCENDING : Icon::DESCENDING; |
| 213 | SvgIcon::make()->name( $sorting_icon )->size( 16 )->color( Color::SECONDARY )->render(); |
| 214 | ?> |
| 215 | </button> |
| 216 | |
| 217 | <div |
| 218 | x-ref="content" |
| 219 | x-show="open" |
| 220 | x-cloak |
| 221 | x-transition.<?php echo esc_attr( $origin ); ?> |
| 222 | @click.outside="handleClickOutside()" |
| 223 | class="tutor-popover" |
| 224 | > |
| 225 | <div class="tutor-popover-menu" style="min-width: 108px;"> |
| 226 | <?php foreach ( $orders as $order => $label ) : ?> |
| 227 | <?php |
| 228 | $order_url = ! empty( $this->base_url ) ? add_query_arg( 'order', $order, $this->base_url ) : add_query_arg( 'order', $order ); |
| 229 | ?> |
| 230 | <?php if ( $this->on_change ) : ?> |
| 231 | <button |
| 232 | type="button" |
| 233 | @click="<?php echo esc_js( $this->on_change ); ?>('<?php echo esc_attr( $order ); ?>'); hide()" |
| 234 | class="tutor-popover-menu-item <?php echo esc_attr( ! $this->active_order && $this->order === $order ? ' tutor-active' : '' ); ?>" |
| 235 | <?php if ( $this->active_order ) : ?> |
| 236 | :class="{ 'tutor-active': (<?php echo esc_attr( $this->active_order ); ?> || '') === '<?php echo esc_attr( $order ); ?>' }" |
| 237 | <?php endif; ?> |
| 238 | > |
| 239 | <?php echo esc_html( $label ); ?> |
| 240 | </button> |
| 241 | <?php else : ?> |
| 242 | <a |
| 243 | href="<?php echo esc_attr( $order_url ); ?>" |
| 244 | class="tutor-popover-menu-item <?php echo esc_attr( $this->order === $order ? ' tutor-active' : '' ); ?>" |
| 245 | > |
| 246 | <?php echo esc_html( $label ); ?> |
| 247 | </a> |
| 248 | <?php endif; ?> |
| 249 | <?php endforeach; ?> |
| 250 | </div> |
| 251 | </div> |
| 252 | </div> |
| 253 | <?php |
| 254 | return ob_get_clean(); |
| 255 | } |
| 256 | } |
| 257 |