19

Hopefully this is a simple question but I couldn't find a clear answer anywhere - I just want to be able to pull in data from a specific entry, where I know the identifier.

In this particular case, the entry is a single. Currently I'm doing this:

{% set entry = craft.entries.section('myChosenSection').first() %}

Is this correct, or is there a more concise way?

Victor
  • 8,376
  • 1
  • 34
  • 61
pumkincreative
  • 761
  • 2
  • 7
  • 15

3 Answers3

39

This is the correct way.

Examples:

Singles:

{% set entry = craft.entries.section('section_handle').one() %}

Channels / Structures:

{% set entry = craft.entries.section('section_handle').slug('my_slug').one() %}

General:

{% set entry = craft.entries.id(5).one() %}

See craft.entries for a list of all properties.

Victor
  • 8,376
  • 1
  • 34
  • 61
  • I would use {% set entry = craft.entries.section('myChosenSection').first() %} to get the first entry in a Channel or Sructure, and {% set entry = craft.entries.section('myChosenSection').find() %} to get the Single. – Andrea DeMers Jul 08 '14 at 13:12
  • Thanks Victor, it too seemed to me counter intuitive to have to use .first() in a single, however it seems if I remove it then the request returns nothing, as does using .find() - have I got something wrong in setup? – pumkincreative Jul 08 '14 at 14:49
  • 3
    Actually first() would still be necessary here. If you want to get an array of multiple entries back, it’s find() that’s not necessary, since find() is the default behavior. – Brandon Kelly Jul 08 '14 at 14:54
  • So for Single:{% set entry = craft.entries.section('myChosenSection').first() %}, and for Channel/Structure array: {% set entry = craft.entries.section('myChosenSection').find() %} or {% set entry = craft.entries.section('myChosenSection') %}, and first item in Channel/Structure array: {% set entry = craft.entries.section('myChosenSection').first() %}? – Andrea DeMers Jul 08 '14 at 15:21
  • @BrandonKelly Is there a reason .first() is necessary? Since there is only one entry which matches the criteria. – Victor Jul 08 '14 at 17:01
  • 4
    @VictorIn craft.entries doesn’t care whether it’s a Single or a Channel or a Structure. It’s only responsible for taking some parameters, passing them off to the ElementsService, and then either returning an array of all the results (find()) or just the first result (first()). You can technically use find() with a Single section if you want; you’ll just get an array back of that one entry. – Brandon Kelly Jul 08 '14 at 19:21
  • I believe using .slug() also requires .first() otherwise I can't seem to access any properties. ie .slug('my_slug').first(); – Alexander Holsgrove May 18 '17 at 08:26
4

I realize this question was geared towards getting the entry via twig. Here is how you could accomplish the same from a plugin. In my case, I wanted to find an entry via slug.

MyPluginController.php

public function actionMyAction() {
    $criteria = craft()->elements->getCriteria(ElementType::Entry);
    $criteria->section = 'mySectionHandle';
    $criteria->slug = $this->_getLastSegment(craft()->request->getUrlReferrer());
    ...

    $entries = $criteria->find();

    if ($entries) {
        foreach ($criteria as $entry) {
            error_log($entry->title);
        }
    } else {
        // No entry found that matches criteria.
    }
}

private function _getLastSegment($url)
{
    $path = parse_url($url, PHP_URL_PATH);
    $trimmed = trim($path, '/');
    $tokens = explode('/', $trimmed);

    return end($tokens);
}
Damon
  • 4,706
  • 1
  • 20
  • 36
1

An alternate way would be to use Twig's |filter() to do the filtering rather than Craft itself.

I can't say how much of a performance difference it makes, but I know that if you're doing very large queries many times, without adequate caching, it could slow your site down if you're constantly making multiple entry queries.

It also allows a bit more flexibility if you're trying to do something non-standard or need a function callback. For example, I wanted to create an array of IDs in Twig and then choose the first entry that matched it, and |filter() worked well in that situation.

{% set featured = [18, 56, 105] %}
{% set entries = craft.entries.section('myChosenSection').all() %}
{% set chosenEntry = entries|filter((entry) => entry.id in featured)|first %}