Plugin Directory

Changeset 3435416


Ignore:
Timestamp:
01/08/2026 06:26:54 PM (3 months ago)
Author:
bmltenabled
Message:

Deploy version 1.4.5

Location:
fetch-meditation/trunk
Files:
2 added
5 edited

Legend:

Unmodified
Added
Removed
  • fetch-meditation/trunk/build.txt

    r3424942 r3435416  
    1 d49718607a4b90698c0a29723550b536c53c5d74
     1e4a2b7c70c860395cdd726cb07cea82e0dbc603c
  • fetch-meditation/trunk/fetch-meditation.php

    r3424942 r3435416  
    77 * Contributors:      pjaudiomv, bmltenabled
    88 * Author:            bmltenabled
    9  * Version:           1.4.4
     9 * Version:           1.4.5
    1010 * Requires PHP:      8.1
    1111 * Requires at least: 6.2
     
    4242    private const DEFAULT_LAYOUT = 'block';
    4343    private const DEFAULT_THEME = 'default';
     44    private const DEFAULT_TABS_LAYOUT = 'tabs';
    4445
    4546    private const PLUG_SLUG = 'fetch-meditation';
     
    261262
    262263    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
    263271        $language = self::determine_option( $attrs, 'language' );
    264         $book     = self::determine_option( $attrs, 'book' );
    265272        $layout   = self::determine_option( $attrs, 'layout' );
    266273        $timezone = self::determine_option( $attrs, 'timezone' );
     
    342349    }
    343350
     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
    344489    private static function build_layout( object $entry, bool $in_block ): string {
    345490        // Render Content As HTML Table or CSS Block Elements
     
    438583        };
    439584        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 '';
    440620    }
    441621
     
    496676            ]
    497677        );
     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        );
    498687    }
    499688
     
    523712        $meditation_layout   = esc_attr( get_option( 'fetch_meditation_layout', self::DEFAULT_LAYOUT ) );
    524713        $meditation_theme    = esc_attr( get_option( 'fetch_meditation_theme' ) );
     714        $tabs_layout        = esc_attr( get_option( 'fetch_meditation_tabs_layout', self::DEFAULT_TABS_LAYOUT ) );
    525715        $jft_language       = esc_attr( get_option( 'fetch_meditation_jft_language' ) );
    526716        $spad_language      = esc_attr( get_option( 'fetch_meditation_spad_language' ) );
     
    551741                <h4>Available Options:</h4>
    552742                <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>
    555745                   
    556746                    <li><strong>Layout:</strong> Choose between table or block layout<br>
     
    569759                    <code>[jft timezone="America/New_York"]</code><br>
    570760                    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>
    571767                </ul>
    572768               
     
    579775                    <li><code>[jft theme="default"]</code> - JFT meditation with default theme instead of JFT style</li>
    580776                    <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>
    581780                </ul>
    582781            </div>
     
    598797                                        'jft' => 'JFT',
    599798                                        'spad' => 'SPAD',
     799                                        'both' => 'Both (Tabbed)',
    600800                                    ]
    601801                                ),
     
    641841                            ?>
    642842                            <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>
    643862                        </td>
    644863                    </tr>
  • fetch-meditation/trunk/js/fetch-meditation.js

    r3279554 r3435416  
    66    const spadLanguageContainer = $('#spad-language-container');
    77    const timezoneContainer = $('#timezone-container');
     8    const tabsLayoutContainer = $('#tabs-layout-container');
    89
    910    if (!bookSelect.length) return;
     
    1516        jftLanguageContainer.hide();
    1617        spadLanguageContainer.hide();
     18        tabsLayoutContainer.hide();
    1719       
    1820        // Show the appropriate container
     
    2123        } else if (selectedBook === 'spad') {
    2224            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();
    2330        }
    2431       
  • fetch-meditation/trunk/readme.txt

    r3424942 r3435416  
    66Requires PHP: 8.1
    77Tested up to: 6.9
    8 Stable tag: 1.4.4
     8Stable tag: 1.4.5
    99License: GPLv2 or later
    1010License URI: http://www.gnu.org/licenses/gpl-2.0.html
     
    2424Basic JFT: [jft]
    2525Basic SPAD: [spad]
     26Both (Tabbed): [fetch_meditation book="both"]
    2627General: [fetch_meditation book="jft"]
    2728Layout: table, block [jft layout="block"] or [spad layout="table"]
     
    2930Timezone (English Only): Any valid IANA [timezone](https://www.php.net/manual/en/timezones.php) [jft timezone="America/New_York"]
    3031Theme: 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
     33TABBED DISPLAY (book="both" only)
     34Display 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"]
    3140
    3241MORE INFORMATION
     
    4251
    4352== 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.
    4458
    4559= 1.4.4 =
  • fetch-meditation/trunk/vendor/composer/installed.php

    r3424942 r3435416  
    22    'root' => array(
    33        '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',
    77        'type' => 'project',
    88        'install_path' => __DIR__ . '/../../',
     
    2121        ),
    2222        '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',
    2626            'type' => 'project',
    2727            'install_path' => __DIR__ . '/../../',
Note: See TracChangeset for help on using the changeset viewer.