0

I am creating a WordPress using https://github.com/nadeem-khan/WordPress-Plugin-Template as a starter template.

This is my settings class file named 'class-xyz.php':

<?php
if (!defined('ABSPATH'))
    exit;

class Xyz_Settings {

    /**
     * The single instance of Xyz_Settings.
     * @var     object
     * @access  private
     * @since   1.0.0
     */
    private static $_instance = null;

    /**
     * The main plugin object.
     * @var     object
     * @access  public
     * @since   1.0.0
     */
    public $parent = null;

    /**
     * Prefix for plugin settings.
     * @var     string
     * @access  public
     * @since   1.0.0
     */
    public $base = '';

    /**
     * Available settings for plugin.
     * @var     array
     * @access  public
     * @since   1.0.0
     */
    public $settings = array();

    public function __construct($parent) {
        $this->parent = $parent;

        $this->base = 'xyzsms_';

        // Initialise settings
        add_action('admin_init', array($this, 'init_settings'));

        // Register plugin settings
        add_action('admin_init', array($this, 'register_settings'));

        // Add settings page to menu
        add_action('admin_menu', array($this, 'add_menu_item'));

        // Add settings link to plugins page
        add_filter('plugin_action_links_' . plugin_basename($this->parent->file), array($this, 'add_settings_link'));
    }

    /**
     * Initialise settings
     * @return void
     */
    public function init_settings() {
        $this->settings = $this->settings_fields();
    }

    /**
     * Add settings page to admin menu
     * @return void
     */
    public function add_menu_item() {
        $page = add_options_page(__('XYZ Settings', 'xyz-template'), __('XYZ Settings', 'xyz-template'), 'manage_options', 'xyz_template_settings', array($this, 'settings_page'));
        add_action('admin_print_styles-' . $page, array($this, 'settings_assets'));
    }

    /**
     * Load settings JS & CSS
     * @return void
     */
    public function settings_assets() {

        // We're including the farbtastic script & styles here because they're needed for the colour picker
        // If you're not including a colour picker field then you can leave these calls out as well as the farbtastic dependency for the wpt-admin-js script below
        wp_enqueue_style('farbtastic');
        wp_enqueue_script('farbtastic');

        // We're including the WP media scripts here because they're needed for the image upload field
        // If you're not including an image upload then you can leave this function call out
        wp_enqueue_media();

        wp_register_script($this->parent->_token . '-settings-js', $this->parent->assets_url . 'js/settings' . $this->parent->script_suffix . '.js', array('farbtastic', 'jquery'), '1.0.0');
        wp_enqueue_script($this->parent->_token . '-settings-js');
    }

    /**
     * Add settings link to plugin list table
     * @param  array $links Existing links
     * @return array        Modified links
     */
    public function add_settings_link($links) {
        $settings_link = '<a href="options-general.php?page=xyz_template_settings">' . __('Settings', 'xyz-template') . '</a>';
        array_push($links, $settings_link);
        return $links;
    }

    /**
     * Build settings fields
     * @return array Fields to be displayed on settings page
     */
    private function settings_fields() {
        $settings['social-bar-position'] = array(
            'title' => __('Bar Position', 'xyz-plugin-bar'),
            'fields' => array(
                array(
                    'id' => 'xyz_position',
                    'label' => __('Position', 'xyz-plugin-bar'),
                    'description' => __('Select the position', 'xyz-plugin-bar'),
                    'type' => 'radio',
                    'options' => array('left' => 'Left', 'right' => 'Right'),
                    'default' => 'left'
                ),
                array(
                    'id' => 'xyz_margin_top',
                    'label' => __('Bar Margin Top', 'xyz-plugin-bar'),
                    'description' => __('Define the margin top', 'xyz-plugin-bar'),
                    'type' => 'text',
                    'placeholder' => __('Enter margin.', 'xyz-plugin-bar'),
                    'default' => '200px'
                )
            )
        );
        $settings['social-networks-bar'] = array(
            'title' => __('Social Networks', 'xyz-plugin-bar'),
            'fields' => array(
                array(
                    'id' => 'xyz_networks',
                    'label' => __('Social', 'xyz-plugin-bar'),
                    'description' => __('Select social.', 'xyz-plugin-bar'),
                    'type' => 'checkbox_multi',
                    'options' => array(
                        'facebook' => 'Facebook'
                    )
                )
            )
        );

        $settings['links-bar'] = array(
            'title' => __('Links', 'xyz-plugin-bar'),
            'description' => __('Enter the Urls for all the selected social networks:', 'xyz-plugin-bar'),
            'fields' => array(
                array(
                    'id' => 'facebook_url',
                    'label' => __('Facebook URL', 'xyz-plugin-bar'),
                    'description' => __('Enter the URL for Facebook.', 'xyz-plugin-bar'),
                    'type' => 'text',
                    'placeholder' => __('Enter Facebook URL', 'xyz-plugin-bar'),
                    'default' => ''
                )
            )
        );

        $settings['custom-classes-bar'] = array(
            'title' => __('Custom Classes', 'xyz-plugin-bar'),
            'description' => __('Add custom classes in the main parent container of the bar (will affect shortcodes as well):', 'xyz-plugin-bar'),
            'fields' => array(
                array(
                    'id' => 'xyz_custom_class',
                    'label' => __('Add Custom Classes in the Bar Parent Container'),
                    'description' => __('Add your own custom CSS class (like customclass1 customclass2). Leave empty if default styling is desired.', 'xyz-plugin-bar'),
                    'type' => 'textarea',
                    'default' => '',
                    'placeholder' => __('Add custom classes like .custom_class1 .custom_class2 .custom_class3 to the main container of the social bar.', 'xyz-plugin-bar')
                )
            )
        );

        $settings['social-bar-custom-colors'] = array(
            'title' => __('Bar Icons Colors', 'xyz-plugin-bar'),
            'description' => __('Select the colors', 'xyz-plugin-bar'),
            'fields' => array(
                array(
                    'id' => 'bar_facebook_icon_custom_color',
                    'label' => __('Facebook Icon Color', 'xyz-plugin-bar'),
                    'description' => __('Default color: #FEFEFE ', 'xyz-plugin-bar'),
                    'type' => 'color',
                    'default' => '#FEFEFE'
                )
            )
        );


        $settings['add-custom-css-bar'] = array(
            'title' => __('Add CSS', 'xyz-plugin-bar'),
            'label' => __('Add CSS', 'xyz-plugin-bar'),
            'description' => __('Paste your CSS', 'xyz-plugin-bar'),
            'fields' => array(
                array(
                    'id' => 'xyz_add_custom_css',
                    'label' => __('Custom CSS', 'wordpress'),
                    'description' => __('Do not style', 'xyz-plugin-bar'),
                    'type' => 'textarea',
                    'default' => '',
                    'placeholder' => __('Do not style .', 'xyz-plugin-bar')
                )
            )
        );

        $settings = apply_filters('xyz_fields', $settings);

        return $settings;
    }

    /**
     * Register plugin settings
     * @return void
     */
    public function register_settings() {
        if (is_array($this->settings)) {
            foreach ($this->settings as $section => $data) {

                // Add section to page
                add_settings_section($section, $data['title'], array($this, 'settings_section'), 'xyz_template_settings');

                foreach ($data['fields'] as $field) {

                    // Validation callback for field
                    $validation = '';
                    if (isset($field['callback'])) {
                        $validation = $field['callback'];
                    }

                    // Register field
                    $option_name = $this->base . $field['id'];
                    register_setting('xyz_template_settings', $option_name, $validation);

                    // Add field to page
                    add_settings_field($field['id'], $field['label'], array($this, 'display_field'), 'xyz_template_settings', $section, array('field' => $field));
                }
            }
        }
    }

    public function settings_section($section) {
        $html = '<p> ' . $this->settings[$section['id']]['description'] . '</p>' . "\n";
        echo $html;
    }

    /**
     * Generate HTML for displaying fields
     * @param  array $args Field data
     * @return void
     */
    public function display_field($args) {

        $field = $args['field'];

        $html = '';

        $option_name = $this->base . $field['id'];
        $option = get_option($option_name);

        $data = '';
        if (isset($field['default'])) {
            $data = $field['default'];
            if ($option) {
                $data = $option;
            }
        }

        switch ($field['type']) {

            case 'text':
            case 'password':
            case 'number':
                $html .= '<input id="' . esc_attr($field['id']) . '" type="' . $field['type'] . '" name="' . esc_attr($option_name) . '" placeholder="' . esc_attr($field['placeholder']) . '" value="' . $data . '"/>' . "\n";
                break;

            case 'text_secret':
                $html .= '<input id="' . esc_attr($field['id']) . '" type="text" name="' . esc_attr($option_name) . '" placeholder="' . esc_attr($field['placeholder']) . '" value=""/>' . "\n";
                break;

            case 'textarea':
                $html .= '<textarea id="' . esc_attr($field['id']) . '" rows="5" cols="50" name="' . esc_attr($option_name) . '" placeholder="' . esc_attr($field['placeholder']) . '">' . $data . '</textarea><br/>' . "\n";
                break;

            case 'checkbox':
                $checked = '';
                if ($option && 'on' == $option) {
                    $checked = 'checked="checked"';
                }
                $html .= '<input id="' . esc_attr($field['id']) . '" type="' . $field['type'] . '" name="' . esc_attr($option_name) . '" ' . $checked . '/>' . "\n";
                break;

            case 'checkbox_multi':
                foreach ($field['options'] as $k => $v) {
                    $checked = false;
                    if (in_array($k, $data)) {
                        $checked = true;
                    }
                    $html .= '<label for="' . esc_attr($field['id'] . '_' . $k) . '"><input type="checkbox" ' . checked($checked, true, false) . ' name="' . esc_attr($option_name) . '[]" value="' . esc_attr($k) . '" id="' . esc_attr($field['id'] . '_' . $k) . '" /> ' . $v . '</label> ';
                }
                break;

            case 'radio':
                foreach ($field['options'] as $k => $v) {
                    $checked = false;
                    if ($k == $data) {
                        $checked = true;
                    }
                    $html .= '<label for="' . esc_attr($field['id'] . '_' . $k) . '"><input type="radio" ' . checked($checked, true, false) . ' name="' . esc_attr($option_name) . '" value="' . esc_attr($k) . '" id="' . esc_attr($field['id'] . '_' . $k) . '" /> ' . $v . '</label> ';
                }
                break;

            case 'select':
                $html .= '<select name="' . esc_attr($option_name) . '" id="' . esc_attr($field['id']) . '">';
                foreach ($field['options'] as $k => $v) {
                    $selected = false;
                    if ($k == $data) {
                        $selected = true;
                    }
                    $html .= '<option ' . selected($selected, true, false) . ' value="' . esc_attr($k) . '">' . $v . '</option>';
                }
                $html .= '</select> ';
                break;

            case 'select_multi':
                $html .= '<select name="' . esc_attr($option_name) . '[]" id="' . esc_attr($field['id']) . '" multiple="multiple">';
                foreach ($field['options'] as $k => $v) {
                    $selected = false;
                    if (in_array($k, $data)) {
                        $selected = true;
                    }
                    $html .= '<option ' . selected($selected, true, false) . ' value="' . esc_attr($k) . '" />' . $v . '</label> ';
                }
                $html .= '</select> ';
                break;

            case 'image':
                $image_thumb = '';
                if ($data) {
                    $image_thumb = wp_get_attachment_thumb_url($data);
                }
                $html .= '<img id="' . $option_name . '_preview" class="image_preview" src="' . $image_thumb . '" /><br/>' . "\n";
                $html .= '<input id="' . $option_name . '_button" type="button" data-uploader_title="' . __('Upload an image', 'xyz-template') . '" data-uploader_button_text="' . __('Use image', 'xyz-template') . '" class="image_upload_button button" value="' . __('Upload new image', 'xyz-template') . '" />' . "\n";
                $html .= '<input id="' . $option_name . '_delete" type="button" class="image_delete_button button" value="' . __('Remove image', 'xyz-template') . '" />' . "\n";
                $html .= '<input id="' . $option_name . '" class="image_data_field" type="hidden" name="' . $option_name . '" value="' . $data . '"/><br/>' . "\n";
                break;

            case 'color':
                ?><div class="color-picker" style="position:relative;">
                    <input type="text" name="<?php esc_attr_e($option_name); ?>" class="color" value="<?php esc_attr_e($data); ?>" />
                    <div style="position:absolute;background:#FFF;z-index:99;border-radius:100%;" class="colorpicker"></div>
                </div>
                <?php
                break;
        }

        switch ($field['type']) {

            case 'checkbox_multi':
            case 'radio':
            case 'select_multi':
                $html .= '<br/><span class="description">' . $field['description'] . '</span>';
                break;

            default:
                $html .= '<label for="' . esc_attr($field['id']) . '"><span class="description">' . $field['description'] . '</span></label>' . "\n";
                break;
        }

        echo $html;
    }

    /**
     * Validate individual settings field
     * @param  string $data Inputted value
     * @return string       Validated value
     */
    public function validate_field($data) {
        if ($data && strlen($data) > 0 && $data != '') {
            $data = urlencode(strtolower(str_replace(' ', '-', $data)));
        }
        return $data;
    }

    /**
     * Load settings page content
     * @return void
     */
    public function settings_page() {

        // Build page HTML
        $html = '<div class="wrap" id="xyz_settings">' . "\n";
        $html .= '<h2>' . __('XYZ Settings', 'xyz-template') . '</h2>' . "\n";
        $html .= '<form method="post" action="options.php" enctype="multipart/form-data">' . "\n";

        // Setup navigation
        $html .= '<ul id="settings-sections" class="subsubsub hide-if-no-js">' . "\n";
        $html .= '<li><a class="tab all current" href="#all">' . __('All', 'xyz-template') . '</a></li>' . "\n";

        foreach ($this->settings as $section => $data) {
            $html .= '<li>| <a class="tab" href="#' . $section . '">' . $data['title'] . '</a></li>' . "\n";
        }

        $html .= '</ul>' . "\n";

        $html .= '<div class="clear"></div>' . "\n";

        // Get settings fields
        ob_start();
        settings_fields('xyz_template_settings');
        do_settings_sections('xyz_template_settings');
        $html .= ob_get_clean();

        $html .= '<p class="submit">' . "\n";
        $html .= '<input name="Submit" type="submit" class="button-primary" value="' . esc_attr(__('Save Settings', 'xyz-template')) . '" />' . "\n";
        $html .= '</p>' . "\n";
        $html .= '</form>' . "\n";
        $html .= '</div>' . "\n";

        echo $html;
    }

    /**
     * Main Xyz_Settings Instance
     *
     * Ensures only one instance of Xyz_Settings is loaded or can be loaded.
     *
     * @since 1.0.0
     * @static
     * @see Xyz()
     * @return Main Xyz_Settings instance
     */
    public static function instance($parent) {
        if (is_null(self::$_instance)) {
            self::$_instance = new self($parent);
        }
        return self::$_instance;
    }

// End instance()

    /**
     * Cloning is forbidden.
     *
     * @since 1.0.0
     */
    public function __clone() {
        _doing_it_wrong(__FUNCTION__, __('Cheatin&#8217; huh?'), $this->parent->_version);
    }

// End __clone()

    /**
     * Unserializing instances of this class is forbidden.
     *
     * @since 1.0.0
     */
    public function __wakeup() {
        _doing_it_wrong(__FUNCTION__, __('Cheatin&#8217; huh?'), $this->parent->_version);
    }

// End __wakeup()
}

All the settings fields are displayed properly but as soon as the submit button is pressed 404 is generated and no settings get saved. What am I missing here?

  • How many fields do you have on the page? Typically you'd only have 1x setting (created via the WP function register_setting()) per page. You'd then add sections to the page (using add_settings_section()), and fields to the sections (using add_settings_field()). It looks like your sanitize_callback is $validation, which is the function/method that WP will use to sanitize/save your setting from options.php, before directing you back. I'm not sure exactly what that is referencing, but I suspet this is your issue. – David Gard Jan 27 '15 at 15:51
  • There are two fields in $settings['social-bar-position'] and all other sections in $settings have a single field. – Nadeem Khan Jan 27 '15 at 17:23
0

The problem was with the huge number of settings I was trying to save and the max_input_vars limit was getting saturated.

I have now solved the issue by using jQuery to hide all the unused settings based on user input before submitting the settings form.

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.