4

Short Question: I'm coming from ExpressionEngine where 'dynamic' would do the trick. However I can't seem to figure out how to do this in Craft.

I want to be able to use one Channel to show content in different places on the site. Can Craft look at a particular URL segment and load the entry?

Longer explanation I have many users who will have their own 'site' on a website. Each 'site' will have four basic pages -welcome -my story -my work -blog

The Blog page will show entries authored by them, but all users will share the same channel.

I have it all working for the main pages. I'm creating a Structure section for each user. I point it to a template (_userTemplates/johnDoe) that contains some variables and includes:

{% extends "_layout" %}
{% set author = "12" %}
{% set sectionName = "johnDoe" %}

{% set content %}
{% include "_partials/content" %}
{% endset %}

Layout looks like this:

<!DOCTYPE html>
<html>
{% include "_partials/htmlHead" %}
<body>

{% include "_partials/nav" %}

{{ content }}

{% include "_partials/footer" %}

</body>
</html>

_partials/nav has dynamic navigation. It pulls the variable "sectionName" from the user's template to show their navigation links for their structure pages.

<nav class="desktop {{ type is defined ? type }}" role="navigation">
    <div>
        <ul>
            {% set pages = craft.entries.section(sectionName) %}
            {% nav page in pages %}
            <li>{{ page.getLink() }}</li>
            {% endnav %}
        </ul>
    </div>
</nav>

_partials/content looks like this:

{% if craft.request.getSegment(3) != '' %}
    <section>
        <div class="grid padded full-768">
            {% include "_partials/contentBuilder" %}
        </div>
    </section>
{% elseif craft.request.getSegment(2) == 'blog' %}
    <section>
        <div class="grid padded full-768">  
            {% include "_partials/blogListing" %}
        </div>
    </section>
{% elseif craft.request.getSegment(3) == '' %}
    <section>
        <div class="grid padded full-768">
            {% include "_partials/contentBuilder" %}
        </div>
    </section>
{% endif %}

The template that contains all the content, _partials/contentBuilder, looks like this:

    <header>
        <h1 class="alpha highlighted">{{ entry.title }}</h1>
    </header>
    {% for content in entry.contentEditor %}
        {% if content.type == 'heading' %}
            <h2>{{ content.heading }}</h2>
        {% elseif content.type == 'subheading' %}
            <h3>{{ content.subheading }}</h3>
        {% elseif content.type == 'image' %}
            {% for image in content.imageFile %}
                <img src="{{ image.url }}"/>
            {% endfor %}
        {% elseif content.type == 'text' %}
            {{ content.text }}
        {% elseif content.type == 'blockquote' %}
            <blockquote>{{ content.blockquoteQuote }}</blockquote>
            {% if content.blockquoteCitation %}
            <cite>{{ content.blockquoteCitation }}</cite>
            {% endif %}
        {% elseif content.type == 'video' %}
            {% if content.videoTitle != '' %}
                <h3>{{ content.videoTitle }}</h3>
            {% endif %}
            {{ craft.embedder.embed (content.videoUrl) }}
        {% endif %}
    {% endfor %}
</article>

This works great for the main Structure pages. However when the template route "johndoe/blog/{slug} points to _userTemplates/johnDoe this does not work. I get "Variable "entry" does not exist". I thought that the template route would look for an entry and then know which entry it is? I will try pulling the entry from the URL segment per one of the answers and see how that works. However I thought the route would work.

EDIT - Got it working using this in _partials/content:

{% if craft.request.getSegment(3) != '' %}
    <section>
        <div >
            {% for entry in craft.entries.slug(slug).find() %}
                {% include "_partials/contentBuilder" %}
            {% endfor %}
        </div>
    </section>
{% elseif craft.request.getSegment(2) == 'updates' %}
    <section>
        <div>   
            {% include "_partials/updateListing" %}
        </div>
    </section>
{% elseif craft.request.getSegment(3) == '' %}
    <section>
        <div>
            {% include "_partials/contentBuilder" %}
        </div>
</section>
{% endif %}

It looks like I was expecting too much from the template route.

The goal of all this is to be able to give people their own "site", and do it quickly with code that is easy to manage and maintain. This method only requires a new section be created, set up the user with proper permissions, create their template partial, and set up the route. If there is a better way to do this, let me know.

  • Is the URL structure for each user's site something like: www.website.com/johnDoe/blog. That is what I had assumed based on your code above for getSegment(2) == 'blog' that the first URL segment was the username. Let us know if that is the structure or if it is another way as it will help fine tune our answers. Thanks! – Alan Miller Mar 26 '15 at 12:08
  • Yes, the URL structure is www.website.com/johndoe/blog. I've updated the question with my latest code and the error I'm getting. – Doug Mar 26 '15 at 15:53
  • Yeah I am not sure why Craft doesn't return the entry model automatically with routes but my guess would be because you may want to do any number of things with the token data. Have you considered trying to automate any of this process with a plugin? That is beyond my skill set but according the documentation a plug-in can create dedicated url's that will preload entry or category variables. buildwithcraft.com/docs/routing – Alan Miller Mar 26 '15 at 18:15
  • Plugins are out of reach for me at the moment. We are wanting to get his out the door quickly, then once we get it working for the few who need it I can look into a plugin. – Doug Mar 26 '15 at 20:29
  • 1
    Now that it is all working, this is much easier to maintain and edit in Craft. In ExpressionEngine I ran into parse order issues often. I was using Stash, Zoo Visitor, Channel Images, and some other plugins for functionality. Between the somewhat unconventional approach and the third party plugins, it was very finicky to work on. Once I got this sorted out, migrating the system over from EE only took a few hours. It is so much cleaner in Craft. Everything I was using those third party plugins for is baked into Craft. – Doug Mar 26 '15 at 20:40
8

You can retrieve the entry by grabbing it from the URL as a variable:

{% set entrySlug = craft.request.lastSegment %}

And then using craft.entries to find the matching content:

{% set entry = craft.entries.slug(entrySlug).find() %}

Alternatively when you set up your route, so that Craft knows which template to load when someone is requesting your entry, you can use the "slug" token which will expose a slug var in your template automatically.

{% set entry = craft.entries.slug(slug).find() %}

Let me know if I understood the question correctly and my apologies for saying anything you already knew!

6

Alan describes how to setup a route via the Settings->Routes area in the CP. If you happen to be managing file based routes you can setup a similar route like so:

return array(

    // Your Custom Section 
    'username/blog/(?P<slug>.*)' =>
    'blog/_entry'

);

The third segment in your route (?P<slug>.*) creates the variable that will be accessible in your template on that page. You can name the dynamic route variable whatever you would like (for example, (?P<anythingYouWantHere>.*)).

When your blog/_entry template gets loaded. That slug variable will be available just like any other global variable. You can access it using the standard output syntax: {{ slug }} or by passing it to your craft.entries tag:

{% set entry = craft.entries.slug(slug).first() %}

{{ entry.title }}

.slug(slug) will limit your query to just return the entry you want and, .first() will make sure you can access that entry without needing to treat it like an array and loop through it.

  • Thanks, I'll be using file based routes. I skimmed through your video on this yesterday. I'll give it a more careful viewing to make sure I understand all this better. – Doug Mar 26 '15 at 20:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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