PagePermissions.php 10.1 KB
<?php
namespace Tz\WordPress\Tools\PagePermissions;

use Tz\WordPress\Tools, Tz\WordPress\Tools\ClientSettings;

use \ReflectionClass, \ReflectionException;
use \WP_User;

/**
 * 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;


function make() {
    Vars::$current_user = _get_current_user();
}

function initAjax() {
    $selected = unserialize($_POST['string_value']);
    include(__DIR__ . 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
 */
function current_user_can_view($post_id = false) {
    static $settings = false;
    if (false === $settings) {
        $settings = new Tools\WP_Option(SETTING_NS);
    }

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

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

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

    // Login required
    if ($data[ELE_SEL] == 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[ELE_SEL] == OPT_CUST) {
        // User isn't even logged in; send message
        if (!is_user_logged_in()) {
            return $settings[ELE_CUST_AUTH];
        }

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

        // User is logged in, but doesn't have sufficient privileges, return message
        return $settings[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
 */
function get_user_role($user = false) {
    if (false === $user) {
        $user_data = Vars::$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}
 */
function is_admin($user = false) {
    return (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
 */
function getFieldNames() {
    static $fields = false;
    if (false !== $fields) {
        return $fields;
    }

    $fields = Array();
/*
    $ref    = new ReflectionClass(__CLASS__);
    $consts = $ref->getConstants();
*/
    // Need to do this since 5.3, namespace instead of Class, can't reflect namespaces
    $consts = Array(
        'ELE_SEL'       => 'general_access'
      , 'ELE_CUST'      => 'roles'
      , 'ELE_AUTH'      => 'message_auth'
      , 'ELE_CUST_AUTH' => 'message_cust_auth'
      , 'ELE_DENIED'    => 'message_cust_denied'
    );

    foreach ($consts as $const => $value) {
        if (substr($const, 0, 4) == 'ELE_') {
            $fields[$const] = $value;
        }
    }

    return $fields;
}

class Vars {
    /**
     * WP current user data
     * @type Array
     */
    public static $current_user = false;
}

namespace Tz\WordPress\Tools\PagePermissions\Admin;

use Tz\WordPress\Tools;
use Tz\WordPress\Tools\PagePermissions;
use Tz\WordPress\Tools\ClientSettings;

const CAPABILITY  = 'manage_page_permissions';
const ADMIN_PAGE  = 'page-permission-settings';
const SUBMIT_HOOK = 'update_def_page_permissions';
const SETTING_NS  = 'page_permission_defaults';

function make() {
    Tools\import('ClientSettings');

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

    Tools\add_filters(__NAMESPACE__ . '\Filters');

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

    Tools\add_actions(__NAMESPACE__ . '\Actions');
}

function viewOptionsPage() {
    $selected = getOptions();

    include(__DIR__ . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . 'settings.php');
}

function viewMetaBox($post, $box_info) {
    $selected = ($post->ID == 0 ? getOptions() : array_shift(get_post_meta($post->ID, PagePermissions\META)));

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

    include(__DIR__ . DIRECTORY_SEPARATOR . 'views' . DIRECTORY_SEPARATOR . 'form.php');
}

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

    $options = getOptions();
    $fields  = PagePermissions\getFieldNames();
    foreach ($fields as $field) {
        if (isset($_POST[$field])) {
            $options[$field] = array_stripslashes($_POST[$field]);
        } else {
            $options[$field] = '';
        }
    }

    $options->save();
}

function array_stripslashes($value) {
    return (is_array($value) ? array_map(__FUNCTION__, $value) : stripslashes($value));
}

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

    $options = new Tools\WP_Option(SETTING_NS);
    return $options;
}

/**
 * Each method is a handler for it's WordPress `add_action` namesake
 */
class 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");
        }

        // This is hackey, but WP does't have hooks for this for some reason...
        // Ideally this is in its own `edit_attachment` method...but that isn't working
        if (isset($_POST['action']) && $_POST['action'] == 'editattachment') {
            $real_id = $_POST['attachment_id'];
            $current = array_shift(get_post_meta($real_id, PagePermissions\META));
    
            $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 (is_null($current)) {
                add_post_meta($real_id, PagePermissions\META, $new, true);
            } else {
                update_post_meta($real_id, PagePermissions\META, $new);
            }
        }
    }

    public static function admin_menu() {
        if (current_user_can(ClientSettings\CAPABILITY)) {
            add_submenu_page(ClientSettings\ADMIN_PAGE, 'Permission Defaults', 'Permission Defaults', CAPABILITY, ADMIN_PAGE, __NAMESPACE__ . '\viewOptionsPage');
            add_meta_box('page_permissions', 'Page Permissions', __NAMESPACE__ . '\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 = array_shift(get_post_meta($_GET['attachment_id'], PagePermissions\META));
            if (is_null($selected)) {
                $selected = getOptions();
            }

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

        _enqueue_script('page-permissions', Tools\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)
        ));
    }

    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 = array_shift(get_post_meta($real_id, PagePermissions\META));

        $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 (is_null($current)) {
            add_post_meta($real_id, PagePermissions\META, $new, true);
        } else {
            update_post_meta($real_id, PagePermissions\META, $new);
        }
    }
}

class Filters {
    public static function flash_uploader() {
        return false;
    }
}

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