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 have a couple of functions that I now combined in a class. The reason for that was that all these functions go towards one goal, and it is more appropriate way to use the globals between these functions. The class consists of three main sections, section one to add my meta boxes, section two adds a options page where sidebars are created, and section three which actually register the sidebars.

My problem now is, section one and two only needs to run on admin side. I know how to achieve that on normal functionality. My problem is how do I achieve that inside a class. I know that you can wrap the complete class inside the is_admin() tag, but that doesn't work here as my sidebars are not displayed then on the front end.

How can I only wrap the first two sections in the is_admin() tag. Here is my class

class PieterGoosen_Custom_Sidebars {
    private $sdwas;

    public function __construct() {

        add_action( 'add_meta_boxes', array( $this, 'add_cspp' ) );
        add_action( 'save_post', array( $this, 'save_cspp' ) );
        add_action( 'admin_init', array( $this, 'init' ) );
        add_action( 'admin_menu', array( $this, 'add_page' ) );
        add_action( 'widgets_init', array( $this, 'sidebars_register' ) );

    }

    /*----------------------------------------------------------------------------------
     *
     *      Create and add meta box to page edit screen
     *
     *---------------------------------------------------------------------------------*/

    public function add_cspp() {

        //Meta box in page screen
        add_meta_box( 
            'custom_sidebar_per_page', 
            __( 'Sidebar options', 'pietergoosen' ), 
            array( $this, 'cspp_link' ),
            'page', 
            'side', 
            'high'
        );

        // Meta box in post screen
        add_meta_box( 
            'custom_sidebar_per_page', 
            __( 'Sidebar options', 'pietergoosen' ), 
            array( $this, 'cspp_link' ),
            'post', 
            'side', 
            'high'
        );
    }

    public function cspp_link( $post ) {

        wp_nonce_field( 'cspp_meta_nonce', 'cspp_nonce' );

        $custom = get_post_custom($post->ID);

        if(isset($custom['_custom_sidebar_per_page']))
            $val = $custom['_custom_sidebar_per_page'][0];
        else
            $val = "default";

        // The actual fields for data entry
        $output = '<p><label for="pietergoosen_new_field">'.__( 'Choose a sidebar to display', 'pietergoosen' ).'</label></p>';
        $output .= '<select name="custom_sidebar_per_page">';

        // Add a default option
        $output .= '<option';
        if($val == "default")
            $output .= ' selected="selected"';
        $output .= ' value="default">'.__( 'No Specified Sidebar', 'pietergoosen' ).'</option>';

        // Fill the select element with all registered sidebars
        if(!empty($this->sdwas))
            foreach($this->sdwas as $sid => $sdwa) {  
                $output .= '<option';  
                if($sdwa == $val)  
                    $output .= ' selected="selected"';  
                $output .= ' value="'.$sdwa.'">'.$sdwa.'</option>';  
            }  

        $output .= '</select>';  

        echo $output;  
    } 

    public function save_cspp($post_id){

        // Check if our nonce is set.
        $nonce = filter_input(INPUT_POST, 'cspp_nonce', FILTER_SANITIZE_STRING);

        // Verify that the nonce is valid.
        if ( empty($nonce) || ! wp_verify_nonce( $nonce, 'cspp_meta_nonce' ) )
            return $post_id;

        // If this is an autosave, our form has not been submitted, so we don't want to do anything.
        if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) 
        return $post_id;

        // Check the user's permissions for pages.
        if ( !current_user_can( 'edit_page', $post_id ) )
            return;

        // Check the user's permissions for posts.
        if ( !current_user_can( 'edit_post', $post_id ) )
            return; 

        /* OK, its safe for us to save the data now. */
        $custom = filter_input(INPUT_POST, 'custom_sidebar_per_page', FILTER_SANITIZE_STRING);

        if(!empty( $_POST['custom_sidebar_per_page'] )) {
            update_post_meta($post_id, '_custom_sidebar_per_page', $custom);
        }else{
            delete_post_meta( $post_id, '_custom_sidebar_per_page');
        }
    }

    /*----------------------------------------------------------------------------------
     *
     *      Register and add a options screen under the "Appearance" menu screen.
     *          Sidebars are created/deleted here.
     *
     *---------------------------------------------------------------------------------*/

    public function init() {

        register_setting( 
            'set_fields', 
            'cspp_get_option', 
            array( $this, 'sanitation' )
        );

        add_settings_section( 
            'general',  
            __( 'Custom sidebars per page', 'pietergoosen' ), 
            '__return_false', 
            'theme_options' 
        );

        add_settings_field( 
            'custom_sidebar_per_page', 
            __( 'Custom sidebars', 'pietergoosen' ), 
            array( $this, 'settings_field' ), 
            'theme_options', 
            'general' 
        );

    }

    public function add_page() {
        add_theme_page(
            __( 'Custom Sidebars', 'pietergoosen' ),     
            __( 'Custom Sidebars', 'pietergoosen' ),     
            'edit_theme_options',                       
            'theme_options',                             
            array( $this, 'render_page' )                
        );
    }

    public function render_page() {
        if (! current_user_can('edit_theme_options') ) 
            return;
         ?>
        <div class="wrap">
            <h2><?php _e( 'Custom Sidebars Per Page Options', 'pietergoosen' ); ?></h2>  
            <p>
                <?php 
                _e( 'Create or remove custom sidebars that can be individually used on posts and pages', 'pietergoosen' )
                ?>
            </p>
            <form method="post" action="options.php">
            <?php
                // This prints out all hidden setting fields
                settings_fields( 'set_fields' ); 
                do_settings_sections( 'theme_options' );
                submit_button(); 
            ?>
            </form>
        </div>
        <?php
    }

    public function sanitation( $input ) {

        $output = array();

        if ( isset( $input['_custom_sidebar_per_page'] ) ) {
        $output['_custom_sidebar_per_page'] = $input['_custom_sidebar_per_page'];
        }   
        return $output;
    }

    public function settings_field() {

        $option1 = get_option( 'cspp_get_option' );

        // A bit of jQuery to handle interactions (add / remove sidebars)
        $val1 = '<script type="text/javascript">';
        $val1 .= '
                    var $ = jQuery;
                    $(document).ready(function(){
                        $(".sidebar_management").on("click", ".delete", function(){
                            $(this).parent().remove();
                        });

                        $("#add_sidebar").click(function(){
                            $(".sidebar_management ul").append("<li>"+$("#new_sidebar_name").val()+" <a href=\'#\' class=\'delete\'>'.__('Delete', 'pietergoosen').'</a> <input type=\'hidden\' name=\'cspp_get_option[_custom_sidebar_per_page][]\' value=\'"+$("#new_sidebar_name").val()+"\' /></li>");
                            $("#new_sidebar_name").val("");
                        })

                    })
        ';

        $val1 .= '</script>';

        $val1 .= '<div class="sidebar_management">';

        $val1 .= '<p><input type="text" id="new_sidebar_name" /></p><p><input class="button-primary" type="button" id="add_sidebar" value="'.__('Add', 'pietergoosen').'" /></p>';

        $val1 .= '<ul>';

        // Display all custom sidebars
        if(isset($option1['_custom_sidebar_per_page']) ? esc_attr($option1['_custom_sidebar_per_page']) : '') {
            $csppval = $option1['_custom_sidebar_per_page'];
            $i = 0;

            foreach($csppval as $sdwa) {
                $val1 .= '<li>'.$sdwa.' <a href="#" class="delete">'.__( 'Delete', 'pietergoosen' ).'</a><input type="hidden" name="cspp_get_option[_custom_sidebar_per_page][]" value="'.$sdwa.'" /></li>';
                $i++;
            }
        }

        $val1 .= '</ul>';

        $val1 .= '</div>';

        echo $val1;
    }

    /*----------------------------------------------------------------------------------
     *
     *      Register the custom sidebars if a value is entered in save in the options
     *          screens. Also create a sidebar ID from this value
     *
     *---------------------------------------------------------------------------------*/

    public function sidebars_register() {

        $option2 = get_option( 'cspp_get_option' );
            if( isset($option2['_custom_sidebar_per_page']))
                $this->sdwas = $option2['_custom_sidebar_per_page'];

        if( isset($this->sdwas) && sizeof($this->sdwas) > 0) {  
            foreach($this->sdwas as $sid => $sdwa) {

                register_sidebar(
                    array (
                        'name'          => $sdwa,
                        'id'            => sanitize_title($sdwa),
                        'description'   => __( 'Page specific sidebars that can be chosen per page', 'pietergoosen' ),
                        'before_widget' => '<aside id="%1$s" class="widget %2$s">',
                        'after_widget'  => '</aside>',
                        'before_title'  => '<h1 class="widget-title">',
                        'after_title'   => '</h1>',
                    )
                );
            }
        }
    }
}

$pgsidebar = new PieterGoosen_Custom_Sidebars();

EDIT

As @isNaN suggested, I have tried that.

public function __construct() {
    if (is_admin()) {
        add_action( 'add_meta_boxes', array( $this, 'add_cspp' ) );
        add_action( 'save_post', array( $this, 'save_cspp' ) );
        add_action( 'admin_init', array( $this, 'init' ) );
        add_action( 'admin_menu', array( $this, 'add_page' ) );
    } 
        add_action( 'widgets_init', array( $this, 'sidebars_register' ) );
    }

I'm not sure if that is the correct way. All functions are still executed by using this method. It is just the hooks that are not executed as they are inside the conditional tag. I really think that there should be a way to completely wrap all relevant functions in the is_admin() conditional tag, not just the action hooks

share|improve this question

2 Answers 2

up vote 2 down vote accepted

Your real problem is the god class. You put rendering, sanitation, validation, saving and fetching data, and registration into one class. Separate your tasks to make it it OOP, and let the main class be a very simple front controller that handles the initial registration only.

Here is a rough start, illustrating how I would do that:

// validate nonces
interface PG_Nonce_Validator_Interface {
    public function is_valid();
    public function get_name();
    public function get_action();
}
class PG_Nonce_Validator implements PG_Nonce_Validator_Interface {
    public function __construct( $base_string ) {}
    public function is_valid() {}
    public function get_name() {}
    public function get_action() {}
}

// validate request for the action 'save_post'
interface PG_Request_Validator_Interface {
    public function is_valid();
}
class PG_Save_Post_Validator implements PG_Request_Validator_Interface {
    public function __construct( PG_Nonce_Validator_Interface $nonce_validator ) {}
    public function is_valid() {}
}

// sanitation
interface PG_Sanitize_Data_Interface {
    public function sanitize( $data );
}
class PG_Sanitize_Data implements PG_Sanitize_Data_Interface {
    public function sanitize( $data ) {}
}

// data access
interface PG_Data_Interface {
    public function save( $data );
    public function get();
}
class PG_Option_Data implements PG_Data_Interface {
    public function __construct( $option_name ) {}
    public function save( $data ) {}
    public function get() {}
}

interface PG_View_Interface {
    public function render();
}

interface PG_Event {
    public function trigger( $name, $data = NULL );
}

class PG_Settings_Page implements PG_View_Interface {

    public function __construct() {

    }

    public function render() {}
}


class PG_Custom_Sidebars {

    private $option_name = 'cspp_get_option';

    // we do not run methods automatically in a constructor
    public function setup() {

        if ( is_admin() )
            $this->register_admin_actions();

        add_action( 'widgets_init', array( $this, 'register_sidebars' ) );
    }

    public function register_sidebars() {}

    private function register_admin_actions() {

        $nonce             = new PG_Nonce_Validator( 'pg_nonce' );
        $request_validator = new PG_Save_Post_Validator( $nonce );
        // and so on …
    }
}

$pg_custom_sidebars = new PG_Custom_Sidebars;
$pg_custom_sidebars->setup();

You can find examples for similar classes in Multilingual Press:

The basic idea is: load and instantiate only the code you actually need. Keep your classes as small as possible, keep them testable.

A View class should never know when it has to show something, just what (a title, a description, a submit button). And it shouldn’t even know where the data comes from.

Maybe you want to store the data in a user meta field later, not in an option? Just create a new concrete implementation for PG_Data_Interface and call that in your controller – without touching any of the other classes.

share|improve this answer
    
Many thanks toscho. +++25 –  Pieter Goosen Apr 19 at 17:55

You can add the is_admin() function in your constructor to separate the logic.

/* php */
public function __construct() {
    if (is_admin()) {
        /* add actions for admins here */
        add_action( 'init', array( $this, 'do_admin_stuff' ) );
    } else {
        /* add actions for front-end here */
        add_action( 'init', array( $this, 'do_front_end_stuff' ) ); 
    }
}
share|improve this answer
    
I have done something like this, but I'm not sure if this/was the correct way. –  Pieter Goosen Apr 19 at 9:23
    
Please see my update. Thanks for your help so far. +1 for that –  Pieter Goosen Apr 19 at 9:31
    
I'm not sure I see the problem now, are you executing functions outside of the action hooks? All your functions are public, so they are available to the rest of your code (other classes, etc) You don't have an "else" in your updated example, so everything passes for admin-view. But only the last hook should trigger on the front end. –  isNaN Apr 19 at 9:39
    
There is no need for the else statement, the third set of code should execute backend and frond end. So that works fine without the else statement. –  Pieter Goosen Apr 19 at 9:53

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.