Fiyatlandırma ve teklif

WooCommerce'te varyasyonlu ürünlerde fiyat aralığını gizlemek

Varyasyonlu bir ürünün fiyatı üç ayrı kod yolunda üç kez üretilir: ebeveyn aralığı, formdaki varyasyon JSON'u ve Store API. Tek filtre üçünü birden kapatmaz; hangi kancanın hangi yüzeye gittiğini ve sonucu kaynak koduyla tek bir REST çağrısıyla nasıl doğrulayacağınızı anlatıyoruz.

Fiyat HTML’ine bir filtre eklediniz, varyasyonlu bir ürünü yeniden yüklediniz ve aralık kayboldu. Sayfada eskiden $89.00 – $340.00 yazan yerde artık Price on request yazıyor. Sonra biri kaynak kodu açtı ve on bir varyasyon fiyatının tamamının JSON olarak işaretlemede durduğunu gördü; blok tema kullanan mağaza sayfası ise hâlâ 89 ile 340 arasında uzanan bir fiyat kaydırıcısı çiziyordu.

WooCommerce’te fiyat aralığını gizlemeye dair tavsiyelerin çoğu o ilk filtrede durur ve basit bir üründe gerçekten de tek gereken budur. Zor durum varyasyonlu ürünlerdir; çünkü aynı sayı, üç ayrı tüketici için üç ayrı kod yolunda üç ayrı kez üretilir. Bu yazı bunların her birini tek tek geziyor, tam kancayı veriyor ve sonucun sayfanın görüntüsüne güvenerek değil, kaynak kodu ve tek bir kimlik doğrulamasız REST çağrısıyla nasıl doğrulanacağını gösteriyor.

Varyasyonlu bir ürünün fiyatının basıldığı üç yer#

Basit bir ürünün tek fiyatı ve tek işleyicisi vardır. Varyasyonlu bir üründe ise çocuklarını özetleyen bir ebeveyn, fiyat sayfa yenilemeden değişebilsin diye her çocuğu tarayıcıya gönderen bir form ve blok temaların PHP çıktısı yerine okuduğu bir REST temsili bulunur. Bunların her biri farklı kod tarafından yazılır; birini gizlemek diğer ikisine hiçbir şey yapmaz.

1. Ebeveyn price_html aralığı#

WC_Product_Variable::get_price_html(), veri deposundan görünür çocuklar arasındaki en düşük ve en yüksek fiyatı ister, bunları wc_format_price_range() ile biçimlendirir ve elde ettiği dizeyi woocommerce_variable_price_html filtresinden geçirir; aralığın iki ucu da indirimdeyse bu filtrenin adı woocommerce_variable_sale_price_html olur. Bütün bunlar, genel woocommerce_get_price_html çalışmadan önce olup biter. Mağaza döngüsünün, tekil ürün özetinin, ilgili ürünlerin, çapraz satışların ve çoğu bileşenin bastığı değer budur. Sunucuda üretilen HTML’dir ve internetteki her kod parçacığının hedeflediği yüzey de burasıdır.

2. Sepete ekle formundaki satır içi varyasyon JSON’u#

Varyasyon formu oluşturulurken WC_Product_Variable::get_available_variations() görünür her varyasyon için bir dizi kurar, şablon da bunu formun data-product_variations niteliğine basar. Her kayıt display_price, display_regular_price ve tamamen işlenmiş bir price_html dizesi içerir; böylece add-to-cart-variation.js, müşteri bir nitelik seçtiği anda sunucuya gidip gelmeden görünen fiyatı değiştirebilir. Ebeveyn aralığını filtrelemek bu diziye hiç dokunmaz. Dizi tümüyle başka bir metot tarafından üretilir ve sayfa kaynağında düz metin olarak durur.

Bilinmesi gereken bir ayrıntı var. woocommerce_ajax_variation_threshold değerinin (varsayılan 30 varyasyon) üzerine çıkıldığında şablon dizi yerine false basar ve tarayıcı varyasyonları get_variation AJAX uç noktasından teker teker çeker. O uç nokta da her kaydı aynı get_available_variation() çağrısıyla kurar, yani tek filtre iki yolu birden kapsar. Ancak bu yalnızca şablona değil veriye kanca takarsanız geçerlidir.

3. Store API price_range#

Blok temalar ve WooCommerce ürün blokları PHP tarafında üretilen fiyatı hiç okumaz. Bunun yerine /wp-json/wc/store/v1/products/<id> adresini çağırır ve bir prices nesnesi alırlar; varyasyonlu bir üründe bu nesne bir price_range taşır, içinde de alt birim cinsinden min_amount ve max_amount bulunur. Filter by Price bloğu bir adım daha ileri gider ve /wp-json/wc/store/v1/products/collection-data?calculate_price_range=true adresini çağırır; bu da kaydırıcının tutamaçlarını nereye koyacağını bilmesi için sonuç kümesinin tamamındaki en düşük ve en yüksek değeri döndürür.

Store API tasarımı gereği kimlik doğrulaması istemez; ön yüzün, daha kimse giriş yapmadan ona ulaşması gerekir. Bu da onu, tüketici anahtarı isteyen wc/v3 REST API’sinden türce farklı kılar. Tarayıcısı olan herkes bu adrese istek atabilir; dolayısıyla fiyatları görsel olarak gizleyen ama bu rotayı dürüstçe yanıtlayan bir mağaza aslında hiçbir şeyi gizlememiştir. Bu aynı zamanda en sıkı test ettiğimiz yüzeydir ve WooCommerce eklentileri için sızıntı testi sürecimizin ekran görüntüsüyle değil bir REST istemcisiyle başlamasının nedenidir.

Fiyat aralığını gizleyen çoğu WooCommerce kod parçacığı neden erken duruyor#

Alışılmış reçete, woocommerce_get_price_html üzerine takılan tek bir filtredir. Yanlış değil, eksik. Bunu varyasyonlu bir üründe çalıştırdığınızda dürüst sonuç şudur: görünen aralık gitmiştir, varyasyon açılır listeleri normal şekilde dolmaya devam eder ve müşteri Mavi / Büyük seçtiği anda JavaScript fiyat alanına $149.00 yazar. Çünkü o dizeyi, filtrenizin hiç görmediği JSON’dan okumuştur. Blok temada mağaza sayfası hiç değişmeyebilir bile; zira ürün bloğu Store API yanıtından oluşturulur ve PHP filtrenizi tümüyle yok sayar.

Veriyi şablonda gizlemenin sorunu genel olarak budur: şablonlar son adımdır ve modern her WooCommerce ön yüzünün onları atlamanın bir yolu vardır. Aynı akıl yürütme fiyatları müşteri giriş yapana kadar gizlemek için de geçerlidir. Kapı, işaretlemenin değil verinin üzerinde durmalıdır.

Üç yüzeyin üçünü birden filtrelemek#

Bunları functions.php yerine küçük bir site eklentisine koyun; böylece bir tema değişikliği kataloğunuzu sessizce açığa çıkaramaz. Ebeveyn aralığıyla başlayın. 100 önceliği, çoğu temayı geçersiz kılacak kadar geç kalmanızı sağlar.

add_filter( 'woocommerce_variable_price_html', 'shop_hide_variable_range', 100 );
add_filter( 'woocommerce_variable_sale_price_html', 'shop_hide_variable_range', 100 );
add_filter( 'woocommerce_get_price_html', 'shop_hide_variable_range', 100 );

function shop_hide_variable_range( $price_html ) {
	return '<span class="price-on-request">'
		. esc_html__( 'Price on request', 'my-shop' )
		. '</span>';
}

Sıra varyasyon yükünde. Tek filtre hem satır içi JSON’u hem de AJAX uç noktasını halleder; çünkü ikisi de kayıtlarını get_available_variation() üzerinden kurar.

add_filter( 'woocommerce_available_variation', 'shop_hide_variation_prices', 100, 3 );

function shop_hide_variation_prices( $data, $product, $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;
}

display_price alanını boşaltmak, kendi temanızda sınamanız gereken kısımdır. Çekirdeğin varyasyon betiği bu değerden hesap yapmaz, ama paket, kapora ve para birimi değiştirici eklentileri bazen yapar; birkaçı da boş dizede JavaScript hatası fırlatır. Bir şey bozulursa iki anahtarı da 0 yapın ve sepete eklemenin hâlâ çalıştığını kontrol edin.

Son olarak Store API. Orada tek bir fiyat filtresi yok, bu yüzden güvenilir yaklaşım rota işleyicisi çalıştıktan sonra yanıtı yeniden yazmaktır. Aşağıdaki kod yükün tamamını dolaşır, yani tek fonksiyon tekil ürünleri, koleksiyonları, sepeti ve collection-data uç noktasını birden kapsar.

add_filter( 'rest_request_after_callbacks', 'shop_blank_store_api_prices', 100, 3 );

function shop_blank_store_api_prices( $response, $handler, $request ) {
	if ( ! $response instanceof WP_REST_Response ) {
		return $response;
	}
	if ( 0 !== strpos( $request->get_route(), '/wc/store/' ) ) {
		return $response;
	}

	$data = $response->get_data();
	shop_blank_prices_walk( $data );
	$response->set_data( $data );

	return $response;
}

function shop_blank_prices_walk( &$node ) {
	if ( ! is_array( $node ) ) {
		return;
	}

	if ( isset( $node['prices'] ) && is_array( $node['prices'] ) ) {
		foreach ( array( 'price', 'regular_price', 'sale_price' ) as $key ) {
			if ( isset( $node['prices'][ $key ] ) ) {
				$node['prices'][ $key ] = '';
			}
		}
		// The variable-product range lives here.
		if ( isset( $node['prices']['price_range'] ) ) {
			$node['prices']['price_range'] = null;
		}
	}

	if ( isset( $node['price_html'] ) ) {
		$node['price_html'] = esc_html__( 'Price on request', 'my-shop' );
	}

	// /products/collection-data?calculate_price_range=true
	if ( isset( $node['price_range']['min_price'] ) ) {
		$node['price_range'] = null;
	}

	foreach ( $node as &$child ) {
		shop_blank_prices_walk( $child );
	}
	unset( $child );
}

Varyasyon fiyatlarının kendisini sıfırlamayın#

Cazip kısayol, woocommerce_variation_prices_price kancasına takılıp sıfır döndürmektir; 0–0 aralığı zaten aralık sayılmaz diye düşünürsünüz. İki şey ters gider. Birincisi, o kanca WooCommerce’in bir hash ile anahtarlanmış geçici veride önbelleğe aldığı fiyat dizisini besler; değerleri değiştirip woocommerce_get_variation_prices_hash değerini de çeşitlendirmezseniz zehirlenmiş dizi her ziyaretçiye sunulur. Sayıları görmesi gereken, giriş yapmış toptancı müşteri dahil. Geçici veriyi silmek de kurtarmaz; aynı anahtar altında yeniden üretilir. İkincisi, en düşük ve en yüksek yalnızca gösterime ait değerler değildir: get_price_html(), varyasyon formu ve varyasyonlu bir üründen fiyat aralığını isteyen başka her şey aynı diziyi okur. Yani bir sayıyı gizlemiş olmazsınız, onu yanlış bir sayıyla değiştirmiş olursunuz.

Bunun yerine getter’a kanca takmak daha da kötüdür: woocommerce_product_variation_get_price ya da woocommerce_product_get_price. Sepetin, sipariş toplamının ve ödeme geçidinin hesabını yaptığı değer budur; ödeme adımına ulaşan müşteri sıfır öder. Sunumu gizleyin, aritmetiği bırakın. Bir müşterinin fiyatı görmesine izin verilmiyorsa mantıklı sonraki adım genellikle onun sipariş vermesini tümüyle engellemektir; bu da fiyat filtresi değil katalog modudur.

Yapılandırılmış veri basıyorsanız dördüncü yüzey#

WooCommerce ürünler için JSON-LD üretir. En ucuz ve en pahalı çocuğu arasında fark bulunan varyasyonlu bir üründe bu, bir AggregateOffer hâline gelir; içinde lowPrice ve highPrice vardır. Yani aralığınız bir kez daha, bir script etiketinin içinde, düz metin olarak karşınızdadır. woocommerce_structured_data_product ile söküp atın.

add_filter( 'woocommerce_structured_data_product', 'shop_strip_offers', 100 );

function shop_strip_offers( $markup ) {
	unset( $markup['offers'] );
	return $markup;
}

Bu yalnızca çekirdeği kapsar. Rank Math, Yoast, All in One SEO ve bağımsız şema eklentilerinin her biri kendi kancalarıyla kendi ürün grafiğini kurar; bunlardan biri etkinse işiniz bitti varsaymadan önce oluşturulmuş sayfada sayıyı aratın.

Nasıl kontrol edilir: kaynak kodu ve tek bir REST çağrısı#

Sayfaya bakmak hiçbir şeyi kanıtlamaz; çünkü asıl veri bir nitelikte ve bir JSON yanıtındadır. WooCommerce’te fiyat aralığını gizleme işini, şu üç komut boş dönene kadar bitmemiş sayın. Komutları oturumu kapatmış hâlde ve birkaç varyasyonu olan gerçek bir varyasyonlu ürün üzerinde çalıştırın.

# 1. Is the variation payload still in the HTML?
curl -s 'https://example.com/product/steel-shelving/' 
  | grep -o 'data-product_variations="[^"]*"' | head -c 400

# 2. What does the Store API hand an anonymous visitor?
curl -s 'https://example.com/wp-json/wc/store/v1/products/1234' 
  | python -m json.tool | grep -A 8 '"prices"'

# 3. What range does the Filter by Price block receive?
curl -s 'https://example.com/wp-json/wc/store/v1/products/collection-data?calculate_price_range=true'

# In the browser console, on the product page:
# JSON.parse( document.querySelector('form.variations_form').dataset.product_variations )

Çoğu kişiyi yakalayan komut birincisidir. Gerçek sayılar taşıyan display_price alanlarının bulunduğu kaçışlanmış JSON basıyorsa, sayfa nasıl görünürse görünsün o üründeki her varyasyon fiyatı herkese açıktır. Blok temaları yakalayan ise üçüncü komuttur: hâlâ 89 ile 340 arasında uzanan bir kaydırıcı, hiçbir ürün kutusunda fiyat görünmese de ziyaretçiye aralığınızı söylemiştir.

Bunu tek ürün için elle yapmak sorun değil; her tema güncellemesinden sonra dört yüz ürün için yapmak sorun. PriceVeil bu yüzden kontrolleri WP-CLI komutu olarak sunar. wp priceveil selftest her ürünü dolaşır ve fiyat HTML’inin, yapılandırılmış verinin, Store API ürün yanıtının ve koleksiyon fiyat aralığının tamamının boş olduğunu doğrular, herhangi bir sızıntıda sıfırdan farklı bir kodla çıkar; wp priceveil scan ise yüzey başına açığa çıkan bilgiyi, CI’da fark alabileceğiniz JSON olarak raporlar.

Yüzey yüzey#

YüzeyKim okurKancaAtlarsanız
Ebeveyn aralığı HTML’iMağaza döngüsü, ürün sayfası, bileşenlerwoocommerce_variable_price_htmlAralık metin olarak basılır
Satır içi varyasyon JSON’uadd-to-cart-variation.jswoocommerce_available_variationHer varyasyon fiyatı kaynak kodunda görünür
get_variation AJAXAynı betik, 30 varyasyonun üzerindewoocommerce_available_variationFiyatlar istek istek gelir
Store API ürün fiyatlarıBlok temalar, ürün blokları, headlessrest_request_after_callbacksprice_range herkese açık ve kimlik doğrulamasız
Koleksiyon fiyat aralığıFilter by Price bloğurest_request_after_callbacksKaydırıcı en düşük ve en yükseği göstermeye devam eder
JSON-LD teklifleriArama motorları, SEO eklentileriwoocommerce_structured_data_productKaynakta lowPrice ve highPrice

Bunun çözmedikleri#

Sınırlar konusunda açık olmak, kod parçacığı saymaktan daha önemlidir.

  • Sıralama hâlâ sırayı sızdırır. wc_product_meta_lookup tablosu her ürün için min_price ve max_price tutar; fiyata göre sıralama sizin filtrelerinizi değil bu tabloyu okur. Fiyata göre sıralayın, katalog kendini en ucuzdan başlayarak dizer. Bu da ekranda hiç sayı olmasa bile rakibinize fiyatlandırmanızın göreli biçimini söyler. Önemliyse fiyat sıralama seçeneklerini kaldırın.
  • Getter’ı doğrudan çağıran tema ve özel kod. $product->get_price() ya da get_variation_prices() çağırıp sonucu ekrana basan bir şablon, yukarıdaki bütün gösterim filtrelerini atlar. Bunu tema dışından hiçbir şey düzeltemez.
  • Ürün akışları. CTX Feed, Google Product Feed ve satıcı entegrasyonları sizin filtrelerinizi değil veritabanını okur ve aralığın tamamını gönül rahatlığıyla yayımlar. Bunları bilerek kapatın.
  • Değişiklikten önce önbelleğe alınmış sayfalar. Tam sayfa önbellekleri ve CDN uçları, bir kez temizlenene kadar eski HTML’i sunmayı sürdürür.
  • Satın alma. Sayıyı gizlemek Sepete Ekle düğmesini kaldırmaz; müşteri yine bir varyasyonu sepete ekleyip fiyatı sepette görebilir. Bunu ayrıca ele alın: ya sepete ekle düğmesini kaldırın ya da yerine bir teklif isteme akışı koyun.

Sırada ne var#

Yukarıdaki filtreleri bir site eklentisine ekleyin, sonra üç kontrolü çok sayıda varyasyonu olan bir varyasyonlu üründe ve iki varyasyonu olan birinde çalıştırın. Üçü de boş dönerse WooCommerce’in kendi ürettiği yüzeyleri kapatmışsınız demektir. Ondan sonra kodun sizin yerinize yanıtlayamayacağı politika sorusuna karar verin: herkesten mi gizlenecek yoksa yalnızca misafirlerden mi, ve ziyaretçi bir sayı görmek yerine ne yapacak.

Kanca listesini Woo sürümleri boyunca elle güncellemeyi tercih etmiyorsanız, aynı kapsam, hedef kitle anahtarı ve CLI kontrolleri PriceVeil belgelerinde anlatılıyor. Özellikle Store API sürümden sürüme yeni alanlar kazanıyor. PriceVeil’in ayarlar ekranı da hem otomatik olarak halledilenleri hem de sizin elle kontrol etmeniz gerekenleri adıyla listeleyen bir kapsam raporu basıyor. Hangi yolu seçerseniz seçin, bir sonraki tema güncellemenizden sonra kaynak kodu kontrolünü yeniden çalıştırın. Bu gerilemeler oradan çıkıyor.

Okumaya devam

İlgili yazılar