WooCommerce en çok satanlar sayfası: total_sales tuzağı
WooCommerce'in popülerlik sıralaması, ürün yayımlandığı günden beri biriken total_sales sayacını okur; iadeler onu azaltmaz. En çok satanlar sayfasını kurmanın üç yolunu, kayan pencere sorgusunu ve stokta yok tuzağını anlatıyoruz.
WooCommerce’te en çok satan ürünler sayfası kurmak kolaydır; şaşırtıcı olan, bu işi yanlış yapmanın da en az o kadar kolay olmasıdır. Sebebi, sıralama yazılarının hiç değinmediği tek bir veritabanı davranışıdır. WooCommerce bir ürünün popüler olup olmadığına total_sales adlı ürün değerini okuyarak karar verir. Bu, ömür boyu çalışan bir sayaçtır. Ürünün yayımlandığı günden beri birikir, hangi ayda olduğunuzu bilmez ve birine iade yaptığınızda azalmaz. 2019’da dört yüz adet satmış bir ürün, bu ayın gerçek kazananının aşağı yukarı kalıcı olarak üstünde durur.
Geri kalan her şey bundan çıkar: sayacın neyi kaydettiği, onu öne çıkarmanın üç dürüst yolu, hangi dönemi kastettiğiniz gibi daha zor bir soru ve en çok satanlar sayfasının neden kimsenin satın alamayacağı ürünlerle dolduğu.
Kısa cevap#
WooCommerce’te en çok satanlar sayfasını üç yoldan kurabilirsiniz: bir arşivi ?orderby=popularity ile sıralayarak, Product Collection bloğunu kullanarak ya da gerçek bir ürün kategorisi oluşturarak. Ne var ki WooCommerce’in yerleşik popülerlik sıralaması total_sales’tir; yani son satışlar değil, ömür boyu çalışan bir sayaç.
- Popülerlik, son dönemi değil ömür boyunu ifade eder. WooCommerce total_sales değerini wc_update_total_sales_counts() ile günceller ve varyasyon satışlarını üst ürüne toplar; iptaller ve silmeler sayıyı düşürür ama iadeler ona dokunmaz, dolayısıyla uzun süredir yayımda olan ürünler daha yeni çok satanları kalıcı olarak geride bırakır.
- Kurmanın üç yolu var. ?orderby=popularity eklemek mevcut bir arşivi sıralar ama size kendine ait bir hedef sayfa vermez; Product Collection bloğu ya da [best_selling_products] kısa kodu kendi URL’si olan gerçek bir sayfa oluşturur ama terim davranışı sunmaz; gerçek bir product_cat terimi ise menüleri, içerik yollarını, sayıları ve katmanlı gezinmeyi getirir, karşılığında sürekli bakım ister.
- Kayan pencereler ömür boyu toplamları yener. 30 günlük bir pencere, insanların en çok satanlar derken kastettiği şeye daha yakındır ve ürünler tükendikçe ya da üretimden kalktıkça kendini düzeltir. Ama bunun sipariş satır kalemlerinden toplanması gerekir; kalemler wc_order_product_lookup analitik tablosunda durur, iadeler de toplamda birbirini götüren negatif satırlar olarak yazılır. Sonuç ayrıca önbelleğe alınmalıdır, örneğin altı saatlik bir transient içinde.
- Stokta olmayanları kaynağında dışarıda bırakın. Yapısı gereği en çok satanlar sayfası, kimsenin satın alamayacağı ürünlerle dolma ihtimali en yüksek sayfadır. Bu yüzden küt bir alet olan global stokta yok görünürlüğü ayarına uzanmak yerine, stokta olmayan ürünleri sıralama kaynağından çıkarın ya da gösterimde en sona itin.
- Bakım iştahınıza göre seçin. Varsayılan popülerlik sıralaması hiçbir bakım gerektirmez; bir blok, bittiğinde dönüp elden geçireceğiniz tek bir kampanya için uygundur; bakımı yapılan bir kategori ise stok koşulları ve bir satış alt sınırı olan kayan pencereler ister. Hangisini seçerseniz seçin, dönemi sayfa açıklamasına yazın.
total_sales aslında neyi sayar#
Sayacı wc_update_total_sales_counts() yönetir; bu fonksiyon includes/wc-order-functions.php dosyasında yer alır. Sipariş durumu geçişlerinde çalışır, satır kalemlerini dolaşır ve her kalemin adedini ürüne ekler ya da üründen çıkarır. İki uygulama ayrıntısı geri kalanlardan daha önemlidir.
Birincisi, yazma işlemini $item->get_product_id() üzerinden yapar; bu da bir varyasyon söz konusu olduğunda üst ürünü döndürür. Varyasyon satışları üst ürüne toplanır, dolayısıyla bu değeri kullanarak varyasyonları birbirine karşı sıralayamazsınız.
İkincisi, sipariş, satışlarının daha önce sayılıp sayılmadığını kaydeden bir bayrak taşır: eski depolamada post meta içindeki _recorded_sales, HPOS altında ise operasyonel veri tablosundaki recorded_sales sütunu. Bayrak siparişin mevcut durumuyla zaten uyuşuyorsa fonksiyon erkenden geri döner; yani durumu kaç kez değişirse değişsin bir sipariş yalnızca bir kez sayılır. Bu, çift sayımı önler. Aynı zamanda kaymanın da açıklamasıdır, çünkü ekleyen olaylarla çıkaran olaylar simetrik değildir.
| Olay | total_sales üzerindeki etkisi |
|---|---|
| Sipariş processing durumuna gelir | Satır adedi kadar artar |
| Sipariş completed durumuna gelir | Satır adedi kadar artar |
| Sipariş on-hold durumuna gelir | Satır adedi kadar artar |
| Sipariş bu üç durumdan birinden cancelled durumuna alınır | Azalır |
| Sipariş çöpe atılır ya da kalıcı olarak silinir | Azalır |
| Sipariş çöpten geri alınır | Yeniden artar |
| Sipariş tamamen ya da kısmen iade edilir | Değişmez |
| Sipariş failed olarak işaretlenir | Değişmez |
O tablodaki iki eksik, işin asıl ilginç kısmıdır. İadeler hiç ele alınmaz. refunded durumuna bağlı bir kanca yoktur; dolayısıyla tamamen iade edilmiş bir sipariş adetlerini ürünün üzerinde kalıcı olarak bırakır, kısmi iade ise sayaç için tamamen görünmezdir. Başarısız siparişler de ele alınmaz; bu tam olarak on-hold durumunun zaten saymış olması yüzünden önemlidir. Hiç ödenmeyen ve sonunda failed olarak işaretlenen bir havale siparişi, adetlerini ürünün üzerinde tutar.
Yaş sorunu ikisinden de büyüktür. Sayacın zaman boyutu yoktur. O bir satış raporu değil, bir onur listesidir. Onu yeniden hesaplayacak ya da sıfırlayacak bir yönetim ekranı yoktur; sayaç bir kez kaydıktan sonra da elinizde doğru değeri yeniden kurabileceğiniz hiçbir kayıt kalmaz. Bir ürünü sıfırlamanız gerekiyorsa bunu kodla, $product->set_total_sales( 0 ); ve ardından $product->save(); ile yaparsınız; ve tahmin yürüttüğünüzü kabul edersiniz.
WooCommerce’te en çok satan ürünler sayfası kurmanın üç dürüst yolu#
1. Zaten elinizde olan bir arşivi sıralayın#
En ucuz seçenek bir sayfa değildir. Herhangi bir ürün arşivine ?orderby=popularity ekleyin, arşiv yerinde yeniden sıralanır; yani hem /shop/?orderby=popularity hem de /product-category/jackets/?orderby=popularity çalışır. Müşteriler aynı şeye, katalog sıralama açılır menüsündeki “Popülerliğe göre sırala” seçeneğinden de ulaşabilir. Bunu mağaza genelinde varsayılan yapmak için Görünüm > Özelleştir > WooCommerce > Ürün Kataloğu altından ayarlayın ya da kodla halledin:
add_filter( 'woocommerce_default_catalog_orderby', function () {
return 'popularity';
} );Bu paneli WooCommerce’in kendisi kaydeder, dolayısıyla temanız ne olursa olsun vardır. Blok tema kullanıyorsanız ve menüde Görünüm > Özelleştir görünmüyorsa, /wp-admin/customize.php adresi paneli yine doğrudan açar.
Bu ucuz bir yoldur ve nedenini bilmek işe yarar. Popülerlik sıralaması bir meta sorgusu değildir. WC_Query, SQL yan tümcelerini filtreleyerek sıralamayı wc_product_meta_lookup.total_sales üzerinde yapar, eşitlik durumunda da ürün kimliğini kullanır. O sütun indeksli değildir, yani veritabanı bir indeks okumak yerine yine sıralama yapar. Ama bunu postmeta tablosunu birleştirip filtreleyerek değil, düz bir tabloda ürün başına tek bir dar satır üzerinde yapar. Normal bir katalogda bütün fark buradan gelir.
Sınırı şudur: sıralanmış bir görünüm bir hedef sayfa değildir. Kendine ait bir başlığı, açıklaması, terimi ve menüde bir yeri yoktur. Arama motorları bir sıralama parametresini genellikle başlı başına bir sayfa değil, arşivin bir varyantı olarak görür; bu da kategori sayfalarının indekslenmemesinin birkaç sebebinden biridir.
2. Bir blok ya da kısa kod yerleştirin#
Güncel yaklaşım, Best Sellers koleksiyonuyla kullanılan Product Collection bloğudur. Bu blok sitede en çok satın alınan ürünleri gösterir; iki ürün aynı sayıda satmışsa daha yakın tarihte yayımlanmış olanı öne alır. Eski, bağımsız “Best Selling Products” bloğu hâlâ çalışıyor ama WooCommerce 9.5 ile yumuşak biçimde kullanımdan kaldırıldı ve blok ekleyiciden gizlendi; bu yüzden onu yalnızca zaten kullanmakta olan sayfalarda görürsünüz. Bir de çekirdekte hâlâ kayıtlı olan klasik kısa kod var:
[best_selling_products limit="12" columns="4"]Üçü de aynı ömür boyu sayacını okur, dolayısıyla yukarıdaki bütün uyarıları devralır. Kazandığınız şey, kendi URL’si ve kendi metni olan gerçek bir sayfadır. Elde edemediğiniz şey ise bir kategoridir: terim yok, terim sayısı yok, içerik yolu yok, arşiv düzeyinde filtreleme yok ve yönetim panelindeki ürün listesinde bir ürünün orada göründüğünü size söyleyen hiçbir şey yok.
3. Gerçek bir kategori kurun#
Üçüncü seçenek, ürünleri Best Sellers adında gerçek bir product_cat terimine koymaktır. O zaman diğer bütün kategoriler gibi davranır, çünkü gerçekten bir kategoridir: menüler ve içerik yolları, terim sayısı, katmanlı gezinme ve onu özel bir işleme gerek kalmadan gören diğer eklentiler.
Bunu elle bir kez yapmak sorun değildir. Mağazayı popülerliğe göre sıralarsınız, yirmi ürünü işaretlersiniz, toplu olarak atarsınız ve iş biter. Sorun ikinci ayda çıkar: liste değişmiştir ve kimse size haber vermemiştir. Bu, kurallara göre ürünleri kategoriye eklemek yazısında ele alınan genel durumdur: üyeliğin, mart ayında verdiğiniz bir karardan değil, bir koşuldan türetilmesi gerekir.
Hangi dönemin en çok satanları?#
Sayfanın ne kadar iş olduğuna karar veren soru budur ve mağazaların çoğu bu soruyu tamamen atlar. Ömür boyu en çok satanlara ulaşmak çok kolaydır ve ürün teşhiri açısından çoğunlukla işe yaramazlar. Geri dönen bir müşteriye, kendisi gelmeden önce neyin popüler olduğunu anlatırlar. Eski ürünleri kayırırlar, çünkü eski ürünlerin daha çok zamanı olmuştur; kayırmayı da sürdürürler, çünkü hâlâ bir miktar satan her ürün için sayaç tek yönde hareket eder. Beş yıllık bir ürünün, kırk adet satan yeni bir ürünün önünde kalması için ayda tek adet satması yeter.
Bir ürün teşhircisinin en çok satanlar derken kastettiği şey neredeyse her zaman kayan bir penceredir: son 30 günde ne satmış. Bu; bir sezonu, bir kampanyayı ya da hareketlenmeye başlamış bir ürünü yansıtır ve kendini düzeltir, çünkü üretimden kalkmış bir ürün grubu ömür boyu sıralamada sonsuza kadar duracakken kayan bir pencereden kendiliğinden düşer. Aynı mantık süresi dolan bir yeni gelenler kategorisi için de geçerlidir: bir pencereyle tanımlanmış sayfa, kimse bakımını yapmadan dürüst kalır.
Kayan pencere neden çok daha ağır bir sorgudur#
Ömür boyu satışlar ürün başına tek bir sayıdır ve zaten okuyacağınız bir satırın üzerinde durur. 30 günlük bir pencere böyle çalışamaz, çünkü bilgi ürünün üzerinde hiç yoktur. Her birinin kendi tarihi olan sipariş satır kalemlerine dağılmıştır ve toplanması gerekir.
Bunu klasik sipariş kalemleri ve kalem meta tabloları üzerinde yapmak gerçekten yavaştır. Neyse ki WooCommerce Analytics tam bu biçimdeki sorular için bir tablo zaten tutuyor: wc_order_product_lookup. Bu tabloda sipariş satırı başına bir satır bulunur ve satır product_id, variation_id, date_created, product_qty ve product_net_revenue alanlarını taşır; ayrıca date_created üzerinde bir indeks vardır. İadeler aynı tabloya, iadenin oluşturulduğu tarihle negatif satırlar olarak yazılır; dolayısıyla bir pencere üzerinden toplam aldığınızda birbirlerini götürürler. Bu, total_sales davranışının tam tersidir ve Analytics ile popülerlik sıralamasının neden birbirini tutmadığını açıklar.
Tablonun yapmadığı şey, kendini filtrelemektir. auto-draft olmayan her sipariş satır alır; pending, cancelled ve failed olanlar dahil. Analytics durum hariç tutmalarını sorgu anında wc_order_stats tablosunu birleştirerek uygular; arama tablosunu doğrudan sorgulamak da aynısını yapmak demektir:
SELECT l.product_id, SUM( l.product_qty ) AS units
FROM wp_wc_order_product_lookup l
INNER JOIN wp_wc_order_stats s ON s.order_id = l.order_id
WHERE l.date_created >= DATE_SUB( NOW(), INTERVAL 30 DAY )
AND s.status NOT IN ( 'wc-pending', 'wc-failed', 'wc-cancelled', 'wc-auto-draft', 'wc-trash' )
GROUP BY l.product_id
HAVING units > 0
ORDER BY units DESC
LIMIT 20;Durumlar orada wc- önekiyle saklanır ve iade satırları üst siparişin durumunu devralır; iade edilmiş bir siparişin negatif satırlarının bu filtreden geçip işini görmesinin sebebi budur. Sonucu önbelleğe alın. En çok satanların gerçek zamanlı hesaplanmasına kimsenin ihtiyacı yok, üstelik maliyet katalog büyüklüğüyle değil sipariş hacmiyle birlikte artıyor:
function my_best_sellers_30d( $limit = 12 ) {
$ids = get_transient( 'my_best_sellers_30d' );
if ( is_array( $ids ) ) {
return $ids;
}
global $wpdb;
$ids = $wpdb->get_col(
$wpdb->prepare(
"SELECT l.product_id
FROM {$wpdb->prefix}wc_order_product_lookup l
INNER JOIN {$wpdb->prefix}wc_order_stats s ON s.order_id = l.order_id
WHERE l.date_created >= DATE_SUB( NOW(), INTERVAL 30 DAY )
AND s.status NOT IN ( 'wc-pending', 'wc-failed', 'wc-cancelled', 'wc-auto-draft', 'wc-trash' )
GROUP BY l.product_id
HAVING SUM( l.product_qty ) > 0
ORDER BY SUM( l.product_qty ) DESC
LIMIT %d",
$limit
)
);
set_transient( 'my_best_sellers_30d', $ids, 6 * HOUR_IN_SECONDS );
return $ids;
}Görüntülemek için kimlikleri wc_get_products() fonksiyonuna geçirin; bu fonksiyon orderby => 'include' ifadesini post__in parametresine eşler, böylece sıralama çıktıya taşınır. Boş durumu koruma altına alın, çünkü boş bir include yok sayılır ve karşınıza bütün katalog çıkar:
$ids = my_best_sellers_30d( 12 );
$products = $ids ? wc_get_products(
array(
'include' => $ids,
'orderby' => 'include',
'limit' => 12,
'status' => 'publish',
)
) : array();Bunlardan herhangi birine güvenmeden önce dört uyarı:
- Tablo Analytics’e bağlıdır. Tabloyu WooCommerce Analytics doldurur. Geçmiş veri içe aktarımı hiç çalışmadıysa eski siparişler eksiktir. İçe aktarma kontrolü Analytics > Ayarlar altındadır.
- Hariç tuttuklarınız raporlarla aynı olmalı. Analytics > Ayarlar > Hariç tutulan durumlar varsayılan olarak pending, cancelled ve failed durumlarını hariç tutar; processing, on-hold ve completed durumlarını sayar; refunded ise hiç hariç tutulamaz. Oradan değiştirirseniz, siz kendi SQL’inizi de değiştirene kadar ikisi sessizce birbirini tutmaz.
- Siz istemedikçe varyasyonlar üste toplanır.
product_idüst üründür; varyasyon bazında sıralama istiyorsanızvariation_idüzerinden gruplayın. Ömür boyu sayacı bunu size hiçbir şekilde veremez. - Her iade adet sayısını değiştirmez. Adet iade etmeden tutar iade etmek, negatif gelir ve sıfır adet yazar; dolayısıyla adetler olduğu yerde kalır. Sıralamayı adede göre yapıyorsanız gelir raporlarınızla küçük uyuşmazlıklar bekleyin.
Bir sayfa kurmak yerine sayılara sadece bakmanız yetiyorsa burada durun: 30 günlük aralıkla Analytics > Ürünler, ürün başına satılan adet ile net satışı, iadelere göre düzeltilmiş halde zaten bedava veriyor. Bir teşhir kararı için doğru kaynak budur. Yukarıdaki iş yalnızca sonucu mağaza vitrinine koymak içindir.
Kayan pencereler neden genelde ücretli bir özelliktir#
Bu özelliğin eklenti pazarını da bu açıklar. total_sales okumak, ürünün üzerinde zaten duran tek bir değeri okumaktır; bu yüzden neredeyse her eklenti, blok ve tema ömür boyu en çok satanları bedavaya sunar. Kayan pencere ise yukarıdaki toplama işine ve onu güncel tutacak zamanlanmış bir göreve ihtiyaç duyar; bu, gerçek bir bakım maliyetidir ve pencereli sürümün neredeyse her zaman bir lisansın arkasında durmasının sebebi budur. Bir araç hangi döneme ait olduğunu söylemeden en çok satanlar vaat ediyorsa, ömür boyu olduğunu varsayın.
Stokta yok tuzağı#
En çok satanlar sayfası, yapısı gereği kimsenin satın alamayacağı ürünlerle dolma ihtimali en yüksek sayfadır. Tükenmek, çok satan bir ürünün yaptığı şeydir. Bunu bir de ömür boyu sıralamayla birleştirin; en üst satırında iki yıl önce üretimden kaldırdığınız bir ürün duran bir sayfa elde edersiniz.
Bunun için WooCommerce > Ayarlar > Ürünler > Envanter altında “Stokta yok görünürlüğü” adında global bir ayar var. Bu ayar stokta olmayan ürünleri katalogdan ve aramadan gizler, ama ürün sayfalarına doğrudan URL ile hâlâ ulaşılabilir. Küt bir alettir: her yerde geçerlidir ve kategorileri, sebebini kimsenin hatırlamadığı biçimde boş gösterebilir. Gerçekten mağaza politikanız buysa kullanın, tek bir sayfanın çözümü olarak değil.
Daha iyi çözüm, stoku yalnızca bu sayfanın düzeyinde ve iki yerde ele almaktır. Sıralamada, stokta olmayan ürünleri kaynak listeden çıkarın; çünkü sayfanın amacı satmaktır. Gösterimde ise sonradan stoku tükenen ürünleri kaldırmak yerine en sona itin; bu, sayfayı dolu tutar ve stokta olmayan ürünleri en sonda göstermek yazısında ele alınmıştır. Kayan pencere burada da yardımcı olur: artık var olmadığı için satmayı bırakmış bir ürün, 30 gün içinde kendiliğinden listeden düşer.
Smart Categories bu tabloda nereye oturuyor#
Yukarıdakilerin hepsi hiçbir şey satın almadan çalışır. İstediğiniz şey üçüncü seçenekse, yani üyeliği elle sürdürülen değil türetilen gerçek bir kategoriyse, eklentimizin yaptığı iş tam olarak budur. Hangi yarısının ücretsiz olduğunu net söylemekte fayda var.
Smart Categories for WooCommerce, gerçek bir WooCommerce ürün kategorisine bir kural kümesi bağlar. Eşleşen ürünlere terimin kendisi atanır; böylece yönetim listeleri, terim sayıları, içerik yolları ve menüler normal davranır. En çok satanlar kategorisi için ücretsiz sürüm size bir Toplam satış sayısı alanı verir; bu, yukarıda konuşulan ömür boyu rakamıdır ve aynı dezavantajları taşır. İşe yarar bir ücretsiz kural şudur: Toplam satış sayısı 25’ten büyük ve Stok durumu Stokta. Kural oluşturucu, siz kaydetmeden önce eşleşen ürünleri ve sayılarını gösterir; böylece eşiği tahmin etmek yerine ayarlayabilirsiniz.

Üyelik; bir ürün oluşturulduğunda ya da güncellendiğinde, fiyat veya stok değiştiğinde ve günlük bir taramada yeniden değerlendirilir. Kendi elinizle yaptığınız atamalara dokunulmaz; eklenti yalnızca kendi oluşturduğu üyelikleri kaldırır. Ücretsiz vitrin ayarları da bu sayfanın ihtiyaç duyduğu iki şeyi kapsar: kategoriyi en çok satana göre sıralamak ve stokta olmayan ürünleri en sona itmek.
Kayan pencere alanları, az önce anlatılan sebeple Pro’da duruyor: 7 günde satılan adet, 30 günde satılan adet, 90 günde satılan adet, 30 günlük gelir, satış hızı (adet/gün) ve son satıştan bu yana geçen gün. 30 günde satılan adet 10’dan büyük ve Stok durumu Stokta şeklinde bir kural, çoğu ürün teşhircisinin en baştan beri istediği sayfayı üretir. Pro, tek site için yılda 59 dolar ve 14 günlük para iade süresiyle geliyor; ücretsiz eklenti wordpress.org üzerinde ve içindeki kural motorunda kategori, kural veya ürün sınırı yok.

Ben olsam ne yapardım#
- Sayfa değil, sıralama istiyorsanız. Popülerliği varsayılan katalog sıralaması yapın ve orada durun. Eklenti yok, sayfa yok, bakım yok.
- Tek bir kampanya için sayfa istiyorsanız. Product Collection bloğu, Best Sellers koleksiyonu; ömür boyu olduğunu kabul edin ve kampanya bittiğinde sayfaya geri dönün.
- Doğruluğunu koruyan bir kategori istiyorsanız. Onu stok koşulu ve satış alt sınırı olan kayan bir pencere olarak tanımlayın, sonra bakımını kendisi yapsın. Arama tablosundan kodla kurun ya da bunu zaten yapan bir eklentiyle.
- Hangisini seçerseniz seçin. Dönemi sayfa açıklamasına yazın. “Son 30 günün en çok satanları” cümlesi ileride çıkacak bir tartışmayı önler ve bir teşhir sayfasıyla bir süsleme arasındaki farkı yaratır.
Sayaç bozuk değil. Saymak üzere yazıldığı şeyi tam olarak sayıyor: bir ürünün yayımlanmasından bu yana biriken adetleri. Sadece, biri en çok satanları sorduğunda kastettiği şey o değil; bunu bir kez bildiğinizde kararın geri kalanı kolaylaşıyor.
