Plugin Directory

Changeset 3755228


Ignore:
Timestamp:
10/19/2026 04:48:49 PM (3 weeks ago)
Author:
vimagesericfabre
Message:

Update to 2.16.30

Location:
vefmusic/trunk
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • vefmusic/trunk/assets/css/vefm-admin.css

    r3726330 r3755228  
    576576}
    577577
    578 /* Second level: the sub-tabs of the Style screen (General, Tracks, Albums, Shows, Next show). They keep
     578/* Second level: the sub-tabs of a screen — Style (General, Tracks, Albums, Shows, Next show...) and the screens that gather Free and Pro (VEFmusic | VEFmusic Pro). They keep
    579579   the classes WordPress knows (the script toggles `nav-tab-active`); only their look changes. */
    580 .vefm-admin .vefm-style-tabs.nav-tab-wrapper {
     580.vefm-admin .vefm-style-tabs.nav-tab-wrapper,
     581.vefm-admin .vefm-subtabs.nav-tab-wrapper {
    581582        display: flex;
    582583        flex-wrap: wrap;
    … …  
    587588}
    588589
    589 .vefm-admin .vefm-style-tabs .nav-tab {
     590.vefm-admin .vefm-style-tabs .nav-tab,
     591.vefm-admin .vefm-subtabs .nav-tab {
    590592        float: none;
    591593        margin: 0;
    … …  
    601603
    602604.vefm-admin .vefm-style-tabs .nav-tab:hover,
    603 .vefm-admin .vefm-style-tabs .nav-tab:focus {
     605.vefm-admin .vefm-style-tabs .nav-tab:focus,
     606.vefm-admin .vefm-subtabs .nav-tab:hover,
     607.vefm-admin .vefm-subtabs .nav-tab:focus {
    604608        color: var(--vefm-a-accent);
    605609        background: color-mix(in srgb, var(--wp-admin-theme-color, #2271b1) 8%, #fff);
    … …  
    608612.vefm-admin .vefm-style-tabs .nav-tab-active,
    609613.vefm-admin .vefm-style-tabs .nav-tab-active:hover,
    610 .vefm-admin .vefm-style-tabs .nav-tab-active:focus {
     614.vefm-admin .vefm-style-tabs .nav-tab-active:focus,
     615.vefm-admin .vefm-subtabs .nav-tab-active,
     616.vefm-admin .vefm-subtabs .nav-tab-active:hover,
     617.vefm-admin .vefm-subtabs .nav-tab-active:focus {
    611618        color: #fff;
    612619        background: var(--vefm-a-accent);
    613620        border-color: var(--vefm-a-accent);
    614621}
     622
     623.vefm-subpanel[hidden] {
     624        display: none;
     625}
  • vefmusic/trunk/assets/css/vefm-buttons.css

    r3746875 r3755228  
    1212 *
    1313 * Adjustable from Style > General (or custom CSS):
     14 *   --vefm-button-bg             background             (default: main color)
     15 *   --vefm-button-text-color     text and icons
    1416 *   --vefm-btn-hover-opacity     hover/focus strength   (default .85)
    1517 *   --vefm-btn-disabled-opacity  disabled strength      (default .6)
    … …  
    2729.vefm-ratings-submit {
    2830        border: 0;
    29         background: var( --vefm-accent, var( --wp--preset--color--primary, #1e1e1e ) );
     31        background: var( --vefm-button-bg, var( --vefm-accent, var( --wp--preset--color--primary, #1e1e1e ) ) );
    3032        color: var( --vefm-button-text-color, var( --wp--preset--color--background, #fff ) );
    3133        cursor: pointer;
    … …  
    3941.vefm-concert-ticket-link:focus,
    4042.vefm-concert-ticket-link:active {
    41         background: var( --vefm-accent, var( --wp--preset--color--primary, #1e1e1e ) );
     43        background: var( --vefm-button-bg, var( --vefm-accent, var( --wp--preset--color--primary, #1e1e1e ) ) );
    4244        color: var( --vefm-button-text-color, var( --wp--preset--color--background, #fff ) );
    4345        text-decoration: none;
  • vefmusic/trunk/assets/css/vefm-frontend.css

    r3746875 r3755228  
    622622        flex: 0 0 auto;
    623623        display: inline-flex;
    624         justify-content: center;
    625         margin: 0 auto;
    626624        gap: 6px;
    627625        border-radius: 20px;
    … …  
    757755        border: 0;
    758756        border-radius: 50%;
    759         background: var( --vefm-accent, var( --wp--preset--color--primary, #1e1e1e ) );
     757        background: var( --vefm-button-bg, var( --vefm-accent, var( --wp--preset--color--primary, #1e1e1e ) ) );
    760758        color: var( --vefm-button-text-color, var( --wp--preset--color--background, #fff ) );
    761759        line-height: 1;
    … …  
    770768.vefm-album-cover-flip .vefm-album-cover-toggle:focus,
    771769.vefm-album-cover-flip .vefm-album-cover-toggle:active {
    772         background: var( --vefm-accent, var( --wp--preset--color--primary, #1e1e1e ) );
     770        background: var( --vefm-button-bg, var( --vefm-accent, var( --wp--preset--color--primary, #1e1e1e ) ) );
    773771        color: var( --vefm-button-text-color, var( --wp--preset--color--background, #fff ) );
    774772}
  • vefmusic/trunk/assets/css/vefm-lightbox.css

    r3746875 r3755228  
    103103        border: 0;
    104104        border-radius: 50%;
    105         background: var( --vefm-accent, var( --wp--preset--color--primary, #1e1e1e ) );
     105        background: var( --vefm-button-bg, var( --vefm-accent, var( --wp--preset--color--primary, #1e1e1e ) ) );
    106106        color: var( --vefm-button-text-color, var( --wp--preset--color--background, #fff ) );
    107107        line-height: 1;
    … …  
    116116.vefm-lightbox .vefm-lightbox-button:focus,
    117117.vefm-lightbox .vefm-lightbox-button:active {
    118         background: var( --vefm-accent, var( --wp--preset--color--primary, #1e1e1e ) );
     118        background: var( --vefm-button-bg, var( --vefm-accent, var( --wp--preset--color--primary, #1e1e1e ) ) );
    119119        color: var( --vefm-button-text-color, var( --wp--preset--color--background, #fff ) );
    120120}
  • vefmusic/trunk/includes/class-vefm-admin-help.php

    r3746875 r3755228  
    451451                                'overview',
    452452                                __( 'Overview', 'vefmusic' ),
    453                                 self::p( __( 'The simplest way to match the plugin to your site, valid everywhere (Gutenberg, Divi 5 and Elementor). Five sub-tabs: General, Tracks, Albums, Shows and Next show — each one adjustable separately.', 'vefmusic' ) )
    454                                 . self::p( __( 'A value left empty keeps the default. The main color, the font and the button text color set here are shared with VEFmusic Pro (cart, donations): no need to set them twice.', 'vefmusic' ) )
     453                                self::p( __( 'The simplest way to match the plugin to your site, valid everywhere (Gutenberg, Divi 5 and Elementor). Six sub-tabs: General, Buttons, Tracks, Albums, Shows and Next show — each one adjustable separately.', 'vefmusic' ) )
     454                                . self::p( __( 'A value left empty keeps the default. The main color, the font and the button colors set here are shared with VEFmusic Pro (cart, donations): no need to set them twice.', 'vefmusic' ) )
    455455                        ),
    456456                        self::topic(
    … …  
    461461                                                array( __( 'Main color', 'vefmusic' ), __( 'the accent color of the blocks.', 'vefmusic' ) ),
    462462                                                array( __( 'Font', 'vefmusic' ), __( 'one default font for the whole site. Left empty, the blocks use the font of your theme.', 'vefmusic' ) ),
     463                                        )
     464                                )
     465                        ),
     466                        self::topic(
     467                                'buttons',
     468                                __( 'Buttons sub-tab', 'vefmusic' ),
     469                                self::terms(
     470                                        array(
     471                                                array( __( 'Button colors', 'vefmusic' ), __( 'background, text, and the same two when the pointer is over a button, for all the buttons at once. Use them to reproduce the buttons of your theme. A color left empty keeps the default: the main color for the background, the theme\'s background color for the text, and on hover your theme\'s own button hover colors if it has any. A color you set always wins over the theme.', 'vefmusic' ) ),
    463472                                                array( __( 'Button shadow', 'vefmusic' ), __( 'one shadow for all the buttons. No color chosen means no shadow: the button style of your theme is kept.', 'vefmusic' ) ),
    464473                                                array( __( 'Button states', 'vefmusic' ), __( 'every button has the same look, only its shape differs. Set how much a button fades when the pointer is over it (or it has keyboard focus) and when it is disabled. Empty fields keep the defaults: 85% and 60%.', 'vefmusic' ) ),
  • vefmusic/trunk/includes/class-vefm-admin-ui.php

    r3726330 r3755228  
    297297                echo '</div>';
    298298        }
     299
     300        /**
     301         * One screen per subject: prints the content of a screen as one or several panels. A panel is
     302         * a part of the screen (for instance "VEFmusic" and "VEFmusic Pro" on the Help screen). With a
     303         * single panel the content is printed as it is, with nothing around it — so a site without Pro
     304         * sees exactly what it always saw. With several, a row of pills switches between the panels,
     305         * and a link ending with "#vefm-sub-{screen}-{key}" opens the matching panel directly.
     306         *
     307         * The panels of other plugins are added with the filter 'vefm_subpanels_{screen}'.
     308         *
     309         * @param string                           $screen Short name of the screen ("help", "diagnostic"...).
     310         * @param array<string,array<string,mixed>> $panels Panel key => 'label' (string), 'callback' (callable).
     311         * @return void
     312         */
     313        public static function render_subpanels( $screen, array $panels ) {
     314                $screen = sanitize_key( $screen );
     315                /**
     316                 * Adds panels to a screen. Each panel: 'label' (string) and 'callback' (callable printing the
     317                 * content, without the page header and without closing the page).
     318                 *
     319                 * @param array $panels Panel key => label, callback.
     320                 */
     321                $panels = apply_filters( 'vefm_subpanels_' . $screen, $panels );
     322
     323                if ( 1 === count( $panels ) ) {
     324                        $panel = reset( $panels );
     325                        call_user_func( $panel['callback'] );
     326                        return;
     327                }
     328
     329                echo '<h2 class="nav-tab-wrapper vefm-subtabs">';
     330                $first = true;
     331                foreach ( $panels as $key => $panel ) {
     332                        printf(
     333                                '<a href="#vefm-sub-%1$s-%2$s" class="nav-tab%3$s">%4$s</a>',
     334                                esc_attr( $screen ),
     335                                esc_attr( sanitize_key( $key ) ),
     336                                $first ? ' nav-tab-active' : '',
     337                                esc_html( $panel['label'] )
     338                        );
     339                        $first = false;
     340                }
     341                echo '</h2>';
     342
     343                $first = true;
     344                foreach ( $panels as $key => $panel ) {
     345                        printf(
     346                                '<div id="vefm-sub-%1$s-%2$s" class="vefm-subpanel"%3$s>',
     347                                esc_attr( $screen ),
     348                                esc_attr( sanitize_key( $key ) ),
     349                                $first ? '' : ' hidden'
     350                        );
     351                        call_user_func( $panel['callback'] );
     352                        echo '</div>';
     353                        $first = false;
     354                }
     355
     356                VEFM_Admin::enqueue_inline_script(
     357                        <<<'JS'
     358jQuery( function ( $ ) {
     359        var $links = $( '.vefm-subtabs a' );
     360        function show( target ) {
     361                $links.removeClass( 'nav-tab-active' ).filter( function () {
     362                        return $( this ).attr( 'href' ) === target;
     363                } ).addClass( 'nav-tab-active' );
     364                $( '.vefm-subpanel' ).attr( 'hidden', true );
     365                $( target ).removeAttr( 'hidden' );
     366        }
     367        $links.on( 'click', function ( e ) {
     368                e.preventDefault();
     369                var target = $( this ).attr( 'href' );
     370                show( target );
     371                if ( window.history && window.history.replaceState ) {
     372                        window.history.replaceState( null, '', target );
     373                }
     374        } );
     375        var hash = window.location.hash;
     376        if ( hash && $links.filter( function () {
     377                return $( this ).attr( 'href' ) === hash;
     378        } ).length ) {
     379                show( hash );
     380        }
     381} );
     382JS,
     383                        'vefm-subpanels',
     384                        array( 'jquery' )
     385                );
     386        }
    299387}
  • vefmusic/trunk/includes/class-vefm-admin.php

    r3746875 r3755228  
    507507                );
    508508                if ( $pro_active ) {
    509                         $parametres_tabs['vefmusic-pro-style']   = __( 'Pro Style', 'vefmusic' );
     509                        // Pro Style is now a sub-tab of Style (added by VEFmusic Pro, see the 'vefm_style_tabs' action).
    510510                        $parametres_tabs['vefmusic-pro-license'] = __( 'License', 'vefmusic' );
    511511                }
    … …  
    517517                $vente_tabs = array();
    518518                if ( $pro_active ) {
     519                        // What the owner opens every day (the sales and their figures) comes first; the settings
     520                        // of the sales (payment, invoicing, shipping) follow.
    519521                        $vente_tabs = array(
     522                                'vefmusic-pro-orders'    => __( 'Completed sales', 'vefmusic' ),
     523                                'vefmusic-pro-revenue'   => __( 'Statistics', 'vefmusic' ),
    520524                                'vefmusic-pro-payment'   => __( 'Payment', 'vefmusic' ),
    521525                                'vefmusic-pro-invoicing' => __( 'Invoicing', 'vefmusic' ),
    … …  
    529533                }
    530534                $marketing_tabs['vefmusic-press-kit'] = __( 'Press kit', 'vefmusic' );
    531                 if ( $pro_active ) {
    532                         // v2.11.0 (import VEFpressKit —) : formulaire de
    533                         // contact/historique des demandes/statistiques de
    534                         // téléchargement/liens limités/liste presse/kits multiples du
    535                         // kit presse, basculés en Pro.
    536                         $marketing_tabs['vefmusic-pro-press-kit'] = __( 'Press kit (Pro)', 'vefmusic' );
    537                 }
    538535                $marketing_tabs['vefmusic-ratings'] = __( 'Visitor ratings', 'vefmusic' );
    539536                $marketing_tabs['vefmusic-stats']   = __( 'Listening stats', 'vefmusic' );
    540                 if ( $pro_active ) {
    541                         $marketing_tabs['vefmusic-pro-revenue'] = __( 'Statistics', 'vefmusic' );
    542                         $marketing_tabs['vefmusic-pro-orders']  = __( 'Completed sales', 'vefmusic' );
    543                 }
    544537
    545538                $aide_tabs = array(
    546539                        'vefmusic-help' => __( 'Help', 'vefmusic' ),
    547540                );
    548                 if ( $pro_active ) {
    549                         $aide_tabs['vefmusic-pro-help'] = __( 'Pro Help', 'vefmusic' );
    550                 }
    551541                $aide_tabs['vefmusic-support']    = __( 'Support & feature requests', 'vefmusic' );
    552542                $aide_tabs['vefmusic-about']      = __( 'About', 'vefmusic' );
    553543                $aide_tabs['vefmusic-diagnostic'] = __( 'Diagnostics', 'vefmusic' );
    554                 if ( $pro_active ) {
    555                         $aide_tabs['vefmusic-pro-diagnostic'] = __( 'Pro Diagnostics', 'vefmusic' );
    556                 }
    557544
    558545                // Order of the pages of the menu: what the owner works on first comes first (the menu entry
    … …  
    1008995                                        'style_accent'               => sanitize_text_field( wp_unslash( $_POST['style_accent'] ?? '' ) ),
    1009996                                        'style_button_text_color'    => sanitize_text_field( wp_unslash( $_POST['style_button_text_color'] ?? '' ) ),
     997                                        // 2.16.29: button background and hover colors.
     998                                        'style_button_bg_color'         => sanitize_text_field( wp_unslash( $_POST['style_button_bg_color'] ?? '' ) ),
     999                                        'style_button_hover_bg_color'   => sanitize_text_field( wp_unslash( $_POST['style_button_hover_bg_color'] ?? '' ) ),
     1000                                        'style_button_hover_text_color' => sanitize_text_field( wp_unslash( $_POST['style_button_hover_text_color'] ?? '' ) ),
    10101001                                        // 2.15.51: global button shadow — see
    10111002                                        // VEFM_Button_Shadow (range clamped there).
    … …  
    11421133.vefm-alpha-label { font-size: 12px; color: #646970; min-width: 34px; display: inline-block; }
    11431134.vefm-shadow-fields { display: flex; flex-wrap: wrap; gap: 8px 16px; margin: 8px 0 0; }
    1144 .vefm-shadow-field { display: inline-flex; flex-direction: column; gap: 2px; font-size: 12px; color: #646970; }',
     1135.vefm-shadow-field { display: inline-flex; flex-direction: column; gap: 2px; font-size: 12px; color: #646970; }
     1136.vefm-button-color { margin: 0 0 12px; }
     1137.vefm-button-color label { display: block; margin-bottom: 4px; font-weight: 600; }
     1138.vefm-style-savebar[hidden] { display: none; }
     1139.vefm-style-savebar, .vefmpro-style-panel > form > .submit { position: sticky; bottom: 0; z-index: 5; margin: 0 -1px; padding: .25rem 0; background: linear-gradient( to bottom, rgba( 255, 255, 255, 0 ), #fff 35% ); }
     1140.vefm-style-savebar .submit, .vefmpro-style-panel > form > .submit { margin: 0; padding: .6rem 0; }',
    11451141                        'vefm-style-page-css'
    11461142                );
    … …  
    14951491                self::render_page_header( __( 'Diagnostics', 'vefmusic' ) );
    14961492                self::render_group_tabs( 'parametres', 'vefmusic-diagnostic' );
    1497                 $this->render_diagnostic_tab();
     1493                VEFM_Admin_UI::render_subpanels(
     1494                        'diagnostic',
     1495                        array(
     1496                                'free' => array(
     1497                                        'label'    => 'VEFmusic',
     1498                                        'callback' => array( $this, 'render_diagnostic_tab' ),
     1499                                ),
     1500                        )
     1501                );
    14981502                echo '</div>';
    14991503        }
    … …  
    15051509                self::render_page_header( __( 'Help', 'vefmusic' ) );
    15061510                self::render_group_tabs( 'aide', 'vefmusic-help' );
    1507                 $this->render_help_tab();
     1511                VEFM_Admin_UI::render_subpanels(
     1512                        'help',
     1513                        array(
     1514                                'free' => array(
     1515                                        'label'    => 'VEFmusic',
     1516                                        'callback' => array( $this, 'render_help_tab' ),
     1517                                ),
     1518                        )
     1519                );
    15081520                echo '</div>';
    15091521        }
    … …  
    15651577                <h2 class="nav-tab-wrapper vefm-style-tabs">
    15661578                        <a href="#vefm-style-general" class="nav-tab nav-tab-active"><?php esc_html_e( 'General', 'vefmusic' ); ?></a>
     1579                        <a href="#vefm-style-buttons" class="nav-tab"><?php esc_html_e( 'Buttons', 'vefmusic' ); ?></a>
    15671580                        <a href="#vefm-style-tracks" class="nav-tab"><?php esc_html_e( 'Tracks', 'vefmusic' ); ?></a>
    15681581                        <a href="#vefm-style-albums" class="nav-tab"><?php esc_html_e( 'Albums', 'vefmusic' ); ?></a>
    15691582                        <a href="#vefm-style-concerts" class="nav-tab"><?php esc_html_e( 'Shows', 'vefmusic' ); ?></a>
    15701583                        <a href="#vefm-style-featured-concert" class="nav-tab"><?php esc_html_e( 'Next show', 'vefmusic' ); ?></a>
     1584                        <?php
     1585                        /**
     1586                         * Lets an add-on (VEFmusic Pro) add its own sub-tab to the Style screen.
     1587                         * The matching panel is printed by the 'vefm_style_panels' action, after the form.
     1588                         */
     1589                        do_action( 'vefm_style_tabs' );
     1590                        ?>
    15711591                </h2>
    15721592
    … …  
    15851605                                        </tr>
    15861606                                        <tr>
    1587                                                 <th><label for="style_button_text_color"><?php esc_html_e( 'Button text color', 'vefmusic' ); ?></label></th>
     1607                                                <th><label for="style_font_family"><?php esc_html_e( 'Font', 'vefmusic' ); ?></label></th>
    15881608                                                <td>
    1589                                                         <input type="hidden" id="style_button_text_color" name="style_button_text_color" value="<?php echo esc_attr( $s['style_button_text_color'] ); ?>" class="vefm-color-field" data-default-color="" />
    1590                                                         <p class="description"><?php esc_html_e( 'Text and icons of every VEFmusic button (and VEFmusic Pro\'s) — unchecked follows the theme\'s background color, white by default.', 'vefmusic' ); ?></p>
     1609                                                        <input type="text" id="style_font_family" name="style_font_family" value="<?php echo esc_attr( $s['style_font_family'] ); ?>" class="regular-text" placeholder="'Poppins', sans-serif" />
     1610                                                        <p class="description">
     1611                                                                <?php esc_html_e( 'Optional — the theme\'s font already applies by default if this field is left empty. Enter it as in CSS: name in single quotes, then a fallback font (e.g. \'Poppins\', sans-serif).', 'vefmusic' ); ?>
     1612                                                                <br />
     1613                                                                <?php esc_html_e( 'Finer control is possible directly in Divi: every VEFmusic module has its own Design > Text tab, with a real native Divi font picker (Google Fonts included) — already working, nothing to configure here. This field is only useful if you want one default font shared across the whole site, without setting it module by module.', 'vefmusic' ); ?>
     1614                                                        </p>
     1615                                                </td>
     1616                                        </tr>
     1617                                </table>
     1618                        </div>
     1619
     1620                        <div id="vefm-style-buttons" class="vefm-style-panel" hidden>
     1621                                <p class="description"><?php esc_html_e( 'The look of every VEFmusic button (and VEFmusic Pro\'s). Leave a field empty and nothing is forced: the button keeps the plugin\'s default look and, on hover, your theme\'s own button hover style if it has one. Fill a field and your choice wins over the theme, on every button.', 'vefmusic' ); ?></p>
     1622                                <table class="form-table">
     1623                                        <tr>
     1624                                                <th><?php esc_html_e( 'Button colors', 'vefmusic' ); ?></th>
     1625                                                <td>
     1626                                                        <?php
     1627                                                        $vefm_button_colors = array(
     1628                                                                'style_button_bg_color'         => __( 'Background', 'vefmusic' ),
     1629                                                                'style_button_text_color'       => __( 'Text', 'vefmusic' ),
     1630                                                                'style_button_hover_bg_color'   => __( 'Background on hover', 'vefmusic' ),
     1631                                                                'style_button_hover_text_color' => __( 'Text on hover', 'vefmusic' ),
     1632                                                        );
     1633                                                        foreach ( $vefm_button_colors as $vefm_button_color_key => $vefm_button_color_label ) :
     1634                                                                ?>
     1635                                                                <div class="vefm-button-color">
     1636                                                                        <label for="<?php echo esc_attr( $vefm_button_color_key ); ?>"><?php echo esc_html( $vefm_button_color_label ); ?></label>
     1637                                                                        <input type="hidden" id="<?php echo esc_attr( $vefm_button_color_key ); ?>" name="<?php echo esc_attr( $vefm_button_color_key ); ?>" value="<?php echo esc_attr( $s[ $vefm_button_color_key ] ); ?>" class="vefm-color-field" data-default-color="" />
     1638                                                                </div>
     1639                                                        <?php endforeach; ?>
     1640                                                        <p class="description"><?php esc_html_e( 'Colors of every VEFmusic button (and VEFmusic Pro\'s), to match the buttons of your theme. A field left empty keeps the default: the background follows the main color, the text follows the theme\'s background color (white by default), and on hover your theme\'s own button hover colors apply if it has any, along with the opacity set in Button states. A color you set here always wins over the theme.', 'vefmusic' ); ?></p>
    15911641                                                </td>
    15921642                                        </tr>
    … …  
    16361686                                                </td>
    16371687                                        </tr>
    1638                                         <tr>
    1639                                                 <th><label for="style_font_family"><?php esc_html_e( 'Font', 'vefmusic' ); ?></label></th>
    1640                                                 <td>
    1641                                                         <input type="text" id="style_font_family" name="style_font_family" value="<?php echo esc_attr( $s['style_font_family'] ); ?>" class="regular-text" placeholder="'Poppins', sans-serif" />
    1642                                                         <p class="description">
    1643                                                                 <?php esc_html_e( 'Optional — the theme\'s font already applies by default if this field is left empty. Enter it as in CSS: name in single quotes, then a fallback font (e.g. \'Poppins\', sans-serif).', 'vefmusic' ); ?>
    1644                                                                 <br />
    1645                                                                 <?php esc_html_e( 'Finer control is possible directly in Divi: every VEFmusic module has its own Design > Text tab, with a real native Divi font picker (Google Fonts included) — already working, nothing to configure here. This field is only useful if you want one default font shared across the whole site, without setting it module by module.', 'vefmusic' ); ?>
    1646                                                         </p>
    1647                                                 </td>
    1648                                         </tr>
    16491688                                </table>
    16501689                        </div>
    … …  
    18741913                        </div>
    18751914
    1876                         <?php submit_button( __( 'Save', 'vefmusic' ) ); ?>
     1915                        <div class="vefm-style-savebar">
     1916                                <?php submit_button( __( 'Save', 'vefmusic' ) ); ?>
     1917                        </div>
    18771918                </form>
    18781919                <?php
     1920                /**
     1921                 * Prints the panels of the sub-tabs added with 'vefm_style_tabs'. They sit OUTSIDE the form of
     1922                 * this screen: each one carries its own form, its own nonce and its own save button, so a
     1923                 * save never touches the settings of another panel. Each panel is a <div> with the classes
     1924                 * "vefm-style-panel" and the attribute data-vefm-own-form, and starts hidden.
     1925                 */
     1926                do_action( 'vefm_style_panels' );
    18791927                $vefm_opacity_label = esc_js( __( 'Opacity', 'vefmusic' ) );
    18801928                $vefm_style_js       = <<<'JS'
    … …  
    19812029                        } );
    19822030
    1983                         // Sous-onglets internes à cette page — un seul formulaire, un
    1984                         // seul bouton Enregistrer en bas, quel que soit l’onglet actif
    1985                         // (tous les champs restent dans le DOM, juste masqués).
     2031                        // Sous-onglets internes à cette page. Les panneaux du formulaire Free
     2032                        // partagent un seul bouton Enregistrer (tous les champs restent dans le
     2033                        // DOM, juste masqués) ; un panneau ajouté par un module (data-vefm-own-form)
     2034                        // a son propre formulaire et son propre bouton : la barre Enregistrer de
     2035                        // Free est alors masquée pour ne pas laisser croire qu’elle l’enregistre.
     2036                        function vefmShowStylePanel( target ) {
     2037                                var $panel = $( target );
     2038                                $( '.vefm-style-tabs a' ).removeClass( 'nav-tab-active' ).filter( function () {
     2039                                        return $( this ).attr( 'href' ) === target;
     2040                                } ).addClass( 'nav-tab-active' );
     2041                                $( '.vefm-style-panel' ).attr( 'hidden', true );
     2042                                $panel.removeAttr( 'hidden' );
     2043                                $( '.vefm-style-savebar' ).prop( 'hidden', $panel.is( '[data-vefm-own-form]' ) );
     2044                        }
    19862045                        $( '.vefm-style-tabs a' ).on( 'click', function ( e ) {
    19872046                                e.preventDefault();
    19882047                                var target = $( this ).attr( 'href' );
    1989                                 $( '.vefm-style-tabs a' ).removeClass( 'nav-tab-active' );
    1990                                 $( this ).addClass( 'nav-tab-active' );
    1991                                 $( '.vefm-style-panel' ).attr( 'hidden', true );
    1992                                 $( target ).removeAttr( 'hidden' );
     2048                                vefmShowStylePanel( target );
     2049                                if ( window.history && window.history.replaceState ) {
     2050                                        window.history.replaceState( null, '', target );
     2051                                }
    19932052                        } );
     2053                        // Unsaved changes: the save bar stays visible at the bottom of the screen, and leaving
     2054                        // the page after a change (not yet saved) asks for confirmation. The state of each form
     2055                        // is compared with the one taken once the page, colour pickers included, is ready —
     2056                        // the colour pickers set their hidden field by script, which fires no event.
     2057                        var vefmForms = $( '.vefm-style-savebar' ).closest( 'form' ).add( '.vefmpro-style-panel form' );
     2058                        var vefmSnap = [];
     2059                        $( window ).on( 'load', function () {
     2060                                vefmForms.each( function ( i ) {
     2061                                        vefmSnap[ i ] = $( this ).serialize();
     2062                                } );
     2063                        } );
     2064                        var vefmSaving = false;
     2065                        vefmForms.on( 'submit', function () {
     2066                                vefmSaving = true;
     2067                        } );
     2068                        $( window ).on( 'beforeunload', function ( e ) {
     2069                                if ( vefmSaving ) {
     2070                                        return;
     2071                                }
     2072                                var dirty = false;
     2073                                vefmForms.each( function ( i ) {
     2074                                        if ( undefined !== vefmSnap[ i ] && $( this ).serialize() !== vefmSnap[ i ] ) {
     2075                                                dirty = true;
     2076                                        }
     2077                                } );
     2078                                if ( dirty ) {
     2079                                        e.preventDefault();
     2080                                        return '';
     2081                                }
     2082                        } );
     2083                        // Direct link to a sub-tab (e.g. the old Pro Style address redirects here).
     2084                        var vefmHash = window.location.hash;
     2085                        if ( vefmHash && $( '.vefm-style-tabs a' ).filter( function () {
     2086                                return $( this ).attr( 'href' ) === vefmHash;
     2087                        } ).length ) {
     2088                                vefmShowStylePanel( vefmHash );
     2089                        }
    19942090                } );
    19952091JS;
    … …  
    24322528         * que le lien entre l’onglet et le rendu réel.
    24332529         */
    2434         private function render_diagnostic_tab() {
     2530        public function render_diagnostic_tab() {
    24352531                VEFM_Diagnostic::render();
    24362532        }
    24372533
    2438         private function render_help_tab() {
     2534        public function render_help_tab() {
    24392535                $groups = self::get_groups();
    24402536
    … …  
    26572753                        <p class="description">
    26582754                                <?php if ( class_exists( 'VEFM_Pro' ) && VEFM_Pro::is_active() ) : ?>
    2659                                         <?php echo wp_kses_post( sprintf( /* translators: %s: lien vers l'onglet Press kit (Pro) */ __( 'An optional contact form before download, download statistics, ready-made PDF templates, limited-use links, a press contact list, and additional independent kits are all available with VEFmusic Pro — see the %s tab.', 'vefmusic' ), '<a href="' . esc_url( admin_url( 'admin.php?page=vefmusic-pro-press-kit' ) ) . '">' . esc_html__( 'Press kit (Pro)', 'vefmusic' ) . '</a>' ) ); ?>
     2755                                        <?php echo wp_kses_post( sprintf( /* translators: %s: link to the VEFmusic Pro panel of the Press kit screen */ __( 'An optional contact form before download, download statistics, ready-made PDF templates, limited-use links, a press contact list, and additional independent kits are all available with VEFmusic Pro — see the %s panel of this screen.', 'vefmusic' ), '<a href="' . esc_url( admin_url( 'admin.php?page=vefmusic-press-kit#vefm-sub-press-kit-pro' ) ) . '">' . esc_html__( 'VEFmusic Pro', 'vefmusic' ) . '</a>' ) ); ?>
    26602756                                <?php else : ?>
    26612757                                        <?php esc_html_e( 'An optional contact form before download, download statistics, ready-made PDF templates, limited-use links, a press contact list, and additional independent kits are all available with VEFmusic Pro — see the About tab for details.', 'vefmusic' ); ?>
    … …  
    27202816                        <p class="description"><?php esc_html_e( 'Tracks and Albums sub-tabs: background and text colors of each track, main (accent) color, VU meter peak color, gap between tracks, padding inside each track and corner radius. A value left empty keeps the default.', 'vefmusic' ); ?></p>
    27212817                        <p class="description"><?php esc_html_e( 'Block titles (album, shows) use the theme\'s heading size and weight by default. A title size set in VEFmusic > Settings > Style replaces that size for the blocks concerned.', 'vefmusic' ); ?></p>
    2722                         <p class="description"><?php esc_html_e( 'The --vefm-accent, --vefm-font-family and --vefm-button-text-color variables set here are shared with VEFmusic Pro (cart, donations) — no need to set them twice.', 'vefmusic' ); ?></p>
     2818                        <p class="description"><?php esc_html_e( 'The --vefm-accent, --vefm-font-family, --vefm-button-bg and --vefm-button-text-color variables set here are shared with VEFmusic Pro (cart, donations) — no need to set them twice.', 'vefmusic' ); ?></p>
    27232819                        <p class="description"><?php esc_html_e( 'Button shadow (General sub-tab): one shadow for all buttons of VEFmusic and VEFmusic Pro — horizontal and vertical offset, blur, spread and color with opacity. No color chosen = no shadow, the theme\'s button style is kept. Icon-only controls (volume, lyrics, quantity) never get it. PayPal buttons are drawn by PayPal itself and can\'t receive it.', 'vefmusic' ); ?></p>
    27242820                <p class="description"><?php esc_html_e( 'For the font, two options: set it once for the whole site in VEFmusic > Settings > Style (General tab), or more finely block by block directly in Divi — every VEFmusic module has its own Design > Text tab with a real native Divi font picker (Google Fonts included), already available with nothing to configure.', 'vefmusic' ); ?></p>
    … …  
    27292825                                <li><strong><?php esc_html_e( 'Divi 5', 'vefmusic' ); ?></strong> — <?php esc_html_e( 'module\'s Advanced tab > Custom CSS, with the same variables. The show poster\'s height now adjusts automatically to the content, no setting needed.', 'vefmusic' ); ?>
    27302826                                        <ul class="vefm-list vefm-list--circle">
    2731                                                 <li><?php esc_html_e( 'Shared (all blocks)', 'vefmusic' ); ?> — <code>--vefm-accent</code>, <code>--vefm-font-family</code>, <code>--vefm-button-shadow</code>, <code>--vefm-button-text-color</code>, <code>--vefm-btn-hover-opacity</code>, <code>--vefm-btn-disabled-opacity</code></li>
     2827                                                <li><?php esc_html_e( 'Shared (all blocks)', 'vefmusic' ); ?> — <code>--vefm-accent</code>, <code>--vefm-font-family</code>, <code>--vefm-button-shadow</code>, <code>--vefm-button-bg</code>, <code>--vefm-button-text-color</code>, <code>--vefm-btn-hover-opacity</code>, <code>--vefm-btn-disabled-opacity</code></li>
    27322828                                                <li><?php esc_html_e( 'Font sizes (all blocks)', 'vefmusic' ); ?> — <code>--vefm-font-size-small</code>, <code>--vefm-font-size-normal</code>, <code>--vefm-font-size-medium</code>, <code>--vefm-font-size-large</code>, <code>--vefm-font-size-x-large</code>, <code>--vefm-font-size-xx-large</code> <?php esc_html_e( '(fallback scale, only used where the active theme doesn\'t define its own font size presets — and always for the show date badge. Shared with VEFmusic Pro).', 'vefmusic' ); ?></li>
    27332829                                                <li><?php esc_html_e( 'Tracks / Album (player) / Random Player', 'vefmusic' ); ?> — <code>--vefm-vu-peak</code>, <code>--vefm-track-bg</code>, <code>--vefm-track-text</code>, <code>--vefm-track-padding</code>, <code>--vefm-track-radius</code>, <code>--vefm-track-gap</code> <?php esc_html_e( '(Random Player has no dedicated Style tab of its own — it reuses --vefm-track-bg, --vefm-track-text and --vefm-track-padding from the Tracks sub-tab, not the others; set those to change how the Random Player looks).', 'vefmusic' ); ?></li>
  • vefmusic/trunk/includes/class-vefm-press-kit-admin.php

    r3746875 r3755228  
    7777                VEFM_Admin::render_group_tabs( 'marketing', 'vefmusic-press-kit' );
    7878
     79                // Editing an additional kit (VEFmusic Pro) takes the whole screen: no panels around it.
     80                /**
     81                 * Lets VEFmusic Pro print the whole screen (the editor of an additional kit) and return true.
     82                 *
     83                 * @param bool $printed Whether a screen was printed.
     84                 */
     85                if ( isset( $_GET['kit'] ) && apply_filters( 'vefm_press_kit_custom_page', false ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- plain navigation, nothing is saved.
     86                        echo '</div>';
     87                        return;
     88                }
     89
     90                // One screen per subject: the press kit of VEFmusic Pro is a panel of this screen.
     91                VEFM_Admin_UI::render_subpanels(
     92                        'press-kit',
     93                        array(
     94                                'free' => array(
     95                                        'label'    => 'VEFmusic',
     96                                        'callback' => array( $this, 'render_body' ),
     97                                ),
     98                        )
     99                );
     100
     101                echo '</div>';
     102        }
     103
     104        /**
     105         * Content of the press kit screen of VEFmusic (a panel of the screen).
     106         */
     107        public function render_body() {
    79108                if ( isset( $_GET['vefm_msg'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- lecture seule d'un message de confirmation, aucune action.
    80109                        $type  = isset( $_GET['vefm_msg_type'] ) && 'error' === sanitize_key( wp_unslash( $_GET['vefm_msg_type'] ) ) ? 'error' : 'success'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
    … …  
    111140                        $this->render_pro_upsell_notice();
    112141                }
    113 
    114                 echo '</div>';
    115142        }
    116143
  • vefmusic/trunk/includes/core/class-vefm-button-shadow.php

    r3726330 r3755228  
    117117                 * @param string[] $selectors CSS selectors, one button type each.
    118118                 */
    119                 $selectors = apply_filters( 'vefm_button_shadow_selectors', self::SELECTORS );
    120                 $clean     = array();
    121                 foreach ( (array) $selectors as $selector ) {
    122                         // A selector never needs braces, semicolons, at-rules or
    123                         // markup: stripping them keeps a filtered value from breaking
    124                         // out of the rule.
    125                         $selector = trim( preg_replace( '/[{};@<\\\\]/', '', wp_strip_all_tags( (string) $selector ) ) );
    126                         if ( '' !== $selector ) {
    127                                 $clean[] = $selector;
    128                         }
    129                 }
    130                 return array_values( array_unique( $clean ) );
     119                return VEFM_Button_States::clean_selectors( apply_filters( 'vefm_button_shadow_selectors', self::SELECTORS ) );
    131120        }
    132121
  • vefmusic/trunk/includes/core/class-vefm-button-states.php

    r3746875 r3755228  
    11<?php
    22/**
    3  * Global button states (hover and disabled strength).
     3 * Global button states (hover and disabled strength, hover colors).
    44 *
    55 * Every VEFmusic button shares one look (assets/css/vefm-buttons.css);
    … …  
    88 *
    99 * - hover / keyboard-focus opacity (--vefm-btn-hover-opacity);
    10  * - disabled opacity (--vefm-btn-disabled-opacity).
     10 * - disabled opacity (--vefm-btn-disabled-opacity);
     11 * - background and text color of a filled button on hover / keyboard focus
     12 *   (printed as rules, only when set, see build_css()).
    1113 *
    1214 * Plain values in, CSS out, like VEFM_Button_Shadow, so VEFmusic Pro
    … …  
    4547                'disabled' => 60,
    4648        );
     49
     50        /**
     51         * Cleans a list of selectors coming from a filter: a selector never
     52         * needs braces, semicolons, at-rules or markup, and stripping them keeps
     53         * a filtered value from breaking out of the rule.
     54         *
     55         * @param mixed $selectors Selectors, one button type each.
     56         * @return string[] Unique, cleaned selectors.
     57         */
     58        public static function clean_selectors( $selectors ) {
     59                $clean = array();
     60                foreach ( (array) $selectors as $selector ) {
     61                        $selector = trim( preg_replace( '/[{};@<\\\\]/', '', wp_strip_all_tags( (string) $selector ) ) );
     62                        if ( '' !== $selector ) {
     63                                $clean[] = $selector;
     64                        }
     65                }
     66                return array_values( array_unique( $clean ) );
     67        }
     68
     69        /**
     70         * Filled buttons, the ones that take a background and a hover color:
     71         * the Free ones plus those added by other plugins (VEFmusic Pro)
     72         * through the filter. Outlined buttons and icon-only controls are left
     73         * out: a background on hover would turn them into filled ones.
     74         *
     75         * @return string[] Cleaned selectors.
     76         */
     77        public static function get_filled_selectors() {
     78                /**
     79                 * Filters the filled buttons that receive the hover colors.
     80                 *
     81                 * @since 2.16.29
     82                 *
     83                 * @param string[] $selectors CSS selectors, one button type each.
     84                 */
     85                return self::clean_selectors( apply_filters( 'vefm_button_filled_selectors', VEFM_Button_Shadow::SELECTORS ) );
     86        }
     87
     88        /**
     89         * Sanitizes one color for printing: hex, rgb()/hsl(), var(--x) and
     90         * named colors pass, anything else (quotes, braces, semicolons) is dropped.
     91         *
     92         * @param mixed $raw Saved value.
     93         * @return string Safe color, or '' when empty.
     94         */
     95        public static function sanitize_color( $raw ) {
     96                return trim( preg_replace( '/[^#a-zA-Z0-9(),.%\s-]/', '', (string) $raw ) );
     97        }
    4798
    4899        /**
    … …  
    87138         * override the default carried by vefm-buttons.css.
    88139         *
    89          * @param array $settings Keys: hover, disabled (percent or '').
    90          * @return string CSS rule.
     140         * @param array $settings Keys: hover, disabled (percent or ''), hover_bg,
     141         *                        hover_text (color or '').
     142         * @return string CSS rules.
    91143         */
    92144        public static function build_css( array $settings ) {
    … …  
    101153                        }
    102154                }
    103                 return '' === $vars ? '' : ':root{' . $vars . '}';
     155                $css = '' === $vars ? '' : ':root{' . $vars . '}';
     156
     157                // Hover / keyboard-focus colors of the filled buttons. One rule per
     158                // selector (an invalid selector would drop a grouped rule for every
     159                // button); ":root" raises the specificity above each component's own
     160                // hover rule, so the setting wins everywhere.
     161                $declarations = '';
     162                $hover_bg     = isset( $settings['hover_bg'] ) ? self::sanitize_color( $settings['hover_bg'] ) : '';
     163                $hover_text   = isset( $settings['hover_text'] ) ? self::sanitize_color( $settings['hover_text'] ) : '';
     164                if ( '' !== $hover_bg ) {
     165                        $declarations .= 'background:' . $hover_bg . ';';
     166                }
     167                if ( '' !== $hover_text ) {
     168                        $declarations .= 'color:' . $hover_text . ';';
     169                }
     170                if ( '' !== $declarations ) {
     171                        foreach ( self::get_filled_selectors() as $selector ) {
     172                                $css .= ':root ' . $selector . ':is(:hover,:focus-visible):not(:disabled,.vefm-play--disabled){' . $declarations . '}';
     173                        }
     174                }
     175                return $css;
    104176        }
    105177
    … …  
    107179         * Reads the saved settings.
    108180         *
    109          * @return array Keys: hover, disabled.
     181         * @return array Keys: hover, disabled, hover_bg, hover_text.
    110182         */
    111183        public static function get_settings() {
    112184                return array(
    113                         'hover'    => VEFM_Settings::get( 'style_button_hover_opacity', '' ),
    114                         'disabled' => VEFM_Settings::get( 'style_button_disabled_opacity', '' ),
     185                        'hover'      => VEFM_Settings::get( 'style_button_hover_opacity', '' ),
     186                        'disabled'   => VEFM_Settings::get( 'style_button_disabled_opacity', '' ),
     187                        'hover_bg'   => VEFM_Settings::get( 'style_button_hover_bg_color', '' ),
     188                        'hover_text' => VEFM_Settings::get( 'style_button_hover_text_color', '' ),
    115189                );
    116190        }
  • vefmusic/trunk/includes/core/class-vefm-renderer.php

    r3746875 r3755228  
    200200                                'fontFamily'            => VEFM_Settings::get( 'style_font_family', '' ),
    201201                                'buttonTextColor'       => VEFM_Settings::get( 'style_button_text_color', '' ),
     202                                'buttonBgColor'         => VEFM_Settings::get( 'style_button_bg_color', '' ),
    202203                        )
    203204                );
    … …  
    408409                        // même principe accentColor ci-dessus, partagé avec Pro.
    409410                        'buttonTextColor'    => '--vefm-button-text-color',
     411                        // 2.16.29: button background (empty = main color).
     412                        'buttonBgColor'      => '--vefm-button-bg',
    410413                        'vuPeakColor'        => '--vefm-vu-peak',
    411414                        'concertBadgeColor'  => '--vefm-concert-badge',
  • vefmusic/trunk/includes/core/class-vefm-settings-transfer.php

    r3746875 r3755228  
    8686                                        // export (setting added 15/09/2026, list not updated).
    8787                                        'style_button_text_color',
     88                                        'style_button_bg_color',
     89                                        'style_button_hover_bg_color',
     90                                        'style_button_hover_text_color',
    8891                                        'style_button_shadow_color',
    8992                                        'style_button_shadow_x',
  • vefmusic/trunk/includes/core/class-vefm-settings.php

    r3746875 r3755228  
    152152                        // séparé, même principe déjà établi pour ces deux-là.
    153153                        'style_button_text_color' => '',
     154                        // 2.16.29: button background and hover colors. Empty = unchanged
     155                        // look (background follows the main color, no color change on hover).
     156                        'style_button_bg_color'         => '',
     157                        'style_button_hover_bg_color'   => '',
     158                        'style_button_hover_text_color' => '',
    154159                        // 2.15.51: global button shadow. Empty color = no
    155160                        // shadow at all (theme button styles untouched); empty
  • vefmusic/trunk/readme.txt

    r3746875 r3755228  
    66Tested up to: 7.1
    77Requires PHP: 8.3
    8 Stable tag: 2.16.27
     8Stable tag: 2.16.30
    99License: GPLv2 or later
    1010License URI: https://www.gnu.org/licenses/gpl-2.0.html
    … …  
    125125== Changelog ==
    126126
     127= 2.16.30 =
     128* New: Style: the Save button stays visible at the bottom of the screen, and leaving the page with unsaved changes asks for confirmation.
     129* Changed: Style: the button settings (colors, shadow, states) have their own "Buttons" sub-tab. Same settings, nothing is lost.
     130* Changed: Style > Buttons now says what follows your theme and what the plugin forces: a field left empty keeps the default look and the theme's own hover style; a color you set always wins.
     131* Changed: one screen per subject. Help, Diagnostics and Press kit can now carry the content of VEFmusic Pro in a second panel of the same screen, and the Pro style settings become a Style sub-tab. Without Pro, nothing changes.
     132
     133= 2.16.29 =
     134* New: Style > General > Button colors. Set the background, the text, the background on hover and the text on hover of all the buttons (VEFmusic Pro's included) to reproduce the buttons of your theme. A field left empty keeps the current look: the background follows the main color and nothing changes color on hover. The button text color setting now lives in this group.
     135* Changed: the buttons share their background and hover rules in fewer places, so the stylesheets are lighter and easier to maintain. No visual change.
     136
     137= 2.16.28 =
     138* Fix: removed redundant centering rules on the cart and "Buy the full album" buttons. No visual change.
     139
    127140= 2.16.27 =
    128141* Maintenance: code comments cleaned up. No change in behavior.
  • vefmusic/trunk/vefmusic.php

    r3746875 r3755228  
    33 * Plugin Name:       VEFmusic
    44 * Description:       Free plugin for a band’s website: audio player, album showcase, show calendar, visitor ratings, SEO structured data. Compatible with Gutenberg, Divi 5 and Elementor, no shortcode. No sales features — see VEFmusic Pro (v-images.com) to sell tracks/albums/merch, manage ticketing or accept donations.
    5  * Version:           2.16.27
     5 * Version:           2.16.30
    66 * Requires at least: 6.0
    77 * Requires PHP:      8.3
    … …  
    5555// ---------------------------------------------------------------------------
    5656
    57 define( 'VEFM_VERSION', '2.16.27' );
     57define( 'VEFM_VERSION', '2.16.30' );
    5858define( 'VEFM_PLUGIN_FILE', __FILE__ );
    5959define( 'VEFM_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
Note: See TracChangeset for help on using the changeset viewer.