3

Sorry if there is an answer out there for this, I've read quite a few posts but have got myself confused. I hope you can point me in the right direction.

I have this code in my EE template:

{exp:switchee variable="{segment_2}" parse="inward"}
{case value="''"}
{exp:channel:entries channel="portfolio" dynamic="no" status="open" disable="pagination|member_data" orderby="date" sort="desc"}
<div class="col-sm-4 col-md-4 col-lg-3"> 

    {cf_portfolio_link}
    {cf_portfolio_image}
    {title}

</div>
{/exp:channel:entries}
{/case}
{case default="yes"}
{exp:channel:entries channel="portfolio" dynamic="no" category="{segment_2_category_id}" status="open" disable="pagination|member_data" orderby="date" sort="desc"}
<div class="col-sm-4 col-md-4 col-lg-3"> 

    {cf_portfolio_link}
    {cf_portfolio_image}
    {title}

</div>
{/exp:channel:entries}
{/case}
{/exp:switchee}

I'd like to do the same in Craft - use one template and filter my entries by segment(2).

At present I have this code in my Craft template (the first case works, the second returns a 404):

{% switch craft.request.getSegment(2) %}
{% case "" %}

{% for item in craft.entries.section('portfolioImages').order('id desc') %}
    <div class="col-sm-4 col-md-4 col-lg-3 work-item"> 
    <a href="{{ item.websiteLink }}" target="_blank" title="View site">
    {% for image in item.image %}
        <img src="{{ image.url() }}" alt="{{ item.alternativeText }}" class="img-responsive center-block" />
    {% endfor %}
    </a>
    <p>{{ item.title }}</p>
    </div>
{% endfor %}

{% default %}

    filtered entries to go here

{% endswitch %}

The URL for my portfolio page is mysite.com/work or mysite.com/work/ecommerce-websites if it has been filtered.

I do have a category group set up in the system called Portfolio with 3 top level categories only:

  • ecommerce-websites
  • promotion-websites
  • product-catalogue-websites

Not sure where to go from here now.

Let me know if you need further information.

Cheers

3 Answers 3

5

/work/ecommerce-websites is giving you a 404 because there is no obvious place to route it. See http://buildwithcraft.com/docs/routing for details on how Craft tries to route each request that comes in.

You have 3 options:

GOOD: Create individual templates for each category

I’m not sure why you would want to do that, but it is an option, so I’m putting it here.

BETTER: Create a dynamic route

You can create a new dynamic route that tells Craft to point URLs that look something like “work/(slug)” to the “work” template, or you might be better off just creating a new “work/_category” template so that you don’t have a single template that is responsible for two entirely different types of pages, which is a little weird. (If there are similarities between the work index and a work category page, you should probably just create a new Work-specific layout template that outputs those things.)

BEST: Make these your primary category URLs

You said you have a category group set up, and the second segment is supposed to match one of them. If this is the primary place that you would expect to find info about these categories on your site, then go into Settings > Categories > [your group] and check the “Categories in this group have their own URLs” checkbox, and fill in the “Category URL Formats” and “Category Template” settings like so:

Craft category group settings

Then, double-click on each of your categories and make sure their Slugs are what you would expect the 2nd segments to be.

Here I’m expecting you’ve decided to create a “work/_category” template as suggested earlier, but if you really want your work index template to be handling these pages you can change the Category Template setting to just plain “work”.

As a bonus with this third approach, you won’t need to fetch your categories manually from the template; a category variable will already be available to the template, so you can go straight to outputting {{ category.title }} or whatever. (See step 4 on http://buildwithcraft.com/docs/routing).

This third technique also applies to sections/entries by the way. I mention that because based on your posted template code ({{ entry.websiteLink }}) it looks like you’re managing entry URLs manually with a custom field, which is really not necessary in Craft. Check the “Entries in this section have their own URLs” checkbox in your section’s settings and Craft will assign a primary URL to all the entries in your section, based on the URL Format you give it.

1
  • Awesome, thanks Brandon!
    – xenowebdev
    Commented Sep 11, 2014 at 9:11
1

After a few more hours of reading and trying, I have now come up with the following solution for displaying a landing page and filtered entries by segment() in the same template: (as a newbie I don't know if this is "best practise", maybe someone could clarify that?)

{% switch craft.request.getSegment(2) %}
{% case "" %}

{% for entry in craft.entries.section('portfolioImages').order('id desc') %}
<div class="col-sm-4 col-md-4 col-lg-3 work-item"> 
    <div class="holder2">
        <div class="portfolio-item2">
            <a href="{{ entry.websiteLink }}" target="_blank" title="View site">
            {% for image in entry.image %}
                    <img src="{{ image.url() }}" alt="{{ entry.alternativeText }}" class="img-responsive center-block" />
            {% endfor %}
            </a>
            <div class="client-name">
                <p>{{ entry.title }}</p>
            </div>
        </div>
    </div>
</div>
{% endfor %}

{% default %}

{% for category in craft.categories.slug(craft.request.getSegment(2)).find() %}
    {% for entry in craft.entries.section('portfolioImages').relatedTo({targetElement: category}).find() %}
        <div class="col-sm-4 col-md-4 col-lg-3 work-item"> 
            <div class="holder2">
                <div class="portfolio-item2">
                    <a href="{{ item.websiteLink }}" target="_blank" title="View site">
                    {% for image in entry.image %}
                            <img src="{{ image.url() }}" alt="{{ entry.alternativeText }}" class="img-responsive center-block" />
                    {% endfor %}
                    </a>
                    <div class="client-name">
                        <p>{{ entry.title }}</p>
                    </div>
                </div>
            </div>
        </div>
    {% endfor %}
{% endfor %}

{% endswitch %}
1

To sum it up, you want a single template to

  • display all "portfolioImages" items if no category is selected (appears in the URL)
  • display only "portfolioImages" items belonging to a category if one category is selected (appears in the URL)

The key is to use categories having their own URLs (in the CP for your category group) and the category variable Craft creates for you automatically if the URL calls for a category page. You can use that variable to specify that you only want entries related to that current category to display.

I wrote a recipe in Craft Cookbook a while back. Have a look at the second version entitled "with native categories".

1
  • No problem. Hope it will help you. The approach is a bit different than with EE but it makes a lot of sense Commented Sep 11, 2014 at 11:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.