Adăugarea unui filtru de taxonomie la lista de administrare pentru un tip de postare personalizat?
Am creat un Tip de Postare Personalizat numit 'listing'
și am adăugat o Taxonomie Personalizată numită 'businesses'
. Aș dori să adaug o listă dropdown de Afaceri la lista de administrare pentru Listări.
Iată cum arată această funcționalitate în lista de administrare pentru Postări (Aș dori același lucru pentru Tipul meu de Postare Personalizat):
Iată codul meu actual (Și aici este același cod pe Gist.):
<?php
/*
Plugin Name: Listing Content Item
Plugin URI:
Description:
Author:
Version: 1.0
Author URI:
*/
class Listing {
var $meta_fields = array("list-address1","list-address2","list-country","list-province","list-city","list-postcode","list-firstname","list-lastname","list-website","list-mobile","list-phone","list-fax","list-email", "list-profile", "list-distributionrange", "list-distributionarea");
public function loadStyleScripts() {
$eventsURL = trailingslashit( WP_PLUGIN_URL ) . trailingslashit( plugin_basename( dirname( __FILE__ ) ) ) . 'css/';
wp_enqueue_style('listing-style', $eventsURL.'listing.css');
}
function Listing() {
// Register custom post types
register_post_type('listing', array(
'labels' => array(
'name' => __('Listings'), 'singular_name' => __( 'Listing' ),
'add_new' => __( 'Add Listing' ),
'add_new_item' => __( 'Add New Listing' ),
'edit' => __( 'Edit' ),
'edit_item' => __( 'Edit Listing' ),
'new_item' => __( 'New Listing' ),
'view' => __( 'View Listing' ),
'view_item' => __( 'View Listing' ),
'search_items' => __( 'Search Listings' ),
'not_found' => __( 'No listings found' ),
'not_found_in_trash' => __( 'No listings found in Trash' ),
'parent' => __( 'Parent Listing' ),
),
'singular_label' => __('Listing'),
'public' => true,
'show_ui' => true, // UI in admin panel
'_builtin' => false, // It's a custom post type, not built in
'_edit_link' => 'post.php?post=%d',
'capability_type' => 'post',
'hierarchical' => false,
'rewrite' => array("slug" => "listings"), // Permalinks
'query_var' => "listings", // This goes to the WP_Query schema
'supports' => array('title','editor')
));
add_filter("manage_edit-listing_columns", array(&$this, "edit_columns"));
add_action("manage_posts_custom_column", array(&$this, "custom_columns"));
// Register custom taxonomy
#Businesses
register_taxonomy("businesses", array("listing"), array(
"hierarchical" => true,
"label" => "Listing Categories",
"singular_label" => "Listing Categorie",
"rewrite" => true,
));
# Region
register_taxonomy("regions", array("listing"), array(
'labels' => array(
'search_items' => __( 'Search Regions' ),
'popular_items' => __( 'Popular Regions' ),
'all_items' => __( 'All Regions' ),
'parent_item' => null,
'parent_item_colon' => null,
'edit_item' => __( 'Edit Region' ),
'update_item' => __( 'Update Region' ),
'add_new_item' => __( 'Add New Region' ),
'new_item_name' => __( 'New Region Name' ),
'separate_items_with_commas' => __( 'Separate regions with commas' ),
'add_or_remove_items' => __( 'Add or remove regions' ),
'choose_from_most_used' => __( 'Choose from the most used regions' ),
),
"hierarchical" => false,
"label" => "Listing Regions",
"singular_label" => "Listing Region",
"rewrite" => true,
));
# Member Organizations
register_taxonomy("organizations", array("listing"), array(
'labels' => array(
'search_items' => __( 'Search Member Organizations' ),
'popular_items' => __( 'Popular Member Organizations' ),
'all_items' => __( 'All Member Organizations' ),
'parent_item' => null,
'parent_item_colon' => null,
'edit_item' => __( 'Edit Member Organization' ),
'update_item' => __( 'Update Member Organization' ),
'add_new_item' => __( 'Add New Member Organization' ),
'new_item_name' => __( 'New Member Organization Name' ),
'separate_items_with_commas' => __( 'Separate member organizations with commas' ),
'add_or_remove_items' => __( 'Add or remove member organizations' ),
'choose_from_most_used' => __( 'Choose from the most used member organizations' ),
),
"hierarchical" => false,
"label" => "Member Organizations",
"singular_label" => "Member Organization",
"rewrite" => true,
));
# Retail Products
register_taxonomy("retails", array("listing"), array(
'labels' => array(
'search_items' => __( 'Search Retail Products' ),
'popular_items' => __( 'Popular Retail Products' ),
'all_items' => __( 'All Retail Products' ),
'parent_item' => null,
'parent_item_colon' => null,
'edit_item' => __( 'Edit Retail Product' ),
'update_item' => __( 'Update Retail Product' ),
'add_new_item' => __( 'Add New Retail Product' ),
'new_item_name' => __( 'New Retail Product Name' ),
'separate_items_with_commas' => __( 'Separate retail products with commas' ),
'add_or_remove_items' => __( 'Add or remove retail products' ),
'choose_from_most_used' => __( 'Choose from the most used retail products' ),
),
"hierarchical" => false,
"label" => "Retail Products",
"singular_label" => "Retail Product",
"rewrite" => true,
));
# Farming Practices
register_taxonomy("practices", array("listing"), array(
'labels' => array(
'search_items' => __( 'Search Farming Practices' ),
'popular_items' => __( 'Popular Farming Practices' ),
'all_items' => __( 'All Farming Practices' ),
'parent_item' => null,
'parent_item_colon' => null,
'edit_item' => __( 'Edit Farming Practice' ),
'update_item' => __( 'Update Farming Practice' ),
'add_new_item' => __( 'Add New Farming Practice' ),
'new_item_name' => __( 'New Farming Practice Name' ),
'separate_items_with_commas' => __( 'Separate farming practices with commas' ),
'add_or_remove_items' => __( 'Add or remove farming practices' ),
'choose_from_most_used' => __( 'Choose from the most used farming practices' ),
),
"hierarchical" => false,
"label" => "Farming Practices",
"singular_label" => "Farming Practice",
"rewrite" => true,
));
# Products
register_taxonomy("products", array("listing"), array(
'labels' => array(
'search_items' => __( 'Search Products' ),
'popular_items' => __( 'Popular Products' ),
'all_items' => __( 'All Products' ),
'parent_item' => null,
'parent_item_colon' => null,
'edit_item' => __( 'Edit Product' ),
'update_item' => __( 'Update Product' ),
'add_new_item' => __( 'Add New Product' ),
'new_item_name' => __( 'New Product Name' ),
'separate_items_with_commas' => __( 'Separate products with commas' ),
'add_or_remove_items' => __( 'Add or remove products' ),
'choose_from_most_used' => __( 'Choose from the most used products' ),
),
"hierarchical" => false,
"label" => "Products",
"singular_label" => "Product",
"rewrite" => true,
));
// Admin interface init
add_action("admin_init", array(&$this, "admin_init"));
add_action("template_redirect", array(&$this, 'template_redirect'));
// Insert post hook
add_action("wp_insert_post", array(&$this, "wp_insert_post"), 10, 2);
}
function edit_columns($columns) {
$columns = array(
"cb" => "<input type=\"checkbox\" />",
"title" => "Business Name",
"description" => "Description",
"list-personal" => "Personal Information",
"list-location" => "Location",
"list-categorie" => "Categorie",
);
return $columns;
}
function custom_columns($column) {
global $post;
switch ($column) {
case "description":
the_excerpt();
break;
case "list-personal":
$custom = get_post_custom();
if(isset($custom["list-firstname"][0])) echo $custom["list-firstname"][0]."<br />";
if(isset($custom["list-lastname"][0])) echo $custom["list-lastname"][0]."<br />";
if(isset($custom["list-email"][0])) echo $custom["list-email"][0]."<br />";
if(isset($custom["list-website"][0])) echo $custom["list-website"][0]."<br />";
if(isset($custom["list-phone"][0])) echo $custom["list-phone"][0]."<br />";
if(isset($custom["list-mobile"][0])) echo $custom["list-mobile"][0]."<br />";
if(isset($custom["list-fax"][0])) echo $custom["list-fax"][0];
break;
case "list-location":
$custom = get_post_custom();
if(isset($custom["list-address1"][0])) echo $custom["list-address1"][0]."<br />";
if(isset($custom["list-address2"][0])) echo $custom["list-address2"][0]."<br />";
if(isset($custom["list-city"][0])) echo $custom["list-city"][0]."<br />";
if(isset($custom["list-province"][0])) echo $custom["list-province"][0]."<br />";
if(isset($custom["list-postcode"][0])) echo $custom["list-postcode"][0]."<br />";
if(isset($custom["list-country"][0])) echo $custom["list-country"][0]."<br />";
if(isset($custom["list-profile"][0])) echo $custom["list-profile"][0]."<br />";
if(isset($custom["list-distributionrange"][0])) echo $custom["list-distributionrange"][0]."<br />";
if(isset($custom["list-distributionarea"][0])) echo $custom["list-distributionarea"][0];
break;
case "list-categorie":
$speakers = get_the_terms(0, "businesses");
$speakers_html = array();
if(is_array($speakers)) {
foreach ($speakers as $speaker)
array_push($speakers_html, '<a href="' . get_term_link($speaker->slug, 'businesses') . '">' . $speaker->name . '</a>');
echo implode($speakers_html, ", ");
}
break;
}
}
// Template selection
function template_redirect() {
global $wp;
if (isset($wp->query_vars["post_type"]) && ($wp->query_vars["post_type"] == "listing")) {
include(STYLESHEETPATH . "/listing.php");
die();
}
}
// When a post is inserted or updated
function wp_insert_post($post_id, $post = null) {
if ($post->post_type == "listing") {
// Loop through the POST data
foreach ($this->meta_fields as $key) {
$value = @$_POST[$key];
if (empty($value)) {
delete_post_meta($post_id, $key);
continue;
}
// If value is a string it should be unique
if (!is_array($value)) {
// Update meta
if (!update_post_meta($post_id, $key, $value)) {
// Or add the meta data
add_post_meta($post_id, $key, $value);
}
}
else
{
// If passed along is an array, we should remove all previous data
delete_post_meta($post_id, $key);
// Loop through the array adding new values to the post meta as different entries with the same name
foreach ($value as $entry)
add_post_meta($post_id, $key, $entry);
}
}
}
}
function admin_init() {
// Custom meta boxes for the edit listing screen
add_meta_box("list-pers-meta", "Personal Information", array(&$this, "meta_personal"), "listing", "normal", "low");
add_meta_box("list-meta", "Location", array(&$this, "meta_location"), "listing", "normal", "low");
}
function meta_personal() {
global $post;
$custom = get_post_custom($post->ID);
if(isset($custom["list-firstname"][0])) $first_name = $custom["list-firstname"][0];else $first_name = '';
if(isset($custom["list-lastname"][0])) $last_name = $custom["list-lastname"][0];else $last_name = '';
if(isset($custom["list-website"][0])) $website = $custom["list-website"][0];else $website = '';
if(isset($custom["list-phone"][0])) $phone = $custom["list-phone"][0];else $phone = '';
if(isset($custom["list-mobile"][0])) $mobile = $custom["list-mobile"][0];else $mobile = '';
if(isset($custom["list-fax"][0])) $fax = $custom["list-fax"][0];else $fax = '';
if(isset($custom["list-email"][0])) $email = $custom["list-email"][0];else $email = '';
?>
<div class="personal">
<table border="0" id="personal">
<tr><td class="personal_field"><label>Firstname:</label></td><td class="personal_input"><input name="list-firstname" value="<?php echo $first_name; ?>" /></td></tr>
<tr><td class="personal_field"><label>Lastname:</label></td><td class="personal_input"><input name="list-lastname" value="<?php echo $last_name; ?>" /></td></tr>
<tr><td class="personal_field"><label>Email:</label></td><td class="personal_input"><input name="list-email" value="<?php echo $email; ?>" size="40"/></td></tr>
<tr><td class="personal_field"><label>Website:</label></td><td class="personal_input"><input name="list-website" value="<?php echo $website; ?>" size="40"/></td></tr>
<tr><td class="personal_field"><label>Phone:</label></td><td class="personal_input"><input name="list-phone" value="<?php echo $phone; ?>" /></td></tr>
<tr><td class="personal_field"><label>Mobile:</label></td><td class="personal_input"><input name="list-mobile" value="<?php echo $mobile; ?>" /></td></tr>
<tr><td class="personal_field"><label>Fax:</label></td><td class="personal_input"><input name="list-fax" value="<?php echo $fax; ?>" /></td></tr>
</table>
</div>
<?php
}
// Admin post meta contents
function meta_location() {
global $post;
$custom = get_post_custom($post->ID);
if(isset($custom["list-address1"])) $address1 = $custom["list-address1"][0];else $address1 = '';
if(isset($custom["list-address2"])) $address2 = $custom["list-address2"][0];else $address2 = '';
if(isset($custom["list-country"])) $country = $custom["list-country"][0];else $country = '';
if(isset($custom["list-province"])) $province = $custom["list-province"][0];else $province = '';
if(isset($custom["list-city"])) $city = $custom["list-city"][0];else $city = '';
if(isset($custom["list-postcode"])) $post_code = $custom["list-postcode"][0];else $post_code = '';
if(isset($custom["list-profile"])) $profile = $custom["list-profile"][0];else $profile = '';
if(isset($custom["list-distributionrange"])) $distribution_range = $custom["list-distributionrange"][0];else $distribution_range = '';
if(isset($custom["list-distributionarea"])) $distribution_area = $custom["list-distributionarea"][0];else $ddistribution_area = '';
?>
<div class="location">
<table border="0" id="location">
<tr><td class="location_field"><label>Address 1:</label></td><td class="location_input"><input name="list-address1" value="<?php echo $address1; ?>" size="60" /></td></tr>
<tr><td class="location_field"><label>Address 2:</label></td><td class="location_input"><input name="list-address2" value="<?php echo $address2; ?>" size="60" /></td></tr>
<tr><td class="location_field"><label>City:</label></td><td class="location_input"><input name="list-city" value="<?php echo $city; ?>" /></td></tr>
<tr><td class="location_field"><label>Province:</label></td><td class="location_input"><input name="list-province" value="Ontario" readonly /></td></tr>
<tr><td class="location_field"><label>Postal Code:</label></td><td class="location_input"><input name="list-postcode" value="<?php echo $post_code; ?>" /></td></tr>
<tr><td class="location_field"><label>Country:</label></td><td class="location_input"><input name="list-country" value="Canada" readonly /></td></tr>
<tr><td class="location_field"><label>Profile:</label></td><td class="location_input"><input name="list-profile" value="<?php echo $profile; ?>" size="60" /></td></tr>
<tr><td class="location_field"><label>Distribution Range:</label></td><td class="location_input"><input name="list-distributionrange" value="<?php echo $distribution_range; ?>" size="60" /></td></tr>
<tr><td class="location_field"><label>Distribution Area:</label></td><td class="location_input"><input name="list-distributionarea" value="<?php echo $distribution_area; ?>" size="60" /></td></tr>
</table>
</div>
<?php
}
}
// Initiate the plugin
add_action("init", "ListingInit");
function ListingInit() {
global $listing;
$listing = new Listing();
$add_css = $listing->loadStyleScripts();
}
Cum pot adăuga o listă dropdown de Afaceri la lista de administrare pentru Listări?

UPDATE iulie 2024:
Acest cod nu mai funcționează. Testat în versiunea curentă de WP la momentul scrierii (6.5.5). Pentru a-l face să funcționeze din nou, sunt necesare câteva modificări la codul din Pasul 1:
Parametrul name
În wp_dropdown_categories()
parametrul name
trebuie să fie slug-ul taxonomiei. Așadar, deși în acest caz nu se schimbă, nu este foarte clar ce ar trebui să schimbe alți oameni. Mai ales pentru că documentația oficială nu menționează acest lucru:
name
string
Valoarea pentru atributul
'name'
al elementului select. Implicit'cat'
.
Aceasta ar putea duce la ideea că este un șir personalizat precum "my_select_name"
. Pentru a elimina confuzia, putem folosi pur și simplu variabila.
wp_dropdown_categories(array(
'name' => $taxonomy,
...
));
Parametrul selected
Parametrul selected
trebuie schimbat la:
wp_dropdown_categories(array(
'selected' => $wp_query->query_vars['term']?? 0,
...
));
Acest lucru se datorează faptului că term
este definit în query_vars
în loc de query
. Dacă termenul nu există în query_vars
, atunci cel mai probabil nu a fost selectat un termen, deci putem folosi operatorul de coalescentă nulă pentru a testa asta și dacă este null|undefined
atunci selectăm opțiunea "arată toate" cu valoarea 0
.
Parametrul value_field
Un nou parametru a fost adăugat în WP 4.2.0: value_field
.
Utilizând acest parametru, putem acum indica WP să folosească un "câmp de termen" specific pentru a popula valorile opțiunilor. Din documentație:
value_field
string
Câmpul termenului care ar trebui utilizat pentru a popula atributul
'value'
al elementelor de opțiune. Acceptă orice câmp valid al termenului: 'term_id'
,'name'
,'slug'
,'term_group'
,'term_taxonomy_id'
,'taxonomy'
,'description'
,'parent'
,'count'
. Implicit'term_id'
.
Adăugarea slug
la acest parametru va popula valorile opțiunilor cu slug-urile termenilor. Deoarece slug-ul este necesar pentru ca funcția de filtrare să funcționeze, acest parametru face ca filtrele să funcționeze doar din codul Pasului 1, fără a fi nevoie de Pasul 2.
Așadar, Pasul 2 poate fi ignorat dacă se utilizează value_field
.
wp_dropdown_categories(array(
'value_field' => 'slug',
...
));
Am lăsat codul original mai jos, așa că faceți aceste modificări după cum s-a detaliat mai sus la codul de mai jos.
ACTUALIZARE: Am inclus un nou răspuns complet, dar am lăsat și răspunsul meu original la sfârșitul articolului, la care se referă primele comentarii.
Salut @tarasm:
Deși am spus că nu ar trebui să fie dificil, este puțin mai complex. Dar înainte să ne cufundăm în cod...
Capturile de ecran:
...să vedem câteva capturi de ecran pentru produsul final:
Pagina de listare fără filtrare:
(sursă: mikeschinkel.com)
Pagina de listare cu filtrare:
(sursă: mikeschinkel.com)
Codul
Așadar, să începem... (Notă: Am folosit o formă singulară pentru numele taxonomiei business
; sper că se potrivește cu a ta. Din multă experiență cu WordPress și dezvoltarea bazelor de date, cred că este cel mai bine să procedezi așa.)
Pasul #1: Hook-ul de acțiune restrict_manage_posts
.
Primul lucru pe care trebuie să-l faci este să agăți acțiunea restrict_manage_posts
care nu are parametri și este apelată din /wp-admin/edit.php
(în v3.0.1 acel apel este pe linia 378). Aceasta îți va permite să generezi dropdown-ul select în locația potrivită deasupra listei de postări Listing.
<?php
add_action('restrict_manage_posts','restrict_listings_by_business');
function restrict_listings_by_business() {
global $typenow;
global $wp_query;
if ($typenow=='listing') {
$taxonomy = 'business';
$business_taxonomy = get_taxonomy($taxonomy);
wp_dropdown_categories(array(
'show_option_all' => __("Show All {$business_taxonomy->label}"),
'taxonomy' => $taxonomy,
'name' => 'business',
'orderby' => 'name',
'selected' => $wp_query->query['term'],
'hierarchical' => true,
'depth' => 3,
'show_count' => true, // Arată # listări în paranteze
'hide_empty' => true, // Nu arăta afaceri fără listări
));
}
}
Începem prin verificarea variabilei $typenow
pentru a ne asigura că suntem într-adevăr pe un post_type
de listing
. Dacă nu faci asta, vei obține acest dropdown pentru toate tipurile de postări, ceea ce în unele cazuri este ceea ce vrei, dar nu în acest caz.
Următorul pas este să încărcăm informații despre taxonomia business folosind get_taxonomy()
. Avem nevoie de ea pentru a prelua eticheta taxonomiei (adică "Businesses"; am fi putut hard-coda, dar nu este bine dacă ai nevoie să internaționalizezi mai târziu). Apoi apelăm wp_dropdown_categories()
cu toate argumentele adecvate în matricea $args
pentru a genera dropdown-ul
<?php
return wp_dropdown_categories(array(
'show_option_all' => __("Show All {$business_taxonomy->label}"),
'taxonomy' => $taxonomy,
'name' => 'business',
'orderby' => 'name',
'selected' => $wp_query->query['term'],
'hierarchical' => true,
'depth' => 3,
'show_count' => true, // Arată # listări în paranteze
'hide_empty' => true, // Nu arăta afaceri fără listări
));
Dar care sunt argumentele potrivite? Să le examinăm pe fiecare în parte:
show_optional_all
- Destul de simplu, este ceea ce este afișat în dropdown inițial și când nu a fost aplicată nicio filtrare. În cazul nostru, va fi "Show All Businesses" dar l-am fi putut numi "Listings for All Businesses" sau orice altceva îți place.taxonomy
- Acest argument spune funcției din ce taxonomie să extragă termenii, chiar dacă funcția arecategories
în numele său. În v2.8 și anterior WordPress nu avea taxonomii personalizate, dar când au fost adăugate, echipa a decis că ar fi mai ușor să adauge un argument de taxonomie la această funcție decât să creeze o altă funcție cu un alt nume.name
- Acest argument îți permite să specifici valoarea pe care WordPress o va folosi pentru atributulname
al elementului <select> generat pentru dropdown. În caz că nu este evident, aceasta este și valoarea care va fi utilizată în URL atunci când se filtrează.orderby
- Acest argument spune WordPress-ului cum să ordoneze rezultatele alfabetic. În cazul nostru am specificat să ordonăm dupăname
al termenilor din taxonomie, adică numele afacerilor în acest caz.selected
- Acest argument este necesar pentru ca dropdown-ul să poată afișa filtrul curent. Ar trebui să fieterm_id
din termenul taxonomiei selectate. În cazul nostru ar putea fiterm_id
din "Business #2". De unde obținem această valoare? Din variabila globală$wp_query
a WordPress; aceasta are o proprietatequery
care conține o matrice cu toți parametrii URL și valorile lor (cu excepția cazului în care un plugin le-a modificat deja, desigur). Dată fiind modul în care WordPress procesează lucrurile, va exista un parametru URLterm
transmis pe URL atunci când utilizatorul face clic pe butonul de filtrare dacă utilizatorul a selectat un termen valid (adică una dintre afacerile listate).hierarchical
- Setând această opțiune latrue
, spui funcției să respecte natura ierarhică a taxonomiei și să le afișeze într-o vizualizare arborescentă dacă termenii (afacerile) au de fapt copii. Pentru o captură de ecran care să arate cum arată acest lucru, vezi mai jos.depth
- Acest argument colaborează cu argumentulhierarchical
pentru a determina cât de adânc trebuie să meargă funcția în afișarea copiilor.show_count
- Dacă estetrue
, acest argument va afișa un număr de postări între paranteze în stânga numelui termenului în dropdown. În acest caz, ar afișa un număr de listări asociate cu afacerile. Pentru o captură de ecran care să arate cum arată acest lucru, vezi mai jos.hide_empty
- În fine, dacă există termeni în taxonomie care nu sunt asociați cu o postare (adică afaceri neasociate cu o listare), atunci setarea acestui parametru latrue
îi va omite din dropdown.
(sursă: mikeschinkel.com)
Pasul #2: Hook-ul de filtrare parse_query
.
În continuare, ne îndreptăm atenția către hook-ul de filtrare parse_query
care are un parametru ($query
) și este apelat din /wp-includes/query.php
(în v3.0.1 acel apel este pe linia 1549). Este apelat când WordPress a terminat de inspectat URL-ul și de setat toate valorile corespunzătoare în $wp_query
-ul activ, inclusiv lucruri precum $wp_query->is_home
și $wp_query->is_author
, etc.
După ce hook-ul de filtrare parse_query
rulează, WordPress va apela get_posts()
și va încărca o listă de postări bazate pe ceea ce este specificat în $wp_query
-ul activ. Astfel, parse_query
este adesea un loc excelent pentru a face WordPress să-și schimbe părerea despre ce postări urmează să încarce.
În cazul tău de utilizare, dorim ca WordPress să filtreze pe baza afacerilor selectate; adică să afișeze doar acele Listări care au fost asociate cu afacerea selectată (aș spune "...doar acele Listări care au fost "categorizate" de afacerea selectată" dar asta nu este tehnic corect; category
este propria taxonomie alături de business
cu excepția faptului că category
este încorporată în WordPress și business
este personalizată. Dar pentru cei familiarizați cu categorizarea postărilor, acest lucru îi poate ajuta să înțeleagă, deoarece funcționează aproape identic. Dar divaghez...)
Să trecem la cod. Primul lucru pe care îl facem este să obținem o referință la query_vars
din $wp_query
-ul activ pentru a fi mai convenabil de lucrat, exact cum se face în funcția parse_query()
a WordPress. Spre deosebire de $wp_query->query
care este utilizat pentru a oglindi parametrii transmiși pe URL, matricea $wp_query->query_vars
este utilizată pentru a controla interogarea pe care o execută WordPress și se așteaptă să fie modificată. Deci, dacă trebuie să modifici una, aceasta ar fi cea aleasă (cel puțin cred că aceasta este diferența dintre cele două; dacă cineva știe altfel, vă rog să mă anunțați pentru a putea actualiza acest lucru!)
<?php
add_filter('parse_query','convert_business_id_to_taxonomy_term_in_query');
function convert_business_id_to_taxonomy_term_in_query($query) {
global $pagenow;
$qv = &$query->query_vars;
if ($pagenow=='edit.php' &&
isset($qv['taxonomy']) && $qv['taxonomy']=='business' &&
isset($qv['term']) && is_numeric($qv['term'])) {
$term = get_term_by('id',$qv['term'],'business');
$qv['term'] = $term->slug;
}
}
Apoi testăm $pagenow
pentru a ne asigura că într-adevăr încărcăm WordPress de la calea URL /wp-admin/edit.php
. Facem acest lucru pentru a nu strica accidental interogările pe alte pagini. De asemenea, verificăm pentru a ne asigura că avem atât business
ca element taxonomy
, cât și un element term
. (Notă: taxonomy
și term
sunt o pereche; sunt utilizate împreună pentru a permite interogarea unui termen de taxonomie; trebuie să le ai pe amândouă sau WordPress nu știe ce taxonomie să inspecteze.)
Te-ai putea întreba cum a ajuns business
în elementul taxonomy
al matricei query_vars
. Ceea ce am scris în hook-ul nostru parse_query
a declanșat magia internă a WordPress care a fost pregătită când ai înregistrat taxonomia "business
" setând query_var
la true (register_taxonomy()
copiază numele taxonomiei ca query_var
; poți să-l schimbi, desigur, dar dacă nu ai un conflict, este mai bine să rămâi cu același):
<?php
add_action('init','register_business_taxonomy');
function register_business_taxonomy() {
register_taxonomy('business',array('listing'),array(
'label' => 'Businesses',
'public'=>true,
'hierarchical'=>true,
'show_ui'=>true,
'query_var'=>true
));
}
Acum $wp_query al WordPress a fost scris pentru a utiliza slug-uri pentru interogări filtrate standard de taxonomie, nu ID-uri de termeni de taxonomie. Pentru acest caz de utilizare, ceea ce avem nevoie cu adevărat pentru a face interogarea noastră de filtrare să funcționeze sunt acestea:
taxonomy
: business
term
: business-1 (adicăslug
-ul)
Nu acestea:
taxonomy
: business
term
: 27 (adicăterm_id
-ul)
În mod interesant și din păcate, dropdown-ul generat de wp_dropdown_categories()
setează atributul value
al <option>
la term_id
-ul termenului (/afacerii), nu la slug
-ul termenului. Așadar, trebuie să convertim $wp_query->query_vars['term']
de la un term_id
numeric la slug
-ul său de tip șir, după cum urmează în fragmentul extras de mai sus (Notă: aceasta nu este cea mai performantă modalitate de a interoga o bază de date, dar până când WordPress adaugă suport pentru term_id-uri în interogarea sa, aceasta este cea mai bună metodă pe care o putem folosi!):
<?php
$term = get_term_by('id',$qv['term'],'business');
$qv['term'] = $term->slug;
Și asta e tot! Cu aceste două funcții obții filtrarea pe care o dorești.
DAR STAI, ESTE MAI MULT! :-)
Am adăugat o coloană "Businesses" listei tale Listing pentru că, ei bine, știam că va fi următoarea ta întrebare. Fără a avea o coloană pentru ceea ce filtrezi, poate fi foarte confuz pentru utilizatorul final. (Eu însumi m-am chinuit cu asta, și eu am fost programatorul!) Poți vedea deja coloana "Businesses" în capturile de ecran anterioare de mai sus.
Pasul #3: Hook-ul de filtrare manage_posts_columns
.
Pentru a adăuga o coloană la lista de postări, trebuie să apelezi încă două (2) hook-uri. Primul este manage_posts_columns
sau versiunea specifică tipului de postare manage_listing_posts_columns
pe care am apelat-o în schimb. Acceptă un parametru (posts_columns
) și este apelat din /wp-admin/includes/template.php
(în v3.0.1 acel apel este pe linia 623):
<?php
add_action('manage_listing_posts_columns', 'add_businesses_column_to_listing_list');
function add_businesses_column_to_listing_list( $posts_columns ) {
if (!isset($posts_columns['author'])) {
$new_posts_columns = $posts_columns;
} else {
$new_posts_columns = array();
$index = 0;
foreach($posts_columns as $key => $posts_column) {
if ($key=='author')
$new_posts_columns['businesses'] = null;
$new_posts_columns[$key] = $posts_column;
}
}
$new_posts_columns['businesses'] = 'Businesses';
return $new_posts_columns;
}
Funcția ta hook manage_posts_columns
primește o matrice de coloane unde valoarea este antetul coloanei afișat și cheia este identificatorul intern al coloanei. Identificatorii standard de coloane pot include următoarele și altele: 'cb'
, 'title
', 'author'
, ``'date'`, etc.
'cb'
este coloana checkbox
, iar atât 'title'
, cât și 'date'
se referă la post_title
și post_date
din tabelul wp_posts
, respectiv. 'author'
este, desigur, câmpul post_author
după ce numele autorului este preluat din tabelul wp_users
.
(sursă: mikeschinkel.com)
Pentru hook-ul manage_posts_columns
, dorim pur și simplu să inserăm coloana noastră businesses
în matricea $posts_columns
înainte de 'author'
, presupunând că alt plugin nu a eliminat încă author
din listă!
$new_posts_columns['businesses'] = 'Businesses';
(Notă în timp ce scriam add_businesses_column_to_listing_list()
mi-a venit în minte că PHP trebuie să aibă o modalitate mai ușoară de a insera o valoare într-o matrice asociativă în ordinea corespunzătoare?!? Sau cel puțin trebuie să existe o funcție în nucleul WordPress pentru a face acest lucru? Dar deoarece Google m-a dezamăgit, am folosit ceea ce a funcționat. Dacă cineva are sugestii alternative, voi fi recunoscător în avans!)
Ceea ce ne aduce în final la...
Pasul #4: Hook-ul de acțiune manage_posts_custom_column
Al doilea lucru din două (2) de care avem nevoie pentru a face afacerile noastre să apară în coloană este să afișăm efectiv numele fiecăreia dintre afacerile asociate folosind hook-ul de acțiune manage_posts_custom_column
. Acest hook acceptă doi (2) parametri (column_id
și post_id
) și este apelat tot din /wp-admin/includes/template.php
(în v3.0.1 acel apel este pe linia 1459):
<?php
add_action('manage_posts_custom_column', 'show_businesses_column_for_listing_list',10,2);
function show_businesses_column_for_listing_list( $column_id,$post_id ) {
global $typenow;
if ($typenow=='listing') {
$taxonomy = 'business';
switch ($column_name) {
case 'businesses':
$businesses = get_the_terms($post_id,$taxonomy);
if (is_array($businesses)) {
foreach($businesses as $key => $business) {
$edit_link = get_term_link($business,$taxonomy);
$businesses[$key] = '<a href="'.$edit_link.'">' . $business->name . '</a>';
}
//echo implode("<br/>",$businesses);
echo implode(' | ',$businesses);
}
break;
}
}
}
Acest hook este apelat pentru fiecare coloană pentru fiecare rând de postare(/afacere). Verificăm mai întâi că lucrăm într-adevăr doar cu tipul de postare personalizat listing
și apoi folosim o instrucțiune switch
pentru a testa column_id
. Am ales switch
deoarece acest hook este adesea folosit pentru a genera output pentru multe coloane diferite, mai ales dacă folosim o funcție pentru multe tipuri de postări diferite, care ar putea arăta ceva de genul:
<?php
add_action('manage_posts_custom_column', 'my_manage_posts_custom_column',10,2);
function my_manage_posts_custom_column( $column_id,$post_id ) {
global $typenow;
switch ("{$typenow}:{$column_id}") {
case 'listing:business':
echo '...orice...';
break;
case 'listing:property':
echo '...orice...';
break;
case 'agent:listing':
echo '...orice...';
break;
}
}
Inspectând cazul nostru de utilizare puțin mai îndeaproape, vedem funcția get_the_terms()
care simplu returnează lista termenilor pentru această taxonomie (adică afacerile pentru această înregistrare). Aici obținem permalink-ul pentru pagina web front-end a termenului care în mod normal listează postările asociate cu termenul, dar care ar putea funcționa diferit în funcție de tema și/sau plugin-urile instalate.
Folosim permalink-ul pentru a crea un hyperlink către termen pentru că îmi place să creez linkuri. Apoi combinăm toate termenii (afacerile) cu hyperlink împreună, separate prin caracterul pipe ('|
') și trimitem către buffer-ul PHP care îl transmite către browser-ul/clientul HTTP al utilizatorului:
<?php
$businesses = get_the_terms($post_id,$taxonomy);
if (is_array($businesses)) {
foreach($businesses as $key => $business) {
$edit_link = get_term_link($business,$taxonomy);
$businesses[$key] = '<a href="'.$edit_link.'">' . $business->name . '</a>';
}
//echo implode("<br/>",$businesses);
echo implode(' | ',$businesses);
}
ACUM am terminat în sfârșit.
Sumar
Așadar, în rezumat, trebuie să folosiți următoarele patru (4) hook-uri pentru a obține atât un filtru cât și o coloană asociată în pagina de listare a postărilor personalizate (Da, va funcționa și cu Articole și Pagini). Acestea sunt:
- Pasul #1: Hook-ul de acțiune
restrict_manage_posts
- Pasul #2: Hook-ul de filtrare
parse_query
- Pasul #3: Hook-ul de filtrare
manage_posts_columns
- Pasul #4: Hook-ul de acțiune
manage_posts_custom_column
De unde să descărcați codul
Dar dacă v-am făcut să citiți tot ce este mai sus, nu aș fi o persoană foarte drăguță dacă v-aș face să căutați și codul doar pentru a-l putea încerca! Dar contrar a ceea ce spun unii oameni, sunt drăguț. Așa că poftim:
- Descărcați codul de la: http://gist.github.com/541505
NOTĂ pentru @tarasm: Am inclus hook-uri pentru register_post_type()
și register_taxonomy()
astfel încât alții să poată încerca acest cod fără a trebui să le recreeze. Probabil veți dori să ștergeți aceste două apeluri de funcții înainte de a testa.
SFÂRȘIT
Răspuns Original:
Salut @tarasm:
Cauți un dropdown în partea de sus ca în acest ecran sau cauți un dropdown pentru fiecare înregistrare de postare și dacă da, cum te-ai aștepta să funcționeze cel din urmă?
(sursa: mikeschinkel.com)
Dacă e primul caz, aruncă o privire la acest răspuns la întrebarea Cum să sortezi zona de administrare a unui tip de postare personalizat WordPress după un câmp personalizat? Dacă asta este ceea ce ai nevoie, pot oferi mai multe detalii specifice legate de taxonomie.

Caut un meniu derulant în partea de sus care să afișeze un filtru pe categorii. Mă întrebam dacă există o metodă standard de a face asta fără a fi nevoie să scriu cod personalizat.

La prima vedere, nu cred că se poate fără cod personalizat, dar nici că ar fi nevoie de mult cod custom. Am un apel cu un client de pregătit, așa că va trebui să revin mai târziu azi.

De fapt, ambele soluții (somatic și MikeSchinkel) nu funcționează când încerci să filtrezi 2 taxonomii diferite în același filtru :-/
Întotdeauna se filtrează după ultima taxonomie când încerci să filtrezi 2+ simultan.

@Ünsal Versiunea actuală de WordPress (3.0) nu suportă interogări multiple de Taxonomie, dar din ce am auzit, acest lucru se va schimba cu versiunea 3.1. Pentru a face acest exemplu să funcționeze cu mai multe taxonomii, ar trebui să adăugați unele join-uri și condiții la interogare prin intermediul hook-urilor de filtrare Posts_join și posts_where.

mulțumesc pentru răspunsul excelent - dar există o mică greșeală de tipar în exemplul de cod din pasul #4: ar trebui să fie $column_id
și nu column_name
. versiunea de pe github este corectă însă.

În WP 3.1+, pașii unu și doi sunt mai bine prezenți în răspunsul lui @drew-gourley (de fapt, pasul 2 din exemplul tău nu a funcționat pentru mine, cred că au fost schimbări în această filtrare în noile versiuni de WordPress).

Mike, cred că ai putea îmbunătăți claritatea acestui (minunat) tutorial, schimbând argumentele wp_dropdown_categories astfel încât 'name' => $taxonomy, pentru a face evident faptul că atributul 'name' al câmpului select trebuie să fie slug-ul taxonomiei înregistrate (sau mai precis, slug-ul query_var). În forma actuală, pare că 'taxonomy' trebuie să fie slug-ul taxonomiei, dar 'name' poate fi orice nume arbitrar, ceea ce cred că nu este chiar cazul, decât dacă ești dispus să analizezi manual șirul de interogare în parse_query

un răspuns foarte strălucit și complet, dar nu ar trebui să returnezi variabila $query în funcția ta convert_business_id_to_taxonomy_term_in_query()?

Mă adaug și eu la lunga listă de complimente anterioare! Lecțiile lui Mike sunt (destul de frecvent) ca un curs universitar. . . . Și aș dori să subliniez pentru oricine cercetează această problemă că răspunsul lui @DrewGourley de mai jos este aur curat :)

Un lucru care nu este imediat evident este că get_term_link() va lega la arhiva publică a unei taxonomii, în loc să afișeze rezultatele filtrate în WP-Admin. Nu sunt sigur dacă există o funcție pentru a genera acest link, așa că trebuie creat manual, de exemplu: <a href="edit.php?CUSTOM_TAXONOMY=FOO&post_type=CUSTOM_POST_TYPE">NUME_TAXONOMIE</a> dar în afară de acest detaliu minor, acest lucru este minunat!

Am vrut să împărtășesc o implementare alternativă. Nu am avut incredibilul tutorial al lui Mike când am încercat să rezolv această problemă, așa că soluția mea este puțin diferită. Mai exact, voi simplifica pasul #1 al lui Mike și voi elimina pasul #2 - ceilalți pași rămân valabili.
În tutorialul lui Mike, folosirea funcției wp_dropdown_categories()
ne scutește de construirea manuală a listei, dar necesită o modificare condiționată complicată a interogării (pasul #2) pentru a gestiona utilizarea ID-ului în loc de slug. Ca să nu mai vorbim de dificultatea de a modifica acel cod pentru a gestiona alte scenarii, cum ar fi filtrele pentru multiple taxonomii.
O altă abordare este să nu folosim deloc funcția imperfectă wp_dropdown_categories()
, ci să construim propriile noastre liste dropdown de la zero. Nu este atât de complicat, necesită mai puțin de 30 de linii de cod și nu necesită deloc utilizarea hook-ului parse_query
:
add_action( 'restrict_manage_posts', 'my_restrict_manage_posts' );
function my_restrict_manage_posts() {
// afișăm aceste filtre de taxonomie doar pe listările dorite de custom post_type
global $typenow;
if ($typenow == 'photos' || $typenow == 'videos') {
// creăm un array de slug-uri de taxonomii pe care vrem să le filtrăm - dacă vrem să preluăm toate taxonomiile, putem folosi get_taxonomies() pentru a construi lista
$filters = array('plants', 'animals', 'insects');
foreach ($filters as $tax_slug) {
// preluăm obiectul taxonomiei
$tax_obj = get_taxonomy($tax_slug);
$tax_name = $tax_obj->labels->name;
// preluăm array-ul de obiecte termen pentru fiecare taxonomie
$terms = get_terms($tax_slug);
// generăm html pentru dropdown-ul de filtrare a taxonomiei
echo "<select name='$tax_slug' id='$tax_slug' class='postform'>";
echo "<option value=''>Afișează tot $tax_name</option>";
foreach ($terms as $term) {
// generăm fiecare opțiune selectată, verificând ultima valoare $_GET pentru a afișa opțiunea curentă selectată
echo '<option value='. $term->slug, $_GET[$tax_slug] == $term->slug ? ' selected="selected"' : '','>' . $term->name .' (' . $term->count .')</option>';
}
echo "</select>";
}
}
}
Prin simpla introducere a taxonomiilor dorite în array-ul $filters
, puteți genera rapid mai multe filtre de taxonomie. Acestea apar exact la fel ca în capturile de ecran ale lui Mike. Apoi puteți continua cu pasul #3 și #4.

@somatic - Actualizare frumoasă! Da, utilizarea funcției wp_dropdown_categories()
necesită multe soluții alternative. Încerc să folosesc funcții de bază când este posibil, dar după cum subliniezi, uneori asta presupune mai multă muncă. Doar demonstrează că în WordPress există adesea mai multe modalități bune de a rezolva o problemă. Bună treabă!

Tocmai a încetat să funcționeze pentru mine pe WordPress 3.1. Încerc să înțeleg exact ce s-a schimbat. Pare că ar trebui să funcționeze în continuare: taxonomia și termenii apar ca valori GET în URL, dar rezultatul este întotdeauna 0 rezultate.

Am încercat să fac asta să funcționeze, dar singura modalitate a fost să folosesc hook-ul parse_query, să verific variabila de interogare a taxonomiei și să setez variabilele de interogare pentru taxonomie și termen pe baza acesteia. Folosesc WP 3.1. Ar trebui să apară taxonomia și termenii în URL când este trimis filtrul?

Funcționează perfect pentru mine! O soluție foarte elegantă, într-adevăr. Îți datorez o bere :)

@somatic Funcționează excelent, dar există vreo modalitate de a face ca $term->count să numere doar termenii pentru acel tip de post? De exemplu, dacă am o taxonomie personalizată atât pentru fotografi cât și pentru videoclipuri, când mă uit la tipul de postare personalizată pentru videoclipuri, îmi va afișa numărul total de postări pentru acel termen din ambele tipuri de postări personalizate, în loc doar numărul total de postări video care folosesc acel termen.

Iată o versiune care creează și aplică automat filtre pentru toate taxonomiile care se aplică tuturor tipurilor de postări personalizate care le folosesc. (ce formulare lungi) Oricum, am ajustat-o să funcționeze cu wp_dropdown_categories() și WordPress 3.1. Proiectul la care lucrez se numește ToDo, poți redenumi funcțiile cu ceva care are sens pentru tine, dar acest cod ar trebui să funcționeze pentru aproape orice în mod automat.
function todo_restrict_manage_posts() {
global $typenow;
$args=array( 'public' => true, '_builtin' => false );
$post_types = get_post_types($args);
if ( in_array($typenow, $post_types) ) {
$filters = get_object_taxonomies($typenow);
foreach ($filters as $tax_slug) {
$tax_obj = get_taxonomy($tax_slug);
wp_dropdown_categories(array(
'show_option_all' => __('Afișează Tot '.$tax_obj->label ),
'taxonomy' => $tax_slug,
'name' => $tax_obj->name,
'orderby' => 'term_order',
'selected' => $_GET[$tax_obj->query_var],
'hierarchical' => $tax_obj->hierarchical,
'show_count' => false,
'hide_empty' => true
));
}
}
}
function todo_convert_restrict($query) {
global $pagenow;
global $typenow;
if ($pagenow=='edit.php') {
$filters = get_object_taxonomies($typenow);
foreach ($filters as $tax_slug) {
$var = &$query->query_vars[$tax_slug];
if ( isset($var) ) {
$term = get_term_by('id',$var,$tax_slug);
$var = $term->slug;
}
}
}
return $query;
}
add_action( 'restrict_manage_posts', 'todo_restrict_manage_posts' );
add_filter('parse_query','todo_convert_restrict');
Reține că folosesc un plugin care adaugă 'term_order' ca modalitate de ordonare a termenilor, va trebui să modifici acest lucru sau să elimini acel argument pentru a reveni la valoarea implicită.

foarte sexy într-adevăr. primeam notificări de eroare, așa că am schimbat if ( isset($var)) în if ( isset($var) && $var>0) pentru a evita încercarea de a găsi termeni asociați cu valoarea 0 din View all. ah, și a trebuit să returnez $query în funcția todo_convert_restrict

Răspuns întârziat
Editare
Am creat Filterama, un plugin care va adăuga această funcționalitate în cel mai simplu mod posibil.
Actualizare pentru WordPress 3.5+
Acum că lucrurile sunt mult mai simple, iată o soluție foarte ușoară ca plugin sau mu-plugin.
Folosește cât mai puține resurse, se încarcă doar pe ecranele necesare și adaugă Coloane + Filtre pentru fiecare taxonomie personalizată.
add_action( 'plugins_loaded', array( 'WCM_Admin_PT_List_Tax_Filter', 'init' ) );
class WCM_Admin_PT_List_Tax_Filter
{
private static $instance;
public $post_type;
public $taxonomies;
static function init()
{
null === self::$instance AND self::$instance = new self;
return self::$instance;
}
public function __construct()
{
add_action( 'load-edit.php', array( $this, 'setup' ) );
}
public function setup()
{
add_action( current_filter(), array( $this, 'setup_vars' ), 20 );
add_action( 'restrict_manage_posts', array( $this, 'get_select' ) );
add_filter( "manage_taxonomies_for_{$this->post_type}_columns", array( $this, 'add_columns' ) );
}
public function setup_vars()
{
$this->post_type = get_current_screen()->post_type;
$this->taxonomies = array_diff(
get_object_taxonomies( $this->post_type ),
get_taxonomies( array( 'show_admin_column' => 'false' ) )
);
}
public function add_columns( $taxonomies )
{
return array_merge( $taxonomies, $this->taxonomies );
}
public function get_select()
{
$walker = new WCMF_walker;
foreach ( $this->taxonomies as $tax )
{
wp_dropdown_categories( array(
'taxonomy' => $tax,
'hide_if_empty' => true,
'show_option_all' => sprintf(
get_taxonomy( $tax )->labels->all_items
),
'hide_empty' => true,
'hierarchical' => is_taxonomy_hierarchical( $tax ),
'show_count' => true,
'orderby' => 'name',
'selected' => '0' !== get_query_var( $tax )
? get_query_var( $tax )
: false,
'name' => $tax,
'id' => $tax,
'walker' => $walker,
) );
}
}
}
Apoi aveți nevoie doar de o clasă Walker personalizată.
class WCMF_walker extends Walker_CategoryDropdown
{
public $tree_type = 'category';
public $db_fields = array(
'parent' => 'parent',
'id' => 'term_id',
);
public $tax_name;
public function start_el( &$output, $term, $depth, $args, $id = 0 )
{
$pad = str_repeat( ' ', $depth * 3 );
$cat_name = apply_filters( 'list_cats', $term->name, $term );
$output .= sprintf(
'<option class="level-%s" value="%s" %s>%s%s</option>',
$depth,
$term->slug,
selected(
$args['selected'],
$term->slug,
false
),
$pad.$cat_name,
$args['show_count']
? " ({$term->count})"
: ''
);
}
}

@goto10 Aveți dreptate. Am actualizat. Apropo: e mai ușor să folosiți direct plugin-ul linked. Va fi disponibil în repository-ul de plugin-uri în una sau două săptămâni. (Deja confirmat).

A trebuit să folosesc $this->setup_vars();
la începutul funcției public function setup()
pentru a avea "manage_taxonomies_for_{$this->post_type}_columns"
funcțional

Dar ar putea fi pentru că îl folosesc într-un fișier function.php al Temei cu add_action( 'init', array( 'WCM_Admin_PT_List_Tax_Filter', 'init' ) );

@Christian Acesta nu este material pentru temă. Aceasta ar trebui să fie într-un plugin și așa cum stă codul de mai sus, se încarcă cu mult înainte de încărcarea Temelor.

@BadHorsie Te rog să încerci dev
–Branch. Am început refactorizarea, dar nu am avut timp să o finalizez.

Am vrut să fac o notă rapidă. În versiunile mai noi de WP, afișarea postărilor în administrare este gestionată de clasa WP_Posts_List_Table. Codul apply_filters arată acum astfel:
if ( 'page' == $post_type )
$posts_columns = apply_filters( 'manage_pages_columns', $posts_columns );
else
$posts_columns = apply_filters( 'manage_posts_columns', $posts_columns, $post_type );
$posts_columns = apply_filters( "manage_{$post_type}_posts_columns", $posts_columns );
Deci, pentru a adăuga coloane noi, un add_filter ar trebui să arate astfel:
add_filter( 'manage_posts_columns', 'my_add_columns', 10, 2);
Iată un exemplu:
function my_add_columns($posts_columns, $post_type)
{
if ('myposttype' == $post_type) {
$posts_columns = array(
"cb" => "<input type=\"checkbox\" />",
"title" => "Titlu",
"anothercolumn" => "Bacon",
"date" => __( 'Data' )
);
return $posts_columns;
}
}
Acum, pentru rândurile de postări. Acesta este codul care gestionează datele coloanelor în liste:
default:
?>
<td <?php echo $attributes ?>><?php
if ( is_post_type_hierarchical( $post->post_type ) )
do_action( 'manage_pages_custom_column', $column_name, $post->ID );
else
do_action( 'manage_posts_custom_column', $column_name, $post->ID );
do_action( "manage_{$post->post_type}_posts_custom_column", $column_name, $post->ID );
?></td>
<?php
Pentru a prelua datele postărilor noastre, trebuie să adăugăm un action hook astfel:
add_action( "manage_(here_goes_your_post_type)_posts_custom_column", "my_posttype_add_column", 10, 2);
Exemplu (acest exemplu folosește taxonomii, dar puteți interoga orice altceva):
function my_posttype_add_column($column_name, $post_id)
{
switch ($column_name) {
case 'anothercolumn':
$flavours = get_the_terms($post_id, 'flavour');
if (is_array($flavours)) {
foreach($flavours as $key => $flavour) {
$edit_link = get_term_link($flavour, 'flavour');
$flavours[$key] = '<a href="'.$edit_link.'">' . $flavour->name . '</a>';
}
echo implode(' | ',$flavours);
}
break;
default:
break;
}
}

FUNCȚIONEAZĂ ÎN WP 3.2!
custom_post_type: books custom_taxonomy: genre
Modifică doar unde scrie: // change HERE
function restrict_books_by_genre() {
global $typenow;
$post_type = 'books'; // change HERE
$taxonomy = 'genre'; // change HERE
if ($typenow == $post_type) {
$selected = isset($_GET[$taxonomy]) ? $_GET[$taxonomy] : '';
$info_taxonomy = get_taxonomy($taxonomy);
wp_dropdown_categories(array(
'show_option_all' => __("Arată toate {$info_taxonomy->label}"),
'taxonomy' => $taxonomy,
'name' => $taxonomy,
'orderby' => 'name',
'selected' => $selected,
'show_count' => true,
'hide_empty' => true,
));
};
}
add_action('restrict_manage_posts', 'restrict_books_by_genre');
function convert_id_to_term_in_query($query) {
global $pagenow;
$post_type = 'books'; // change HERE
$taxonomy = 'genre'; // change HERE
$q_vars = &$query->query_vars;
if ($pagenow == 'edit.php' && isset($q_vars['post_type']) && $q_vars['post_type'] == $post_type && isset($q_vars[$taxonomy]) && is_numeric($q_vars[$taxonomy]) && $q_vars[$taxonomy] != 0) {
$term = get_term_by('id', $q_vars[$taxonomy], $taxonomy);
$q_vars[$taxonomy] = $term->slug;
}
}
add_filter('parse_query', 'convert_id_to_term_in_query');

A trebuit să lucrez la o funcționalitate similară nu cu mult timp în urmă și nefiind mulțumit de răspunsurile existente, iată alternativa mea. Anul este 2021.
Am dorit ceva simplu și ușor de implementat. O modalitate rapidă și eficientă de a obține toate taxonomiile personalizate din fiecare tip de postare personalizată și de a le adăuga ca opțiuni de filtrare.
Erau câteva cerințe preliminare:
- Am vrut să evit utilizarea variabilelor globale.
- Codul trebuia să fie portabil, fără variabile hardcodate, pentru a fi reutilizabil.
- Să aibă o ierarhie vizibilă, perfectă pentru taxonomii cu termeni înrudite.
- Să respecte opțiunile de vizibilitate ale taxonomiei. (ex: argumentul
show_admin_column
din funcțiaregister_taxonomy
. - Afișarea numărului de postări.
- Aspectul general să se potrivească cu WordPress.
Am transformat-o într-un plugin pentru o integrare mai ușoară, puteți obține ultima versiune la https://wordpress.org/plugins/cpt-admin-taxonomy-filtering/.
Filtrare cu ierarhie de termeni și număr de postări | Filtre multiple pentru tipuri de postări personalizate |
---|---|
![]() |
![]() |
Dacă doriți doar să o adăugați în function.php
, copiați și lipiți următorul script.
Necesită cel puțin WordPress
4.8.0
și PHP:4.0
.
<?php
add_action( 'restrict_manage_posts', 'cpt_admin_taxonomy_filtering' );
if ( ! function_exists( 'cpt_admin_taxonomy_filtering' ) ) {
function cpt_admin_taxonomy_filtering() {
/**
* Obține obiectul ecranului curent.
*
* @link https://developer.wordpress.org/reference/functions/get_current_screen/
*/
$screen = get_current_screen();
// Tipuri de postări implicite WordPress
$restricted_post_types = array(
'post',
'page',
'attachment',
'revision',
'nav_menu_item',
);
if ( 'edit' === $screen->base && ! in_array( $screen->post_type, $restricted_post_types ) ) {
/**
* Returnează numele sau obiectele taxonomiilor înregistrate pentru obiectul sau tipul de obiect solicitat, cum ar fi un obiect de postare sau numele tipului de postare.
*
* @link https://developer.wordpress.org/reference/functions/get_object_taxonomies/
*/
$taxonomies = get_object_taxonomies( $screen->post_type, 'objects' );
// Parcurge fiecare taxonomie
foreach ( $taxonomies as $taxonomy ) {
if ( $taxonomy->show_admin_column ) {
/**
* Afișează sau returnează lista dropdown HTML de categorii.
*
* @link https://developer.wordpress.org/reference/functions/wp_dropdown_categories/
*/
wp_dropdown_categories(
array(
'show_option_all' => $taxonomy->labels->all_items,
'pad_counts' => true,
'show_count' => true,
'hierarchical' => true,
'name' => $taxonomy->query_var,
'id' => 'filter-by-' . $taxonomy->query_var,
'class' => '',
'value_field' => 'slug',
'taxonomy' => $taxonomy->query_var,
'hide_if_empty' => true,
)
);
};
};
};
};
};

Această funcționalitate nu este foarte cunoscută, dar începând cu WordPress 3.5, poți pasa parametrul 'show_admin_column' => true
la register_taxonomy
. Aceasta face două lucruri:
- Adaugă coloana taxonomiei în vizualizarea listei tipurilor de postări din panoul de administrare
- Făcând clic pe numele termenului din coloana taxonomiei, lista va fi filtrată automat după acel termen.
Deci, nu exact la fel ca un câmp de selectare, dar aproape aceeași funcționalitate, cu doar o singură linie de cod.
https://make.wordpress.org/core/2012/12/11/wordpress-3-5-admin-columns-for-custom-taxonomies/
De asemenea, după cum poți citi, există un nou filtru special pentru adăugarea manuală a coloanei taxonomiei (dacă chiar ai nevoie de asta).

Mulțumesc tuturor pentru răspunsuri. Știu că aceasta este o întrebare veche, dar aș dori să adaug soluția mai simplă care poate fi folosită în prezent. Acest lucru va necesita doar 2 pași și va folosi mai multe funcționalități disponibile în nucleu. Sper că acest lucru va ajuta pe cineva.
Pasul 1: adăugați 'show_admin_column' => true
în funcția register_taxonomy
.
Acest lucru va adăuga o coloană în vizualizarea listă care conține link-uri pentru filtrarea listei după acel termen. Poate fi aplicat atât pentru taxonomii ierarhice, cât și pentru cele neierarhice.
Exemplu:
register_taxonomy( 'custom_cat', array( 'custom_post_type' ), array(
'hierarchical' => true,
'labels' => array(
'name' => __( 'Categorii', 'iside' ),
'singular_name' => __( 'Categorie', 'iside' ),
'search_items' => __( 'Caută Categorii', 'iside' ),
'all_items' => __( 'Toate Categoriile', 'iside' ),
'parent_item' => __( 'Categorie Părinte', 'iside' ),
'parent_item_colon' => __( 'Categorie Părinte:', 'iside' ),
'edit_item' => __( 'Editează Categorie', 'iside' ),
'update_item' => __( 'Actualizează Categorie', 'iside' ),
'add_new_item' => __( 'Adaugă Categorie Nouă', 'iside' ),
'new_item_name' => __( 'Nouă Categorie', 'iside' ),
'menu_name' => __( 'Categorii', 'iside' ),
),
'public' => true,
'publicly_queryable'=> true,
'show_ui' => true,
'show_in_menu' => true,
'show_in_nav_menus' => true,
'show_in_rest' => true,
'show_tagcloud' => false,
'show_in_quick_edit'=> true,
'show_admin_column' => true, // <-- magia aplicată aici
'query_var' => true,
) );
Pasul 2: adăugați dropdown-ul de taxonomie prin filtrul restrict_manage_posts
Acest lucru va adăuga un meniu dropdown de selectare în opțiunile de filtrare din partea de sus. Va folosi funcția implicită wp_dropdown_categories
pentru a simplifica procesul. Rețineți că trebuie să setăm numele dropdown-ului la query_var folosit pentru taxonomie. De asemenea, rețineți că value_field
trebuie setat la slug (implicit va fi term_id).
Exemplu:
add_action( 'restrict_manage_posts', 'iside_add_filter_to_admin', 10, 2 );
function iside_add_filter_to_admin( $post_type = 'post', $which = 'top' ) {
if( $post_type == 'custom_post_type' ) {
$selected = isset( $_GET['custom_cat'] ) ? esc_attr($_GET['custom_cat']) : 0;
wp_dropdown_categories(array(
'show_option_all' => __( 'Arată Toate Categoriile', 'iside' ),
'taxonomy' => 'custom_cat',
'name' => 'custom_cat', // <-- asigurați-vă că se potrivește cu query_var
'orderby' => 'name',
'selected' => $selected,
'hierarchical' => true,
'depth' => 3,
'show_count' => true,
'hide_empty' => true,
'value_field' => 'slug', // <-- folosește slug în loc de term_id
));
}
}
Atât. Nu este nevoie să adăugați mai mult :-)

Foarte frumos și simplu, mulțumesc. Un punct de remarcat - ai o eroare în sintaxa ta aici (există o paranteză în plus): $selected = isset( $_GET['custom_cat'] ) ? esc_attr($_GET['custom_cat') ]) : 0; care ar trebui să fie în schimb astfel: $selected = isset( $_GET['custom_cat'] ) ? esc_attr($_GET['custom_cat' ]) : 0;

Iată o modalitate de a face acest lucru folosind acțiunea restrict_manage_posts
. Pare să funcționeze bine pentru mine și adaugă abilitatea de a filtra după taxonomie pentru toate tipurile de postări și taxonomiile aferente.
// înregistrează fiecare meniu derulant pentru filtrarea după taxonomii
function sunrise_fbt_add_taxonomy_filters() {
global $typenow; // tipul curent de postare
$taxonomies = get_taxonomies('','objects');
foreach($taxonomies as $taxName => $tax) {
if(in_array($typenow,$tax->object_type) && $taxName != 'category' && $taxName != 'tags') {
$terms = get_terms($taxName);
if(count($terms) > 0) {
// Verifică dacă e ierarhic - dacă da, construiește meniu derulant ierarhic
if($tax->hierarchical) {
$args = array(
'show_option_all' => 'Toate '.$tax->labels->name,
'show_option_none' => 'Selectează '.$tax->labels->name,
'show_count' => 1,
'hide_empty' => 0,
'echo' => 1,
'hierarchical' => 1,
'depth' => 3,
'name' => $tax->rewrite['slug'],
'id' => $tax->rewrite['slug'],
'class' => 'postform',
'depth' => 0,
'tab_index' => 0,
'taxonomy' => $taxName,
'hide_if_empty' => false);
$args['walker'] = new Walker_FilterByTaxonomy;
wp_dropdown_categories($args);
} else {
echo "<select name='".$tax->rewrite['slug']."' id='".$tax->rewrite['slug']."' class='postform'>";
echo "<option value=''>Afișează toate ".$tax->labels->name."</option>";
foreach ($terms as $term) {
echo '<option value="' . $term->slug . '"', $_GET[$taxName] == $term->slug ? ' selected="selected"' : '','>' . $term->name .' (' . $term->count .')</option>';
}
echo "</select>";
}
}
}
}
}
add_action( 'restrict_manage_posts', 'sunrise_fbt_add_taxonomy_filters', 100 );
/**
* Creează o listă derulantă HTML de Categorii.
*
* @package WordPress
* @since 2.1.0
* @uses Walker
*/
class Walker_FilterByTaxonomy extends Walker {
var $tree_type = 'category';
var $db_fields = array ('parent' => 'parent', 'id' => 'term_id');
function start_el(&$output, $category, $depth, $args) {
$args['selected'] = get_query_var( $args['taxonomy'] );
$pad = str_repeat(' ', $depth * 3);
$cat_name = apply_filters('list_cats', $category->name, $category);
$output .= "\t<option class=\"level-$depth\" value=\"".$category->slug."\"";
if ( $category->slug == $args['selected'] )
$output .= ' selected="selected"';
$output .= '>';
$output .= $pad.$cat_name;
if ( $args['show_count'] )
$output .= ' ('. $category->count .')';
if ( $args['show_last_update'] ) {
$format = 'Y-m-d';
$output .= ' ' . gmdate($format, $category->last_update_timestamp);
}
$output .= "</option>\n";
}
}
O observație - am încercat să limitez adâncimea deoarece unele dintre taxonomiile mele ierarhice sunt destul de mari, dar nu a funcționat - ar putea fi o eroare în funcția wp_dropdown_categories
?

Actualizare a răspunsului lui @Drew Gourley pentru WP 3.3.1 (și incorporând codul de la http://wordpress.org/support/topic/wp_dropdown_categories-generating-url-id-number-instead-of-slug?replies=6#post-2529115):
add_action('restrict_manage_posts', 'xyz_restrict_manage_posts');
function xyz_restrict_manage_posts() {
global $typenow;
$args = array('public'=>true, '_builtin'=>false);
$post_types = get_post_types($args);
if(in_array($typenow, $post_types)) {
$filters = get_object_taxonomies($typenow);
foreach ($filters as $tax_slug) {
$tax_obj = get_taxonomy($tax_slug);
$term = get_term_by('slug', $_GET[$tax_obj->query_var], $tax_slug);
wp_dropdown_categories(array(
'show_option_all' => __('Arată Tot '.$tax_obj->label ),
'taxonomy' => $tax_slug,
'name' => $tax_obj->name,
'orderby' => 'term_order',
'selected' => $term->term_id,
'hierarchical' => $tax_obj->hierarchical,
'show_count' => false,
// 'hide_empty' => true,
'hide_empty' => false,
'walker' => new DropdownSlugWalker()
));
}
}
}
//Clasă pentru filtrarea dropdown. Folosită cu wp_dropdown_categories() pentru a face dropdown-ul să folosească slug-uri în loc de ID-uri.
class DropdownSlugWalker extends Walker_CategoryDropdown {
function start_el(&$output, $category, $depth, $args) {
$pad = str_repeat(' ', $depth * 3);
$cat_name = apply_filters('list_cats', $category->name, $category);
$output .= "\t<option class=\"level-$depth\" value=\"".$category->slug."\"";
if($category->term_id == $args['selected'])
$output .= ' selected="selected"';
$output .= '>';
$output .= $pad.$cat_name;
$output .= "</option>\n";
}
}

Versiunea ierarhică a răspunsului lui @somatic, la cererea lui @kevin:
<?php
add_action( 'restrict_manage_posts', 'my_restrict_manage_posts' );
function my_restrict_manage_posts() {
// afișează aceste filtre de taxonomie doar pe listările dorite de tipuri personalizate de postări
global $typenow;
if ($typenow == 'photos' || $typenow == 'videos') {
// creează o listă de slug-uri de taxonomii după care dorești să filtrezi - dacă vrei să obții toate taxonomiile, poți folosi get_taxonomies() pentru a construi lista
$filters = array('plants', 'animals', 'insects');
foreach ($filters as $tax_slug) {
// obține obiectul taxonomiei
$tax_obj = get_taxonomy($tax_slug);
$tax_name = $tax_obj->labels->name;
// generează HTML pentru meniul dropdown de filtrare după taxonomie
echo "<select name='$tax_slug' id='$tax_slug' class='postform'>";
echo "<option value=''>Afișează tot $tax_name</option>";
generate_taxonomy_options($tax_slug,0,0);
echo "</select>";
}
}
}
function generate_taxonomy_options($tax_slug, $parent = '', $level = 0) {
$args = array('show_empty' => 1);
if(!is_null($parent)) {
$args = array('parent' => $parent);
}
$terms = get_terms($tax_slug,$args);
$tab='';
for($i=0;$i<$level;$i++){
$tab.='--';
}
foreach ($terms as $term) {
// generează fiecare opțiune pentru select, verifică ultima valoare $_GET pentru a afișa opțiunea curentă selectată
echo '<option value='. $term->slug, $_GET[$tax_slug] == $term->slug ? ' selected="selected"' : '','>' .$tab. $term->name .' (' . $term->count .')</option>';
generate_taxonomy_options($tax_slug, $term->term_id, $level+1);
}
}
?>
Am eliminat practic codul care crea opțiunile și l-am pus într-o funcție separată. Funcția 'generate_taxonomy_options', pe lângă parametrul tax_slug, mai primește și parametrii parent și level. Funcția presupune că creează opțiuni pentru părintele 0, care va selecta toți termenii de la nivelul rădăcină. În buclă, funcția se va apela recursiv, folosind termenul curent ca părinte și crește nivelul cu unu. Adaugă automat liniuțe pe măsură ce cobori în ierarhie și voila!

Adaugă pur și simplu acest cod în fișierul functions.php sau în codul unui plugin (și înlocuiește YOURCUSTOMTYPE și YOURCUSTOMTAXONOMY). (Am obținut codul de pe generatewp)
add_action( 'restrict_manage_posts', 'filter_backend_by_taxonomies' , 99, 2);
function filter_backend_by_taxonomies( $post_type, $which ) {
// Aplică acest filtru doar pentru un anumit tip de postare personalizată (CPT)
if ( 'YOURCUSTOMTYPE' !== $post_type )
return;
// Listă de taxonomii personalizate după care se filtrează
$taxonomies = array( 'YOURCUSTOMTAXONOMY' );
foreach ( $taxonomies as $taxonomy_slug ) {
// Preluare date despre taxonomie
$taxonomy_obj = get_taxonomy( $taxonomy_slug );
$taxonomy_name = $taxonomy_obj->labels->name;
// Preluare termeni ai taxonomiei
$terms = get_terms( $taxonomy_slug );
// Afișare HTML pentru filtru
echo "<select name='{$taxonomy_slug}' id='{$taxonomy_slug}' class='postform'>";
echo '<option value="">' . sprintf( esc_html__( 'Categorie', 'text_domain' ), $taxonomy_name ) . '</option>';
foreach ( $terms as $term ) {
printf(
'<option value="%1$s" %2$s>%3$s (%4$s)</option>',
$term->slug,
( ( isset( $_GET[$taxonomy_slug] ) && ( $_GET[$taxonomy_slug] == $term->slug ) ) ? ' selected="selected"' : '' ),
$term->name,
$term->count
);
}
echo '</select>';
}
}

Tutorialul lui Mike pe acest subiect este excelent! Probabil că nu m-aș fi obosit să adaug această funcționalitate în plugin-ul meu Media Categories dacă ar fi trebuit să o descopăr singur.
Cu toate acestea, cred că utilizarea parse_query
și apoi interogarea pentru termen nu este necesară. Este mai curat să creezi propria clasă personalizată walker. Poate că acest lucru nu era posibil atunci când a scris postarea sa - are 3 ani la momentul scrierii acestui text.
Verifică acest fragment de cod minunat de pe github. Funcționează perfect, schimbă ID-urile din valorile dropdown-ului în slug-uri, astfel încât funcționează în mod nativ fără a modifica interogarea.

Am încercat ambele coduri, de la Mike și somatic, și m-am întrebat cum să obțin un lucru din fiecare tehnică:
Cu codul lui Mike, afișează lista derulantă cu opțiunea ierarhică, ceea ce ajută foarte mult. Dar pentru a afișa două liste derulante a trebuit să duplic instrucțiunea if ($typenow=='produtos') {...}
în funcția restrict_listings_by_business()
și de asemenea if ($pagenow=='edit.php' && ... }
în funcția convert_business_id_to_taxonomy_term_in_query($query)
, ceea ce acum produce mult cod.
Cu codul lui somatic, trebuie doar să specific taxonomiile pe care doresc să le văd ca liste derulante și funcționează; $filters = array('taxo1', 'taxo2');
Întrebare: pot să folosesc abordarea lui somatic și să am și opțiunea ierarhică?
Mulțumesc mult oricum pentru acest tutorial, a fost de mare ajutor!

Acesta este un fragment de cod util care permite filtrarea postărilor sau a unui tip de postare personalizată după un termen specific dintr-o taxonomie în panoul de administrare WordPress.
/* Filtrează CPT după Taxonomie Personalizată */
function rave_core_backend_by_portfolio_taxonomies( $post_type, $which ) {
// Aplică acest filtru doar pentru un anumit CPT
if ( 'portfolio' !== $post_type )
return;
// Listă de slug-uri de taxonomii personalizate după care se filtrează
$taxonomies = array( 'portfolio_cat' );
foreach ( $taxonomies as $taxonomy_slug ) {
// Preluare date despre taxonomie
$taxonomy_obj = get_taxonomy( $taxonomy_slug );
$taxonomy_name = $taxonomy_obj->labels->name;
// Preluare termeni din taxonomie
$terms = get_terms( $taxonomy_slug );
// Afișare HTML pentru filtru
echo "<select name='{$taxonomy_slug}' id='{$taxonomy_slug}' class='postform'>";
echo '<option value="">' . sprintf( esc_html__( 'Toate %s', 'rave-core' ), $taxonomy_name ) . '</option>';
foreach ( $terms as $term ) {
printf(
'<option value="%1$s" %2$s>%3$s (%4$s)</option>',
$term->slug,
( ( isset( $_GET[$taxonomy_slug] ) && ( $_GET[$taxonomy_slug] == $term->slug ) ) ? ' selected="selected"' : '' ),
$term->name,
$term->count
);
}
echo '</select>';
}
}
add_action( 'restrict_manage_posts', 'rave_core_backend_by_portfolio_taxonomies' , 99, 2);

Îmi cer scuze pentru faptul că, fiind un utilizator nou, nu pot posta comentarii, dar pot posta un răspuns...
Începând cu WordPress 3.1 (RC 1), răspunsul lui Mike (care m-a ajutat atât de bine în ultimele luni) nu mai funcționează pentru mine; limitarea după orice termen dintr-o taxonomie copil returnează un rezultat gol.
Am încercat actualizarea lui Somatic și a funcționat excelent; chiar mai bine, funcționează cu interogări multiple de taxonomii, care au fost integrate în această versiune.
