Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I am developing a theme and I wanted to add some extra content to the built in background options page. I know how to use the settings API to create new theme options and settings but I can't seem to figure out where it's actually calling to the background page. I have searched through wp-includes/theme.php and still not much there except to calls to the background functions and nothing that actually renders the page.

Could this not be done with an action?

share|improve this question

2 Answers 2

up vote 6 down vote accepted

The page content for custom backgrounds is created in wp-admin/custom-background.php. There is no action available where the fields are printed.

To add new fields we have to print JavaScript into the page footer. The action is 'admin_footer-appearance_page_custom-background'.

To save those field values we have to hook into 'load-appearance_page_custom-background'.

The following example adds a new option for background-origin – useful if you have set a border around body in your stylesheet.

enter image description here

add_action(
    'load-appearance_page_custom-background',
    array ( 'T5_Background_Origin', 'get_instance' )
);

/**
 * Add a new row to the background options table for 'background-origin'.
 *
 * @author  Thomas Scholz http://toscho.de
 * @version 2012.09.10
 */
class T5_Background_Origin
{
    /**
     * Main instance.
     * @type object|NULL
     */
    protected static $instance = NULL;

    /**
     * The name for the option. Will be saved as theme option.
     *
     * @link http://www.w3.org/TR/css3-background/#the-background-origin
     * @type string
     */
    protected $option = 'background_origin';

    /**
     * Label on the left side of our new option.
     *
     * @type string
     */
    protected $table_header = 'Background Origin';

    /**
     * Return an instance.
     *
     * @wp-hook load-appearance_page_custom-background
     * @return object
     */
    public static function get_instance()
    {
        NULL === self::$instance and self::$instance = new self;
        return self::$instance;
    }

    /**
     * Save our option and register the form.
     *
     * @wp-hook load-appearance_page_custom-background
     */
    public function __construct()
    {
        add_action(
            'admin_footer-appearance_page_custom-background',
            array ( $this, 'form' )
        );

        if ( empty ( $_POST[ $this->option ] ) )
        {
            return;
        }

        check_admin_referer( $this->option, "_t5nonce-$this->option" );
        set_theme_mod( $this->option, $_POST[ $this->option ] );
    }

    /**
     * Create the form elements.
     *
     * @wp-hook admin_footer-appearance_page_custom-background
     * @return void
     */
    public function form()
    {
        $nonce = wp_nonce_field(
            $this->option,
            "_t5nonce-$this->option",
            TRUE, // check referer
            FALSE // do not echo
            );
        $html = $nonce . $this->get_radio_fields();
        $this->print_script( $html );
    }

    /**
     * Create the jQuery function that inserts our form fields.
     *
     * @param  string $html Radio buttons
     * @return void
     */
    protected function print_script( $html )
    {
        $row = "'<tr><th>$this->table_header</th><td>$html</td></tr>'";
        ?>
<script>jQuery( function <?php echo $this->option; ?>($) {
    $('.form-table:last').append(<?php echo $row; ?>);
});</script>
<?php
    }

    /**
     * Helper for form(). Create radio input fields
     *
     * @return string
     */
    protected function get_radio_fields()
    {
        $value  = get_theme_mod( $this->option, 'padding-box' );
        $radios = array ( 'padding-box', 'border-box', 'content-box' );
        $html   = "<p>";

        foreach ( $radios as $radio )
        {
            $html .= sprintf(
                ' <input type="radio" name="%1$s" value="%2$s" id="%3$s"%4$s>'
                . ' <label for="%3$s">%2$s</label> ',
                $this->option,
                $radio,
                "$this->option-$radio",
                // returns ' as value delimiters and has to be escaped
                addslashes( checked( $value, $radio, FALSE ) )
            );
        }

        return "$html</p>";
    }
}
share|improve this answer
    
Thank you for such a detailed answer. Not quite what I needed to to do but it certainly points me in the right direction. –  Jacob Rambo Sep 10 '12 at 1:56
    
Thanks for posting this, it's still useful even 20 months on. –  David Gard Jun 10 at 23:40

I found the answer provided by @toscho very useful, but as I had more than one option to add, I have amended the code a little so that all I have to do is create a simple extended Class with a few options.

I also found it inconvenient to have the options simply added to the end of the list, so I've added a 'position' argument that allows you to select any of these options -

  • 'first' - Before the first setting (currently Position)
  • 'last'- After the last setting (current Background Colour)
  • Integer position - The row number to insert the setting before (must be an integer)

Here is the code -

add_action('load-appearance_page_custom-background', array('PS_Background_Setting_Random', 'get_instance'));
add_action('load-appearance_page_custom-background', array('PS_Background_Setting_Position_Y', 'get_instance'));
add_action('load-appearance_page_custom-background', array('PS_Background_Setting_Size', 'get_instance'));

/**
 * Add a new 'Random Background' setting to the Customise Background admin page
 */
final class PS_Background_Setting_Random extends PS_Background_Setting{

    /**
     * The main instance
     *
     * @var object|null
     */
    protected static $instance = null;

    /**
     * Return an instance of this class
     *
     * @return object   An instance of this class
     */
    public static function get_instance(){

        NULL === self::$instance and self::$instance = new self;
        return self::$instance;

    }

    /**
     * Constructor
     */
    public function __construct(){

        $args = array(
            'mod'       => 'ps_background_random',
            'default'   => 'yes',
            'label'     => __('Random Background', 'djg_photo_show'),
            'position'  => 'first',
            'options'   => array(
                'yes'   => __('Yes', 'djg_photo_show'),
                'no'    => __('No', 'djg_photo_show')
            )
        );

        parent::__construct($args);

    }

}

/**
 * Add a new 'Background Position (Y)' setting to the Customise Background admin page
 */
final class PS_Background_Setting_Position_Y extends PS_Background_Setting{

    /**
     * The main instance
     *
     * @var object|null
     */
    protected static $instance = null;

    /**
     * Return an instance of this class
     *
     * @return object   An instance of this class
     */
    public static function get_instance(){

        NULL === self::$instance and self::$instance = new self;
        return self::$instance;

    }

    /**
     * Constructor
     */
    public function __construct(){

        $args = array(
            'mod'       => 'ps_background_position_y',
            'default'   => 'cover',
            'label'     => __('Position (Y)', 'djg_photo_show'),
            'position'  => 3,
            'options'   => array(
                'top'       => __('Top', 'djg_photo_show'),
                'center'    => __('Centre', 'djg_photo_show'),
                'bottom'    => __('Bottom', 'djg_photo_show')
            )
        );

        parent::__construct($args);

    }

}

/**
 * Add a new 'Background Size' setting to the Customise Background admin page
 */
final class PS_Background_Setting_Size extends PS_Background_Setting{

    /**
     * The main instance
     *
     * @var object|null
     */
    protected static $instance = null;

    /**
     * Return an instance of this class
     *
     * @return object   An instance of this class
     */
    public static function get_instance(){

        NULL === self::$instance and self::$instance = new self;
        return self::$instance;

    }

    /**
     * Constructor
     */
    public function __construct(){

        $args = array(
            'mod'       => 'ps_background_size',
            'default'   => 'cover',
            'label'     => __('Size', 'djg_photo_show'),
            'position'  => 6,
            'options'   => array(
                'auto'      => __('Auto', 'djg_photo_show'),
                'contain'   => __('Contain', 'djg_photo_show'),
                'cover'     => __('Cover', 'djg_photo_show')
            )
        );

        parent::__construct($args);

    }

}

/**
 * Add a new setting to the Customise Background admin page
 */
class PS_Background_Setting{

    /**
     * The name for the theme modification option
     *
     * @var string
     */
    private $mod = '';

    /**
     * The default value to return if $mod is not yet set
     *
     * @var mixed
     */
    private $default = false;

    /**
     * The label for the additional setting
     *
     * @var string
     */
    private $label = '';

    /**
     * The options to use for creating the fields for the additional setting
     *
     * @var array
     */
    private $options = array();

    /**
     * The nonce for the additional setting
     *
     * @var string
     */
    private $nonce;

    /**
     * The HTML fields for all of the options for the additional setting
     *
     * @var string
     */
    private $fields;

    /**
     * The position in which to insert the option
     *
     * @var string
     */
    private $position = 'last';

    /**
     * Constructor
     */
    public function __construct($args = array()){

        /** Map the args to this object */
        foreach($args as $key => $value) :
            $this->$key = $value;
        endforeach;

        /** Ensure that all of the required $args are valid */
        if(!$this->is_valid_args()) :
            return;
        endif;

        add_action('admin_footer-appearance_page_custom-background', array($this, 'output_additional_setting'));

        /** Check to see if there is an option to save */
        if(!empty($_POST[$this->mod])):

            /** Check the nonce is valid and save the updated setting */
            check_admin_referer($this->mod, "_ps_nonce-$this->mod");
            set_theme_mod($this->mod, $_POST[$this->mod]);

        endif;

    }

    /**
     * Ensure that all of the required $args are valid
     */
    private function is_valid_args(){

        return (empty($this->mod) || empty($this->label) || empty($this->options)) ? false : true;

    }

    /**
     * Output the additional custom fields to the custom backgrounds page
     */
    public function output_additional_setting(){

        $this->nonce = wp_nonce_field(  // Create a nonce for each settings so that it can be checked when the user saves
            $this->mod,             // The nonce $action
            "_ps_nonce-$this->mod", // The nonce $name
            true,                   // Also create a referer nonce
            false                   // Do not echo
        );
        $this->set_fields();    // Set up the fields for this setting
        $this->print_script();  // Print the jQuery that will insert the setting into the DOM

    }

    /**
     * Create the HTML fileds for all of the options required for the additional setting
     *
     * @return string   The fields for the additional setting
     */
    private function set_fields(){

        $saved_value = get_theme_mod($this->mod, $this->default);

        foreach($this->options as $value => $description) :

            $checked = ($value === $saved_value) ? 'checked="true"' : false;

            $fields[] = sprintf(
                '<label>'.
                '<input type="radio" id="%1$s" name="%2$s" value="%3$s" %4$s>'.
                '%5$s</label> ',
                "$this->mod-$key",  /** %1$s - The option ID */
                $this->mod,         /** %2$s - The option name */
                $value,             /** %3$s - The option vale */
                $checked,           /** %4$s - Whether or not the option should be checked */
                $description        /** %5$s - The option description */
            );

        endforeach;

        $this->fields = join('', $fields);

    }

    /**
     * Create the $row to insert in to the DOM and the jQuery function to carry out the insertion
     */
    private function print_script(){

        $row = sprintf(
            '<tr>'.
            '<th scope="row">%1$s</th>'.
            '<td><fieldset>'.
            '<legend class="screen-reader-text"><span>Background %1$s</span></legend>'.
            '%2$s%3$s</fieldset></td></tr>',            
            $this->label,   /** %1$s - The setting label */
            $this->nonce,   /** %2$s - The nonce field for this setting */
            $this->fields   /** %3$s - The setting fields */
        );

        if(!is_int($this->position)) :
            $this->position = (in_array($this->position, array('first', 'last'))) ? $this->position : 'last';
        endif;
?>
<script id="custom-background-mod-<?php echo $this->mod; ?>">jQuery(function <?php echo $this->mod; ?>($){

    /** Insert the '<?php echo $this->mod; ?>' setting option in to the Custom Background admin page */
    var row = '<?php echo $row; ?>';
    var rows = $('.form-table:last tr');
<?php if(is_int($this->position)) : ?>
    var position = parseInt('<?php echo $this->position; ?>');
    if(position < 0){
        rows.first().before(row);
    }
    else if(position > rows.length){
        rows.last().after(row);
    }
    else{
        rows.eq(position - 1).before(row);
    }
<?php elseif($this->position === 'first') : ?>
    $('.form-table:last tr:first').before(row);
<?php else : ?>
    $('.form-table:last tr:last').after(row);
<?php endif; ?>

});</script>
<?php
    }

}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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