WooCommerce'te belirli bir kategoride fiyat nasıl gizlenir
Beş satırlık bir filtre fiyat HTML'ini gizler, ama fiyat filtresi, varyasyon JSON'u, Store API, JSON-LD ve REST rakamı sızdırmaya devam eder. Kuralı tek bir yüklem olarak yazıp her yüzeyde aynı cevabı verdirmenin yolu.
Fiyat gizleyen mağazaların çoğu aslında fiyatların hepsini gizlemek istemez. Bir ürün grubu siparişe özel üretilir, yalnızca bayilere satılır ya da proje bazında fiyatlanır; o grup “fiyat sorunuz” demeli, diğer dört yüz ürün ise hem fiyatını hem de Sepete Ekle butonunu korumalıdır. WooCommerce’te belirli bir kategoride fiyat gizleme kuralı arıyorsanız, işin ilk yarısı bugün yapıştırabileceğiniz beş satırlık bir filtredir.
İkinci yarısı ise bir hafta süren kısımdır. O beş satır, ürün sayfasındaki ve mağaza döngüsündeki fiyat HTML’ini değiştirir. Fiyat filtresi bileşenini, varyasyonlu bir ürün sayfasına gömülü varyasyon JSON’unu, blok temanın okuduğu Store API yanıtını, SEO eklentinizin bastığı JSON-LD teklifini ya da pazaryeri bağlayıcınızın çektiği wc/v3 REST verisini değiştirmez. Kısmen gizlenmiş bir kataloğu tutarlı tutmak, tamamen gizlenmiş bir kataloğu tutarlı tutmaktan zordur; çünkü her yüzeyin aynı ürün hakkında aynı evet-hayır cevabını vermesi gerekir, oysa varsayılan olarak her biri bu cevabı ayrı ayrı hesaplar.
WooCommerce’te belirli bir kategoride fiyat gizleme kuralı aslında nedir#
Bu bir yüklemdir: bir ürün ve o anki ziyaretçi verildiğinde, fiyat gizli mi değil mi? Bu yüklemi tek bir fonksiyon içinde bir kez yazın ve her filtrenin onu çağırmasını sağlayın. Sık görülen hata, koşulu doğrudan fiyat filtresinin içine yazmak, üç hafta sonra yapılandırılmış veri filtresinin içine biraz farklı bir şey yazmak ve ikisinin varyasyonlarda ya da alt kategorilerde birbiriyle çeliştiğini hiç fark etmemektir.
Filtreyle değil, fonksiyonla başlayın.
// Which product_cat terms are quote-only, including their children.
function shop_hidden_term_ids() {
static $ids = null;
if ( null !== $ids ) {
return $ids;
}
$ids = array();
foreach ( array( 'made-to-order', 'trade-only' ) as $slug ) {
$term = get_term_by( 'slug', $slug, 'product_cat' );
if ( ! $term ) {
continue;
}
$ids[] = (int) $term->term_id;
$ids = array_merge( $ids, get_term_children( $term->term_id, 'product_cat' ) );
}
$ids = array_values( array_unique( array_map( 'intval', $ids ) ) );
return $ids;
}
// The single source of truth. Everything else calls this.
function shop_price_is_hidden( $product ) {
if ( ! $product instanceof WC_Product ) {
return false;
}
$id = $product->is_type( 'variation' ) ? $product->get_parent_id() : $product->get_id();
return has_term( shop_hidden_term_ids(), 'product_cat', $id );
}Buradaki iki ayrıntı, insanların en sık yanlış yaptığı ayrıntılardır. Birincisi, has_term() yalnızca gönderiye gerçekten atanmış terimlerle eşleşir; ağaçta yukarı doğru yürümez. Ürünleriniz CNC parçaları kategorisindeyse ve bu kategori de Siparişe özel kategorisinin bir alt kategorisiyse, has_term( 'made-to-order', ... ) false döner ve hiçbir şey gizlenmez. Alt terimleri get_term_children() ile toplamak bunu düzeltir; listeyi bir static içinde önbelleğe almak da kırk ürünlük bir döngüde ürün başına iki terim sorgusu çalıştırmanızı engeller.
İkincisi, bir WC_Product_Variation nesnesinin kendine ait kategorisi yoktur; doğrudan ona sorarsanız her zaman false döner. Üst ürünün kimliğini çözün, yoksa üst ürün olması gerektiği gibi görünürken gruptaki her varyasyon kontrolden sıyrılır. Gruplanmış ürünlerde durum tam tersidir: her alt ürün, kendi kategorileri olan sıradan ve bağımsız bir üründür. Dolayısıyla yalnızca teklife açık bir alt ürün, geri kalanı görünür olan gruplanmış bir üst ürünün içinde gizlenir; görünür bir alt ürün de gizli bir üst ürünün içinde fiyatını korur. Bu genelde doğru davranıştır, ama gerçekte ne istediğinizle karşılaştırıp doğrulayın.
Kategorilerin tamamı yerine tek tek ürünleri işaretlemeyi tercih ediyorsanız, product_cat yerine product_tag kullanıp ürünleri quote-only etiketiyle etiketleyin ya da post meta olarak kaydettiğiniz bir onay kutusunu okuyun. Yüklemin imzası aynı kaldığı için bu yazının geri kalanı değişmez.
Herkesin başladığı filtre#
Yüklem yerine oturduktan sonra görünen kısım kısadır.
add_filter( 'woocommerce_get_price_html', 'shop_filter_price_html', 100, 2 );
function shop_filter_price_html( $price_html, $product ) {
if ( shop_price_is_hidden( $product ) ) {
return '<span class="price-on-request">' . esc_html__( 'Price on request', 'my-shop' ) . '</span>';
}
return $price_html;
}100 önceliği göründüğünden daha önemlidir. Pek çok tema ve para birimi değiştirici eklenti de woocommerce_get_price_html filtresine bağlanır; geç çalışmak, son sözü sizin söylemeniz demektir. Bu tek filtre; tekil ürün sayfasını, mağaza ve kategori döngülerini, ilgili ürünleri, upsell ve çapraz satış ürünlerini ve gruplanmış ürün tablosunu kapsar, çünkü hepsi get_price_html() üzerinden render edilir.
Biçimlendirilmiş HTML yerine ham fiyatı okuyan hiçbir şeyi kapsamaz. Bu yazının geri kalanının tamamı da bununla ilgili.
Yalnızca kategoriye göre değil, role göre hedefleme#
Kategori “hangi ürünler” sorusunu yanıtlar, rol ise “hangi kişiler” sorusunu. Bayi kataloglarının çoğunda ikisi birden gerekir: siparişe özel ürün grubu genel ziyaretçiler için yalnızca teklife açıktır, ama onaylı bir toptancı hesabı fiyatları görebilmeli ve normal şekilde sipariş verebilmelidir. Rol kontrolünü aynı yüklemin içine koyun ki zamanla ondan ayrışmasın. Aşağıdaki sürüm, önceki shop_price_is_hidden() fonksiyonunun yerine geçer. İkisini birden bırakırsanız PHP yeniden tanımlama hatası verip durur.
function shop_price_is_hidden( $product ) {
if ( ! $product instanceof WC_Product ) {
return false;
}
$id = $product->is_type( 'variation' ) ? $product->get_parent_id() : $product->get_id();
if ( ! has_term( shop_hidden_term_ids(), 'product_cat', $id ) ) {
return false;
}
$can_see = array( 'wholesale_customer', 'shop_manager', 'administrator' );
$user = wp_get_current_user();
if ( $user->ID && array_intersect( $can_see, (array) $user->roles ) ) {
return false;
}
return true;
}Rol dalıyla ilgili üç uyarı. Sayfa önbellekleri genellikle bütün anonim ziyaretçilere tek bir önbelleklenmiş kopya sunar ve oturum açmış kullanıcılar için devre dışı kalır; istediğiniz davranış da budur, ama yanlış yapılandırılmış bir önbellek toptan fiyat içeren bir sayfayı misafir bir ziyaretçiye verir. Güvenmeden önce gizli pencerede test edin. REST ve Store API isteklerinde çoğu zaman oturum açmış bir kullanıcı hiç yoktur, bu yüzden yüklem bir oturum olduğunu varsaymak yerine varsayılan olarak gizlemeye geçmelidir. Son olarak, rol kontrolü bir görüntüleme kuralıdır, yetkilendirme sistemi değil. Fiyatlandırma için yeterlidir; bir belgeyi gizli tutmanın yolu değildir.
Tek bir ürün grubu değil de mağazanın tamamı hesap arkasına alınacaksa, müşteriler giriş yapana kadar WooCommerce fiyatlarını gizlemek yazısındaki daha basit desen, buradakinden daha iyi bir başlangıç noktasıdır.
Kısmen gizlenmiş bir katalog nerelerden sızar#
Fiyat HTML’inde duran bir belirli kategoride fiyat gizleme kuralının ters gidebileceği sekiz yer daha vardır. İşte kabaca insanların bunları keşfetme sırasıyla; keşif genellikle kendi rakamlarını bir Google sonucunda bulmakla olur.
- Fiyata göre sıralama. Sırala: fiyat artan denetimi gizli ürünlerinizi hâlâ doğru sıralar, çünkü sıralamayı
wc_product_meta_lookuptablosu üzerinden yapar. Gizli bir ürünün iki görünür ürün arasında nereye düştüğünü izleyen herkes, o ürünün fiyatını birkaç sterlinlik hata payıyla ikili aramayla bulabilir. - Fiyat filtresi. Klasik Fiyata göre filtrele bileşeni de blok editörünün fiyat filtresi de en düşük ve en yüksek değeri aynı arama tablosundan okur. Görünür kataloğunuz en fazla £300’e çıkarken £8,400’e kadar giden bir kaydırıcı, gizli ürün grubunun ne tuttuğunu ziyaretçiye söylemiş olur.
- Varyasyonlu ürünler.
get_price_html()sayfadaki “£x’ten başlayan” aralığını halleder, ama WooCommerce her varyasyonun fiyatını ayrıcadata-product_variationsJSON’una da basar; böylece ön yüz betiği fiyatları istek atmadan değiştirebilir. Kaynağı görüntüleyin, hepsi orada. - Store API. Blok ürün ızgaraları ve bunların filtre blokları
/wp-json/wc/store/v1/productsadresini okur; buradakipricesdüğümü ham tutarlardan kendi şeması üzerinden serileştirilir ve hiçbir zamanwoocommerce_get_price_htmlfiltresinden geçmez.collection-datauç noktası da toplulaştırılmış fiyat aralığını ayrıca bir kez daha döndürür. - Yapılandırılmış veri. WooCommerce çekirdeği, içinde fiyat bulunan bir JSON-LD
Offernesnesi basar. Rank Math, Yoast, All in One SEO ve şema eklentileri de birbirinden bağımsız olarak aynısını yapar. Her biri ayrı bir kod yoludur ve her biri Google’ın zengin sonuçlarını besler. - REST ve GraphQL.
wc/v3ürün ve varyasyon uç noktalarıprice,regular_price,sale_priceveprice_htmlalanlarını dışarı açar. WooGraphQL ile birlikte çalışan WPGraphQL da aynı değerleri farklı alan adları altında açar. - Sepet, ödeme ve e-posta. Gizli bir ürün hâlâ sepete eklenebiliyorsa mini sepet, sipariş özeti tablosu ve onay e-postası fiyatı hiç çekinmeden basar.
- Ürün akışları. CTX Feed, Google Product Feed ve benzeri dışa aktarıcılar fiyatları doğrudan ürün nesnesinden okur. Hiçbir görüntüleme filtresi onları durduramaz.
Bunlardan üçünün kısa ve makul çözümleri var. Önce yapılandırılmış veri, çünkü arama sonuçlarına düşen o:
add_filter( 'woocommerce_structured_data_product', function ( $markup, $product ) {
if ( shop_price_is_hidden( $product ) ) {
unset( $markup['offers'] );
}
return $markup;
}, 10, 2 );Bu yalnızca WooCommerce çekirdeğini kapsar. Rank Math, Yoast, All in One SEO ve kullandığınız her şema eklentisi kendi grafiğini kurar ve her biri kendi filtresini ister.
Ardından hem ürünler hem varyasyonlar için klasik REST API:
function shop_blank_rest_prices( $response, $object ) {
if ( ! shop_price_is_hidden( $object ) ) {
return $response;
}
foreach ( array( 'price', 'regular_price', 'sale_price' ) as $field ) {
if ( isset( $response->data[ $field ] ) ) {
$response->data[ $field ] = '';
}
}
$response->data['price_html'] = '';
return $response;
}
add_filter( 'woocommerce_rest_prepare_product_object', 'shop_blank_rest_prices', 10, 2 );
add_filter( 'woocommerce_rest_prepare_product_variation_object', 'shop_blank_rest_prices', 10, 2 );Ve ürün sayfasındaki varyasyon JSON’u:
add_filter( 'woocommerce_available_variation', function ( $data, $parent, $variation ) {
if ( shop_price_is_hidden( $variation ) ) {
$data['price_html'] = '<span class="price-on-request">' . esc_html__( 'Price on request', 'my-shop' ) . '</span>';
$data['display_price'] = '';
$data['display_regular_price'] = '';
}
return $data;
}, 10, 3 );Sonuncusu konusunda kendinize karşı dürüst olun: display_price alanını boşaltmak, sepete ekleme betiğini üzerinde çalışacağı sayıdan yoksun bırakır; bu yüzden adet toplamları ve bazı tema betikleri tuhaf davranır. Bu ancak, fiyatı gizli bir ürünün zaten satın alınabilir olmaması gerektiği için kabul edilebilir; bir sonraki bölümün konusu da bu. Fiyat aralıkları sorununun geneli varyasyonlu ürünlerde fiyat aralığını gizlemek yazısında daha ayrıntılı ele alınıyor.
Store API, bir kod parçacığı koleksiyonunun keyifli olmaktan çıktığı yerdir. woocommerce_get_price_html filtresinin, sayısal prices nesnesi için alan alan çalışan derli toplu bir karşılığı yoktur; sonunda /wc/store/v1/ rotalarına gönderilen REST yanıtını araya girip yakalar, prices düğümünü, price_html dizesini ve collection-data içindeki toplulaştırılmış aralığı yeniden yazarsınız, sonra aynı işi sepet yanıtları için tekrarlarsınız. Bu tamamen yapılabilir bir şeydir, ama birkaç yüz satır tutar ve şema sürümü her değiştiğinde yeniden test edilmesi gerekir. Bir eklentinin ekmeğini hak ettiği nokta kabaca burasıdır: PriceVeil tek bir kuralı sunucu tarafında mağaza ön yüzüne, Store API’ye, yapılandırılmış veriye (WooCommerce çekirdeğinin JSON-LD çıktısı ile birlikte Rank Math, Yoast, All in One SEO ve Schema & Structured Data for WP), wc/v3 REST API’sine ve GraphQL’e uygular. Ücretsiz sürümü fiyatı ya herkesten ya da yalnızca misafirlerden gizler; kuralın hangi kategorilere, ürünlere ve rollere uygulanacağını seçmek Pro özelliğidir.
Fiyat HTML filtresi gerçekte hangi yüzeyleri kapsıyor#
| Yüzey | Fiyat HTML filtresi kapsıyor mu? | Ne gerekiyor |
|---|---|---|
| Ürün sayfası, mağaza döngüsü, ilgili ürünler | Evet | Başka bir şey gerekmiyor |
| Gruplanmış ürün tablosu | Evet | Her alt ürün kendi kategorilerine göre değerlendirilir; istediğinizin bu olduğunu doğrulayın |
| Varyasyonlu ürün fiyat aralığı | Evet | Ayrıca varyasyon JSON filtresi |
| Sayfa kaynağındaki varyasyon JSON’u | Hayır | woocommerce_available_variation |
| Fiyata göre sıralama, fiyat filtresi | Hayır | Denetimleri kaldırın ya da terimleri sorgudan çıkarın |
Store API prices ve koleksiyon aralığı | Hayır | Store rotaları için REST yanıtını yeniden yazın |
| JSON-LD, çekirdek ve SEO eklentileri | Hayır | Her kaynak için ayrı bir filtre |
REST wc/v3, GraphQL | Hayır | Her uç noktada fiyat alanlarını boşaltın |
| Sepet, ödeme, e-postalar | Hayır | Ürünü satın alınabilir olmaktan çıkarın |
| Ürün akışı dışa aktarıcıları | Hayır | Kategorileri akış eklentisinde hariç tutun |
Fiyatı gizlemek genellikle butonu da kaldırmak demektir#
Görünür fiyatı olmayan ama Sepete Ekle butonu çalışan bir ürün, iki uçtan da kötüdür: müşteri kendisine hiç gösterilmemiş bir rakam üzerinden alışverişi tamamlayabilir ve sorunu ilk kez bir iade talebiyle görürsünüz. Yalnızca gizli alt kümedeki ürünleri satın alınamaz hale getirin.
add_filter( 'woocommerce_is_purchasable', function ( $purchasable, $product ) {
return shop_price_is_hidden( $product ) ? false : $purchasable;
}, 10, 2 );Bu tek filtre çok iş görür, çünkü WooCommerce sepete bir şey eklendiğinde satın alınabilirliği yeniden denetler; Store API üzerinden eklendiğinde de öyle. Buton yine de klasik döngüden ve tekil ürün şablonundan kaldırılmalı, blok temalar da kendi çözümünü ister; Sepete Ekle butonunu kaldırmak ve eklentisiz katalog modu kurmak yazılarının ikisi de bunu baştan sona anlatıyor. Bunun yerine PriceVeil kullanıyorsanız katalog modu ücretsizdir: sepete ekleme işlevini varyasyon formu dahil klasik ve blok şablonlardan söküp alır ve Store API’ye gelen sepet yazma isteklerini reddeder, böylece API bir arka kapıya dönüşmez. Ama bu, mağaza genelinde çalışan bir anahtardır; gizlemenin herhangi bir parçasını seçili kategorilere, ürünlere ya da rollere daraltmak Pro hedeflemesine girer.
Sonra ziyaretçiye yapacak başka bir şey verin. Sepete Ekle butonunun bulunduğu yerde duran bir teklif iste butonu, sayfanın altındaki bir “bize ulaşın” satırının asla olamayacağı kadar bariz bir sonraki adımdır; teklif isteme akışı eklemek yazısı formu, nonce’u, hız sınırlamayı ve taleplerin nereye düşmesi gerektiğini ele alıyor.
Bunların hiçbirinin çözmediği şeyler#
get_price()fonksiyonunu doğrudan çağıran temalar. Bazı sayfa oluşturucular ve premium temalar fiyatları ham getirici üzerinden ya da kendi ürün bileşenlerinden render eder. Hiçbir görüntüleme filtresi oraya ulaşmaz; şablonu bulup düzenlemeniz gerekir.- Akışlar ve entegrasyonlar. Bir eklenti kataloğunuzu Google’a, Meta’ya ya da bir pazaryerine aktarıyorsa, gizli kategorileri o eklentinin kendi ayarlarında hariç tutun. Temanızın
functions.phpdosyasındaki hiçbir şey bunu sizin yerinize yapmaz. - Zaten önbelleklenmiş ve zaten dizine alınmış sayfalar. Kuralı eklemeden önce önbelleklenmiş bir sayfa, önbellek temizlenene kadar eski HTML’i sunmaya devam eder; geçen ay taranmış bir arama sonucu da Google yeniden tarayana kadar eski fiyatı göstermeye devam eder. Her şeyi bir kez temizleyin, sonra etkilenen adresler için yeniden dizine alma isteyin.
- Geriye kalanlardan çıkarım yapmak. Sıralama, filtreleme ve çok yönlü arama, sayının kendisi hiç görünmese bile kararlı bir ziyaretçinin gizli fiyatı dar bir aralığa sıkıştırmasına izin verir. Bu ticari olarak önemliyse, sayının sır kaldığını varsaymak yerine o arşivlerdeki fiyat sıralama ve filtreleme denetimlerini kaldırın.
- Kendi yönetim panelinizden aldığınız dışa aktarımlar. CSV dışa aktarımları, faturalar ve personele giden sipariş e-postaları hâlâ gerçek rakamları içerir; içermelidir de.
Bundan sonra ne yapmalı#
Önce yüklemi yazın ve onu functions.php yerine küçük bir site eklentisinde tutun; böylece bir tema güncellemesi fiyatlandırma kurallarınızı da beraberinde götüremez. Fiyat HTML filtresini, satın alınabilirlik filtresini, yapılandırılmış veri filtresini ve REST filtrelerini ekleyin. Sonra varsaymak yerine doğrulayın: gizli ürünlerden birini gizli pencerede açın, kaynağı görüntüleyin ve ham HTML içinde rakamı arayın; /wp-json/wc/store/v1/products?per_page=100 adresine gidip orada da arayın; adresi Google’ın Zengin Sonuç Testi’nden geçirin; bir kategoriyi fiyata göre sıralayıp sıranın size ne söylediğine bakın. Bunun için kullandığımız yöntem ve her yüzeyi ayrı ayrı kontrol etmenin gerekçesi her WooCommerce eklentisini nasıl sızıntı testinden geçirdiğimiz yazısında anlatılıyor.
Bu kontrol listesi temiz dönerse işiniz bitmiştir ve kod tamamen sizindir. İşin dağıldığı yer Store API ve şema katmanlarıysa (blok temalarda alışılmış sonuç budur) PriceVeil’in belgeleri eklentinin nasıl yapılandırıldığını anlatıyor, ayarlar ekranı hem otomatik olarak korunanı hem de hâlâ kendinizin kontrol etmesi gerekeni tek tek adlandıran bir kapsam raporu basıyor ve wp priceveil selftest komutu her ürünü dolaşarak fiyat HTML’inin, yapılandırılmış verinin ve Store API yanıtının boş olduğunu doğruluyor, herhangi bir sızıntıda sıfırdan farklı bir çıkış koduyla sonlanıyor. Her hâlükârda, belirli bir kategoride fiyat gizleme kuralını yapıştırılıp unutulacak bir kod parçacığı olarak değil, katalog genelinde test edilmesi gereken bir değişmez olarak ele alın.
