Constants
23 hours ago
Accordion.php
23 hours ago
Alert.php
23 hours ago
AttachmentCard.php
23 hours ago
Avatar.php
23 hours ago
Badge.php
23 hours ago
BaseComponent.php
23 hours ago
Button.php
23 hours ago
ConfirmationModal.php
23 hours ago
CourseFilter.php
23 hours ago
DateFilter.php
23 hours ago
DropdownFilter.php
23 hours ago
EmptyState.php
23 hours ago
FileUploader.php
23 hours ago
InputField.php
23 hours ago
Modal.php
23 hours ago
Nav.php
23 hours ago
Pagination.php
23 hours ago
Popover.php
23 hours ago
PreviewTrigger.php
23 hours ago
Progress.php
23 hours ago
SearchFilter.php
23 hours ago
Sorting.php
23 hours ago
StarRating.php
23 hours ago
StarRatingInput.php
23 hours ago
StatusSelect.php
23 hours ago
SvgIcon.php
23 hours ago
Table.php
23 hours ago
Tabs.php
23 hours ago
Tooltip.php
23 hours ago
WPEditor.php
23 hours ago
Button.php
408 lines
| 1 | <?php |
| 2 | /** |
| 3 | * Tutor Component: Button |
| 4 | * |
| 5 | * Provides a fluent builder for rendering buttons with |
| 6 | * different sizes, variants, and styles. |
| 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\Components\Constants\Size; |
| 17 | use Tutor\Components\Constants\Variant; |
| 18 | use Tutor\Components\Constants\Color; |
| 19 | |
| 20 | defined( 'ABSPATH' ) || exit; |
| 21 | |
| 22 | /** |
| 23 | * Button Component Class. |
| 24 | * |
| 25 | * Example usage: |
| 26 | * ``` |
| 27 | * Button::make() |
| 28 | * ->label( 'Enroll Now' ) |
| 29 | * ->size( Size::LARGE ) |
| 30 | * ->variant( Variant::PRIMARY ) |
| 31 | * ->icon( 'tutor-icon-play' ) |
| 32 | * ->attr( 'data-id', 101 ) |
| 33 | * ->render(); |
| 34 | * ``` |
| 35 | * |
| 36 | * @since 4.0.0 |
| 37 | */ |
| 38 | class Button extends BaseComponent { |
| 39 | |
| 40 | /** |
| 41 | * Button label text. |
| 42 | * |
| 43 | * @since 4.0.0 |
| 44 | * |
| 45 | * @var string |
| 46 | */ |
| 47 | protected $label = ''; |
| 48 | |
| 49 | /** |
| 50 | * Button size (small|medium|large). |
| 51 | * |
| 52 | * @since 4.0.0 |
| 53 | * |
| 54 | * @see Size constants |
| 55 | * |
| 56 | * @var string |
| 57 | */ |
| 58 | protected $size = Size::MEDIUM; |
| 59 | |
| 60 | /** |
| 61 | * Button variant style (primary|secondary, etc). |
| 62 | * |
| 63 | * @since 4.0.0 |
| 64 | * |
| 65 | * @see Size constants |
| 66 | * |
| 67 | * @var string |
| 68 | */ |
| 69 | protected $variant = Variant::PRIMARY; |
| 70 | |
| 71 | /** |
| 72 | * Button HTML tag (button|a). |
| 73 | * |
| 74 | * @since 4.0.0 |
| 75 | * |
| 76 | * @var string |
| 77 | */ |
| 78 | protected $tag = 'button'; |
| 79 | |
| 80 | /** |
| 81 | * Button attributes. |
| 82 | * |
| 83 | * @since 4.0.0 |
| 84 | * |
| 85 | * @var array |
| 86 | */ |
| 87 | protected $attributes = array(); |
| 88 | |
| 89 | /** |
| 90 | * The SVG icon name or markup. |
| 91 | * |
| 92 | * @since 4.0.0 |
| 93 | * |
| 94 | * @var string |
| 95 | */ |
| 96 | protected $icon = ''; |
| 97 | |
| 98 | /** |
| 99 | * Icon width. |
| 100 | * |
| 101 | * @var int |
| 102 | */ |
| 103 | protected $icon_size = 16; |
| 104 | |
| 105 | /** |
| 106 | * Icon color. |
| 107 | * |
| 108 | * @var string |
| 109 | */ |
| 110 | protected $icon_color = ''; |
| 111 | |
| 112 | /** |
| 113 | * Button icon position |
| 114 | * |
| 115 | * @since 4.0.0 |
| 116 | * |
| 117 | * @var string |
| 118 | */ |
| 119 | private const POSITION_LEFT = 'left'; |
| 120 | private const POSITION_RIGHT = 'right'; |
| 121 | |
| 122 | /** |
| 123 | * The icon position relative to label. Accepts 'left' or 'right'. |
| 124 | * |
| 125 | * @since 4.0.0 |
| 126 | * |
| 127 | * @var string |
| 128 | */ |
| 129 | protected $icon_position = 'left'; |
| 130 | |
| 131 | /** |
| 132 | * Icon attributes. |
| 133 | * |
| 134 | * @var array |
| 135 | */ |
| 136 | protected $icon_attributes = array(); |
| 137 | |
| 138 | /** |
| 139 | * Whether to flip the button icon in RTL. |
| 140 | * |
| 141 | * @since 4.0.0 |
| 142 | * |
| 143 | * @var bool |
| 144 | */ |
| 145 | protected $flip_rtl = false; |
| 146 | |
| 147 | /** |
| 148 | * Whether button is disabled. |
| 149 | * |
| 150 | * @since 4.0.0 |
| 151 | * |
| 152 | * @var bool |
| 153 | */ |
| 154 | protected $disabled = false; |
| 155 | |
| 156 | /** |
| 157 | * Whether button is an icon-only button. |
| 158 | * |
| 159 | * @since 4.0.0 |
| 160 | * |
| 161 | * @var bool |
| 162 | */ |
| 163 | protected $icon_only = false; |
| 164 | |
| 165 | /** |
| 166 | * Whether button is a block button. |
| 167 | * |
| 168 | * @since 4.0.0 |
| 169 | * |
| 170 | * @var bool |
| 171 | */ |
| 172 | protected $block = false; |
| 173 | |
| 174 | /** |
| 175 | * Set button label text. |
| 176 | * |
| 177 | * @since 4.0.0 |
| 178 | * |
| 179 | * @param string $label Button label text. |
| 180 | * |
| 181 | * @return $this |
| 182 | */ |
| 183 | public function label( $label ) { |
| 184 | $this->label = esc_html( $label ); |
| 185 | return $this; |
| 186 | } |
| 187 | |
| 188 | /** |
| 189 | * Set button size. |
| 190 | * |
| 191 | * @since 4.0.0 |
| 192 | * |
| 193 | * @param string $size Button size (small|medium|large). |
| 194 | * |
| 195 | * @return $this |
| 196 | */ |
| 197 | public function size( $size ) { |
| 198 | $allowed = $this->get_allowed_sizes(); |
| 199 | if ( in_array( $size, $allowed, true ) ) { |
| 200 | $this->size = $size; |
| 201 | } |
| 202 | return $this; |
| 203 | } |
| 204 | |
| 205 | /** |
| 206 | * Set button block state. |
| 207 | * |
| 208 | * @since 4.0.0 |
| 209 | * |
| 210 | * @param bool $block Whether the button is a block button. |
| 211 | * |
| 212 | * @return $this |
| 213 | */ |
| 214 | public function block( bool $block = true ): self { |
| 215 | $this->block = $block; |
| 216 | return $this; |
| 217 | } |
| 218 | |
| 219 | /** |
| 220 | * Set button variant style. |
| 221 | * |
| 222 | * @since 4.0.0 |
| 223 | * |
| 224 | * @param string $variant Button variant (primary|secondary|success|danger|link). |
| 225 | * |
| 226 | * @return $this |
| 227 | */ |
| 228 | public function variant( $variant ) { |
| 229 | $this->variant = sanitize_html_class( $variant ); |
| 230 | return $this; |
| 231 | } |
| 232 | |
| 233 | /** |
| 234 | * Set the SVG icon for the button. |
| 235 | * |
| 236 | * @since 4.0.0 |
| 237 | * |
| 238 | * @param string $icon SVG icon name or markup. |
| 239 | * @param string $position Optional. Icon position: 'left' or 'right'. |
| 240 | * @param int $size Optional. Icon size (width and height). |
| 241 | * @param string $color Optional. Icon color (use \Tutor\Components\Constants\Color). |
| 242 | * @param array $attributes Optional. Icon attributes. |
| 243 | * |
| 244 | * @return $this |
| 245 | */ |
| 246 | public function icon( string $icon, string $position = 'left', int $size = 16, string $color = '', array $attributes = array() ): self { |
| 247 | $this->icon = $icon; |
| 248 | $this->icon_position = in_array( $position, array( self::POSITION_LEFT, self::POSITION_RIGHT ), true ) ? $position : 'left'; |
| 249 | $this->icon_size = $size; |
| 250 | $this->icon_color = $color; |
| 251 | $this->icon_attributes = $attributes; |
| 252 | return $this; |
| 253 | } |
| 254 | |
| 255 | /** |
| 256 | * Set the HTML tag for rendering. |
| 257 | * |
| 258 | * @since 4.0.0 |
| 259 | * |
| 260 | * @param bool $icon_only Whether the button is icon-only. |
| 261 | * |
| 262 | * @return $this |
| 263 | */ |
| 264 | public function icon_only( bool $icon_only = true ): self { |
| 265 | $this->icon_only = $icon_only; |
| 266 | return $this; |
| 267 | } |
| 268 | |
| 269 | /** |
| 270 | * Flip the button icon in RTL. |
| 271 | * |
| 272 | * Use this only for directional icons such as arrows, |
| 273 | * chevrons and pagination controls. |
| 274 | * |
| 275 | * @since 4.0.0 |
| 276 | * |
| 277 | * @return $this |
| 278 | */ |
| 279 | public function flip_rtl(): self { |
| 280 | $this->flip_rtl = true; |
| 281 | return $this; |
| 282 | } |
| 283 | |
| 284 | /** |
| 285 | * Set the HTML tag for rendering. |
| 286 | * |
| 287 | * @since 4.0.0 |
| 288 | * |
| 289 | * @param string $tag HTML tag (button|a). |
| 290 | * |
| 291 | * @return $this |
| 292 | */ |
| 293 | public function tag( $tag ) { |
| 294 | if ( in_array( $tag, array( 'a', 'button' ), true ) ) { |
| 295 | $this->tag = $tag; |
| 296 | } |
| 297 | return $this; |
| 298 | } |
| 299 | |
| 300 | /** |
| 301 | * Set button disabled state. |
| 302 | * |
| 303 | * @since 4.0.0 |
| 304 | * |
| 305 | * @param bool $disabled Whether the button is disabled. |
| 306 | * |
| 307 | * @return $this |
| 308 | */ |
| 309 | public function disabled( $disabled = true ) { |
| 310 | $this->disabled = (bool) $disabled; |
| 311 | return $this; |
| 312 | } |
| 313 | |
| 314 | /** |
| 315 | * Allowed sizes |
| 316 | * |
| 317 | * @since 4.0.0 |
| 318 | * |
| 319 | * @return array |
| 320 | */ |
| 321 | public function get_allowed_sizes() { |
| 322 | return array( |
| 323 | Size::SMALL, |
| 324 | Size::MEDIUM, |
| 325 | Size::LARGE, |
| 326 | Size::X_SMALL, |
| 327 | ); |
| 328 | } |
| 329 | |
| 330 | /** |
| 331 | * Get the final button HTML. |
| 332 | * |
| 333 | * @since 4.0.0 |
| 334 | * |
| 335 | * @return string HTML output. |
| 336 | */ |
| 337 | public function get(): string { |
| 338 | $classes = sprintf( |
| 339 | 'tutor-btn tutor-btn-%1$s tutor-btn-%2$s', |
| 340 | esc_attr( $this->variant ), |
| 341 | esc_attr( $this->size ) |
| 342 | ); |
| 343 | |
| 344 | if ( $this->disabled ) { |
| 345 | $this->attributes['disabled'] = 'disabled'; |
| 346 | $classes .= ' disabled'; |
| 347 | } |
| 348 | |
| 349 | if ( $this->block ) { |
| 350 | $classes .= ' tutor-btn-block'; |
| 351 | } |
| 352 | |
| 353 | if ( $this->icon_only ) { |
| 354 | $classes .= ' tutor-btn-icon'; |
| 355 | if ( ! empty( $this->label ) && empty( $this->attributes['aria-label'] ) ) { |
| 356 | $this->attributes['aria-label'] = $this->label; |
| 357 | } |
| 358 | } |
| 359 | |
| 360 | $this->attributes['class'] = trim( "{$classes} " . ( $this->attributes['class'] ?? '' ) ); |
| 361 | |
| 362 | $attributes = $this->get_attributes_string(); |
| 363 | |
| 364 | // Prepare icon HTML if exists. |
| 365 | $icon_html = ''; |
| 366 | if ( ! empty( $this->icon ) ) { |
| 367 | if ( false !== strpos( $this->icon, '<svg' ) ) { |
| 368 | $icon_html = $this->icon; |
| 369 | } else { |
| 370 | ob_start(); |
| 371 | SvgIcon::make() |
| 372 | ->name( $this->icon ) |
| 373 | ->size( $this->icon_size ) |
| 374 | ->color( $this->icon_color ) |
| 375 | ->flip_rtl( $this->flip_rtl ) |
| 376 | ->attrs( $this->icon_attributes ) |
| 377 | ->render(); |
| 378 | $icon_html = ob_get_clean(); |
| 379 | } |
| 380 | } |
| 381 | |
| 382 | if ( ! empty( $icon_html ) && empty( $this->label ) ) { |
| 383 | $this->attributes['class'] .= ' tutor-btn-icon'; |
| 384 | // Re-render attributes to include updated class. |
| 385 | $attributes = $this->get_attributes_string(); |
| 386 | } |
| 387 | |
| 388 | // Build button inner HTML depending on icon position. |
| 389 | if ( $this->icon_only ) { |
| 390 | $content = $icon_html; |
| 391 | } else { |
| 392 | $content = self::POSITION_RIGHT === ( $this->icon_position ? $this->icon_position : self::POSITION_LEFT ) |
| 393 | ? sprintf( '%1$s%2$s', esc_html( $this->label ), $icon_html ) |
| 394 | : sprintf( '%1$s%2$s', $icon_html, esc_html( $this->label ) ); |
| 395 | } |
| 396 | |
| 397 | $this->component_string = sprintf( |
| 398 | '<%1$s %2$s>%3$s</%1$s>', |
| 399 | esc_attr( $this->tag ), |
| 400 | $attributes, |
| 401 | $content |
| 402 | ); |
| 403 | |
| 404 | return $this->component_string; |
| 405 | } |
| 406 | |
| 407 | } |
| 408 |