1
\$\begingroup\$

I created a plugin to update cart automatically on quantity change with some additional options. I want to focus only on the main plugin file, skipping uninstall.php and .js file which are entirely okay.

I will start with good things about my code.

I am happy with how settings work. After installation, values in plugin settings are pre-filled and plugin can properly read these defaults. If the plugin is deactivated and activated again, defaults don't override settings from database. Seems simple, but wasn't covered in WordPress codex and getting it to work gave me quite a headache.

Variable is properly passed to .js file and CSS style correctly applied in head, so I don't need to style one element in separate CSS file.

Now I will go with some doubts about my code.

I create new class when in admin, but I will need to access this class later to get settings value by calling acau_get_settings function defined in this class. Can I restrict some part of this class to be admin-only or I really need it all to work correctly?

<?php
/*
 * Plugin Name: Ajax Cart AutoUpdate for WooCommerce
 * Description: Automatically updates cart page and mini cart when quantity is changed. Optionally turns off cart page notices.
 * Version: 1.0
 * Author: taisho
 * Text Domain: ajax-cart-autoupdate
 * Domain Path: /lang
 * WC requires at least: 2.6.0
 * WC tested up to: 3.6.2
 */

// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
    die;
}

// Create settings class.
class ajax_cart_autoupdate_settings
{   
    private $options;   
    private $settings_page_name;
    private $settings_menu_name;

    public function __construct()
    {               
        $this->settings_page_name = 'ajax-cart-autoupdate';
        $this->settings_menu_name = 'Ajax Cart AutoUpdate';

        // Initialize and register settings. 
        add_action( 'admin_init', array( $this, 'register_settings' ) );
        // Add settings page.
        add_action( 'admin_menu', array( $this, 'add_settings_page' ) );
        // Add settings link to plugins page.
        add_action( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'add_settings_link' ) );
    }

    public function register_settings()
    {   
        register_setting( 'acau_settings', 'acau_settings', array( $this, 'sanitize' ) );

        // ID / title / callback / page
        add_settings_section( 'configuration_section', __( 'Configuration', 'ajax-cart-autoupdate' ), array( $this, 'print_section_info' ), $this->settings_page_name );

        // ID / title / callback / page / section
        add_settings_field( 'acau_update_delay', __( 'Update delay', 'ajax-cart-autoupdate' ), array( $this, 'acau_update_delay_callback' ), $this->settings_page_name, 'configuration_section' );
        add_settings_field( 'acau_positive_qty', __( 'Cart minimum quantity', 'ajax-cart-autoupdate' ), array( $this, 'acau_positive_qty_callback' ), $this->settings_page_name, 'configuration_section' );
        add_settings_field( 'acau_cart_notices_off', __( 'Cart page notices', 'ajax-cart-autoupdate' ), array( $this, 'acau_cart_notices_off_callback' ), $this->settings_page_name, 'configuration_section' );

    }

    public function add_settings_page()
    {
        // This page will be under "Settings"
        add_options_page(
            'Settings Admin', $this->settings_menu_name, 'manage_options', $this->settings_page_name, array( $this, 'create_settings_page' )
        );
    }

    /**
     * Get the option that is saved or the default.
     *
     * @param string $index. The option we want to get.
     */
    public function acau_get_settings( $index = false ) {
        $defaults = array ( 'acau_update_delay' => 1000,'acau_positive_qty' => true,'acau_cart_notices_off' => true );
        $settings = get_option( 'acau_settings', $defaults );
        $settings = wp_parse_args( $settings, $defaults );

        if ( $index && isset( $settings[ $index ] ) ) {
            return $settings[ $index ];
        }

        return $settings;
    }

    public function create_settings_page()
    {      
        $this->options = $this->acau_get_settings();        

        ?>
        <div class="wrap">
            <h1>Ajax Cart AutoUpdate for WooCommerce</h1>
            <form method="post" action="options.php">
            <?php
                // This prints out all hidden setting fields
                settings_fields( 'acau_settings' );
                do_settings_sections( $this->settings_page_name );
                submit_button();
            ?>
            </form>
        </div>
        <?php
    }

    function add_settings_link( $links ) {
        $links = array_merge( array(
            '<a href="' . esc_url( admin_url( '/options-general.php?page=' . $this->settings_page_name ) ) . '">' . __( 'Settings' ) . '</a>'
        ), $links );
        return $links;
    }

    /**
     * Sanitize each setting field as needed
     *
     * @param array $input Contains all settings fields as array keys
     */
    public function sanitize( $input )
    {
        $new_input = array();
        if( isset( $input['acau_update_delay'] ) )
            $new_input['acau_update_delay'] = absint( $input['acau_update_delay'] );
        if( isset( $input['acau_positive_qty'] ) )
            $new_input['acau_positive_qty'] = ( $input['acau_positive_qty'] == 1 ? 1 : 0 );
        if( isset( $input['acau_cart_notices_off'] ) )
            $new_input['acau_cart_notices_off'] = ( $input['acau_cart_notices_off'] == 1 ? 1 : 0 );     

        return $new_input;
    }

    /** 
     * Print the Section text
     */

    public function print_section_info()
    {
        return;
        // print 'Enter your settings below:';
    }

    /** 
     * Get the settings option array and print one of its values
     */
    public function acau_update_delay_callback()
    {
        printf(
            '<input type="text" id="acau_update_delay" name="acau_settings[acau_update_delay]" value="%1$s" />
            <p class="description">%2$s</p>',
            isset( $this->options['acau_update_delay'] ) ? esc_attr( $this->options['acau_update_delay']) : '',
            __( 'Delay in miliseconds since last action affecting product quantity. Low values will trigger update when customers are in the middle of changing quantity. High values will make them wait and wonder why the cart doesn\'t recalculate.', 'ajax-cart-autoupdate' )
        );
    }

    public function acau_positive_qty_callback() {
        printf(
        '<fieldset>
            <label><input id="acau_positive_qty" type="checkbox" name="acau_settings[acau_positive_qty]" value="1" %1$s />%2$s</label>
        </fieldset>',
        isset( $this->options['acau_positive_qty'] ) && ( 1 == $this->options['acau_positive_qty'] )  ? 'checked="checked" ':'',
        __( 'Change minimum product quantity on cart page from 0 to 1. If unchecked, 0 quantity is valid and such products are removed on cart update.', 'ajax-cart-autoupdate' )       
        );
    }

    public function acau_cart_notices_off_callback() {
        printf(
        '<fieldset>
            <label><input id="acau_cart_notices_off" type="checkbox" name="acau_settings[acau_cart_notices_off]" value="1" %1$s />%2$s</label>
        </fieldset>',
        isset( $this->options['acau_cart_notices_off'] ) && ( 1 == $this->options['acau_cart_notices_off'] ) ? 'checked="checked" ':'',
        __( 'Turn off notices on cart page. Most common are "Cart updated." and notice about product removed from cart.', 'ajax-cart-autoupdate' )      
        );
    }
}

if( is_admin() )
    $my_settings_page = new ajax_cart_autoupdate_settings();

Here is how this plugin runs on cart page. I'm creating a new instance of settings class within function ajax_cart_autoupdate and access settings with acau_get_settings function. Before adding this function to my class, I could access settings values, but only if they were saved on database. It would lead to situation when on fresh install settings page were filled, but accessing value from class would pick 0 in case of acau_update_delay, as it wasn't stored on db. I think it can be potentially slow, but my biggest hurdle is how I would get value in multiple different functions? Would I need to create a new class instance each time? This is what I need to overcome, in order to be able to create another plugin which will have more different settings used in different functions.

// Only if WooCommerce is active (doesn't work for Github installations which have version in folder name).
if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) || ( get_site_option('active_sitewide_plugins') && array_key_exists( 'woocommerce/woocommerce.php', get_site_option('active_sitewide_plugins') ) ) ) {

    // Run plugin.
    add_action( 'template_redirect', 'run_acau' );
    function run_acau() {   
        if (! is_cart() ) return; // Only if it's cart page.
        // Enqueue CSS and js file. Localize to use php variables from plugin settings.
        add_action( 'wp_enqueue_scripts', 'ajax_cart_autoupdate' );         
    }

    function ajax_cart_autoupdate( ) {

        $plugin_abbv_name = 'acau';
        $plugin_slug = 'ajax-cart-autoupdate-for-woocommerce';
        $plugin_short_slug = 'ajax-cart-autoupdate';

        // wp_enqueue_style( $plugin_short_slug . '-style', plugins_url() . '/' . $plugin_slug . '/css/' . $plugin_slug . '.css');

        /*don't display default "Update cart" button, its behavior can still be triggered automatically,
        in WooCommerce 3.4.0 input element type was changed to button,
        class .button is present in all versions (at least from 2.6 when AJAX cart appeared in WooCommerce core) */
        add_action('wp_head', 'hide_update_cart_button', 20);

        wp_enqueue_script( $plugin_short_slug, plugins_url() . '/' . $plugin_slug . '/js/' . $plugin_slug . '.js', array('jquery'), '', true);

        $acau_settings_page = new ajax_cart_autoupdate_settings();

        // js variable name => variable value
        $data = array (
            'acau_update_delay' => $acau_settings_page->acau_get_settings('acau_update_delay'),             
        );      

        wp_localize_script( $plugin_short_slug, 'phpVars', $data );

        // Cart page minimum qty = 1 instead of 0.
        if (1 == $acau_settings_page->acau_get_settings('acau_positive_qty') ) {                
            add_filter( 'woocommerce_quantity_input_args', 'custom_cart_min_qty', 10, 2 );              
        }

        /* Don't display any notices, it includes:
        - "Cart updated."
        - removed cart item notice
        - the one when checkout session expires and cart items disappear (it duplicates no items in cart standard message).
        */      
        if (1 == $acau_settings_page->acau_get_settings('acau_cart_notices_off') ) {
            WC()->session->set( 'wc_notices', null );
        }

    }   

    function hide_update_cart_button() {
        echo "<style>.button[name='update_cart']{ display: none!important;}</style>";
    }

    function custom_cart_min_qty( $args, $product ) {
       $args['min_value'] = 1;
       return $args;
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.