Motivasyon
Oldukça uzun, bir o kadar da gerekliliği tartışılır kod parçasını paylaşmak üzereyim. Baştan söyleyelim, biraz döngüler dönecek if statementlar kontrol edilecek. Bunlara bağlı olarak, eğer blogunuzda çok post varsa build time kötü derecede etkilenecek. Ne kadar etkisi olur, 11 postluk blogta şu an için yorum yapamıyorum. Gerçi, duruma göre sadeleştirmeniz bazı loopları kaldırmanız mümkün. Uzatmayalım, işe koyulalım.
Kodu adım adım açıklamadan önce, algoritmayı özetleyelim.
Durum:
- Birçok koleksiyonumuz var.
Eğer koleksiyon yapısını bilmiyorsanız ve umrunuzda değilse devam edebilirsiniz, konumuzla doğrudan ilgisi yok. Koleyksiyonlar hakkında henüz yazmadım ama okumak isteyenler için:
- Her post’a ait bir ya da daha fazla etiket var. (post.tags dizisi)
- Örneğin, bu post için, post.tags = [jekyll, liquid, pagination, tag-filter]
- Birden fazla post aynı etiketle etikenlemiş olabilir.
- Örneğin bunun gibi 7 post daha var “jekyll” etiketine sahip.
- Herhangi iki postun birden fazla etiketi ortak olabilir.
- Örneğin, hem jekyll, hem liquid etiketlerine sahip 4 ayrı post mevcut.
Jekyll’da “posts” koleksiyonlardan biridir ve “post” o koleksiyondan bir üyeye karşılık gelir. Ancak bu yazıda “post” derken yazılan bir metinden (bir url) bahsediyorum, teknik anlamda herhangir koleksiyonun herhangi bir üyesinden bahsediyorum.
Amaç:
- Tüm postlar arasından (all_posts) mevcut sayfanın etiketlerinden (page.tags) en az birine sahip olan postları elde etmek.
Çözüm
{% assign constant_limit = 4 %}
{% assign count = 0 %}
{% for collection in site.collections %}
{% assign name = collection.label %}
{% assign all_posts = all_posts | concat: site[name] %}
{% endfor %}
{% assign all_posts = all_posts | sort: date | reverse %}
{% for item in all_posts %}
{% if item.url == page.url %}
{% continue %}
{% endif %}
{% if count == constant_limit %}
{% break %}
{% endif %}
{% for tag in page.tags %}
{% if item.tags contains tag %}
<li style="list-style: square"><a href="{{item.url}}">{{item.title}}</a></li>
{% assign count = count | plus: 1%}
{% break %}
{% endif %}
{% endfor %}
{% endfor %}
{% if count < constant_limit %}
{% for item in all_posts %}
{% if item.url == page.url %}
{% continue %}
{% endif %}
<li style="list-style: square"><a href="{{item.url}}">{{item.title}}</a></li>
{% assign count = count | plus: 1%}
{% if count == constant_limit %}
{% break %}
{% endif %}
{% endfor %}
{% endif %}
Tüm kod yukarıdaki gibi, şimdi adım adım açıklayalım buradaki mantığı.
Tüm Koleksiyonları Birleştir
Öncelikle, tüm koleksiyonları bir tek dizide birleştirmeliyiz. Eğer koleksiyon yapısını kullanmıyorsanız, bu adımı geçip all_posts
yazan yerlere site.posts
yazabilir ve kendinize göre aşağıdaki kodu uyarlayabilirsiniz.
{% for collection in site.collections %}
{% assign name = collection.label %}
{% assign all_posts = all_posts | concat: site[name] %}
{% endfor %}
Döngü Mantığı
İç içe iki döngü olacak, all_posts’da herbir post için page.tags’de herbir etiket için. Eğer post etiketi içeriyorsa yazdıracağız.
{% for item in all_posts %}
{% for tag in page.tags %}
{% if item.tags contains tag %}
<li><a href="{{item.url}}">{{item.title}}</a></li>
{% break %}
{% endif %}
{% endfor %}
{% endfor %}
Burada break
olmadığı durumda, herbir ortak etiket için aynı yazıyı tekrar listeleyecektir döngü içinde. break
ile bir kere yazdırdıktan sonra döngüden çıkmak istiyoruz. Böylece tekrara düşmeyeceğiz.
Mevcut Sayfayı Dikkate Al
Mevcut sayfa da kendisiyle ortak etiketlere (tamamen aynı) sahip olduğu için eklenecektir. {% if item.url != page.url %}
koşulunu ekleyerek ya da all_posts döngüsünde aşağıdaki koşuk eklenerek
{% if item.url == page.url %}
{% continue %}
{% endif %}
bu problemi kolayca çözebiliriz.
Bir Limit Olmalı
Yüzlerce postunuz olduğunu düşünün, okuyucuyu bütün arşivinizi tavsiye ederek korkutmak istemezsiniz. Ayrıca break
statementlar ile döngüyü kısaltatabiliriz.
{% if count == constant_limit %}
{% break %}
{% endif %}
Ya Limitin Altında Kalırsak ?
Sonuçta bu da mümkün. Hatta hiç yazmadığınız bir konu hakkında yazıyorsanız o kadar işten sonra çıktı alamamınız da mümkün. Bunun için ben son yazılan postlardan sırasıyla eklemeyi düşündüm. Farklı çözümler de üretilebilir.
Kod kendini açıklar nitelikte. Yukarıdaki gibi, aynı sayfayı eklememek, mevcut sayfayı eklememek ve limiti geçmemek için kontroller yapıyoruz. Çıkabildiğimiz zaman döngüden çıkıyoruz, sonuna kadar gitmiyoruz.
{% if count < constant_limit %}
{% for item in all_posts %}
{% if item.url == page.url %}
{% continue %}
{% endif %}
<li style="list-style: square"><a href="{{item.url}}">{{item.title}}</a></li>
{% assign count = count | plus: 1%}
{% if count == constant_limit %}
{% break %}
{% endif %}
{% endfor %}
{% endif %}
Kesinlikle overkill ama liquid syntaxına biraz daha alışmamı sağladı.