Jekyll for a portfolio using data, collections, etc - jekyll

I'm using Jekyll to build a portfolio showcasing my design work. I'm getting confused on whether I should use a 'data' file (yml) and loop through content on my templates or use 'collections'.
My content is structured like this:
Homepage:
Featured Item
Client Hero 1
Client Hero 2
Client Hero 3
Client Hero 4
Client Hero 5
All of these link to their respective 'Client' page where i'll have images as jpgs in the same format for all case studies.
I'm confused on how to best use data, collections, etc to build out my site while keeping updating as efficient as possible.
My current solution uses _data/projects.yml where i have defined for 5 clients:
category: Pitch
description: "Lorem Ipsum Dolar Erat"
title: "Client John Smith"
shortname: "john-smith"
publish: false
featured: true
All of this is looped through and featured on the homepage. Now, I can create each post myself and add content manually but i believe there is a better way. How can I use collections and/or multiple individual project data files to best address this?
My idea situation would be defining content in yml or data files for each individual client and having 10 images, numbered 1 to 10 automatically brought in from /client name/ into a client layout.

collection are beta, so, not production ready. Just don't use them as they can break without notice.
data are not creating pages, an if you want to refer to data file from a page/post, you have to loop over to get a match between site.data.client and page.client or post.client. This is an option but you will have datas in page/post and in data files. all over the place.
creating a page/post with front-matter custom vars ensure that you get all datas in same place. And you can easily loop over page/post variables to get things done.
I prefer #3 and in any client/clientName.html I personally do :
---
category: Pitch
description: "Lorem Ipsum Dolar Erat"
title: "Client John Smith"
shortname: "john-smith"
publish: false
featured: true
img:
- img-02.jpg
- img-03.jpg
---
{% include _client.html %}
That's it : all in the same place.
And on the home page you can loop with :
{% for page in site.pages %}
{% if page.category == 'Pitch' and page.featured = 'true' %}
And also loop over page/post.img
The idea is to get all in the same place. But it's really up to you.
Happy Jekyll !

Related

Creating a alert functionality in django wagtail

I am trying to create a alert section for a menu (similar to the menu on this page https://metageeky.github.io/mega-menu/responsive-header.html)
*Each alert should have an effective date (date alert is “posted” live) and resolved date (date alert is “removed” live). Each alert will also have a maximum of one to two sentences of text describing situation.
The number of active/current alerts will appear in parenthesis following the icon and ALERT link text.
The icon and text are Dark Orange. When you hover over the icon and text, an underline appears.
When users click on the link, they are taken to a page that lists all active alerts. At bottom of page, message displays “If you are experiencing an issue, please contact us at....”
If there are no Alerts:
The number of alerts in parenthesis following the icon and link text will not appear.
Both the icon and alert text will be Primary Blue.
When Users click on the link, they are taken to a secondary alerts page that displays a message that says “There are currently no active alerts. If you are experiencing an issue, please contact us at...”
How would i achieve this?
Thank you.
There is a lot to unpack in your question but here is a high level approach.
1. Define your model
Read the Django docs on how to create a Model
Read the Django docs on what types of Fields exist
In your models.py, you will need to create a new model that has all the data you need for your requirements.
from django.db import models
class Alert(models.Model):
title = models.CharField()
description = models.TextField()
date_from = models.DateTimeField()
date_to = models.DateTimeField()
2. Ensure you can edit/manage your model data
Now you need to provide a way for your admin users to access the data model, edit & create items.
Wagtail has a great Snippets feature that allows this to work without too many changes, you will need to add #register_snippet on your model and also define some panels.
from wagtail.admin.edit_handlers import FieldPanel
from wagtail.snippets.models import register_snippet
from django.db import models
#register_snippet
class Alert(models.Model):
#... fields (defined above)
panels = [
FieldPanel('title'),
FieldPanel('description'),
FieldPanel('date_from'),
FieldPanel('date_to'),
]
def __str__(self):
return self.title
3. Prepare a template tag to show the queried data
Now you will need to work out how to query the model in a way that it will return the alerts based on your requirements (current date should be within the date range of the data).
Django has docs on writing queries
The simplest way to get the results of this query into the template will be with a custom Template Tag
An inclusion_tag is a way to have a small template fragment that can be used anywhere with custom data (without having to pass it into each View).
In the example below, you will still need to create the template file current_alerts.html which will contain how you want to render the alerts.
In your template tag template you can also use the page_url tag to provide a link to the alerts_page
# template_tags/custom_tags.py
# remember to create a template_tags/__init__.py file also
from django import template
from .models import Alert
register = template.Library()
#register.inclusion_tag('current_alerts.html')
def show_alerts():
# just returns all alerts, but this query can be refined to suit what you need
current_alerts = alerts.Objects.all()
alerts_page = AlertPage.Objects.all().first() # this assumes there will only ever be one
return {'alerts_page',alerts_page,'current_alerts': current_alerts}
4. Use your template tag & add styling
Now you need to include the tag at the top of the page inside your root/shared template.
{% extends "base.html" %}
{% load custom_tags %}
{% block body_class %}template-blogpage{% endblock %}
​{% show_alerts %}
{% block content %}...{% endblock %}
5. Create a AlertsPage
You will need to create a new Page type to redirect users to within your alerts link.
https://docs.wagtail.io/en/stable/topics/pages.html
This Page can be anywhere in your tree and the Page's view template can also use the same shared template or you can pass the alerts to the view via the template context

How to name twig files by the region they are in?

I am using Drupal with the Commerce Module to build a webshop. I am using the Commerce Cart Block to display a cart icon with the amount of items in the cart, in the navigation bar.
Now I would also like to display the Cart Block on the Cart page, but with a different template than being used in the navigation bar.
I am using the debug mode, which let me see what I could call the file names to use them like I would like to. But above both Cart Blocks it says the same file name, so I can't output two different templates. I tried putting primary_menu-- before the navigation cart block and content-- (the region the cart block is going to be in), but they don't work.
<!-- THEME DEBUG -->
<!-- THEME HOOK: 'commerce_cart_block' -->
<!-- BEGIN OUTPUT from 'themes/custom/verdamigo/templates/commerce-cart-block.html.twig' -->
This is shown above both cart blocks (which are on the same page). So how can I use two different templates for both blocks.
primary_menu--commerce-cart-block.html.twig
is not working.
I would like to be able to edit both the block in the primary_menu and the block in the content-region. But both carts get output with the same template.
In an effort to decouple Blocks from Displays, Drupal 8 renders a block independently of which display it's in and what region/weight it has in that display (see Twig Template naming conventions) :
Region-specific block templates are not available in Drupal 8.
This removes the ability to override block.tpl.php by region, and for hook_preprocess_block() to adjust variables based on it. Instead, core developers recommend to manage block template overrides with CSS or using additional blocks.
But you can still work around this by implementing hook_theme_suggestions_HOOK_alter() :
function SOME_theme_suggestions_block_alter(array &$suggestions, array $variables) {
if (!empty($variables['elements']['#id'])) {
$block_id = $variables['elements']['#id'];
$block = Drupal\block\Entity\Block::load(block_id);
$region = $block->getRegion();
// Allow per-region block templating.
$suggestions[] = 'block__' . $region . '__' . $block_id;
}
return $suggestions;
}
Note : the template name should begin with "block" since you override a block template, so in your case the override file should be named block--primary_menu--commerce-cart-block.html.twig.

Building a HubL template with an array of objects editable by user in page edit

I'm trying to build a Hubl Template which my client can use to add additional podcast episodes to a list in page edit. I'm able to generate the code with a Hubl Template like so:
{% set episodes = [{
id: "1",
date: "9/12/16"
},{
id: "2",
date: "9/12/16"
},{
id: "3"
date: "9/12/16"
},{
id: "4",
date: "9/12/16"
}]%}
{% for episode in episodes %}
<h2 class="podcast-title">Episode {{episode.id}}</h2>
<h4 class="podcast-date">{{episode.date}}</h4>
{% endfor %}
My problem is that I don't want to have my client come into the page template every time to add additional episodes. I want the episodes to be editable by the "page edit" page.
I am able to do this with single images like so:
{% image "hero_image" label='Select a hero image',
src='imageurl', no_wrapper=True,
export_to_template_context=True %}
But I don't know how or if it is possible to do this with an array of objects.
Have you considered creating a separate "blog" in their HubSpot portal specifically for Podcasts? It may be labeled a blog, but it works well for managing any regular-cadence published content.
If that's not an option, I'd recommend using a Flexible Column in your template layout and using a custom module for each podcast.
How do Flexible Columns work
Creating Custom Modules
This way, as your client is editing a page to post a new podcast, he/she can add any module desired to the flexible column -- you'll need to teach how to find+add your Podcast listing module, but it can't be any harder than you were attempting with template code :)

In Pelican, how to create a page dedicated to hosting all the blog articles?

In pelican, by default, blog articles are listed on the index.html file.
What I want instead is that I use a static page as my home page and put all the blog articles on a dedicated "Blog" page.
How can I get this done?
While there are several possible methods for achieving your desired goals, I would start with the following changes to your settings file:
SITEURL = '/blog'
OUTPUT_PATH = 'output/blog'
PAGE_URL = '../{slug}.html'
PAGE_SAVE_AS = '../{slug}.html'
DISPLAY_PAGES_ON_MENU = False
DISPLAY_CATEGORIES_ON_MENU = False
MENUITEMS = [('Home', '/'), ('Blog', '/blog/')]
Put your blog posts in content/ as usual, and then create your home page with the following headers and save as content/pages/home.md:
Title: Home
URL: ../
Save_as: ../index.html
This is the home page.
Caveats:
Dynamic navigation menu generation has been effectively turned off since it doesn't work well with this configuration. Highlighting for the currently-active menu item — a feature you normally get out-of-the-box — will not be present in this configuration and, if desired, must be implemented separately in your theme.
If your theme's base.html template has a link to your site home that depends on SITEURL (e.g., as the notmyidea theme does), you will need to change the link to point to <a href="/"> instead.
Set the following in the pelicanconf
DIRECT_TEMPLATES = ['blog']
PAGINATED_DIRECT_TEMPLATES = ['blog']
1st line will set blog.html for the articles
2nd line will allow pagination of blog.html file
For the index page, create a pages folder in the content directory and create the .md file there and set save_as:index.html this will save the md file as index.html
This is covered in the Pelican FAQ
- "How can I override the generated URL of a specific page or article?"
Basically, in your contents folder, create two subfolders:
/contents/blogs, which will store all your blog entries
/content/pages, which will store your other static pages (including your home page)
In the pages subfolder, create a file (e.g. home.rst) with the option :save_as: index.html, which will make this file your home page. E.g.:
Home
####
:date: 2015-05-22 12:30
:url:
:save_as: index.html
This is my home page
In your pelicanconf.py file, specify the following options:
DISPLAY_PAGES_ON_MENU = False
DISPLAY_CATEGORIES_ON_MENU = True
USE_FOLDER_AS_CATEGORY = True
PATH = 'content'
ARTICLE_PATHS = ['articles',]
PAGE_PATHS = ['pages',]
MENUITEMS = ()
You should now have a home page and a contents bar with a Blogs menu.
If you want to add more menus to the contents bar (for example an About or CV menu), create the corresponding files in your pages folder, and add them to MENUITEMS:
MENUITEMS = (
('About', '/pages/about.html'),
('CV', '/pages/cv.html'),
)
I have an answer similar to the one Justin Mayer gave, except in mine I change blog article urls instead of page urls.
I've been getting the following error when trying to use the answer above, so it might be useful to other people having the same issue
ERROR: Skipping volunteering.rst: file '../volunteering.html' would be written outside output path
ERROR: Skipping presentations.rst: file '../presentations.html' would be written outside output path
Make all article urls to be under 'blog/' url
ARTICLE_URL = "blog/{date:%Y}-{date:%m}-{date:%d}-{slug}.html"
ARTICLE_SAVE_AS = "blog/{date:%Y}-{date:%m}-{date:%d}-{slug}.html"
Put blog index under 'blog/' url
INDEX_SAVE_AS = "blog/index.html"
Add a explicit menu item for blog index
MENUITEMS = [
('home', '/'),
('blog', '/blog'),
]
As your page is now an index page, automatically displaying link to that page in the menu will lead to a broken link, so you will have to set the following option and specify the following flag
DISPLAY_PAGES_ON_MENU = False
For the new index page, add a directive save_as, like Justin Mayer pointed it out. Here how it looks in rst
About
=====
:slug: about
:category: About
:save_as: index.html
This should give you a home page and an index page for articles.
When you want to add more static pages, you will also need to add them in menu items that still contains '/pages' prefix in the url if you want links to the pages appear in a menu. i.e for the volunteering.rst with the following content,
Volunteering
============
:slug: about
:category: About
Your MENUITEMS variable will look like the following
MENUITEMS = [
('home', '/'),
('blog', '/blog'),
('volunteering', '/pages/volunteering'),
]
I tested this answer on pelican 4.2.0.
You can use the following settings to put the index file for example at /blog/index.html.
INDEX_SAVE_AS = 'blog/index.html'
INDEX_URL = 'blog/'
Then you created a home.md page and use "save_as: index.html" directive for the actual home page.

Embedding Templates in the Header File Based On Categories

I am using ExpressionEngine 2.2.1 and am trying to create a conditional that will cause a page to show a specific navigation template based on the page's category. For example, I am creating a public profile for someone who is a part of a competition in London. When someone visits his profile, I would like the page to show, not only his profile, but also a banner with an image of London & navigation that is specific to the London competition. I would like to do this by adding a conditional with categories since we have so many competitors in many different cities. I have created a category titled "London Competitors English" and it has the ID of "56". Once I have created the competitor's profile within EE, I select the category, "London Competitors English," however, when I go to the page, the default navigation template is loading rather than the London template. I created code based on my research and most related example here: http://expressionengine.com/forums/viewthread/185555/. What do I have wrong in my code?:
FILE ONE: (condensed portion of) competitor_profiles_en/index.html where "competitor_profiles_en" is the template:
{exp:channel:entries limit="1" url_title={segment_2} }
{embed="includes/header"}
<div class="xx">
<h2>{competitor_first_name}<br>{competitor_last_name}</h2>
...
</div>
{/exp:channel:entries}
FILE TWO: (condensed portion of) my header.html file :
{if segment_1 == 'home'}
{embed="includes/_nav_landing"}
{if:elseif "{categories}{category_id}{/categories}" == "56"}
{embed="includes/_nav_city_lon_en"}
{if:else}
{embed="includes/_nav_internal"}
{/if}
The problem is that embeds are processed after all other tags, in a completely separate process. So when your includes/header embed runs, it has no categories to speak of, because it's not actually running within a Channel Entries tag.
Unless you need to pass variables to includes/header (which you don't appear to be doing here, but you may have removed that for simplicity), I'd move your includes/header to a snippet instead, so it will be processed inline with your Channel Entries tag.
Derek's answer was spot on, and I would like to elaborate on my method of putting his suggestion into action.
I found information about snippets here http://expressionengine.com/user_guide/templates/globals/snippets.html and watched this tutorial here http://www.youtube.com/watch?v=AEEudo0BrRA&feature=related. I then created a snippet within the control panel (Design > Templates > Snippets) that included all of the code that was in the header file and titled it snippet_header_en. Because ExpressionEngine includes snippets as a part of the template that they are in, EE recognized my conditional including the categories that I created. Here is the revised code:
FILE ONE: (condensed portion of) competitor_profiles_en/index.html where "competitor_profiles_en" is the template:
{exp:channel:entries limit="1" url_title={segment_2} }
{snippet_header_en}
<div class="xx">
<h2>{competitor_first_name}<br>{competitor_last_name}</h2>
...
</div>
{/exp:channel:entries}
FILE TWO: (condensed portion of) my header.html file :
As previously mentioned, I moved this code to the snippet section of the EE control panel.