Changeset 3435416
- Timestamp:
- 01/08/2026 06:26:54 PM (3 months ago)
- Location:
- fetch-meditation/trunk
- Files:
-
- 2 added
- 5 edited
-
build.txt (modified) (1 diff)
-
css/fetch-meditation-tabs.css (added)
-
fetch-meditation.php (modified) (12 diffs)
-
js/fetch-meditation-tabs.js (added)
-
js/fetch-meditation.js (modified) (3 diffs)
-
readme.txt (modified) (4 diffs)
-
vendor/composer/installed.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
fetch-meditation/trunk/build.txt
r3424942 r3435416 1 d49718607a4b90698c0a29723550b536c53c5d74 1 e4a2b7c70c860395cdd726cb07cea82e0dbc603c -
fetch-meditation/trunk/fetch-meditation.php
r3424942 r3435416 7 7 * Contributors: pjaudiomv, bmltenabled 8 8 * Author: bmltenabled 9 * Version: 1.4. 49 * Version: 1.4.5 10 10 * Requires PHP: 8.1 11 11 * Requires at least: 6.2 … … 42 42 private const DEFAULT_LAYOUT = 'block'; 43 43 private const DEFAULT_THEME = 'default'; 44 private const DEFAULT_TABS_LAYOUT = 'tabs'; 44 45 45 46 private const PLUG_SLUG = 'fetch-meditation'; … … 261 262 262 263 public static function render_shortcode( string|array $attrs = [] ): string { 264 $book = self::determine_option( $attrs, 'book' ); 265 266 // Handle 'both' option - render tabbed interface 267 if ( 'both' === $book ) { 268 return static::render_both_shortcode( $attrs ); 269 } 270 263 271 $language = self::determine_option( $attrs, 'language' ); 264 $book = self::determine_option( $attrs, 'book' );265 272 $layout = self::determine_option( $attrs, 'layout' ); 266 273 $timezone = self::determine_option( $attrs, 'timezone' ); … … 342 349 } 343 350 351 /** 352 * Render both JFT and SPAD meditations in a tabbed interface 353 * 354 * @param string|array $attrs Shortcode attributes 355 * @return string Rendered tabbed content 356 */ 357 private static function render_both_shortcode( string|array $attrs = [] ): string { 358 static $instance_counter = 0; 359 $instance_counter++; 360 361 $layout = self::determine_option( $attrs, 'layout' ); 362 $tabs_layout = self::determine_option( $attrs, 'tabs_layout' ); 363 364 // Determine languages for each book 365 $jft_language = isset( $attrs['jft_language'] ) ? sanitize_text_field( strtolower( $attrs['jft_language'] ) ) : self::determine_option( $attrs, 'language' ); 366 $spad_language = isset( $attrs['spad_language'] ) ? sanitize_text_field( strtolower( $attrs['spad_language'] ) ) : self::determine_option( $attrs, 'language' ); 367 368 // Determine timezones for each book 369 $jft_timezone = isset( $attrs['jft_timezone'] ) ? sanitize_text_field( $attrs['jft_timezone'] ) : self::determine_option( $attrs, 'timezone' ); 370 $spad_timezone = isset( $attrs['spad_timezone'] ) ? sanitize_text_field( $attrs['spad_timezone'] ) : self::determine_option( $attrs, 'timezone' ); 371 372 // Determine themes for each book 373 $jft_theme = isset( $attrs['jft_theme'] ) ? sanitize_text_field( strtolower( $attrs['jft_theme'] ) ) : 'jft-style'; 374 $spad_theme = isset( $attrs['spad_theme'] ) ? sanitize_text_field( strtolower( $attrs['spad_theme'] ) ) : 'spad-style'; 375 376 // Enqueue tabs CSS and JavaScript 377 self::enqueue_tabs_assets(); 378 379 // Fetch JFT meditation 380 $jft_selected_language = self::get_language_enum( 'jft', $jft_language ); 381 $jft_use_timezone = 'english' === $jft_language && ! empty( $jft_timezone ) ? $jft_timezone : null; 382 $jft_settings = new JFTSettings( $jft_selected_language, $jft_use_timezone ); 383 $jft_content = ''; 384 try { 385 $jft_instance = JFT::getInstance( $jft_settings ); 386 $jft_entry = $jft_instance->fetch(); 387 if ( is_string( $jft_entry ) ) { 388 $jft_content = static::render_error_message( $jft_entry, 'jft', $jft_language ); 389 } else { 390 $jft_content = static::build_layout( $jft_entry, 'block' === $layout ); 391 } 392 } catch ( \Exception $e ) { 393 $jft_content = static::render_error_message( $e->getMessage(), 'jft', $jft_language ); 394 } catch ( \Error $e ) { 395 $jft_content = static::render_error_message( 'Service temporarily unavailable', 'jft', $jft_language ); 396 } 397 398 // Fetch SPAD meditation 399 $spad_selected_language = self::get_language_enum( 'spad', $spad_language ); 400 $spad_use_timezone = 'english' === $spad_language && ! empty( $spad_timezone ) ? $spad_timezone : null; 401 $spad_settings = new SPADSettings( $spad_selected_language, $spad_use_timezone ); 402 $spad_content = ''; 403 try { 404 $spad_instance = SPAD::getInstance( $spad_settings ); 405 $spad_entry = $spad_instance->fetch(); 406 if ( is_string( $spad_entry ) ) { 407 $spad_content = static::render_error_message( $spad_entry, 'spad', $spad_language ); 408 } else { 409 $spad_content = static::build_layout( $spad_entry, 'block' === $layout ); 410 } 411 } catch ( \Exception $e ) { 412 $spad_content = static::render_error_message( $e->getMessage(), 'spad', $spad_language ); 413 } catch ( \Error $e ) { 414 $spad_content = static::render_error_message( 'Service temporarily unavailable', 'spad', $spad_language ); 415 } 416 417 // Build tabbed or accordion interface 418 if ( 'accordion' === $tabs_layout ) { 419 return static::render_accordion( $instance_counter, $jft_content, $spad_content, $jft_theme, $spad_theme ); 420 } 421 422 // Build tabbed interface (horizontal) 423 $content = "\n<div class=\"meditation-tabs-container\" data-instance-id=\"{$instance_counter}\" data-layout=\"tabs\">\n"; 424 $content .= " <ul class=\"meditation-tab-list\" role=\"tablist\">\n"; 425 $content .= " <li role=\"presentation\">\n"; 426 $content .= " <button class=\"meditation-tab-button\" role=\"tab\" data-tab-id=\"jft\" aria-selected=\"true\" aria-controls=\"meditation-panel-jft-{$instance_counter}\" tabindex=\"0\">Just For Today</button>\n"; 427 $content .= " </li>\n"; 428 $content .= " <li role=\"presentation\">\n"; 429 $content .= " <button class=\"meditation-tab-button\" role=\"tab\" data-tab-id=\"spad\" aria-selected=\"false\" aria-controls=\"meditation-panel-spad-{$instance_counter}\" tabindex=\"-1\">Spiritual Principle A Day</button>\n"; 430 $content .= " </li>\n"; 431 $content .= " </ul>\n"; 432 $content .= " <div class=\"meditation-tab-content\">\n"; 433 $content .= " <div class=\"meditation-tab-panel\" role=\"tabpanel\" id=\"meditation-panel-jft-{$instance_counter}\" data-tab-id=\"jft\" aria-labelledby=\"tab-jft\">\n"; 434 $content .= ' <style>' . static::get_inline_theme_css( $jft_theme ) . "</style>\n"; 435 $content .= $jft_content; 436 $content .= " </div>\n"; 437 $content .= " <div class=\"meditation-tab-panel\" role=\"tabpanel\" id=\"meditation-panel-spad-{$instance_counter}\" data-tab-id=\"spad\" aria-labelledby=\"tab-spad\" hidden>\n"; 438 $content .= ' <style>' . static::get_inline_theme_css( $spad_theme ) . "</style>\n"; 439 $content .= $spad_content; 440 $content .= " </div>\n"; 441 $content .= " </div>\n"; 442 $content .= "</div>\n"; 443 444 return $content; 445 } 446 447 /** 448 * Render accordion layout for both books 449 * 450 * @param int $instance_counter Unique instance ID 451 * @param string $jft_content JFT meditation content 452 * @param string $spad_content SPAD meditation content 453 * @param string $jft_theme JFT theme 454 * @param string $spad_theme SPAD theme 455 * @return string Rendered accordion HTML 456 */ 457 private static function render_accordion( int $instance_counter, string $jft_content, string $spad_content, string $jft_theme, string $spad_theme ): string { 458 $content = "\n<div class=\"meditation-accordion-container\" data-instance-id=\"{$instance_counter}\" data-layout=\"accordion\">\n"; 459 460 // JFT Accordion Item 461 $content .= " <div class=\"meditation-accordion-item\">\n"; 462 $content .= " <button class=\"meditation-accordion-button active\" aria-expanded=\"true\" aria-controls=\"meditation-accordion-jft-{$instance_counter}\">\n"; 463 $content .= " <span>Just For Today</span>\n"; 464 $content .= " <span class=\"meditation-accordion-icon\"></span>\n"; 465 $content .= " </button>\n"; 466 $content .= " <div class=\"meditation-accordion-panel active\" id=\"meditation-accordion-jft-{$instance_counter}\">\n"; 467 $content .= ' <style>' . static::get_inline_theme_css( $jft_theme ) . "</style>\n"; 468 $content .= $jft_content; 469 $content .= " </div>\n"; 470 $content .= " </div>\n"; 471 472 // SPAD Accordion Item 473 $content .= " <div class=\"meditation-accordion-item\">\n"; 474 $content .= " <button class=\"meditation-accordion-button\" aria-expanded=\"false\" aria-controls=\"meditation-accordion-spad-{$instance_counter}\">\n"; 475 $content .= " <span>Spiritual Principle A Day</span>\n"; 476 $content .= " <span class=\"meditation-accordion-icon\"></span>\n"; 477 $content .= " </button>\n"; 478 $content .= " <div class=\"meditation-accordion-panel\" id=\"meditation-accordion-spad-{$instance_counter}\" hidden>\n"; 479 $content .= ' <style>' . static::get_inline_theme_css( $spad_theme ) . "</style>\n"; 480 $content .= $spad_content; 481 $content .= " </div>\n"; 482 $content .= " </div>\n"; 483 484 $content .= "</div>\n"; 485 486 return $content; 487 } 488 344 489 private static function build_layout( object $entry, bool $in_block ): string { 345 490 // Render Content As HTML Table or CSS Block Elements … … 438 583 }; 439 584 wp_enqueue_style( self::PLUG_SLUG, plugin_dir_url( __FILE__ ) . 'css/' . $css_file, false, '1.0.0', 'all' ); 585 } 586 587 /** 588 * Enqueue tabs CSS and JavaScript 589 * 590 * @return void 591 */ 592 private static function enqueue_tabs_assets(): void { 593 static $enqueued = false; 594 if ( $enqueued ) { 595 return; 596 } 597 $enqueued = true; 598 $base_url = plugin_dir_url( __FILE__ ); 599 wp_enqueue_style( self::PLUG_SLUG . '-tabs', $base_url . 'css/fetch-meditation-tabs.css', [], filemtime( plugin_dir_path( __FILE__ ) . 'css/fetch-meditation-tabs.css' ), 'all' ); 600 wp_enqueue_script( self::PLUG_SLUG . '-tabs', $base_url . 'js/fetch-meditation-tabs.js', [], filemtime( plugin_dir_path( __FILE__ ) . 'js/fetch-meditation-tabs.js' ), true ); 601 } 602 603 /** 604 * Get inline CSS content for a theme 605 * 606 * @param string $theme The theme name 607 * @return string CSS content 608 */ 609 private static function get_inline_theme_css( string $theme ): string { 610 $css_file = match ( strtolower( $theme ) ) { 611 'jft-style' => 'fetch-meditation-jft.css', 612 'spad-style' => 'fetch-meditation-spad.css', 613 default => 'fetch-meditation.css', 614 }; 615 $css_path = plugin_dir_path( __FILE__ ) . 'css/' . $css_file; 616 if ( file_exists( $css_path ) ) { 617 return wp_strip_all_tags( file_get_contents( $css_path ) ); 618 } 619 return ''; 440 620 } 441 621 … … 496 676 ] 497 677 ); 678 register_setting( 679 self::SETTINGS_GROUP, 680 'fetch_meditation_tabs_layout', 681 [ 682 'type' => 'string', 683 'default' => self::DEFAULT_TABS_LAYOUT, 684 'sanitize_callback' => 'sanitize_text_field', 685 ] 686 ); 498 687 } 499 688 … … 523 712 $meditation_layout = esc_attr( get_option( 'fetch_meditation_layout', self::DEFAULT_LAYOUT ) ); 524 713 $meditation_theme = esc_attr( get_option( 'fetch_meditation_theme' ) ); 714 $tabs_layout = esc_attr( get_option( 'fetch_meditation_tabs_layout', self::DEFAULT_TABS_LAYOUT ) ); 525 715 $jft_language = esc_attr( get_option( 'fetch_meditation_jft_language' ) ); 526 716 $spad_language = esc_attr( get_option( 'fetch_meditation_spad_language' ) ); … … 551 741 <h4>Available Options:</h4> 552 742 <ul> 553 <li><strong>Book:</strong> Choose between JFT or SPAD(not needed for [jft] and [spad] shortcodes)<br>554 <code>[fetch_meditation book="jft"]</code> or <code>[fetch_meditation book="spad"]</code></li>743 <li><strong>Book:</strong> Choose between JFT, SPAD, or Both (not needed for [jft] and [spad] shortcodes)<br> 744 <code>[fetch_meditation book="jft"]</code>, <code>[fetch_meditation book="spad"]</code>, or <code>[fetch_meditation book="both"]</code></li> 555 745 556 746 <li><strong>Layout:</strong> Choose between table or block layout<br> … … 569 759 <code>[jft timezone="America/New_York"]</code><br> 570 760 Common timezones: America/New_York, America/Chicago, America/Denver, America/Los_Angeles, Europe/London, etc.</li> 761 762 <li><strong>Tabbed Display (book="both" only):</strong><br> 763 <code>tabs_layout="tabs"</code> or <code>tabs_layout="accordion"</code> - Controls display style (default: tabs)<br> 764 <code>jft_language="english"</code>, <code>spad_language="german"</code> - Set different languages for each book<br> 765 <code>jft_timezone="America/New_York"</code>, <code>spad_timezone="America/Chicago"</code> - Set different timezones<br> 766 <code>jft_theme="jft-style"</code>, <code>spad_theme="spad-style"</code> - Set different themes for each book</li> 571 767 </ul> 572 768 … … 579 775 <li><code>[jft theme="default"]</code> - JFT meditation with default theme instead of JFT style</li> 580 776 <li><code>[fetch_meditation book="spad" theme="jft-style"]</code> - SPAD meditation with JFT style theme</li> 777 <li><code>[fetch_meditation book="both"]</code> - Display both JFT and SPAD in tabbed interface</li> 778 <li><code>[fetch_meditation book="both" tabs_layout="accordion"]</code> - Accordion layout (stacked)</li> 779 <li><code>[fetch_meditation book="both" jft_language="spanish" spad_language="german"]</code> - Different languages for each book</li> 581 780 </ul> 582 781 </div> … … 598 797 'jft' => 'JFT', 599 798 'spad' => 'SPAD', 799 'both' => 'Both (Tabbed)', 600 800 ] 601 801 ), … … 641 841 ?> 642 842 <p class="description">Choose the visual theme for the meditation display. Note: [jft] shortcode defaults to JFT Style, [spad] shortcode defaults to SPAD Style.</p> 843 </td> 844 </tr> 845 <tr valign="top" id="tabs-layout-container"> 846 <th scope="row">Tabs Layout</th> 847 <td> 848 <?php 849 echo wp_kses( 850 static::render_select_option( 851 'fetch_meditation_tabs_layout', 852 $tabs_layout, 853 [ 854 'tabs' => 'Tabs (horizontal)', 855 'accordion' => 'Accordion (stacked)', 856 ] 857 ), 858 $allowed_html 859 ); 860 ?> 861 <p class="description">Only applies when Book is set to "Both (Tabbed)".</p> 643 862 </td> 644 863 </tr> -
fetch-meditation/trunk/js/fetch-meditation.js
r3279554 r3435416 6 6 const spadLanguageContainer = $('#spad-language-container'); 7 7 const timezoneContainer = $('#timezone-container'); 8 const tabsLayoutContainer = $('#tabs-layout-container'); 8 9 9 10 if (!bookSelect.length) return; … … 15 16 jftLanguageContainer.hide(); 16 17 spadLanguageContainer.hide(); 18 tabsLayoutContainer.hide(); 17 19 18 20 // Show the appropriate container … … 21 23 } else if (selectedBook === 'spad') { 22 24 spadLanguageContainer.show(); 25 } else if (selectedBook === 'both') { 26 // For 'both', show both language containers and tabs layout 27 jftLanguageContainer.show(); 28 spadLanguageContainer.show(); 29 tabsLayoutContainer.show(); 23 30 } 24 31 -
fetch-meditation/trunk/readme.txt
r3424942 r3435416 6 6 Requires PHP: 8.1 7 7 Tested up to: 6.9 8 Stable tag: 1.4. 48 Stable tag: 1.4.5 9 9 License: GPLv2 or later 10 10 License URI: http://www.gnu.org/licenses/gpl-2.0.html … … 24 24 Basic JFT: [jft] 25 25 Basic SPAD: [spad] 26 Both (Tabbed): [fetch_meditation book="both"] 26 27 General: [fetch_meditation book="jft"] 27 28 Layout: table, block [jft layout="block"] or [spad layout="table"] … … 29 30 Timezone (English Only): Any valid IANA [timezone](https://www.php.net/manual/en/timezones.php) [jft timezone="America/New_York"] 30 31 Theme: default, jft-style, spad-style [jft theme="default"] or [fetch_meditation theme="spad-style"] (Note: [jft] defaults to jft-style, [spad] defaults to spad-style) 32 33 TABBED DISPLAY (book="both" only) 34 Display both JFT and SPAD meditations in an interactive interface: 35 - Basic (horizontal tabs): [fetch_meditation book="both"] 36 - Accordion layout: [fetch_meditation book="both" tabs_layout="accordion"] 37 - Different languages: [fetch_meditation book="both" jft_language="spanish" spad_language="german"] 38 - Different timezones: [fetch_meditation book="both" jft_timezone="America/New_York" spad_timezone="America/Chicago"] 39 - Different themes: [fetch_meditation book="both" jft_theme="jft-style" spad_theme="spad-style"] 31 40 32 41 MORE INFORMATION … … 42 51 43 52 == Changelog == 53 54 = 1.4.5 = 55 56 * Added tabbed interface support with book="both" attribute. 57 * New tabs_layout attribute (tabs/accordion) for controlling display style. 44 58 45 59 = 1.4.4 = -
fetch-meditation/trunk/vendor/composer/installed.php
r3424942 r3435416 2 2 'root' => array( 3 3 'name' => 'bmlt/fetch-meditation-wp', 4 'pretty_version' => '1.4. 4',5 'version' => '1.4. 4.0',6 'reference' => ' d49718607a4b90698c0a29723550b536c53c5d74',4 'pretty_version' => '1.4.5', 5 'version' => '1.4.5.0', 6 'reference' => 'e4a2b7c70c860395cdd726cb07cea82e0dbc603c', 7 7 'type' => 'project', 8 8 'install_path' => __DIR__ . '/../../', … … 21 21 ), 22 22 'bmlt/fetch-meditation-wp' => array( 23 'pretty_version' => '1.4. 4',24 'version' => '1.4. 4.0',25 'reference' => ' d49718607a4b90698c0a29723550b536c53c5d74',23 'pretty_version' => '1.4.5', 24 'version' => '1.4.5.0', 25 'reference' => 'e4a2b7c70c860395cdd726cb07cea82e0dbc603c', 26 26 'type' => 'project', 27 27 'install_path' => __DIR__ . '/../../',
Note: See TracChangeset
for help on using the changeset viewer.