問題描述
問題
WP 用來刪除我的查詢變數的值,然後才能過濾使用者列表。
我的程式碼
此功能將自定義列新增到/wp-admin/users.php 上的 Users 表中:
function add_course_section_to_user_meta( $columns ) {
$columns['course_section'] = 'Section';
return $columns;
}
add_filter( 'manage_users_columns', 'add_course_section_to_user_meta' );
該函式告訴 WP 如何填充列中的值:
function manage_users_course_section( $val, $col, $uid ) {
if ( 'course_section' === $col )
return get_the_author_meta( 'course_section', $uid );
}
add_filter( 'manage_users_custom_column', 'manage_users_course_section' );
這在 Users 表上面新增了一個下拉式清單和 Filter 按鈕:
function add_course_section_filter() {
echo '<select name="course_section" style="float:none;">';
echo '<option value="">Course Section...</option>';
for ( $i = 1; $i <= 3; ++$i ) {
if ( $i == $_GET[ 'course_section' ] ) {
echo '<option value="'.$i.'" selected="selected">Section '.$i.'</option>';
} else {
echo '<option value="'.$i.'">Section '.$i.'</option>';
}
}
echo '<input id="post-query-submit" type="submit" class="button" value="Filter" name="">';
}
add_action( 'restrict_manage_users', 'add_course_section_filter' );
此功能更改使用者查詢以新增我的 meta_query:
function filter_users_by_course_section( $query ) {
global $pagenow;
if ( is_admin() &&
'users.php' == $pagenow &&
isset( $_GET[ 'course_section' ] ) &&
!empty( $_GET[ 'course_section' ] )
) {
$section = $_GET[ 'course_section' ];
$meta_query = array(
array(
'key' => 'course_section',
'value' => $section
)
);
$query->set( 'meta_key', 'course_section' );
$query->set( 'meta_query', $meta_query );
}
}
add_filter( 'pre_get_users', 'filter_users_by_course_section' );
其他資訊
它正確地建立了我的下拉式清單。當我選擇課程部分並單擊 Filter 時,頁面重新整理,course_section 顯示在 URL 中,但沒有與之相關聯的值。如果我檢查 HTTP 請求,它顯示它提交了正確的變數值,但是後來有一個 302 Redirect 似乎刪除了我選擇的值。
如果我透過直接在 URL 中輸入 course_section 變數,過濾器將按預期方式工作。
我的程式碼大致基於 this code from Dave Court 。
我也嘗試使用這個程式碼列出我的查詢 var,但是沒有運氣:
function add_course_section_query_var( $qvars ) {
$qvars[] = 'course_section';
return $qvars;
}
add_filter( 'query_vars', 'add_course_section_query_var' );
我正在使用 WP 4.4 。任何想法為什麼我的過濾器不工作?
最佳解決方案
是什麼導致的問題
問題是 restrict_manage_users 操作被呼叫了兩次:一旦超過了 Users 表,並且一直是 BELOW 。這意味著使用相同的名稱建立兩個 select 下拉式清單。當單擊 Filter 按鈕時,第二個 select 元素 (即表中的一個) 中的任何值都將覆蓋第一個 Filter 元素中的值,即表中的值。
如果您想潛入 WP 源,restrict_manage_users 操作將從 WP_Users_List_Table::extra_tablenav($which)中觸發,WP_Users_List_Table::extra_tablenav($which)操作是建立本機下拉選單以更改使用者角色的功能。該函式有 $which 變數的幫助,它可以告訴它是否在表單之上或之下建立 select,並允許它給兩個不同的 name 屬性的下拉式清單。不幸的是,$which 變數不會傳遞給 restrict_manage_users 動作,所以我們必須提出另一種方式來區分我們自己的自定義元素。
像 @Linnea 在上面建議的一種方法是新增一些 JavaScript 來捕獲 Filter 點選並同步兩個下拉式清單的值。我選擇了一個現在我將介紹的 PHP-only 解決方案。
如何修復
您可以利用將 HTML 輸入轉換為陣列的能力,然後過濾陣列以擺脫任何未定義的值。以下是程式碼:
function add_course_section_filter() {
if ( isset( $_GET[ 'course_section' ]) ) {
$section = $_GET[ 'course_section' ];
$section = !empty( $section[ 0 ] ) ? $section[ 0 ] : $section[ 1 ];
} else {
$section = -1;
}
echo ' <select name="course_section[]" style="float:none;"><option value="">Course Section...</option>';
for ( $i = 1; $i <= 3; ++$i ) {
$selected = $i == $section ? ' selected="selected"' : '';
echo '<option value="' . $i . '"' . $selected . '>Section ' . $i . '</option>';
}
echo '<input type="submit" class="button" value="Filter">';
}
add_action( 'restrict_manage_users', 'add_course_section_filter' );
function filter_users_by_course_section( $query ) {
global $pagenow;
if ( is_admin() &&
'users.php' == $pagenow &&
isset( $_GET[ 'course_section' ] ) &&
is_array( $_GET[ 'course_section' ] )
) {
$section = $_GET[ 'course_section' ];
$section = !empty( $section[ 0 ] ) ? $section[ 0 ] : $section[ 1 ];
$meta_query = array(
array(
'key' => 'course_section',
'value' => $section
)
);
$query->set( 'meta_key', 'course_section' );
$query->set( 'meta_query', $meta_query );
}
}
add_filter( 'pre_get_users', 'filter_users_by_course_section' );
獎金:PHP 7 重構
由於我對 PHP 7 感到興奮,如果您在 PHP 7 伺服器上執行 WP,則使用無法合併的運運算元?? 可以使用更短,更性感的版本:
function add_course_section_filter() {
$section = $_GET[ 'course_section' ][ 0 ] ?? $_GET[ 'course_section' ][ 1 ] ?? -1;
echo ' <select name="course_section[]" style="float:none;"><option value="">Course Section...</option>';
for ( $i = 1; $i <= 3; ++$i ) {
$selected = $i == $section ? ' selected="selected"' : '';
echo '<option value="' . $i . '"' . $selected . '>Section ' . $i . '</option>';
}
echo '<input type="submit" class="button" value="Filter">';
}
add_action( 'restrict_manage_users', 'add_course_section_filter' );
function filter_users_by_course_section( $query ) {
global $pagenow;
if ( is_admin() && 'users.php' == $pagenow) {
$section = $_GET[ 'course_section' ][ 0 ] ?? $_GET[ 'course_section' ][ 1 ] ?? null;
if ( null !== $section ) {
$meta_query = array(
array(
'key' => 'course_section',
'value' => $section
)
);
$query->set( 'meta_key', 'course_section' );
$query->set( 'meta_query', $meta_query );
}
}
}
add_filter( 'pre_get_users', 'filter_users_by_course_section' );
請享用!
次佳解決方案
在核心中,底部輸入名稱標有例項號,例如。 new_role(上) 和 new_role2(底部) 。以下是類似命名約定的兩種方法,即 course_section1(上) 和 course_section2(底部):
方法#1
由於 $which 變數 (頂部,底部) 沒有被傳遞給 restrict_manage_users 鉤子,所以我們可以透過建立我們自己的該鉤子的版本來解決這個問題:
我們建立一個可以訪問 $which 變數的動作鉤子 wpse_restrict_manage_users:
add_action( 'restrict_manage_users', function()
{
static $instance = 0;
do_action( 'wpse_restrict_manage_users', 1 === ++$instance ? 'top' : 'bottom' );
} );
然後我們可以鉤住它:
add_action( 'wpse_restrict_manage_users', function( $which )
{
$name = 'top' === $which ? 'course_section1' : 'course_section2';
// your stuff here
} );
我們現在有 $name 作為 course_section1 在頂部和 course_section2 在底部。
方法#2
讓我們鉤住 restrict_manage_users,顯示下拉式清單,每個例項的名稱不同:
function add_course_section_filter()
{
static $instance= 0;
// Dropdown options
$options = '';
foreach( range( 1, 3 ) as $rng )
{
$options = sprintf(
'<option value="%1$d" %2$s>Section %1$d</option>',
$rng,
selected( $rng, get_selected_course_section(), 0 )
);
}
// Display dropdown with a different name for each instance
printf(
'<select name="%s" style="float:none;"><option value="0">%s</option>%s</select>',
'course_section' . ++$instance,
__( 'Course Section...' ),
$options
);
// Button
printf (
'<input id="post-query-submit" type="submit" class="button" value="%s" name="">',
__( 'Filter' )
);
}
add_action( 'restrict_manage_users', 'add_course_section_filter' );
在那裡我們使用了核心函式 selected()和幫助函式:
/**
* Get the selected course section
* @return int $course_section
*/
function get_selected_course_section()
{
foreach( range( 1, 2) as $rng )
$course_section = ! empty( $_GET[ 'course_section' . $rng ] )
? $_GET[ 'course_section' . $rng ]
: -1; // default
return (int) $course_section;
}
那麼當我們檢查 pre_get_users 動作回撥中選定的課程時,我們也可以使用這個。
第三種解決方案
我在 Wordpress 4.4 和 Wordpress 4.3.1 中測試了你的程式碼。與版本 4.4,我遇到完全一樣的問題。但是,您的程式碼在 4.3.1 版中正常工作!
我認為這是一個 WordPress 的 bug 。我不知道是否還有報道。我認為錯誤背後的原因可能是提交按鈕正在傳送查詢 vars 兩次。如果檢視查詢 vars,您會看到 course_section 被列出兩次,一次是正確的值,一次為空。
編輯:這是 JavaScript 解決方案
只需將其新增到主題的 functions.php 檔案中,然後將 NAME_OF_YOUR_INPUT_FIELD 更改為輸入欄位的名稱!由於 WordPress 會自動在管理端載入 jQuery,所以您不必排隊任何指令碼。這段程式碼只是將更改偵聽器新增到下拉式清單中,然後自動更新其他下拉式清單以匹配相同的值。 More explanation here.
add_action( 'in_admin_footer', function() {
?>
<script type="text/javascript">
var el = jQuery("[name='NAME_OF_YOUR_INPUT_FIELD']");
el.change(function() {
el.val(jQuery(this).val());
});
</script>
<?php
} );
希望這可以幫助!
參考文獻
注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。