WordPress の管理画面にユーザー権限グループに応じた class を出力する

管理画面の body_class に相当する admin_body_class にフィルターフックをかけて、ユーザーの権限グループを含める方法

出力されるソースの修正ができない場合、これを使ってCSSで非表示にすることができますね。
CSSの読み込みは、admin_initなどで、wp_enqueue_style すればオッケー。

admin_body_class で渡されてくるものは文字列形式なので、扱いがちょっとめんどくさいのだけど。

function add_user_role_class( $admin_body_class ) {
	global $current_user;
	if ( ! $admin_body_class ) {
		$admin_body_class .= ' ';
	}
	$admin_body_class .= 'role-' . urlencode( $current_user->roles[0] );
	return $admin_body_class;
}
add_filter( 'admin_body_class', 'add_user_role_class' );

出力結果はこんな感じ

<body class="wp-admin wp-core-ui no-js  role-administrator index-php auto-fold admin-bar branch-3-5 version-3-5 admin-color-fresh locale-ja no-customize-support">

role-administrator で判別可能ですね。

非表示にする以外にもいろんな使い方ができそうな気がするので、こんな方法あるよってーのがあったら こそっと 教えてくださいw

カスタム投稿タイプを管理する Custom Post Type Maker を試してみた

管理画面からカスタム投稿タイプやら、カスタム分類やらを設定するために有名なプラグインといえば、Custom Post Type UI だと思いますが、デバッグモードにすると notice エラーが出たり(あまり人のこと言えない。。)、アップデートもしばらくされておらず、3.5 で追加になったパラメーターの指定ができなかったり、UIが今ひとつ使いにくいなど、今後にちょっと心配があり、代替となるプラグインで良いものないかなと探していたところ、Custom Post Type Maker の存在を知り、試してみました。

結論から言うと、現バージョンでは、使用すべきではないというのが私の判断です。

カスタム投稿タイプなどを新しく追加した場合、表示されるURLが新たに加わりますが、パーマリンク使用時にこのURLを表示するためには、リライトルールというマッピングデータを更新してあげる必要があります。

Custom Post Type Maker は、Webページ表示時にこのリライトルールを毎回再生成しているのですね。こうすることによって、新しくカスタム投稿タイプやカスタム分類を追加したときにも、自動的に表示されるようになるのですが、このリライトルールの再生成は、それなりに重い処理で表示の際に毎回やるようなことではありません。これは、Codex の flush_rewrite_rules の説明にもしっかりと注意書きとして載っています。

Important: Flushing the rewrite rules is an expensive operation, there are tutorials and examples that suggest executing it on the ‘init’ hook. This is bad practice. Instead you should flush rewrite rules on the activation hook of a plugin, or when you know that the rewrite rules need to be changed ( e.g. the addition of a new taxonomy or post type in your code ).

WordPress は、3.3 で、リライトルールの改善を行い、この処理も大幅に軽減はされていますが、毎回行うようなことではありません。

私の判断ではありますが、この点が改善されるまで、利用すべきでないプラグインととらえています。

カスタム分類を利用して、先頭に固定表示を実現する

WordPress には、先頭に固定表示の機能もありますが、1ページ目の最初にモリッと差し込まれるので、表示件数が変わってしまったり、ページ送りにも対応できません。

これを、カスタム分類を用いて、

  • 該当分類に属するものを、home 表示の際に優先表示
  • 1ページの表示投稿数は、設定通りにする
  • 先頭固定表示の記事のあとは、それ以外の記事を最新順に
  • ページ送り・ページナビに影響がでないこと

を満たすものを作ってみました。

具体的には、news というカスタム分類で、sticky という分類に属する投稿を先頭表示されるようにしています。

また、些細な工夫として、複数箇所から呼ばれる get_custom_sticky_posts で、wp_cache_set と wp_cache_get を使っています。これを使うと、実行結果がメモリ上にキャッシュされるため、複数回呼ばれるような場面においても、パフォーマンスロスを防ぐことができるようになります。

/*
 * 通常表示されるべき投稿を先頭固定の投稿で差し替える
 */
function insert_custom_sticky_posts( $posts, $wp_query ) {
	if ( ! is_admin() && $wp_query->is_home() ) {
		$stickies = get_custom_sticky_posts();
		if ( $stickies ) {
			$posts_per_page = $wp_query->get( 'posts_per_page' );
			$paged = $wp_query->get( 'paged' ) ? $wp_query->get( 'paged' ) : 1;

			if ( count( $stickies ) >= $posts_per_page * $paged ) { // 全て差し替え
				$posts = array_slice( $stickies, $posts_per_page * ( $paged - 1 ), $posts_per_page );
			} elseif ( count( $stickies ) > $posts_per_page * ( $paged - 1 ) ) {
				$insert_sickies = array_slice( $stickies, $posts_per_page * ( $paged - 1 ), $posts_per_page );
				$posts = array_merge( $insert_sickies, $posts );
				$posts = array_slice( $posts, 0, $posts_per_page );
			}
		}
	}
	return $posts;
}
add_filter( 'the_posts', 'insert_custom_sticky_posts', 10, 2 );

/*
 * 全投稿数に先頭固定の投稿数を足す
 */
function add_custom_sticky_posts_count( $found_posts, $wp_query ) {
	if ( ! is_admin() && $wp_query->is_home() && ! $wp_query->get( 'suppress_filters' ) ) {
		$found_posts = $found_posts + count( get_custom_sticky_posts() );
	}

	return $found_posts;
}
add_filter( 'found_posts', 'add_custom_sticky_posts_count', 10, 2 );

/*
 * SQL文のLIMIT 句を改変し、先頭固定の投稿数文を差し引いた開始位置にする
 */
function replace_custom_sticky_posts_limit_sql( $limits, $wp_query ) {
	if ( ! is_admin() && $wp_query->is_home() ) {
		$stickies = get_custom_sticky_posts();
		if ( $stickies ) {
			$posts_per_page = $wp_query->get( 'posts_per_page' );
			$paged = $wp_query->get( 'paged' ) ? $wp_query->get( 'paged' ) : 1;

			$start = $posts_per_page * ( $paged - 1 ) - count( $stickies );
			if ( $start < 0 ) {
				$start = 0;
			}
			$limits = "LIMIT $start, $posts_per_page";
		}
	}

	return $limits;
}
add_filter( 'post_limits', 'replace_custom_sticky_posts_limit_sql', 10, 2 );

/*
 * 通常表示の記事から、先頭固定表示する投稿を除外する
 */
function ignore_custom_stickies( $wp_query ) {
	if ( ! is_admin() && $wp_query->is_home() && ! $wp_query->get( 'suppress_filters' ) ) {
		$wp_query->set(
			'tax_query',
			array(
				'relation' => 'AND',
				array(
					'taxonomy' => 'news',
					'terms' => array( 'sticky' ),
					'field' => 'slug',
					'operator' => 'NOT IN',
				),
			)
		);
	}
}
add_action( 'pre_get_posts' , 'ignore_custom_stickies' );

/*
 * 先頭固定表示する投稿を全て取得する
 */
function get_custom_sticky_posts() {
	$cache_key = 'custom-sticky-posts';
	$stickies = wp_cache_get( $cache_key );

	if ( $stickies === false ) {
		$stickies = get_posts(
			array(
				'posts_per_page' => -1,
				'tax_query' => array(
					'relation' => 'AND',
					array(
						'taxonomy' => 'news',
						'terms' => array( 'sticky' ),
						'field' => 'slug',
						'operator' => 'IN',
					),
				)
			)
		);
		wp_cache_set( $cache_key, $stickies );
	}
	return $stickies;
}

■ 更新
2013.03.22 suppress_filters による条件分岐を追加しました。

WordPress 3.5 からの新アップローダーでもメディア表示をアップロードしたユーザーのみに限定する

以前投稿した、WordPress のメディア表示をアップロードしたユーザーのみに限定する では、3.5から導入された新アップローダーのメディア表示には対応できていませんでした。これは、新アップローダーが Ajax で動作しているため、先の記事で紹介した条件分岐の is_main_query に合致せず、ユーザーでの限定条件が付加されなかったのが原因です。

新アップローダーの画像取得は、wp-admin/includes/ajax-actions.phpwp_ajax_query_attachments で行われています。
画像の取得自体は、WP_Query を利用しているので、旧バージョンで用いた pre_get_posts でのフックも有効ではありますが、残念な事に、このままだとこの関数によるクエリーかどうかの判別条件が曖昧です。

そこで、この Ajax が動作するときのみ有効となる定数を設定して、それを pre_get_posts の条件に加えることにします。

WordPress の Ajax は、wp-admin/admin-ajax.php にリクエストされ、アクションフックを用いて、実行関数が呼ばれるようになっています。該当箇所のコードは、

CODE 1

add_action( 'wp_ajax_' . $_GET['action'], 'wp_ajax_' . str_replace( '-', '_', $_GET['action'] ), 1 );

となっており、画像取得の場合は、wp_ajax_query-attachments というフックが呼ばれます。Ajax の実行関数が呼ばれる優先度は、CODE 1 を見てわかるように 1 となっているので、定数の定義を行うには、これより優先度が高い(数字が少ない)優先度を設定して、早く行わなければなりません。

優先度 0 にて、DOING_QUERY_ATTACHMENT という定数を設定し、この定数の定義の有無により、ユーザーの条件を付加させるためには、

CODE 2

/*
 * メディアの抽出条件にログインユーザーの絞り込み条件を追加する
 */
function display_only_self_uploaded_medias( $wp_query ) {
	if ( is_admin() && ( $wp_query->is_main_query() || ( defined( 'DOING_QUERY_ATTACHMENT' ) && DOING_QUERY_ATTACHMENT ) ) && $wp_query->get( 'post_type' ) == 'attachment' ) {
		$user = wp_get_current_user();
		$wp_query->set( 'author', $user->ID );
	}
}
add_action( 'pre_get_posts', 'display_only_self_uploaded_medias' );


function define_doing_query_attachment_const() {
	if ( ! defined( 'DOING_QUERY_ATTACHMENT' ) ) {
		define( 'DOING_QUERY_ATTACHMENT', true );
	}
}
add_action( 'wp_ajax_query-attachments', 'define_doing_query_attachment_const', 0 );

と、いった感じになります。

WordPress の記事一覧で他ユーザーの投稿を非表示にする

http://ja.forums.wordpress.org/topic/15002 への回答例として

他ユーザーの投稿を編集する権限がない場合に、一覧表示から他ユーザーの記事を除外してしまう方法

function exclude_other_posts( $wp_query ) {
	if ( isset( $_REQUEST['post_type'] ) && post_type_exists( $_REQUEST['post_type'] ) ) {
		$post_type = get_post_type_object( $_REQUEST['post_type'] );
		$cap_type = $post_type->cap->edit_other_posts;
	} else {
		$cap_type = 'edit_others_posts';
	}

	if ( is_admin() && $wp_query->is_main_query() && ! $wp_query->get( 'author' ) && ! current_user_can( $cap_type ) ) {
		$user = wp_get_current_user();
		$wp_query->set( 'author', $user->ID );
	}
}
add_action( 'pre_get_posts', 'exclude_other_posts' );
所有 (1) | すべて (7) | 公開済み (4) | 下書き (3)

の数字が合わなくなってしまうのが気になる方は、CSSで .count に display: none; があたるようにしてください。