WooCommerce'te stokta olmayan ürünleri en sona alma
WooCommerce'te stokta olmayan ürünleri en sona alan yerleşik bir ayar yoktur. Çalışan posts_clauses filtresi, yerleşik gizleme ayarının gerçekte neye dokunduğu ve ön siparişlerin neden kendi sırasını hak ettiği aşağıda.
WooCommerce kategori sayfalarında stokta olmayan ürünleri en sona alan bir ayar yoktur. Envanter ayarları size tek bir kol verir, ya gizlersiniz ya gösterirsiniz; katalog sıralama seçenekleri de — varsayılan, popülerlik, ortalama puan, en yeni, fiyat — stok durumunu tamamen yok sayar. Satın alınamayan ürünleri en alta itmek için posts_clauses üzerinde bir filtre gerekir. Çalışan kod aşağıda, yanında da çoğu rehberin atladığı iki konu var: yerleşik gizleme ayarı gerçekte neye dokunuyor ve ön siparişteki ürünlere ne oluyor.
Kısa cevap#
WooCommerce’te stokta olmayan ürünleri en sona almak için yerleşik bir ayar yoktur; çözüm, `wc_product_meta_lookup` tablosuna join edilen ve 20 önceliğinde çalışan bir `posts_clauses` filtresidir. Bu filtre stok durumunu, müşterinin seçtiği sıralamanın önüne koyar.
- Yalnızca geri gelmeyecekse gizleyin. Gizleme, bu yıl dönmeyecek mevsimlik ürünlere ve bir yönlendirmeyle eşleştirilmiş, üretimi durmuş SKU’lara uygundur; bunun dışında ürünleri sayfada tutun, orada URL’lerini, iç bağlantılarını ve stoka gelince haber verme formlarını korurlar.
- Yerleşik ayar işin yarısını yapar. “Hide out of stock items from the catalog” seçeneğini işaretlemek ürünleri mağaza, kategori, etiket ve nitelik arşivlerinden, ilgili ürünlerden ve varyasyon açılır listelerinden kaldırır; site aramasından, kendi URL’lerinden, XML site haritasından ve kategori sayaçlarından kaldırmaz.
- Sıralamayı arama tablosu üzerinden yapın. Kodu ayakta tutan üç ayrıntı var: WooCommerce’in kendi geri çağrıları sıralamanızı ezmesin diye 20 önceliği, yinelenen tablo takma adına karşı bir `strstr()` join koruması ve stok sırasını başa eklemek — böylece müşterinin seçtiği sıralama her stok grubunun içinde geçerli kalır.
- Ön siparişlere kendi sıralarını verin. WooCommerce `onbackorder` durumunu stokta sayar; bu yüzden o ürünler gizli görünürlük terimini hiçbir zaman almaz ve gizleme ayarı onlara dokunmaz. `CASE` ifadesinin ön siparişleri stokta olmayanlarla birlikte değil, ayrı bir sırada değerlendirmesinin nedeni budur.
- Filesort maliyeti sınırlıdır. Sütunu bir `CASE` ifadesinin içine almak indeksini kullanılamaz hale getirir ve filesort’u zorunlu kılar; ama WooCommerce kategori arşivleri zaten `menu_order` ve `post_title` üzerinde filesort yapıyor. Yani bu, yeni bir işlem eklemez, var olan işlemi genişletir.
Önce karar verin: gizlemek mi, en sona almak mı?#
Bunlar farklı maliyetleri olan iki farklı karardır ve sık duyulan “gizlemek SEO için kötüdür” tavsiyesi mekanizmayı tam olarak doğru anlatmaz.
Hide out of stock items from the catalog seçeneğini işaretlemek hiçbir şeyi yayından kaldırmaz. Ürün publish durumunu korur, URL’si çalışmaya devam eder, XML site haritanızda kalır ve dizine eklenebilir olmayı sürdürür. Kaybettiği şey, kendi kataloğunuzdan gelen bütün iç bağlantılardır. Kategori sayfaları, mağaza sayfası, nitelik arşivleri: ürün hepsinden kaybolur, ona ulaşan tek yol Google, dışarıdan bir bağlantı ya da bir yer imi olarak kalır. Aylar içinde iç bağlantısı olmayan sayfalar daha seyrek taranır ve daha az iç sıralama ağırlığı taşır. Bu ani bir düşüş değil, yavaş bir aşınmadır.
Asıl keskin maliyet müşteri tarafındadır. Geçen sezon sizden alışveriş etmiş biri ürünü arar, hiçbir şey bulamaz ve o ürünü artık satmadığınız sonucuna varır. Geçmişinden ürün sayfasına gelen bir ziyaretçi “Out of stock” yazısını görür, breadcrumb üzerinden kategoriye döner ve az önce baktığı ürünü bulamaz. İkisi de önlenebilir.
Stokta olmayan ürünleri en sona almak URL’yi çalışır durumda tutar, iç bağlantıyı korur ve insanların hâlâ ulaşabildiği bir sayfaya stoka gelince haber verme formu koymanıza imkân verir. Ayrıca kategori sayfalarını dolu tutar; bir tedarikçi gecikmesi yüzünden kategoride dört ürün kalacaksa bunun önemi büyüktür. Zayıf kategori sayfaları, WooCommerce kategori sayfalarının dizine eklenmemesinin en yaygın nedenlerinden biridir ve bu sayfaları bir stok ayarıyla boşaltmak, o sorunu yaratmanın en hızlı yoludur.
Gizleme üç durumda doğru karardır: bu yıl geri dönmeyecek mevsimlik ürünlerde, ürün sayfasının bir geleceği kalmamış, üretimi durmuş SKU’larda ve soluk renkli kartlarla dolu bir sayfanın terk edilmiş bir mağaza izlenimi verdiği kategorilerde. Üretimi durmuş ürünlerde gizleme işin yalnızca yarısıdır. Geri kalanı, en yakın canlı ürüne ya da üst kategoriye giden bir 301 yönlendirmesidir. WooCommerce yönlendirme oluşturmaz; bu iş SEO eklentinize ya da özel bir yönlendirme eklentisine düşer.
Yerleşik gizleme ayarı gerçekte ne yapar#
Ayar WooCommerce → Settings → Products → Inventory altında, Out of stock visibility başlığında yer alır. Mekanizmayı bilmekte fayda var, çünkü karşılaşacağınız bütün uç durumları o açıklıyor.
WooCommerce, product_visibility adında gizli bir taksonomi tutar. Bir ürün her kaydedildiğinde veri deposu ürünün stok durumunu kontrol eder ve durum tam olarak outofstock ise ürüne bir outofstock terimi atar. Ayar açıkken WC_Query, ürün arşivlerine bu terimi dışlayan bir taksonomi sorgusu ekler:
array(
'taxonomy' => 'product_visibility',
'field' => 'term_taxonomy_id',
'terms' => $product_visibility_not_in,
'operator' => 'NOT IN',
)Bu, ürün arşivi sorgusuna eklenmiş bir taksonomi dışlaması olduğu için yalnızca o sorgunun çalıştığı yerlerde geçerlidir, başka hiçbir yerde değil.
| Nerede | Ayardan etkileniyor mu? |
|---|---|
| Mağaza sayfası, kategori, etiket ve nitelik arşivleri | Evet |
| İlgili ürünler | Evet — ürün veri deposu aynı terimi sorgunun dışlanan terim ID’lerine ekler |
| Varyasyonlu bir üründeki varyasyon açılır listeleri | Evet — get_available_variations() stokta olmayan varyasyonları atlar |
Site araması, ?s=shirt&post_type=product dahil | Hayır — arama yalnızca exclude-from-search terimini dışlar |
| Ürünün kendi URL’si | Hayır — sayfa normal şekilde açılmaya devam eder |
| XML site haritası | Hayır — orası SEO eklentinizin alanı ve o, yazı durumuna bakar |
| Menülerdeki ve bileşenlerdeki kategori ürün sayıları | Hayır — sayılar terim tablosundan gelir ve gizlenen ürünleri de içerir |
Arama satırı çekirdekte gerçek bir eksiktir. WC_Query::pre_get_posts(), sorgu bir ürün yazı türü arşivi ya da bir ürün taksonomi arşivi değilse erkenden geri döner. Arama sonuçları sayfasında bu erken dala girer ve orada yalnızca exclude-from-search terimi dışlanır; dolayısıyla stokta olmayan dışlaması hiç eklenmez ve kutu işaretli olsa bile o ürünler aramada görünmeye devam eder. Durum defalarca bildirildi ve hâlâ böyle çalışıyor; aramanın da filtrelenmesini istiyorsanız dışlamayı kendiniz eklemeniz gerekir.
Destek talebi doğuran ikinci konu sayaç uyuşmazlığıdır. Bir kategori bileşeni “Montlar (54)” derken arşivde dokuz ürün listelenir, çünkü wp_term_taxonomy.count yayımlanmış ürünleri sayar ve stoktan haberi yoktur. Bunun bir ayarı yok. Bu sayılar menünüzde görünüyorsa, tek başına bu bile stokta olmayan ürünleri gizlemek yerine göstermek için yeterli bir gerekçedir. Üstelik bu, üst kategori arşivinin zaten sayacının ima ettiğinden farklı bir küme listelediği üst kategorinin ürünleri göstermemesi davranışıyla birleşerek katlanır.
WooCommerce’te stokta olmayan ürünler en sona nasıl alınır#
WooCommerce 3.6’dan beri wp_wc_product_meta_lookup adında bir arama tablosu var; ürün başına tek bir denormalize satır tutuyor: fiyat aralığı, toplam satış, puan, stok miktarı ve stock_status. WooCommerce’in kendi fiyat, popülerlik ve puan sıralamaları da bu tabloya join yapar ve stock_status sütununun kendi indeksi vardır. postmeta yerine bu tabloyu kullanın.
Şunu küçük bir site eklentisine ya da alt temanızın functions.php dosyasına koyun:
add_filter( 'posts_clauses', 'el_in_stock_products_first', 20, 2 );
function el_in_stock_products_first( $clauses, $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return $clauses;
}
if ( ! is_shop() && ! is_product_taxonomy() ) {
return $clauses;
}
global $wpdb;
// WooCommerce may have joined the lookup table already, for price or
// popularity sorting. Joining it twice is a duplicate-alias SQL error.
if ( ! strstr( $clauses['join'], 'wc_product_meta_lookup' ) ) {
$clauses['join'] .= " LEFT JOIN {$wpdb->wc_product_meta_lookup} wc_product_meta_lookup
ON {$wpdb->posts}.ID = wc_product_meta_lookup.product_id ";
}
$stock_rank = "CASE wc_product_meta_lookup.stock_status
WHEN 'instock' THEN 0
WHEN 'onbackorder' THEN 1
ELSE 2
END ASC";
// Prepend, so the shopper's chosen sort still applies within each group.
$clauses['orderby'] = '' !== trim( $clauses['orderby'] )
? $stock_rank . ', ' . $clauses['orderby']
: $stock_rank;
return $clauses;
}Buradaki üç ayrıntı taşıyıcı niteliktedir.
- Öncelik 20. WooCommerce kendi
posts_clausesgeri çağrılarını varsayılan öncelik olan 10 ile kaydeder ve bu geri çağrılarorderbydizesinin sonuna eklemek yerine dizenin tamamını değiştirir. 10 ile çalıştırırsanız “Sort by price” seçen bir müşteri stok sıralamanızı siler. 20 ile çalıştırırsanız WooCommerce ne karar verdiyse onun başına eklersiniz. - Join koruması. Çekirdek de tam olarak bu
strstrkontrolünü kendiappend_product_sorting_table_join()yardımcısında kullanır. Bunu atlarsanız ziyaretçinin fiyata göre sıraladığı her sayfa yinelenen takma ad SQL hatası verir. - Başa eklemek, değiştirmek değil. Stok birincil anahtar olur, geri kalan her şey eşitlik bozucuya dönüşür. Stoktaki ürünler yine fiyata,
menu_orderalanına ya da çok satanlar sayfasındaki toplam satışa göre sıralanır. Stokta olmayanlar da aynısını yapar, sadece sayfanın alt kısmında.
Dikkat edilmesi gereken bir davranış var. Join bir LEFT JOIN olduğu için arama tablosunda satırı bulunmayan bir ürün NULL değerini stock_status olarak alır, ELSE dalına düşer ve gerçek stoku ne olursa olsun en dibe iner. Arama tablosu güncelliğini yitirmişse — genelde suçlu içe aktarmalar ve doğrudan SQL güncellemeleridir — bu, stoktaki ürünlerin nedensiz yere en sona düşmesi olarak görünür. Tabloyu WooCommerce → Status → Tools altındaki Regenerate product lookup tables ile yeniden oluşturun. Hatanın diğer yöne düşmesini tercih ediyorsanız CASE ifadesini tersine çevirin, böylece yalnızca bilinen bir outofstock değeri geri plana atılır:
$stock_rank = "CASE wc_product_meta_lookup.stock_status
WHEN 'outofstock' THEN 2
WHEN 'onbackorder' THEN 1
ELSE 0
END ASC";postmeta sürümü ve neden ikinci tercih olduğu#
WooCommerce 3.6’dan eski bir sürümdeyseniz ya da devraldığınız bir sitede arama tablosu güvenilir değilse, aynı fikir _stock_status anahtarı üzerinde, yani postmeta tablosunda da çalışır. Yukarıdaki fonksiyonda join’i ve CASE ifadesini şunlarla değiştirin:
$clauses['join'] .= " LEFT JOIN {$wpdb->postmeta} AS stock_meta
ON {$wpdb->posts}.ID = stock_meta.post_id
AND stock_meta.meta_key = '_stock_status' ";
$stock_rank = "CASE stock_meta.meta_value
WHEN 'instock' THEN 0
WHEN 'onbackorder' THEN 1
ELSE 2
END ASC";Aynı trim() kontrolünü, $stock_rank değerini başa eklerken de koruyun. Boş bir orderby değerinin sonuna ekleme yapmak arkada bir virgül bırakır ve WooCommerce’in kendisinin sıralamadığı her arşivde SQL hatası verir.
Bunun yerine düz bir meta_value ASC sıralaması olarak yazıldığını da göreceksiniz. O sıralama doğru sonucu tasarım gereği değil, tesadüfen üretir: instock, onbackorder öncesinde, o da outofstock öncesinde sıralanır. Özel bir stok durumu kaydeden herhangi bir eklenti bu dizinin herhangi bir yerine düşebilir, dolayısıyla açık CASE daha güvenlidir. Daha da önemlisi, gerçek bir mağazada postmeta milyonlarca satıra ulaşır ve indeksi sizi doğru meta_key değerine götürür, sıralanmış bir değer kümesine değil. Arama tablosunu tercih edin.
Join edilmiş bir sütuna göre sıralamak neden bir performans meselesidir#
Bunu yayına almadan önce katalog büyüklüğü konusunda dürüst olun. stock_status sütunu indekslidir ama indeks burada işe yaramaz. Sütunu bir CASE ifadesinin içine almak onu arama için kullanılamaz hale getirir; üstelik ardından farklı bir tablodan gelen ikinci bir anahtara göre sıralama yaparsınız. MySQL bunu, LIMIT 16 uygulanmadan önce kategoriyle eşleşen her satır üzerinde geçici bir tablo ve bir filesort ile çözer.
Hafifletici gerçek şu: WooCommerce kategori arşivleri zaten filesort yapıyor. Varsayılan katalog sıralaması önce menu_order, sonra post_title üzerindedir ve menu_order da indeksli değildir, yani sorgu zaten geçici bir tablo kuruyordu. Yeni bir sıralama eklemiyor, var olanı genişletiyorsunuz. Bir kategorideki birkaç bin ürüne kadar bu, bir WooCommerce sayfa yüklemesinin yaptığı diğer her şeyin yanında ölçülebilir bile değildir. Eşleşen satır sayısı on binlere ulaştığında sorgunun en yavaş kısmı haline gelir; tahmin yürütmek yerine EXPLAIN çalıştırmanın zamanı da orasıdır.
Oraya gelirseniz iki hafifletme yolu var. Sayfa önbelleği, trafiğin büyük kısmını oluşturan anonim ziyaretçiler için bu maliyeti tümüyle ortadan kaldırır. Ya da sıralamayı zamanlanmış bir görevle önceden hesaplayıp menu_order alanına yazın — bedeli, WooCommerce’in elle ürün sıralaması için kullandığı alandan vazgeçmektir.
Bir de uyumluluk notu. Kod is_main_query() ile korunuyor; klasik temalar için doğru olan budur. Blok tema kullanıyorsanız ve hiçbir şey değişmiyorsa, arşiv büyük olasılıkla bir Product Collection bloğu tarafından oluşturuluyordur; bu blok, sorguyu şablondan devralacak şekilde ayarlanmış olsa bile kendi WP_Query nesnesini kurar. Sorgunun post_type değerinin product olup olmadığını sınayın, is_main_query() kontrolünü değil. Sıradan sayfalardaki kısa kodlar ve ürün blokları da ayrı sorgulardır, onlar da bunu almaz.
Ön siparişler: çoğu rehberin görmezden geldiği üçüncü durum#
Bulacağınız kodların neredeyse tamamı stoku ikili bir değer gibi ele alır. WooCommerce’te üç durum vardır ve üçüncüsü insanları yanıltan bir şekilde davranır.
- instock. Şu anda satın alınabilir.
- outofstock. Satın alınamaz.
- onbackorder. Satın alınabilir, sonra gönderilir. Bu durumu, stok yönetimi açıkken miktar tükendiğinde ve Allow backorders ayarı “Allow, but notify customer” olarak seçildiğinde alırsınız. Ayarı düz “Allow” yaparsanız ürün bunun yerine
instockkalmaya devam eder.
Asıl önemli kısım şu. Gizleme ayarı tam olarak outofstock dizesine bakar ve WC_Product::is_in_stock() “durum outofstock değil” biçiminde tanımlanmıştır. Yani ön siparişteki bir ürün, WooCommerce açısından stoktadır. outofstock görünürlük terimini hiçbir zaman almaz, dolayısıyla gizleme kutusunu işaretlemek ön siparişteki ürünleri gizlemez. Aksini varsayan satıcılar, üçte biri altı hafta sonra gönderilecekken tamamen dolu görünen bir katalogla kalır.
Yukarıdaki CASE ifadesinin üç dallı olmasının nedeni budur. Ön siparişler hâlâ gelir demektir, bu yüzden ölü stokla birlikte en dipte durmamalıdırlar; ama müşterinin perşembe günü eline alabileceği bir üründen de önde gelmemelidirler. Onları ortaya yerleştirin. Ön sipariş tedarik süreleriniz pratikte stokta olmamakla aynı anlama gelecek kadar uzunsa, onlara da THEN 2 verin ve yolunuza devam edin.
Sıralamanın asıl sorun olmadığı durumlar#
Sıralama tek bir sayfanın düzenini düzeltir. Her ürünün satın alınabilir olması gereken, ücretli trafiğe açılan bir iniş sayfasını ya da menüden bağlayabileceğiniz bir “Hemen kargoya hazır” koleksiyonunu size vermez. Bunlar için farklı bir sıralama değil, farklı bir sayfa gerekir: üyeliği stok durumuna göre tanımlanan ve kendi kendine doğru kalan bir sayfa.
Bunun elle yapılan bir sürümü mümkündür ve küçük bir katalogda öyle de yapmalısınız. Kategoriyi oluşturun, Products ekranına gidin, Filter by stock status açılır listesini kullanın, sonuçları işaretleyin ve Edit toplu işlemiyle kategoriyi topluca atayın. Stok sabitken gerçekten de en ucuz cevap budur. Stok her gün hareket etmeye başladığı anda işe yaramaz olur, çünkü üyelik bir anlık görüntüdür ve o görüntü salı gününe kalmadan yanlıştır — aynı ödünleşme, her türlü ürünleri kategorilere toplu atama işlemi için geçerlidir.
Smart Categories for WooCommerce ile yapmak#
Smart Categories for WooCommerce bizim eklentimizdir ve bu işin her iki yarısını da kapsar. Kural kümesini paralel bir taksonomiye değil, gerçek bir product_cat terimine bağlar; böylece ortaya çıkan kategori menülerde, breadcrumb’larda ve terim sayaçlarında diğer WooCommerce kategorileri gibi davranır. Stock status alanının In stock olduğu bir kural, koleksiyonu yalnızca satın alınabilir ürünlerle dolu tutar; kural ürün oluşturma ve güncellemede, fiyat veya stok değişiminde ve günlük bir taramada yeniden değerlendirilir. Gruplar iç içe geçebildiği için Stock status is In stock AND (Category is Montlar OR Category is Paltolar) AND NOT Tag is clearance ifadesi, elle yeniden çalıştırdığınız bir filtre değil, kaydedilmiş tek bir kural kümesidir. Aynı mekanizma, kendi kendini boşaltan bir indirim kategorisini de çalıştırır.

Özellikle sıralama sorunu için, ücretsiz sürümde kategori bazında bir vitrin ayarı var; bu ayar stokta olmayan ürünleri o kategorinin mağaza sayfasında en sona iter ya da orada gizler. Yalnızca akıllı kategorilerde geçerlidir; yani bu koleksiyonları zaten kuruyorsanız doğru araç, tek istediğiniz site genelinde bir sıralamaysa yanlış araçtır — orada yukarıdaki filtre daha az hareketli parça içerir. Eklenti yalnızca kategori ve etiket üyeliğini atar, başka bir şey yapmaz: meta başlık veya açıklama yok, yönlendirme yok, zayıf kategorileri gizleme ayarı yok. Bunlar SEO eklentinizde kalır.
Özet#
Stokta olmayan ürünleri yalnızca geri gelmeyeceklerse gizleyin ve bunu bir yönlendirmeyle eşleştirin. Aksi halde onları sayfada tutun ve posts_clauses üzerinde, wc_product_meta_lookup tablosuna join edilen bir filtreyle en alta sıralayın; müşterinin seçtiği sıralamanın korunması için filtreyi 20 önceliğinde çalıştırın. Ön siparişlere kendi sıralarını verin, çünkü WooCommerce onları stokta sayar ve gizleme ayarı onlara dokunmaz. Sonra da gidip kategori sayaçlarınızı kontrol edin, çünkü her iki durumda da size yalan söylüyorlardı.
