PagePermissions.php 10.8 KB
<?php
/**
 * Public API
 */
class PagePermissions {
    /**
     * The name of the custom field stored in a post/page
     * @type String
     */
    const META = 'accessible_to_roles';
    const OPT  = '';

    const ELE_SEL       = 'general_access';
    const ELE_CUST      = 'roles';
    const ELE_AUTH      = 'message_auth';
    const ELE_CUST_AUTH = 'message_cust_auth';
    const ELE_DENIED    = 'message_cust_denied';

    /**
     * Lookup value for ELE_SEL for all users
     * @type Integer
     */
    const OPT_ALL  = 0;
    /**
     * Lookup value for ELE_SEL for login required
     * @type Integer
     */
    const OPT_AUTH = 1;
    /**
     * Lookup value for ELE_SEL for custom roles
     * @type Integer
     */
    const OPT_CUST = 2;

    /**
     * WP current user data
     * @type Array
     */
    private static $current_user = false;

    public static function init() {
        if (false !== self::$current_user) {
            throw new OverflowException('PagePermissions already initialized');
        }

        self::$current_user = _get_current_user();
    }

    public static function initAjax() {
        $selected = unserialize($_POST['string_value']);
        include(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . 'form.php');
    }

    /**
     * The key function in all of this; called by the Theme,
     *  this determines if the user is able to view the page.
     * @param {Integer} $post_id
     * @returns {Boolean|String} true if user can view, error message if not
     * @throw InvalidArgumentException
     */
    public static function current_user_can_view($post_id = false) {
        static $settings = false;
        if (false === $settings) {
            $settings = new WP_Option(PagePermissionsAdmin::SETTING_NS);
        }

        if (false === $post_id) {
            global $post;
            $post_id = $post->ID;
        }

        // Meta value hasn't been set, getting settings defaults
        if ('' === $data = get_custom_data(self::META, $post_id)) {
            $data = Array(self::ELE_SEL => $settings[self::ELE_SEL], self::ELE_CUST => $settings[self::ELE_CUST]);
        }

        // Anyone has access, God has no limitations
        if ($data[self::ELE_SEL] == self::OPT_ALL || self::is_admin()) {
            return true;
        }

        // Login required
        if ($data[self::ELE_SEL] == self::OPT_AUTH) {
            // User is logged in
            if (is_user_logged_in()) {
                return true;
            }

            // Not logged in; return "login required" message
            return $settings[self::ELE_AUTH];
        }

        // Specific role required
        if ($data[self::ELE_SEL] == self::OPT_CUST) {
            // User isn't even logged in; send message
            if (!is_user_logged_in()) {
                return $settings[self::ELE_CUST_AUTH];
            }

            // User meets role required
            if (isset($data[self::ELE_CUST][self::get_user_role()])) {
                return true;
            }

            // User is logged in, but doesn't have sufficient privileges, return message
            return $settings[self::ELE_DENIED];
        }

        // This shouldn't happend; but just in case
        return 'An unknown permission error has occurred';
    }

    /**
     * @param {Integer|String} $user Username or ID of user to lookup (or false for current user)
     * @returns {String} $role The key of the users' role
     */
    public static function get_user_role($user = false) {
        if (false === $user) {
            $user_data = self::$current_user;
        } else {
            $user_data = new WP_User($user);
        }

        // or should I throw an exception?
        if ($user_data->ID == 0) {
            return '';
        }

        $user_roles = $user_data->roles;
        $user_role  = array_shift($user_roles);

        return $user_role;
    }

    /**
     * Determine if a user is a site administrator
     * @param {Integer|String} $user Username or ID of user to lookup (or false for current user)
     * @returns {Boolean}
     */
    public static function is_admin($user = false) {
        return (self::get_user_role($user) == 'administrator' ? true : false);
    }

    /**
     * Get a lookup of all the forum elements
     * @returns {Array} An associative array of the forum elemnts name/values
     */
    public static function getFieldNames() {
        static $fields = false;
        if (false !== $fields) {
            return $fields;
        }

        $fields = Array();
        $ref    = new ReflectionClass(__CLASS__);
        $consts = $ref->getConstants();
        foreach ($consts as $const => $value) {
            if (substr($const, 0, 4) == 'ELE_') {
                $fields[$const] = $value;
            }
        }

        return $fields;
    }
}

/**
 * Aministration control
 */
class PagePermissionsAdmin {
    const CAPABILITY  = 'manage_page_permissions';
    const ADMIN_PAGE  = 'page-permission-settings';
    const SUBMIT_HOOK = 'update_def_page_permissions';
    const SETTING_NS  = 'page_permission_defaults';

    public static function make() {
        static $made = false;
        if ($made) {
            throw new OverflowException('make has already beed called');
        }
        $made = true;

        TzTools::import('ClientSettings');

        $role = get_role('administrator');
        $role->add_cap(self::CAPABILITY);

        add_filters('PagePermissionsAdmin_Filters');

        if (isset($_POST[self::SUBMIT_HOOK]) && current_user_can(self::CAPABILITY)) {
            self::submit();
        }

        add_actions('PagePermissions_Actions');
    }

    public static function viewOptionsPage() {
        $selected = self::getOptions();

        include(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . 'settings.php');
    }

    public static function viewMetaBox($post, $box_info) {
        $selected = ($post->ID == 0 ? self::getOptions() : get_custom_data(PagePermissions::META, $post->ID));

        // If the post doesn't have the field saved get defaults
        if (empty($selected)) {
            $selected = self::getOptions();
        }

        include(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . 'form.php');
    }

    /**
     * Handles saving data when a post/page is saved
     */
    public static function submit() {
        unset($_POST[self::SUBMIT_HOOK]);

        $options = self::getOptions();
        $fields  = PagePermissions::getFieldNames();
        foreach ($fields as $field) {
            if (isset($_POST[$field])) {

                // This should probably be done via a recursive fn call or array_walk or something
                if (is_array($_POST[$field])) {
                    $options[$field] = Array();
                    foreach ($_POST[$field] as $key => $val) {
                        $options[$field][$key] = stripslashes($_POST[$field]);
                    }
                } else {
                    // not sure if stripslashes should go here or in WP_Options
                    $options[$field] = stripslashes($_POST[$field]);
                }
            } else {
                $options[$field] = '';
            }
        }

        $options->save();
    }

    public static function getOptions() {
        static $options = false;
        if (false !== $options) {
            return $options;
        }

        $options = new WP_Option(self::SETTING_NS);
        return $options;
    }
}

/**
 * Each method is a handler for it's WordPress `add_action` namesake
 */
class PagePermissions_Actions {
    public static function init() {
        register_taxonomy(PagePermissions::META, 'attachment', Array('hierarachical' => false, 'label' => 'Page Permissions', 'query_var' => false));

        $file = $_SERVER['REQUEST_URI'];
        if ($file == '/wp-admin/media-new.php' && !PagePermissions::is_admin()) {
            header("Location: " . $file . "?flash=0");
        }
    }

    public static function admin_menu() {
        if (current_user_can(ClientSettings::CAPABILITY)) {
            add_submenu_page(ClientSettings::ADMIN_PAGE, 'Permission Defaults', 'Permission Defaults', PagePermissionsAdmin::CAPABILITY, PagePermissionsAdmin::ADMIN_PAGE, Array('PagePermissionsAdmin', 'viewOptionsPage'));
            add_meta_box('page_permissions', 'Page Permissions', Array('PagePermissionsAdmin', 'viewMetaBox'), 'page', 'side', 'low');
        }
    }

    public static function admin_print_scripts() {
        $innerhtml = '';
        if ('0' !== ($change_field = (isset($_GET['attachment_id']) ? 'attachments[' . $_GET['attachment_id'] . '][' . PagePermissions::META . ']' : '0'))) {
            $selected = get_custom_data(PagePermissions::META, $_GET['attachment_id']);
            if (empty($selected)) {
                $selected = PagePermissionsAdmin::getOptions();
            }

            ob_start();
            require(dirname(__FILE__) . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . 'form.php');
            $innerhtml = ob_get_contents();
            ob_end_clean();
        }

        _enqueue_script('page-permissions', plugins_url('PagePermissions.js', __FILE__));
        _localize_script('page-permissions', 'TzPagePermissionsData', Array(
            'trigger'      => PagePermissions::ELE_SEL
          , 'focus'        => PagePermissions::OPT_CUST
          , 'change_field' => $change_field
          , 'innerHTML'    => rawurlencode($innerhtml)
        ));

//attachments[304][accessible_to_roles]
//a:2:{s:14:"general_access";s:1:"1";s:5:"roles";a:1:{s:6:"editor";s:1:"1";}}
    }

    public static function save_post($post_id) {
        if ($_POST['action'] == 'autosave') {
            return;
        }

        if (false === ($real_id = _is_post_revision($post_id))) {
            $real_id = $post_id;
        }
        $current = get_custom_data(PagePermissions::META, $real_id);

        $new = Array();
        $new[PagePermissions::ELE_SEL] = $_POST[PagePermissions::ELE_SEL];
        if (isset($_POST[PagePermissions::ELE_CUST])) {
            $new[PagePermissions::ELE_CUST] = $_POST[PagePermissions::ELE_CUST];
        } else {
            $new[PagePermissions::ELE_CUST] = Array();
        }

        if (empty($current)) {
            add_post_meta($real_id, PagePermissions::META, $new, true);
        } else {
            update_post_meta($real_id, PagePermissions::META, $new);
        }
    }
}

class PagePermissionsAdmin_Filters {
    public static function image_upload_iframe_src($result) {
        return $result . '&flash=0';
    }

    public static function video_upload_iframe_src($result) {
        return $result . '&flash=0';
    }

    public static function audio_upload_iframe_src($result) {
        return $result . '&flash=0';
    }
}

    if (isset($_POST['tz_pp_ajax'])) {
        PagePermissions::initAjax();
    } else {
       PagePermissions::init();
        PagePermissionsAdmin::make();
    }
?>