post_status == 'private'); } } // Whether the current posts is of the given level function is_post_level($level = 0) { global $postlevels_post_key; $val = get_post_custom_values($postlevels_post_key); if (!empty($val)) return ($val == $level); else return ($level == 0); } } else { // Not logged in, define fast functions that don't use the DB // in case they're used in the templates function is_post_level($level = 0) { return ($level == 0); } if (!function_exists('is_private')) { function is_private() { return false; } } // Perhaps we're supposed to show previews? global $postlevels_post_preview; $postlevels_post_preview = get_option('postlevels_post_preview'); if (($postlevels_post_preview == 'title') || ($postlevels_post_preview == 'excerpt') || ($postlevels_post_preview == 'teaser')) { // Initialize global variables global $postlevels_post_key, $postlevels_user_key, $postlevels_current_user_level; $postlevels_post_key = get_option('postlevels_post_key'); $postlevels_user_key = get_option('postlevels_user_key'); $postlevels_current_user_level = get_option('postlevels_default_user_level'); // Setup filters add_filter('query', 'postlevels_query'); add_filter('the_content', 'postlevels_the_content'); add_filter('the_title', 'postlevels_the_title'); add_filter('get_comment_text', 'postlevels_get_comment_text'); if ($postlevels_post_preview == 'title') add_filter('get_the_excerpt', 'postlevels_the_excerpt'); } } } // Creates the database-stored options for the plugins that customize // the plugin's behavior function postlevels_setup_options() { add_option('postlevels_post_key', 'post_level', "The name of the custom field used for specifiying a post's level", 'yes'); add_option('postlevels_user_key', 'postlevels_user_level', "The name of the custom field used for specifiying a user's privacy level", 'yes'); add_option('postlevels_default_post_level', '0', "Default post level for private posts", 'yes'); add_option('postlevels_default_user_level', '0', "Default user privacy level for users", 'yes'); add_option('postlevels_private_before_title', '', "Default text placed before the title of a private post", 'yes'); add_option('postlevels_private_after_title', '', "Default text placed after the title of a private post", 'yes'); add_option('postlevels_post_preview', 'none', "Whether users see a preview of private posts", 'yes'); } function postlevels_posts_distinct($distinct) { return ($distinct == '') ? 'DISTINCT' : $distinct; } function postlevels_posts_groupby($groupby) { global $wpdb; return ($groupby == '') ? $wpdb->posts.'.ID' : $groupby; } function postlevels_get_comment_text($text) { global $post; if ($post->post_status != 'private') return $text; return "
You must be logged in to see this private comment
"; } function postlevels_the_content($content) { global $postlevels_post_preview, $post; if($post->post_status != 'private') return $content; if (($postlevels_post_preview == 'teaser') && preg_match('//', $post->post_content)) { return $content; } else if (($postlevels_post_preview == 'excerpt') && ($post->post_excerpt != '')) { // Ideally, we would use get_the_excerpt, but that causes issues return "" . $post->post_excerpt . '
'; } else { return 'You must be logged in to see this private post
'; } } function postlevels_the_excerpt($excerpt) { global $postlevels_post_preview, $post; if (($post->post_status != 'private')) return $excerpt; return "You must be logged in to see this private post
"; } // Edit the many SQL queries that do not have specific filters // This is almost guaranteed to break some day function postlevels_query($sql) { global $postlevels_current_user_level, $postlevels_post_key, $wpdb; // Hack, for now if (postlevels_query_match($sql)) { // Collect the cleanup hacks in one place ... $sql = postlevels_query_cleanup($sql); // Add the join $sql = preg_replace("/([\s|,]){$wpdb->posts}([\s|,])/", "$1({$wpdb->posts} LEFT JOIN {$wpdb->postmeta} as pl_{$wpdb->postmeta} ON ({$wpdb->posts}.ID = pl_{$wpdb->postmeta}.post_id))$2", $sql); // Modify the where clause $sql = preg_replace("/({$wpdb->posts}\.)?post_status[\s]*=[\s]*[\'|\"]publish[\'|\"]/", " ({$wpdb->posts}.post_status = 'publish' OR ({$wpdb->posts}.post_status = 'private' AND (pl_{$wpdb->postmeta}.meta_key = '$postlevels_post_key' AND pl_{$wpdb->postmeta}.meta_value <= $postlevels_current_user_level )))", $sql); // Check for distinct if (strpos(strtoupper($sql), "DISTINCT") === false) { $sql = str_replace("{$wpdb->posts}.*", "DISTINCT {$wpdb->posts}.*", $sql); $sql = preg_replace("/[\s]\*/", " DISTINCT {$wpdb->posts}.*", $sql); } } return $sql; } function postlevels_query_cleanup($sql) { global $wpdb; // Watch out for ambiguity with post2cat if (strpos($sql, "post2cat") !== false) { $sql = preg_replace("/[\s]post_id/", " {$wpdb->post2cat}.post_id", $sql); } // For extended live archives only if (function_exists('af_ela_super_archive')) { // ELA uses p as a shorthand for the posts table ... undo that work $sql = preg_replace("/[\s]p[\s]/", ' ', $sql); $sql = preg_replace("/([\s|(])p\./", "$1{$wpdb->posts}.", $sql); } if (is_search() && function_exists('UTW_ShowTagsForCurrentPost')) { // UTW's INNER join causes issues ... maybe this will be fixed in the next version? $sql = str_replace("INNER JOIN", "LEFT JOIN", $sql); } return $sql; } // Tells us whether or not we should edit the query function postlevels_query_match($sql) { global $wpdb; return ((preg_match("/post_status[\s]*=[\s]*[\'|\"]publish[\'|\"]/", $sql)) && (preg_match("/[\s|,]{$wpdb->posts}[\s|,]/", $sql))); } // Enable users with the right level to read a private post // This is required because single post viewing has special logic // $allcaps = Capabilities the user currently has // $caps = Primitive capabilities being tested / requested // $args = array with: // $args[0] = original meta capability requested // $args[1] = user being tested // $args[2] = post id to view // See code for assumptions function postlevels_has_cap($allcaps, $caps, $args) { // This handler is only set up to deal with certain // capabilities. Ignore all other calls into here. if (!in_array('read_private_posts', $caps) && !in_array('read_private_pages', $caps)) { // These aren't the droids you're looking for return $allcaps; } global $postlevels_post_key, $postlevels_user_key; // As of WP 2.0, read_private_post is only requested when viewing // a single post. When this happens, the args[] array has three values, // as shown above. If WP changes the args[], this plugin will break // UPDATE: WP 2.1 has read_private_pages // The level of the post being tested $post_level = get_post_meta($args[2], $postlevels_post_key, true); if ($post_level == '') { $post_level = get_option('postlevels_default_post_level'); } // The level of the user being tested $user_level = get_usermeta($args[1], $postlevels_user_key); if ($user_level == '') { $user_level = get_option('postlevels_default_user_level'); } // Add the capabilities $allcaps['read_private_posts'] = $allcaps['read_private_pages'] = ($user_level >= $post_level); return $allcaps; } // Modifies the text of a private post function postlevels_the_title($title, $incomingpost = null) { // It's really annoying that WP will call this function sometimes // with a string for the second paramter, and sometimes with // an object ... this checks for that. if (!is_object($incomingpost)) { global $post; $incomingpost = $post; } if ($incomingpost->post_status == 'private') { $title = str_replace("Private: ", "", $title); return get_option('postlevels_private_before_title') . $title . get_option('postlevels_private_after_title'); } else { return $title; } } // Gets the user level of the current user // If the user isn't logged in, returns null function postlevels_get_user_level() { if (!is_user_logged_in()) { return null; } global $user_ID, $postlevels_user_key; get_currentuserinfo(); $postlevels_current_user_level = get_usermeta($user_ID, $postlevels_user_key, true); // Only want numbers here if (($postlevels_current_user_level == '') || !is_numeric($postlevels_current_user_level)) { return intval(get_option('postlevels_default_user_level')); } return intval($postlevels_current_user_level); } // Sets up the post levels admin menu function postlevels_admin_hook() { global $postlevels_post_key, $postlevels_user_key; if (function_exists('add_submenu_page')) { add_submenu_page('plugins.php', 'Post Levels Configuration', 'Post Levels Configuration', 8, __FILE__, 'postlevels_conf'); add_submenu_page('users.php', 'User Levels', 'User Levels', 8, __FILE__, 'postlevels_users'); } add_filter('manage_posts_columns', 'postlevels_add_column'); add_action('manage_posts_custom_column', 'postlevels_do_column'); add_action('simple_edit_form', 'postlevels_do_form'); add_action('edit_page_form', 'postlevels_do_form'); add_action('edit_form_advanced', 'postlevels_do_form'); add_filter('status_save_pre', 'postlevels_status_save'); add_action('save_post', 'postlevels_post_save'); } // Called when a post is saved, updates the post level function postlevels_post_save($post_ID) { global $postlevels_post_key; $post = get_post($post_ID); if (($_POST['post_level'] != '') || ($post->post_status == 'private')) { // Private post with no post level gets default if ($_POST['post_level'] == '') { $post_level = get_option('postlevels_default_post_level'); } else { $post_level = $_POST['post_level']; } // Check if old value exists so we know whether to update or add $old_value = get_post_meta($post_ID, $postlevels_post_key, true); if ($old_value != '') { update_post_meta($post_ID, $postlevels_post_key, $post_level); } else { add_post_meta($post_ID, $postlevels_post_key, $post_level); } } } // Called before post status is updated on save. Marks // post as private if the post level is set function postlevels_status_save($post_status) { if (($_POST['post_level'] != '') && ($post_status == 'publish')) return 'private'; else return $post_status; } // Adds a post level column to manage post list function postlevels_add_column($posts_columns) { $posts_columns['post_level'] = 'Post Level'; return $posts_columns; } // Outputs the post level value for each post in the manage post list function postlevels_do_column($column_name) { global $postlevels_post_key; if ($column_name != 'post_level') return false; global $post; if ($post->post_status != 'private') { echo 'Public'; return true; } echo get_post_meta($post->ID, $postlevels_post_key, true); return true; } // Called during the edit form, outputs the post level drop down function postlevels_do_form() { global $post, $postlevels_post_key; echo ''; } // Post Levels configuration page function postlevels_conf() { global $postlevels_user_key, $postlevels_post_key; global $table_prefix; $default_user_key = $table_prefix . 'user_level'; ?>Post Levels is a plugin that allows you to restrict access to your posts based upon the user's access level.
' . __('Options saved.') . '
' . __('User levels changed for ') . count($userids) . ' ' . __('user(s)') . '
'; } else { echo '' . __('No users updated (none checked)') . '
' . __('No users updated (you must click the button below "Update User Levels")') . '
This page controls the level of each user, which determines what posts can and cannot be seen by that user.