Plugin Directory

Changeset 2463414


Ignore:
Timestamp:
01/27/2021 09:50:02 AM (5 years ago)
Author:
hqtheme
Message:

AJAX support for admin settings - install and activate plugins, enable options

Location:
hqtheme-extra
Files:
18 edited
1 copied

Legend:

Unmodified
Added
Removed
  • hqtheme-extra/tags/1.0.8/hqtheme-extra.php

    r2452710 r2463414  
    55 * Plugin URI:        https://marmot.hqwebs.net/marmot/?utm_source=wp-admin&utm_medium=link&utm_campaign=default&utm_term=hqtheme-extra&utm_content=plugin-uri
    66 * Description:       HQTheme Extra adds extras for Marmot Theme - Ready sites one click import
    7  * Version:           1.0.7
     7 * Version:           1.0.8
    88 * Requires at least: 5.3
    99 * Requires PHP:      7.2
     
    5757 * @var string
    5858 */
    59 const VERSION = '1.0.7';
     59const VERSION = '1.0.8';
    6060
    6161// Load Autoloader
  • hqtheme-extra/tags/1.0.8/inc/hqlib/assets/css/style.css

    r2404450 r2463414  
    154154}
    155155
     156/* HQT FORM SUBMIT LOADER */
     157.hqt-form.loading .hqt-container-body:before {
     158    content: "";
     159    display: block;
     160    position: absolute;
     161    top: 0;
     162    left: 0;
     163    right: 0;
     164    bottom: 0;
     165    z-index: 99;
     166    background: rgba(255,255,255,0.4);
     167}
     168
     169/* HQT ACTION BUTTON LOADER */
     170.hqt-btn-loader {
     171    display: none;
     172    position: relative;
     173    margin-left: 5px;
     174    width: 30px;
     175    height: 16px;
     176    background: none;
     177    vertical-align: text-top;
     178}
     179a[data-action].loading,
     180.btn.loading,
     181.hqt-form.loading .btn-hqt-container[type="submit"] {
     182    pointer-events: auto! important;
     183    cursor: not-allowed! important;
     184}
     185a[data-action].loading .hqt-btn-loader,
     186.btn.loading .hqt-btn-loader,
     187.hqt-form.loading .btn-hqt-container[type="submit"] .hqt-btn-loader {
     188    display: inline-block;
     189}
     190.hqt-btn-loader span {
     191    position: absolute;
     192    top: 7px;
     193    width: 6px;
     194    height: 6px;
     195    border-radius: 50%;
     196    background: #fff;
     197    animation-timing-function: cubic-bezier(0, 1, 1, 0);
     198}
     199.hqt-btn-loader span:nth-child(1) {
     200    left: 0px;
     201    animation: hqt-ellipsis-1 0.6s infinite;
     202}
     203.hqt-btn-loader span:nth-child(2) {
     204    left: 0px;
     205    animation: hqt-ellipsis-2 0.6s infinite;
     206}
     207.hqt-btn-loader span:nth-child(3) {
     208    left: 10px;
     209    animation: hqt-ellipsis-2 0.6s infinite;
     210}
     211.hqt-btn-loader span:nth-child(4) {
     212    left: 20px;
     213    animation: hqt-ellipsis-3 0.6s infinite;
     214}
     215@keyframes hqt-ellipsis-1 {
     216    0% {transform: scale(0);}
     217    100% {transform: scale(1);}
     218}
     219@keyframes hqt-ellipsis-2 {
     220    0% {transform: translate(0, 0);}
     221    100% {transform: translate(10px, 0);}
     222}
     223@keyframes hqt-ellipsis-3 {
     224    0% {transform: scale(1);}
     225    100% {transform: scale(0);}
     226}
     227
    156228/* TABS */
    157229.hqt-tabs {
     
    289361    transition: all 0.3s ease;
    290362}
     363.hqt-container a[data-hqt-action-btn] {
     364    display: flex;
     365    flex-wrap: nowrap;
     366}
    291367.hqt-container a:hover {
    292368    color: #1f87da;
     
    295371    font-size: 16px;
    296372}
    297 
     373.hqt-container-body {
     374    position: relative;
     375}
    298376/* CONTAINER FIELDSET */
    299377.hqt-fieldset {
     
    536614    cursor: pointer;
    537615    margin: 0;
    538     line-height: 1;
     616    line-height: normal;
    539617    font-size: 14px;
    540618    text-decoration: none;
     
    9521030}
    9531031
     1032/* HQT CONTAINER NOTIFICATIONS */
     1033.hqt-ajax-notification {
     1034    position: fixed;
     1035    bottom: -999px;
     1036    left: 50%;
     1037    transform: translateX(-50%);
     1038    right: auto;
     1039    transition: all 0.3s ease;
     1040    padding: 20px 30px;
     1041    color: #fff;
     1042    display: inline-block;
     1043}
     1044.hqt-ajax-notification.show {
     1045    bottom: 30px;
     1046}
     1047.hqt-ajax-notification.__success {
     1048    background: #5cc75f;
     1049}
     1050.hqt-ajax-notification.__error {
     1051    background: #ff0048;
     1052}
     1053
     1054
    9541055/* ADMIN NOTICES*/
    9551056.hq-notice {}
  • hqtheme-extra/tags/1.0.8/inc/hqlib/assets/js/script.js

    r2404450 r2463414  
    55    var HQLib = {
    66
     7        translate: [],
     8
    79        init: function () {
     10            HQLib.translate = hqlibData.translate;
     11
    812            HQLib.initTabs();
    913            HQLib.initSelect2();
    1014            HQLib.initFieldsConditionalLogic();
    1115            HQLib.initRepeater();
    12             //HQLib.initAjaxSubmit();
     16            HQLib.initActionButtons();
     17            HQLib.initFormSubmit();
    1318            $(document).on('hqlib/container/loader/show', HQLib.showLoader);
    1419            $(document).on('hqlib/container/loader/hide', HQLib.hideLoader);
     20
     21            $(document).on('hqlib/container/saved', HQLib.toggleAjaxNotification);
    1522        },
    1623        getUrlParam: function (param, url = null) {
     
    124131            $('body').removeClass('loading-content');
    125132        },
    126         initAjaxSubmit: function () {
     133        initFormSubmit: function () {
    127134            $('.hqt-container > form.hqt-form').each(function () {
    128135                var $form = $(this);
     136
     137                // Append submit button loader
     138                $form.find('.hqt-container-footer button[type="submit"]').each(function () {
     139                    var $button = $(this);
     140                    $button.append('<span class="hqt-btn-loader"><span></span><span></span><span></span><span></span></span>');
     141                    $button.find('.hqt-btn-loader span').css('background', $button.css('color'));
     142                });
     143
    129144                $form.submit(function (e) {
    130145                    if (typeof window.FormData === 'function') {
    131                         e.preventDefault();
    132                         HQLib.formSubmit($form);
     146                        HQLib.formSubmit($form, e);
    133147                    }
    134148                });
    135             });
    136         },
    137         formSubmit: function (form) {
     149
     150                $form.on('form/loader/show', function () {
     151                    $(this).addClass('loading');
     152                })
     153                $form.on('form/loader/hide', function () {
     154                    $(this).removeClass('loading');
     155                })
     156            });
     157        },
     158        formSubmit: function (form, event) {
    138159            var $form = $(form);
     160
     161            if (true === $form.data('ajax-submit')) {
     162                // Ajax submit action
     163                event.preventDefault();
     164
     165                var formData = $form.serializeArray();
     166                formData.push({name: 'action', value: 'hqlib_save_options'});
     167
     168                $.ajax({
     169                    url: ajaxurl,
     170                    type: 'POST',
     171                    dataType: 'json',
     172                    data: formData,
     173                    beforeSend: function () {
     174                        $form.trigger('form/loader/show');
     175                    }
     176                }).complete(function (jqXHR) {
     177                    $form.trigger('form/loader/hide');
     178                }).fail(function (jqXHR) {
     179                    $(document).trigger('hqlib/container/saved', ['Error while saving settings. Please try again.', 2]);
     180                }).done(function (result) {
     181                    if (result.success) {
     182                        $(document).trigger('hqlib/container/saved');
     183                    } else {
     184                        $(document).trigger('hqlib/container/saved', ['Error while saving settings. Please try again.', 2]);
     185                    }
     186                });
     187            } else {
     188                // Just show loader
     189                $form.trigger('form/loader/show');
     190            }
     191        },
     192        initActionButtons: function () {
     193            // Install / Activate plugins
     194            $('[data-hqt-action-btn]').each(function (i, el) {
     195                var $button = $(this);
     196                var action = $button.data('action');
     197
     198                // Change button text
     199                if ($button.data('action-label')) {
     200                    var label = $button.html(), actionLabel;
     201
     202                    if ('install-activate' == action) {
     203                        if ($button.data('install-url').length) {
     204                            actionLabel = HQLib._('install');
     205                        } else {
     206                            actionLabel = HQLib._('activate');
     207                        }
     208                    } else if ('enable' == action) {
     209                        actionLabel = HQLib._('enable');
     210                    }
     211
     212                    switch ($button.data('action-label')) {
     213                        case 'prepend':
     214                            $button.html(actionLabel + ' ' + label);
     215                            break;
     216                        case 'replace':
     217                            $button.html(actionLabel);
     218                            break;
     219                    }
     220                }
     221                // Wrap button text in span tag
     222                if (!$button.find('.btn-label').length) {
     223                    $button.wrapInner('<span class="btn-label"></span>');
     224
     225                    // Append some html for ajax spinner on button only elements
     226                    if (!$button.find('.hqt-btn-loader').length) {
     227                        $button.append('<span class="hqt-btn-loader"><span></span><span></span><span></span><span></span></span>');
     228                        $button.find('.hqt-btn-loader span').css('background', $button.css('color'));
     229                    }
     230                }
     231
     232                // Bind button click event
     233                HQLib.bindActionButton($button);
     234            });
     235        },
     236        bindActionButton: function (button) {
     237            var $button = $(button);
     238            $button.off('click');
     239            $button.on('click', function (e) {
     240                e.preventDefault();
     241                var $this = $(this);
     242
     243                if ($this.hasClass('loading')) {
     244                    return false;
     245                }
     246
     247                switch ($this.data('action')) {
     248                    case 'install-activate':
     249                        if ($this.data('install-url').length) {
     250                            // Install if plugin is missing
     251                            HQLib.installPluginByBtn($this);
     252                        } else {
     253                            // Activate if plugin is installed
     254                            HQLib.activatePluginByBtn($this);
     255                        }
     256                        break;
     257                    case 'enable':
     258                        // Enable option
     259                        HQLib.enableOptionByBtn($this);
     260                        break;
     261                }
     262            });
     263
     264            // Bind show/hide button loader
     265            $button.on('loader/show', function () {
     266                $(this).addClass('loading');
     267            });
     268            $button.on('loader/hide', function () {
     269                $(this).removeClass('loading');
     270                HQLib.bindActionButton($(this));
     271            });
     272        },
     273        installPluginByBtn: function (button) {
     274            var $button = $(button);
     275
     276            if (!$button.data('install-url').length) {
     277                return false;
     278            }
     279
     280            $.ajax({
     281                url: $button.data('install-url'),
     282                type: 'GET',
     283                beforeSend: function (xhr) {
     284                    $button.trigger('loader/show');
     285                    $button.find('.btn-label').html(HQLib._('installing'));
     286                }
     287            }).complete(function (jqXHR) {
     288                $button.trigger('loader/hide');
     289            }).fail(function (jqXHR) {
     290                $button.find('.btn-label').html(HQLib._('install'));
     291                alert('Plugin installation fail. Please try again.');
     292            }).done(function (result) {
     293                // Display notification
     294                $(document).trigger('hqlib/container/saved', ['Plugin successfully installed.']);
     295                // Set `Activate` button
     296                $button.find('.btn-label').html(HQLib._('activate'));
     297                $button.data('install-url', '');
     298                HQLib.bindActionButton($button);
     299            });
     300        },
     301        activatePluginByBtn: function (button) {
     302            var $button = $(button);
     303
     304            if (!$button.data('activate-url').length) {
     305                return false;
     306            }
     307
     308            $.ajax({
     309                url: $button.data('activate-url'),
     310                type: 'GET',
     311                beforeSend: function (xhr) {
     312                    $button.trigger('loader/show');
     313                    $button.find('.btn-label').html(HQLib._('activating'));
     314                }
     315            }).complete(function (jqXHR) {
     316                $button.trigger('loader/hide');
     317            }).fail(function (jqXHR) {
     318                $(document).trigger('hqlib/container/saved', ['Plugin activation fail. Please try again.', 2]);
     319            }).done(function (result) {
     320                HQLib.buttonCallbackAction($button);
     321            });
     322        },
     323        enableOptionByBtn: function (button) {
     324            var $button = $(button);
     325            var $form = $button.closest('form');
    139326            var formData = $form.serializeArray();
    140             formData.push({name: 'action', value: 'hqlib_save_options'});
     327            var [container, option] = $button.data('option');
     328            var data = [];
     329
     330            data.push({name: 'hqt-container[' + HQLib.addHqlibPrefix(container) + ']', value: HQLib.addHqlibPrefix(container)});
     331            data.push({name: HQLib.addHqlibPrefix(option), value: 'on'});
     332            data.push({name: 'action', value: 'hqlib_save_options'});
     333            data.push(formData.filter(x => x.name === 'hqt_options_nonce')[0]);
    141334
    142335            $.ajax({
     
    144337                type: 'POST',
    145338                dataType: 'json',
    146                 data: formData,
    147                 beforeSend: function () {}
     339                data: data,
     340                beforeSend: function () {
     341                    $button.trigger('loader/show');
     342                    $button.find('.btn-label').html(HQLib._('enabling'));
     343                }
     344            }).complete(function (jqXHR) {
     345                $button.trigger('loader/hide');
    148346            }).fail(function (jqXHR) {
    149                 console.log(jqXHR);
     347                $(document).trigger('hqlib/container/saved', ['Error occurred. Please try again later.', 2]);
    150348            }).done(function (result) {
    151                 console.log(result);
    152             });
     349                if (result.success) {
     350                    $button.find('.btn-label').html(HQLib._('enabled'));
     351                }
     352                HQLib.buttonCallbackAction($button);
     353            });
     354
     355        },
     356        buttonCallbackAction: function (button) {
     357            var $button = $(button);
     358            if (!$button.data('callback').length) {
     359                return false;
     360            }
     361            switch ($button.data('callback')) {
     362                case 'refresh-page':
     363                    location.reload();
     364                    break;
     365                case 'label-activated':
     366                    $button.replaceWith(HQLib._('activated'));
     367                    break;
     368                case 'hide':
     369                    $button.fadeOut();
     370            }
     371        },
     372        addHqlibPrefix: function (name) {
     373            if (!name.match("^" + hqlibData.hqlib_prefix)) {
     374                name = hqlibData.hqlib_prefix + name;
     375            }
     376            return name;
     377        },
     378        toggleAjaxNotification: function (e, message = 'Settings saved successfully!', status) {
     379            // TODO improve if multiple notifications comes
     380            var type = 'success';
     381            if ('undefined' !== typeof status) {
     382                switch (parseInt(status)) {
     383                    case 1:
     384                        type = 'success';
     385                        break;
     386                    case 2:
     387                        type = 'error';
     388                        break;
     389                }
     390            }
     391            var notification = $('<div class="hqt-ajax-notification __' + type + '">' + message + '</div>');
     392            $('body').append(notification);
     393           
     394            // Add class for transition effect
     395            setTimeout(function () {
     396                notification.addClass('show');
     397            }, 1);
     398           
     399            setTimeout(function () {
     400                notification.fadeOut(function () {
     401                    $(this).remove();
     402                });
     403            }, 2000);
     404        },
     405        _: function (key) {
     406            if (HQLib.translate[key].length) {
     407                return HQLib.translate[key];
     408            }
     409            return false;
    153410        }
    154411    };
  • hqtheme-extra/tags/1.0.8/inc/hqlib/helper.php

    r2452710 r2463414  
    281281            $license_check = true;
    282282        }
    283         if (null != $check_license) {
     283        if (null !== $check_license) {
    284284            $license_check = boolval($check_license);
    285285        }
    286 
    287286        if ($license_check && !\HQLib\License::is_activated()) {
    288287            $response->success = false;
     
    300299                if ('plugin' == $require['type']) {
    301300                    if (!empty($require['plugin_file']) && !is_plugin_active($require['plugin_file'])) {
     301                        $install_url = '';
     302                        $activate_url = wp_nonce_url('plugins.php?action=activate&amp;plugin=' . $require['plugin_file'] . '&amp;plugin_status=all&amp;paged=1&amp;s', 'activate-plugin_' . $require['plugin_file']);
    302303                        if (is_plugin_installed($require['plugin_file'])) {
    303304                            // Activate
    304305                            $btn_label = _x('Activate', 'admin', 'hqtheme-extra');
    305                             $btn_url = wp_nonce_url('plugins.php?action=activate&amp;plugin=' . $require['plugin_file'] . '&amp;plugin_status=all&amp;paged=1&amp;s', 'activate-plugin_' . $require['plugin_file']);
    306306                        } else {
    307307                            // Install
    308308                            $btn_label = _x('Install', 'admin', 'hqtheme-extra');
    309                             $btn_url = wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=' . $require['plugin_name']), 'install-plugin_' . $require['plugin_name']);
     309                            $install_url = wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=' . $require['plugin_name']), 'install-plugin_' . $require['plugin_name']);
    310310                        }
    311311                        $response->success = false;
     
    315315                            <div class="text-italic text-brighter"><?php echo sprintf($require['label'] . ' %s', _x('plugin is missing', 'admin', 'hqtheme-extra')); ?></div>
    316316                            <div class="ml-2">
    317                                 <a href="<?php echo $btn_url; ?>"><?php echo $btn_label; ?></a>
     317                                <a href="#"
     318                                   data-hqt-action-btn
     319                                   data-action="install-activate"
     320                                   data-install-url="<?php echo esc_attr($install_url); ?>"
     321                                   data-activate-url="<?php echo esc_attr($activate_url); ?>"
     322                                   data-callback="refresh-page">
     323                                       <?php echo $btn_label; ?>
     324                                </a>
    318325                            </div>
    319326                        </div>
     
    357364                        <div class="pt-1 d-flex justify-content-justify">
    358365                            <div class="text-italic text-brighter"><?php echo sprintf($require['label'] . ' %s', _x('module is disabled', 'admin', 'hqtheme-extra')); ?></div>
    359                             <?php if (!empty($require['link'])) : ?>
     366                            <?php if (self::can_module_be_active($require['module'])) : ?>
    360367                                <div class="ml-2">
    361                                     <a href="<?php echo esc_url(admin_url($require['link'])); ?>">Settings</a>
     368                                    <a href="#"
     369                                       data-hqt-action-btn
     370                                       data-action="enable"
     371                                       data-option="<?php echo esc_attr(json_encode($require['option'])); ?>"
     372                                       data-callback="refresh-page">
     373                                           <?php _ex('Enable', 'admin', 'hqtheme-extra'); ?>
     374                                    </a>
     375                                </div>
     376                            <?php elseif (!empty($require['link'])) : ?>
     377                                <div class="ml-2">
     378                                    <a href="<?php echo esc_url(admin_url($require['link'])); ?>"><?php _ex('Settings', 'admin', 'hqtheme-extra'); ?></a>
    362379                                </div>
    363380                            <?php endif; ?>
     
    405422        $module_data = self::get_module_data($module_id);
    406423
    407         if (!\HQLib\Helper::field_requires_check($module_data)->success) {
     424        if (!\HQLib\Helper::can_module_be_active($module_id, $module_data)) {
    408425            return false;
    409426        }
     
    421438
    422439    /**
     440     * Check if theme module pass the requirements
     441     * @param string $module_id
     442     * @param array $module_data
     443     * @return boolean
     444     */
     445    public static function can_module_be_active($module_id, $module_data = null) {
     446        if (null === $module_data) {
     447            $module_data = self::get_module_data($module_id);
     448        }
     449        if ($module_data) {
     450            return \HQLib\Helper::field_requires_check($module_data, false)->success;
     451        }
     452        return false;
     453    }
     454
     455    /**
    423456     * Get widget config data
    424457     * @param string $widget_id
  • hqtheme-extra/tags/1.0.8/inc/hqlib/hqlib.php

    r2404450 r2463414  
    6363        $data = [
    6464            '_ajax_nonce' => wp_create_nonce('hq-lib'),
     65            'hqlib_prefix' => HQLIB_PREFIX,
     66            'translate' => $this->getHqlibDataTranslate(),
    6567        ];
    6668        wp_localize_script('hqlib-script', 'hqlibData', $data);
     
    108110    }
    109111
     112    public function getHqlibDataTranslate() {
     113        return [
     114            'activate' => _x('Activate', 'admin', 'hqtheme-extra'),
     115            'activating' => _x('Activating', 'admin', 'hqtheme-extra'),
     116            'activated' => _x('Activated', 'admin', 'hqtheme-extra'),
     117            'install' => _x('Install', 'admin', 'hqtheme-extra'),
     118            'installing' => _x('Installing', 'admin', 'hqtheme-extra'),
     119            'enable' => _x('Enable', 'admin', 'hqtheme-extra'),
     120            'enabling' => _x('Enabling', 'admin', 'hqtheme-extra'),
     121            'enabled' => _x('Enabled', 'admin', 'hqtheme-extra'),
     122        ];
     123    }
     124
    110125}
    111126
  • hqtheme-extra/tags/1.0.8/inc/hqlib/meta.php

    r2387736 r2463414  
    143143            <?php endif; ?>
    144144            <input type="hidden" name="hqt-metabox[<?php echo $callback['id']; ?>]" value="<?php echo esc_attr($callback['id']); ?>">
    145             <div class="hqt-container__fields my-2">
     145            <div class="hqt-container__fields m-0 mt-2">
    146146                <?php foreach ($container->get_fields() as $field) : ?>
    147147                    <?php $field->render_clearfix(['left', 'both']); ?>
  • hqtheme-extra/tags/1.0.8/inc/hqlib/options.php

    r2430987 r2463414  
    1717        $containerClasses = array_merge(['hqt-container'], (array) apply_filters('hqt/container/' . $container_key . '/classes', []));
    1818        ?>
    19         <div class="<?php echo implode(' ', $containerClasses); ?>">
     19        <div id="hqt-container-<?php echo $container->get_container_name(true); ?>" class="<?php echo implode(' ', $containerClasses); ?>">
    2020            <?php if ($container->is_submitable()) : ?>
    21                 <form class="hqt-form" method="post">
     21            <form class="hqt-form" method="post" data-ajax-submit="<?php echo $container->get_ajax_submit() ? 'true' : 'false'; ?>">
    2222                    <?php
    2323                    wp_nonce_field(\HQLib\HQLIB_PREFIX . 'options_nonce', 'hqt_options_nonce');
     
    6666
    6767    private static function render_container($container) {
    68         $container->render_title();
    69         ?>
    70         <div class="hqt-container__fields">
     68        ?>
     69        <div class="hqt-container-body">
    7170            <?php
    72             $group = $container->is_grouped_options() ? $container->get_container_name() : '';
    73             $storage = $container->get_storage();
    74             foreach ($container->get_fields() as $field) :
    75                 \HQLib\Options::render_field($field, $storage, $group);
    76             endforeach;
     71            $container->render_title();
    7772            ?>
     73            <div class="hqt-container__fields">
     74                <?php
     75                $group = $container->is_grouped_options() ? $container->get_container_name() : '';
     76                $storage = $container->get_storage();
     77                foreach ($container->get_fields() as $field) :
     78                    \HQLib\Options::render_field($field, $storage, $group);
     79                endforeach;
     80                ?>
     81            </div>
    7882        </div>
    7983        <?php
     
    8690        }
    8791        ?>
    88         <div class="hqt-tabs hqt-tabs-<?php echo $tabs->get_layout(); ?>">
     92        <div id="hqt-tabs-<?php echo $tabs->get_id(); ?>" class="hqt-tabs hqt-tabs-<?php echo $tabs->get_layout(); ?>">
    8993            <ul class="hqt-tabs-nav">
    9094                <?php
     
    119123                    ?>
    120124                    <div class="<?php echo join(' ', $classes); ?>" id="<?php echo $tab_key; ?>">
    121                         <?php
    122                         \HQLib\Options::display_container($tab_key);
    123                         ?>
     125                        <?php \HQLib\Options::display_container($tab_key); ?>
    124126                    </div>
    125127                    <?php
     
    211213            return;
    212214        }
    213 
    214215        foreach ($_POST['hqt-container'] as $container_key) {
    215216            $container_key = sanitize_key($container_key);
    216             if ($container = Options\Container::get($container_key)) {
    217 
    218                 $group = $container->is_grouped_options() ? $container->get_container_name() : '';
    219 
    220                 if (empty($group)) {
    221                     foreach ($container->get_fields() as $field) {
    222                         if (!$field->is_storable()) {
    223                             continue;
    224                         }
    225                         if (isset($_POST[$field->get_field_name()])) {
    226                             if (is_array($_POST[$field->get_field_name()])) {
    227                                 $data = filter_var_array($_POST[$field->get_field_name()], FILTER_SANITIZE_STRING);
    228                             } else {
    229                                 $data = sanitize_text_field($_POST[$field->get_field_name()]);
    230                             }
    231                             if ('options' === $container->get_storage()) {
    232                                 update_option($field->get_field_name(), $data, $field->is_autoload());
    233                             } else if ('theme_mods' === $container->get_storage()) {
    234                                 set_theme_mod($field->get_field_name(), $data);
    235                             }
    236                         }
    237                     }
    238                 } else {
    239                     $data = [];
    240                     foreach ($container->get_fields() as $field) {
    241                         if (!$field->is_storable()) {
    242                             continue;
    243                         }
    244                         if (isset($_POST[$field->get_field_name()])) {
    245                             if (is_array($_POST[$field->get_field_name()])) {
    246                                 $data[$field->get_field_name(true)] = filter_var_array($_POST[$field->get_field_name()], FILTER_SANITIZE_STRING);
    247                             } else {
    248                                 $data[$field->get_field_name(true)] = sanitize_text_field($_POST[$field->get_field_name()]);
    249                             }
    250                         }
    251                     }
    252                     if (count($data)) {
     217
     218            if (!$container = Options\Container::get($container_key)) {
     219                wp_send_json_error(_x('Options container not found', 'save options', 'hqtheme-extra'));
     220            }
     221            $group = $container->is_grouped_options() ? $container->get_container_name() : '';
     222
     223            if (empty($group)) {
     224                foreach ($container->get_fields() as $field) {
     225                    if (!$field->is_storable()) {
     226                        continue;
     227                    }
     228                    if (isset($_POST[$field->get_field_name()])) {
     229                        if (is_array($_POST[$field->get_field_name()])) {
     230                            $data = filter_var_array($_POST[$field->get_field_name()], FILTER_SANITIZE_STRING);
     231                        } else {
     232                            $data = sanitize_text_field($_POST[$field->get_field_name()]);
     233                        }
    253234                        if ('options' === $container->get_storage()) {
    254                             update_option($group, $data, $container->is_autoload());
     235                            update_option($field->get_field_name(), $data, $field->is_autoload());
    255236                        } else if ('theme_mods' === $container->get_storage()) {
    256                             set_theme_mod($group, $data);
    257                         }
    258                     }
    259                 }
    260             }
    261         }
    262 
    263         add_action('admin_print_footer_scripts', 'HQLib\Options::admin_print_scripts');
     237                            set_theme_mod($field->get_field_name(), $data);
     238                        }
     239                    }
     240                }
     241            } else {
     242                // Get saved group options if available
     243                $group_options = \HQLib\hq_get_option(\HQLib\Helper::remove_hqlib_prefix($group));
     244                $data = [];
     245               
     246                // Get submitted options
     247                foreach ($container->get_fields() as $field) {
     248                    if (!$field->is_storable()) {
     249                        continue;
     250                    }
     251                    if (isset($_POST[$field->get_field_name()])) {
     252                        if (is_array($_POST[$field->get_field_name()])) {
     253                            $data[$field->get_field_name(true)] = filter_var_array($_POST[$field->get_field_name()], FILTER_SANITIZE_STRING);
     254                        } else {
     255                            $data[$field->get_field_name(true)] = sanitize_text_field($_POST[$field->get_field_name()]);
     256                        }
     257                    }
     258                }
     259               
     260                // Merge submitted options into saved array
     261                $data = wp_parse_args($data, $group_options);
     262                if (count($data)) {
     263                    if ('options' === $container->get_storage()) {
     264                        update_option($group, $data, $container->is_autoload());
     265                    } else if ('theme_mods' === $container->get_storage()) {
     266                        set_theme_mod($group, $data);
     267                    }
     268                }
     269            }
     270        }
     271        if (!wp_doing_ajax()) {
     272            add_action('admin_print_footer_scripts', 'HQLib\Options::admin_print_scripts');
     273        } else {
     274            wp_send_json_success();
     275        }
    264276    }
    265277
  • hqtheme-extra/tags/1.0.8/inc/hqlib/options/container.php

    r2430987 r2463414  
    3434     */
    3535    protected $disable_submit = false;
     36   
     37    /**
     38     *
     39     * @var boolean
     40     */
     41    protected $ajax_submit = false;
    3642
    3743    /**
     
    243249    public function is_submitable() {
    244250        return !$this->disable_submit;
     251    }
     252   
     253    public function set_ajax_submit($ajax = true) {
     254        $this->ajax_submit = $ajax;
     255        return $this;
     256    }
     257   
     258    public function get_ajax_submit() {
     259        return $this->ajax_submit;
    245260    }
    246261
  • hqtheme-extra/tags/1.0.8/readme.txt

    r2452710 r2463414  
    55Tested up to: 5.5
    66Requires PHP: 7.2
    7 Stable tag: 1.0.7
     7Stable tag: 1.0.8
    88License: GPL v2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    4949== Changelog ==
    5050
    51 = 1.0.7 - 2021-01-08- =
     51= 1.0.8 - 2021-01-27 =
     52* AJAX support for admin settings - install and activate plugins, enable options
     53
     54= 1.0.7 - 2021-01-08 =
    5255* Theme setup wizard improvements
    5356* Escape admin_url
    5457
    55 = 1.0.6 - 2020-12-03- =
     58= 1.0.6 - 2020-12-03 =
    5659* Marmot theme options added
    5760* Theme setup wizard improvements
  • hqtheme-extra/trunk/hqtheme-extra.php

    r2452710 r2463414  
    55 * Plugin URI:        https://marmot.hqwebs.net/marmot/?utm_source=wp-admin&utm_medium=link&utm_campaign=default&utm_term=hqtheme-extra&utm_content=plugin-uri
    66 * Description:       HQTheme Extra adds extras for Marmot Theme - Ready sites one click import
    7  * Version:           1.0.7
     7 * Version:           1.0.8
    88 * Requires at least: 5.3
    99 * Requires PHP:      7.2
     
    5757 * @var string
    5858 */
    59 const VERSION = '1.0.7';
     59const VERSION = '1.0.8';
    6060
    6161// Load Autoloader
  • hqtheme-extra/trunk/inc/hqlib/assets/css/style.css

    r2404450 r2463414  
    154154}
    155155
     156/* HQT FORM SUBMIT LOADER */
     157.hqt-form.loading .hqt-container-body:before {
     158    content: "";
     159    display: block;
     160    position: absolute;
     161    top: 0;
     162    left: 0;
     163    right: 0;
     164    bottom: 0;
     165    z-index: 99;
     166    background: rgba(255,255,255,0.4);
     167}
     168
     169/* HQT ACTION BUTTON LOADER */
     170.hqt-btn-loader {
     171    display: none;
     172    position: relative;
     173    margin-left: 5px;
     174    width: 30px;
     175    height: 16px;
     176    background: none;
     177    vertical-align: text-top;
     178}
     179a[data-action].loading,
     180.btn.loading,
     181.hqt-form.loading .btn-hqt-container[type="submit"] {
     182    pointer-events: auto! important;
     183    cursor: not-allowed! important;
     184}
     185a[data-action].loading .hqt-btn-loader,
     186.btn.loading .hqt-btn-loader,
     187.hqt-form.loading .btn-hqt-container[type="submit"] .hqt-btn-loader {
     188    display: inline-block;
     189}
     190.hqt-btn-loader span {
     191    position: absolute;
     192    top: 7px;
     193    width: 6px;
     194    height: 6px;
     195    border-radius: 50%;
     196    background: #fff;
     197    animation-timing-function: cubic-bezier(0, 1, 1, 0);
     198}
     199.hqt-btn-loader span:nth-child(1) {
     200    left: 0px;
     201    animation: hqt-ellipsis-1 0.6s infinite;
     202}
     203.hqt-btn-loader span:nth-child(2) {
     204    left: 0px;
     205    animation: hqt-ellipsis-2 0.6s infinite;
     206}
     207.hqt-btn-loader span:nth-child(3) {
     208    left: 10px;
     209    animation: hqt-ellipsis-2 0.6s infinite;
     210}
     211.hqt-btn-loader span:nth-child(4) {
     212    left: 20px;
     213    animation: hqt-ellipsis-3 0.6s infinite;
     214}
     215@keyframes hqt-ellipsis-1 {
     216    0% {transform: scale(0);}
     217    100% {transform: scale(1);}
     218}
     219@keyframes hqt-ellipsis-2 {
     220    0% {transform: translate(0, 0);}
     221    100% {transform: translate(10px, 0);}
     222}
     223@keyframes hqt-ellipsis-3 {
     224    0% {transform: scale(1);}
     225    100% {transform: scale(0);}
     226}
     227
    156228/* TABS */
    157229.hqt-tabs {
     
    289361    transition: all 0.3s ease;
    290362}
     363.hqt-container a[data-hqt-action-btn] {
     364    display: flex;
     365    flex-wrap: nowrap;
     366}
    291367.hqt-container a:hover {
    292368    color: #1f87da;
     
    295371    font-size: 16px;
    296372}
    297 
     373.hqt-container-body {
     374    position: relative;
     375}
    298376/* CONTAINER FIELDSET */
    299377.hqt-fieldset {
     
    536614    cursor: pointer;
    537615    margin: 0;
    538     line-height: 1;
     616    line-height: normal;
    539617    font-size: 14px;
    540618    text-decoration: none;
     
    9521030}
    9531031
     1032/* HQT CONTAINER NOTIFICATIONS */
     1033.hqt-ajax-notification {
     1034    position: fixed;
     1035    bottom: -999px;
     1036    left: 50%;
     1037    transform: translateX(-50%);
     1038    right: auto;
     1039    transition: all 0.3s ease;
     1040    padding: 20px 30px;
     1041    color: #fff;
     1042    display: inline-block;
     1043}
     1044.hqt-ajax-notification.show {
     1045    bottom: 30px;
     1046}
     1047.hqt-ajax-notification.__success {
     1048    background: #5cc75f;
     1049}
     1050.hqt-ajax-notification.__error {
     1051    background: #ff0048;
     1052}
     1053
     1054
    9541055/* ADMIN NOTICES*/
    9551056.hq-notice {}
  • hqtheme-extra/trunk/inc/hqlib/assets/js/script.js

    r2404450 r2463414  
    55    var HQLib = {
    66
     7        translate: [],
     8
    79        init: function () {
     10            HQLib.translate = hqlibData.translate;
     11
    812            HQLib.initTabs();
    913            HQLib.initSelect2();
    1014            HQLib.initFieldsConditionalLogic();
    1115            HQLib.initRepeater();
    12             //HQLib.initAjaxSubmit();
     16            HQLib.initActionButtons();
     17            HQLib.initFormSubmit();
    1318            $(document).on('hqlib/container/loader/show', HQLib.showLoader);
    1419            $(document).on('hqlib/container/loader/hide', HQLib.hideLoader);
     20
     21            $(document).on('hqlib/container/saved', HQLib.toggleAjaxNotification);
    1522        },
    1623        getUrlParam: function (param, url = null) {
     
    124131            $('body').removeClass('loading-content');
    125132        },
    126         initAjaxSubmit: function () {
     133        initFormSubmit: function () {
    127134            $('.hqt-container > form.hqt-form').each(function () {
    128135                var $form = $(this);
     136
     137                // Append submit button loader
     138                $form.find('.hqt-container-footer button[type="submit"]').each(function () {
     139                    var $button = $(this);
     140                    $button.append('<span class="hqt-btn-loader"><span></span><span></span><span></span><span></span></span>');
     141                    $button.find('.hqt-btn-loader span').css('background', $button.css('color'));
     142                });
     143
    129144                $form.submit(function (e) {
    130145                    if (typeof window.FormData === 'function') {
    131                         e.preventDefault();
    132                         HQLib.formSubmit($form);
     146                        HQLib.formSubmit($form, e);
    133147                    }
    134148                });
    135             });
    136         },
    137         formSubmit: function (form) {
     149
     150                $form.on('form/loader/show', function () {
     151                    $(this).addClass('loading');
     152                })
     153                $form.on('form/loader/hide', function () {
     154                    $(this).removeClass('loading');
     155                })
     156            });
     157        },
     158        formSubmit: function (form, event) {
    138159            var $form = $(form);
     160
     161            if (true === $form.data('ajax-submit')) {
     162                // Ajax submit action
     163                event.preventDefault();
     164
     165                var formData = $form.serializeArray();
     166                formData.push({name: 'action', value: 'hqlib_save_options'});
     167
     168                $.ajax({
     169                    url: ajaxurl,
     170                    type: 'POST',
     171                    dataType: 'json',
     172                    data: formData,
     173                    beforeSend: function () {
     174                        $form.trigger('form/loader/show');
     175                    }
     176                }).complete(function (jqXHR) {
     177                    $form.trigger('form/loader/hide');
     178                }).fail(function (jqXHR) {
     179                    $(document).trigger('hqlib/container/saved', ['Error while saving settings. Please try again.', 2]);
     180                }).done(function (result) {
     181                    if (result.success) {
     182                        $(document).trigger('hqlib/container/saved');
     183                    } else {
     184                        $(document).trigger('hqlib/container/saved', ['Error while saving settings. Please try again.', 2]);
     185                    }
     186                });
     187            } else {
     188                // Just show loader
     189                $form.trigger('form/loader/show');
     190            }
     191        },
     192        initActionButtons: function () {
     193            // Install / Activate plugins
     194            $('[data-hqt-action-btn]').each(function (i, el) {
     195                var $button = $(this);
     196                var action = $button.data('action');
     197
     198                // Change button text
     199                if ($button.data('action-label')) {
     200                    var label = $button.html(), actionLabel;
     201
     202                    if ('install-activate' == action) {
     203                        if ($button.data('install-url').length) {
     204                            actionLabel = HQLib._('install');
     205                        } else {
     206                            actionLabel = HQLib._('activate');
     207                        }
     208                    } else if ('enable' == action) {
     209                        actionLabel = HQLib._('enable');
     210                    }
     211
     212                    switch ($button.data('action-label')) {
     213                        case 'prepend':
     214                            $button.html(actionLabel + ' ' + label);
     215                            break;
     216                        case 'replace':
     217                            $button.html(actionLabel);
     218                            break;
     219                    }
     220                }
     221                // Wrap button text in span tag
     222                if (!$button.find('.btn-label').length) {
     223                    $button.wrapInner('<span class="btn-label"></span>');
     224
     225                    // Append some html for ajax spinner on button only elements
     226                    if (!$button.find('.hqt-btn-loader').length) {
     227                        $button.append('<span class="hqt-btn-loader"><span></span><span></span><span></span><span></span></span>');
     228                        $button.find('.hqt-btn-loader span').css('background', $button.css('color'));
     229                    }
     230                }
     231
     232                // Bind button click event
     233                HQLib.bindActionButton($button);
     234            });
     235        },
     236        bindActionButton: function (button) {
     237            var $button = $(button);
     238            $button.off('click');
     239            $button.on('click', function (e) {
     240                e.preventDefault();
     241                var $this = $(this);
     242
     243                if ($this.hasClass('loading')) {
     244                    return false;
     245                }
     246
     247                switch ($this.data('action')) {
     248                    case 'install-activate':
     249                        if ($this.data('install-url').length) {
     250                            // Install if plugin is missing
     251                            HQLib.installPluginByBtn($this);
     252                        } else {
     253                            // Activate if plugin is installed
     254                            HQLib.activatePluginByBtn($this);
     255                        }
     256                        break;
     257                    case 'enable':
     258                        // Enable option
     259                        HQLib.enableOptionByBtn($this);
     260                        break;
     261                }
     262            });
     263
     264            // Bind show/hide button loader
     265            $button.on('loader/show', function () {
     266                $(this).addClass('loading');
     267            });
     268            $button.on('loader/hide', function () {
     269                $(this).removeClass('loading');
     270                HQLib.bindActionButton($(this));
     271            });
     272        },
     273        installPluginByBtn: function (button) {
     274            var $button = $(button);
     275
     276            if (!$button.data('install-url').length) {
     277                return false;
     278            }
     279
     280            $.ajax({
     281                url: $button.data('install-url'),
     282                type: 'GET',
     283                beforeSend: function (xhr) {
     284                    $button.trigger('loader/show');
     285                    $button.find('.btn-label').html(HQLib._('installing'));
     286                }
     287            }).complete(function (jqXHR) {
     288                $button.trigger('loader/hide');
     289            }).fail(function (jqXHR) {
     290                $button.find('.btn-label').html(HQLib._('install'));
     291                alert('Plugin installation fail. Please try again.');
     292            }).done(function (result) {
     293                // Display notification
     294                $(document).trigger('hqlib/container/saved', ['Plugin successfully installed.']);
     295                // Set `Activate` button
     296                $button.find('.btn-label').html(HQLib._('activate'));
     297                $button.data('install-url', '');
     298                HQLib.bindActionButton($button);
     299            });
     300        },
     301        activatePluginByBtn: function (button) {
     302            var $button = $(button);
     303
     304            if (!$button.data('activate-url').length) {
     305                return false;
     306            }
     307
     308            $.ajax({
     309                url: $button.data('activate-url'),
     310                type: 'GET',
     311                beforeSend: function (xhr) {
     312                    $button.trigger('loader/show');
     313                    $button.find('.btn-label').html(HQLib._('activating'));
     314                }
     315            }).complete(function (jqXHR) {
     316                $button.trigger('loader/hide');
     317            }).fail(function (jqXHR) {
     318                $(document).trigger('hqlib/container/saved', ['Plugin activation fail. Please try again.', 2]);
     319            }).done(function (result) {
     320                HQLib.buttonCallbackAction($button);
     321            });
     322        },
     323        enableOptionByBtn: function (button) {
     324            var $button = $(button);
     325            var $form = $button.closest('form');
    139326            var formData = $form.serializeArray();
    140             formData.push({name: 'action', value: 'hqlib_save_options'});
     327            var [container, option] = $button.data('option');
     328            var data = [];
     329
     330            data.push({name: 'hqt-container[' + HQLib.addHqlibPrefix(container) + ']', value: HQLib.addHqlibPrefix(container)});
     331            data.push({name: HQLib.addHqlibPrefix(option), value: 'on'});
     332            data.push({name: 'action', value: 'hqlib_save_options'});
     333            data.push(formData.filter(x => x.name === 'hqt_options_nonce')[0]);
    141334
    142335            $.ajax({
     
    144337                type: 'POST',
    145338                dataType: 'json',
    146                 data: formData,
    147                 beforeSend: function () {}
     339                data: data,
     340                beforeSend: function () {
     341                    $button.trigger('loader/show');
     342                    $button.find('.btn-label').html(HQLib._('enabling'));
     343                }
     344            }).complete(function (jqXHR) {
     345                $button.trigger('loader/hide');
    148346            }).fail(function (jqXHR) {
    149                 console.log(jqXHR);
     347                $(document).trigger('hqlib/container/saved', ['Error occurred. Please try again later.', 2]);
    150348            }).done(function (result) {
    151                 console.log(result);
    152             });
     349                if (result.success) {
     350                    $button.find('.btn-label').html(HQLib._('enabled'));
     351                }
     352                HQLib.buttonCallbackAction($button);
     353            });
     354
     355        },
     356        buttonCallbackAction: function (button) {
     357            var $button = $(button);
     358            if (!$button.data('callback').length) {
     359                return false;
     360            }
     361            switch ($button.data('callback')) {
     362                case 'refresh-page':
     363                    location.reload();
     364                    break;
     365                case 'label-activated':
     366                    $button.replaceWith(HQLib._('activated'));
     367                    break;
     368                case 'hide':
     369                    $button.fadeOut();
     370            }
     371        },
     372        addHqlibPrefix: function (name) {
     373            if (!name.match("^" + hqlibData.hqlib_prefix)) {
     374                name = hqlibData.hqlib_prefix + name;
     375            }
     376            return name;
     377        },
     378        toggleAjaxNotification: function (e, message = 'Settings saved successfully!', status) {
     379            // TODO improve if multiple notifications comes
     380            var type = 'success';
     381            if ('undefined' !== typeof status) {
     382                switch (parseInt(status)) {
     383                    case 1:
     384                        type = 'success';
     385                        break;
     386                    case 2:
     387                        type = 'error';
     388                        break;
     389                }
     390            }
     391            var notification = $('<div class="hqt-ajax-notification __' + type + '">' + message + '</div>');
     392            $('body').append(notification);
     393           
     394            // Add class for transition effect
     395            setTimeout(function () {
     396                notification.addClass('show');
     397            }, 1);
     398           
     399            setTimeout(function () {
     400                notification.fadeOut(function () {
     401                    $(this).remove();
     402                });
     403            }, 2000);
     404        },
     405        _: function (key) {
     406            if (HQLib.translate[key].length) {
     407                return HQLib.translate[key];
     408            }
     409            return false;
    153410        }
    154411    };
  • hqtheme-extra/trunk/inc/hqlib/helper.php

    r2452710 r2463414  
    281281            $license_check = true;
    282282        }
    283         if (null != $check_license) {
     283        if (null !== $check_license) {
    284284            $license_check = boolval($check_license);
    285285        }
    286 
    287286        if ($license_check && !\HQLib\License::is_activated()) {
    288287            $response->success = false;
     
    300299                if ('plugin' == $require['type']) {
    301300                    if (!empty($require['plugin_file']) && !is_plugin_active($require['plugin_file'])) {
     301                        $install_url = '';
     302                        $activate_url = wp_nonce_url('plugins.php?action=activate&amp;plugin=' . $require['plugin_file'] . '&amp;plugin_status=all&amp;paged=1&amp;s', 'activate-plugin_' . $require['plugin_file']);
    302303                        if (is_plugin_installed($require['plugin_file'])) {
    303304                            // Activate
    304305                            $btn_label = _x('Activate', 'admin', 'hqtheme-extra');
    305                             $btn_url = wp_nonce_url('plugins.php?action=activate&amp;plugin=' . $require['plugin_file'] . '&amp;plugin_status=all&amp;paged=1&amp;s', 'activate-plugin_' . $require['plugin_file']);
    306306                        } else {
    307307                            // Install
    308308                            $btn_label = _x('Install', 'admin', 'hqtheme-extra');
    309                             $btn_url = wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=' . $require['plugin_name']), 'install-plugin_' . $require['plugin_name']);
     309                            $install_url = wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=' . $require['plugin_name']), 'install-plugin_' . $require['plugin_name']);
    310310                        }
    311311                        $response->success = false;
     
    315315                            <div class="text-italic text-brighter"><?php echo sprintf($require['label'] . ' %s', _x('plugin is missing', 'admin', 'hqtheme-extra')); ?></div>
    316316                            <div class="ml-2">
    317                                 <a href="<?php echo $btn_url; ?>"><?php echo $btn_label; ?></a>
     317                                <a href="#"
     318                                   data-hqt-action-btn
     319                                   data-action="install-activate"
     320                                   data-install-url="<?php echo esc_attr($install_url); ?>"
     321                                   data-activate-url="<?php echo esc_attr($activate_url); ?>"
     322                                   data-callback="refresh-page">
     323                                       <?php echo $btn_label; ?>
     324                                </a>
    318325                            </div>
    319326                        </div>
     
    357364                        <div class="pt-1 d-flex justify-content-justify">
    358365                            <div class="text-italic text-brighter"><?php echo sprintf($require['label'] . ' %s', _x('module is disabled', 'admin', 'hqtheme-extra')); ?></div>
    359                             <?php if (!empty($require['link'])) : ?>
     366                            <?php if (self::can_module_be_active($require['module'])) : ?>
    360367                                <div class="ml-2">
    361                                     <a href="<?php echo esc_url(admin_url($require['link'])); ?>">Settings</a>
     368                                    <a href="#"
     369                                       data-hqt-action-btn
     370                                       data-action="enable"
     371                                       data-option="<?php echo esc_attr(json_encode($require['option'])); ?>"
     372                                       data-callback="refresh-page">
     373                                           <?php _ex('Enable', 'admin', 'hqtheme-extra'); ?>
     374                                    </a>
     375                                </div>
     376                            <?php elseif (!empty($require['link'])) : ?>
     377                                <div class="ml-2">
     378                                    <a href="<?php echo esc_url(admin_url($require['link'])); ?>"><?php _ex('Settings', 'admin', 'hqtheme-extra'); ?></a>
    362379                                </div>
    363380                            <?php endif; ?>
     
    405422        $module_data = self::get_module_data($module_id);
    406423
    407         if (!\HQLib\Helper::field_requires_check($module_data)->success) {
     424        if (!\HQLib\Helper::can_module_be_active($module_id, $module_data)) {
    408425            return false;
    409426        }
     
    421438
    422439    /**
     440     * Check if theme module pass the requirements
     441     * @param string $module_id
     442     * @param array $module_data
     443     * @return boolean
     444     */
     445    public static function can_module_be_active($module_id, $module_data = null) {
     446        if (null === $module_data) {
     447            $module_data = self::get_module_data($module_id);
     448        }
     449        if ($module_data) {
     450            return \HQLib\Helper::field_requires_check($module_data, false)->success;
     451        }
     452        return false;
     453    }
     454
     455    /**
    423456     * Get widget config data
    424457     * @param string $widget_id
  • hqtheme-extra/trunk/inc/hqlib/hqlib.php

    r2404450 r2463414  
    6363        $data = [
    6464            '_ajax_nonce' => wp_create_nonce('hq-lib'),
     65            'hqlib_prefix' => HQLIB_PREFIX,
     66            'translate' => $this->getHqlibDataTranslate(),
    6567        ];
    6668        wp_localize_script('hqlib-script', 'hqlibData', $data);
     
    108110    }
    109111
     112    public function getHqlibDataTranslate() {
     113        return [
     114            'activate' => _x('Activate', 'admin', 'hqtheme-extra'),
     115            'activating' => _x('Activating', 'admin', 'hqtheme-extra'),
     116            'activated' => _x('Activated', 'admin', 'hqtheme-extra'),
     117            'install' => _x('Install', 'admin', 'hqtheme-extra'),
     118            'installing' => _x('Installing', 'admin', 'hqtheme-extra'),
     119            'enable' => _x('Enable', 'admin', 'hqtheme-extra'),
     120            'enabling' => _x('Enabling', 'admin', 'hqtheme-extra'),
     121            'enabled' => _x('Enabled', 'admin', 'hqtheme-extra'),
     122        ];
     123    }
     124
    110125}
    111126
  • hqtheme-extra/trunk/inc/hqlib/meta.php

    r2387736 r2463414  
    143143            <?php endif; ?>
    144144            <input type="hidden" name="hqt-metabox[<?php echo $callback['id']; ?>]" value="<?php echo esc_attr($callback['id']); ?>">
    145             <div class="hqt-container__fields my-2">
     145            <div class="hqt-container__fields m-0 mt-2">
    146146                <?php foreach ($container->get_fields() as $field) : ?>
    147147                    <?php $field->render_clearfix(['left', 'both']); ?>
  • hqtheme-extra/trunk/inc/hqlib/options.php

    r2430987 r2463414  
    1717        $containerClasses = array_merge(['hqt-container'], (array) apply_filters('hqt/container/' . $container_key . '/classes', []));
    1818        ?>
    19         <div class="<?php echo implode(' ', $containerClasses); ?>">
     19        <div id="hqt-container-<?php echo $container->get_container_name(true); ?>" class="<?php echo implode(' ', $containerClasses); ?>">
    2020            <?php if ($container->is_submitable()) : ?>
    21                 <form class="hqt-form" method="post">
     21            <form class="hqt-form" method="post" data-ajax-submit="<?php echo $container->get_ajax_submit() ? 'true' : 'false'; ?>">
    2222                    <?php
    2323                    wp_nonce_field(\HQLib\HQLIB_PREFIX . 'options_nonce', 'hqt_options_nonce');
     
    6666
    6767    private static function render_container($container) {
    68         $container->render_title();
    69         ?>
    70         <div class="hqt-container__fields">
     68        ?>
     69        <div class="hqt-container-body">
    7170            <?php
    72             $group = $container->is_grouped_options() ? $container->get_container_name() : '';
    73             $storage = $container->get_storage();
    74             foreach ($container->get_fields() as $field) :
    75                 \HQLib\Options::render_field($field, $storage, $group);
    76             endforeach;
     71            $container->render_title();
    7772            ?>
     73            <div class="hqt-container__fields">
     74                <?php
     75                $group = $container->is_grouped_options() ? $container->get_container_name() : '';
     76                $storage = $container->get_storage();
     77                foreach ($container->get_fields() as $field) :
     78                    \HQLib\Options::render_field($field, $storage, $group);
     79                endforeach;
     80                ?>
     81            </div>
    7882        </div>
    7983        <?php
     
    8690        }
    8791        ?>
    88         <div class="hqt-tabs hqt-tabs-<?php echo $tabs->get_layout(); ?>">
     92        <div id="hqt-tabs-<?php echo $tabs->get_id(); ?>" class="hqt-tabs hqt-tabs-<?php echo $tabs->get_layout(); ?>">
    8993            <ul class="hqt-tabs-nav">
    9094                <?php
     
    119123                    ?>
    120124                    <div class="<?php echo join(' ', $classes); ?>" id="<?php echo $tab_key; ?>">
    121                         <?php
    122                         \HQLib\Options::display_container($tab_key);
    123                         ?>
     125                        <?php \HQLib\Options::display_container($tab_key); ?>
    124126                    </div>
    125127                    <?php
     
    211213            return;
    212214        }
    213 
    214215        foreach ($_POST['hqt-container'] as $container_key) {
    215216            $container_key = sanitize_key($container_key);
    216             if ($container = Options\Container::get($container_key)) {
    217 
    218                 $group = $container->is_grouped_options() ? $container->get_container_name() : '';
    219 
    220                 if (empty($group)) {
    221                     foreach ($container->get_fields() as $field) {
    222                         if (!$field->is_storable()) {
    223                             continue;
    224                         }
    225                         if (isset($_POST[$field->get_field_name()])) {
    226                             if (is_array($_POST[$field->get_field_name()])) {
    227                                 $data = filter_var_array($_POST[$field->get_field_name()], FILTER_SANITIZE_STRING);
    228                             } else {
    229                                 $data = sanitize_text_field($_POST[$field->get_field_name()]);
    230                             }
    231                             if ('options' === $container->get_storage()) {
    232                                 update_option($field->get_field_name(), $data, $field->is_autoload());
    233                             } else if ('theme_mods' === $container->get_storage()) {
    234                                 set_theme_mod($field->get_field_name(), $data);
    235                             }
    236                         }
    237                     }
    238                 } else {
    239                     $data = [];
    240                     foreach ($container->get_fields() as $field) {
    241                         if (!$field->is_storable()) {
    242                             continue;
    243                         }
    244                         if (isset($_POST[$field->get_field_name()])) {
    245                             if (is_array($_POST[$field->get_field_name()])) {
    246                                 $data[$field->get_field_name(true)] = filter_var_array($_POST[$field->get_field_name()], FILTER_SANITIZE_STRING);
    247                             } else {
    248                                 $data[$field->get_field_name(true)] = sanitize_text_field($_POST[$field->get_field_name()]);
    249                             }
    250                         }
    251                     }
    252                     if (count($data)) {
     217
     218            if (!$container = Options\Container::get($container_key)) {
     219                wp_send_json_error(_x('Options container not found', 'save options', 'hqtheme-extra'));
     220            }
     221            $group = $container->is_grouped_options() ? $container->get_container_name() : '';
     222
     223            if (empty($group)) {
     224                foreach ($container->get_fields() as $field) {
     225                    if (!$field->is_storable()) {
     226                        continue;
     227                    }
     228                    if (isset($_POST[$field->get_field_name()])) {
     229                        if (is_array($_POST[$field->get_field_name()])) {
     230                            $data = filter_var_array($_POST[$field->get_field_name()], FILTER_SANITIZE_STRING);
     231                        } else {
     232                            $data = sanitize_text_field($_POST[$field->get_field_name()]);
     233                        }
    253234                        if ('options' === $container->get_storage()) {
    254                             update_option($group, $data, $container->is_autoload());
     235                            update_option($field->get_field_name(), $data, $field->is_autoload());
    255236                        } else if ('theme_mods' === $container->get_storage()) {
    256                             set_theme_mod($group, $data);
    257                         }
    258                     }
    259                 }
    260             }
    261         }
    262 
    263         add_action('admin_print_footer_scripts', 'HQLib\Options::admin_print_scripts');
     237                            set_theme_mod($field->get_field_name(), $data);
     238                        }
     239                    }
     240                }
     241            } else {
     242                // Get saved group options if available
     243                $group_options = \HQLib\hq_get_option(\HQLib\Helper::remove_hqlib_prefix($group));
     244                $data = [];
     245               
     246                // Get submitted options
     247                foreach ($container->get_fields() as $field) {
     248                    if (!$field->is_storable()) {
     249                        continue;
     250                    }
     251                    if (isset($_POST[$field->get_field_name()])) {
     252                        if (is_array($_POST[$field->get_field_name()])) {
     253                            $data[$field->get_field_name(true)] = filter_var_array($_POST[$field->get_field_name()], FILTER_SANITIZE_STRING);
     254                        } else {
     255                            $data[$field->get_field_name(true)] = sanitize_text_field($_POST[$field->get_field_name()]);
     256                        }
     257                    }
     258                }
     259               
     260                // Merge submitted options into saved array
     261                $data = wp_parse_args($data, $group_options);
     262                if (count($data)) {
     263                    if ('options' === $container->get_storage()) {
     264                        update_option($group, $data, $container->is_autoload());
     265                    } else if ('theme_mods' === $container->get_storage()) {
     266                        set_theme_mod($group, $data);
     267                    }
     268                }
     269            }
     270        }
     271        if (!wp_doing_ajax()) {
     272            add_action('admin_print_footer_scripts', 'HQLib\Options::admin_print_scripts');
     273        } else {
     274            wp_send_json_success();
     275        }
    264276    }
    265277
  • hqtheme-extra/trunk/inc/hqlib/options/container.php

    r2430987 r2463414  
    3434     */
    3535    protected $disable_submit = false;
     36   
     37    /**
     38     *
     39     * @var boolean
     40     */
     41    protected $ajax_submit = false;
    3642
    3743    /**
     
    243249    public function is_submitable() {
    244250        return !$this->disable_submit;
     251    }
     252   
     253    public function set_ajax_submit($ajax = true) {
     254        $this->ajax_submit = $ajax;
     255        return $this;
     256    }
     257   
     258    public function get_ajax_submit() {
     259        return $this->ajax_submit;
    245260    }
    246261
  • hqtheme-extra/trunk/readme.txt

    r2452710 r2463414  
    55Tested up to: 5.5
    66Requires PHP: 7.2
    7 Stable tag: 1.0.7
     7Stable tag: 1.0.8
    88License: GPL v2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    4949== Changelog ==
    5050
    51 = 1.0.7 - 2021-01-08- =
     51= 1.0.8 - 2021-01-27 =
     52* AJAX support for admin settings - install and activate plugins, enable options
     53
     54= 1.0.7 - 2021-01-08 =
    5255* Theme setup wizard improvements
    5356* Escape admin_url
    5457
    55 = 1.0.6 - 2020-12-03- =
     58= 1.0.6 - 2020-12-03 =
    5659* Marmot theme options added
    5760* Theme setup wizard improvements
Note: See TracChangeset for help on using the changeset viewer.