5

I am working on a news section. There is a single featured news story so the lightswitch marked with ('1') displays the latest entry as the featured story.

Below this the rest of the entries are displayed so here I then display all other latest entries with the lightswitch marked with ('0') or in this case ('not 1').

My problem is that if two or three entries are all marked as the featured story (or a user creates an entry and marks it as featured then repeats a few days later and doesn't uncheck the previous one) then they will not display in the below section. Is there anyway to only allow one lightswitch to be checked as ('1') at any one time.

Featured entry:

{% for entry in craft.entries.section('news').featured('1').limit(1) %}

All other news entries:

{% for entry in craft.entries.section('news').limit(4).featured('not 1') %}

  • You could just add an entry field to your News page (restricted to one entry) and set it from there? – Jamie Wade Jan 21 '16 at 12:58
6

You'd have to write a custom plugin that added an event listener for the entries.saveEntry event.

Inside the event listener, you could check if the entry being saved has a true value for the featured Lightswitch field, and if so – pull all other entries with a true value for that same field (in the same section), setting their featured attribute to false before re-saving them.

Something like the below would go into your plugin's primary class:

public function init()
{
    parent::init();

    craft()->on('entries.saveEntry', function (Event $event) {

        $entry = $event->params['entry'];

        if ($entry->section->handle !== 'news' || !$entry->featured) {
            return false;
        }

        // Get all entries from the same section with a `true` value for the Lightswitch field
        $entries = craft()->elements->getCriteria(ElementType::Entry, array(
            'section' => 'news',
            'featured' => true,
            'id' => 'not ' . $entry->id,
            'limit' => null,
        ))->findAll();

        // Update all other entries' Lightswitch field value to `false`
        foreach ($entries as $entry) {
            $entry->getContent()->setAttribute('featured', false);
            craft()->entries->saveEntry($entry);
        }

    });

}

If you're new to plugin development in Craft, I'd suggest looking at the Business Logic plugin template or the pluginfactory.io app – also it'd be a good idea to read the official docs on the subject.

If you don't want to write a plugin, you could also solve this by foregoing the featured field for the entries. If you added a featuredNewsStory Entries field to a Global Set instead (and limited the Entries field to 1 entry), you'd make sure that there was only ever one featured news story in the system. The editiorial workflow would suffer, though – publishing a new, featured news story in this manner would mean that the editor would first have to create the story, then pop into the Global Set after saving the entry to actually mark it as "featured".

Anyway, here's how you could pull the featured news story from a global, as well as the other news stories that aren't featured:

{% set featuredNewsStory = yourGlobalSetHandle.featuredNewsStory.first() %}
{% set otherNewsStories = craft.entries.section('news').id(featuredNewsStory ? 'not ' ~ featuredNewsStory.id : null) %}

Of course, there is another possible "workaround" here: continue with your current solution, but add another clause; making sure that the featured news story pulled is the newest one only:

{% set featuredNewsStory = craft.entries.section('news').featured(1).order('postDate desc').limit(1).first() %}
{% set otherNewsStories = craft.entries.section('news').id(featuredNewsStory ? 'not ' ~ featuredNewsStory.id : null) %}

With the above in place, you could just communicate to your client that "if you set more than one entry to be featured, only the newest one will actually display as featured" or the like.

  • Thanks for the detailed reply. I don't think it is worth the time actually creating a plugin to do such a small task but I will look into it. I may explore using some other methods such as adding a radio button to do a similar task – itisconor Jan 21 '16 at 16:14
  • 1
    @itisconor I hear you, though the PHP above is literally 90% of the plugin, though ;) – Mats Mikkel Rummelhoff Jan 21 '16 at 16:21
  • 1
    This answer helped me a lot, thank you very much. I add my 2 cents: I had problems with validation to force the update of all the featured attribute, because it failed the validation of some files fields. I solved limiting the validation to the featured attributed with $entry->getContent()->validate('featured'); – Masiorama Jan 27 '16 at 10:04
4

There's no way of linking the value of lightswitch fields between entries in Craft (or even within the same entry, but then a radio button field type would be more suitable).

You could create a Global to hold the featured story. This would have an entries field, limited to one entry (or however many featured stories you wanted to have). You can limit the entries field to only being able to link to entries from one section if you like.

This gives you a central place to set the featured entries, independent of the individual entries. This setting the featured entry can be done easily without needing to edit multiple entries and to try and remember which entry is currently set to be the featured one.

If you Global was called featuredStories, and the entries filed called selectedEntries, you would get the list of entryIds for the featured entries like this:

{% set featuredEntryIds = featuredStories.selectedEntries.ids() | join(',') %}

which you can use to find the featured entry like this:

{% for entry in craft.entries.section('news').id(featuredEntryIds) %}

and the other news entries like this:

{% for entry in craft.entries.section('news').id('not ' ~ featuredEntryIds) %}
  • Cheers for getting back to me. I think I may explore looking at radio buttons here and work around it that way. For the clients usability I feel that creating a global would be too confusing but again I will test a few options to see what works best. Thanks again – itisconor Jan 21 '16 at 16:18

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.