Is is possible to allow auto-updates for a plugin? I’ve been developing my first Craft plugin and I think it would be really cool to be able to offer auto-updating for it, is there a way to hook into the update page you would use to update Craft? or is this something that could happen in the future?

I understand you could probably achieve this manually, I’ve seen a couple of plugins do this but then on later updates some remove this functionality, is this not a good idea to try and do? is it worth looking into how Craft does this in the core files and try to tap into that or would that be a big no no…

The way I was thinking of achieving this manually myself is:

Deploy a base version on my own server
Create a service that talks(Guzzle?) to the server to check the users version against the server version
Look into the methods that Craft uses to copy and back up
files and use those methods to update the plugin if needed

Any pointers or info would be appreciated,

Thanks!

You could go through all of that effort, or you could just wait until the plugin store gets finished and any plugin that is listed in the store will get automatic updating for free nicely integrated into Craft's auto-updating functionality. :)


Grouping entries by title in Craft 3 I need to group a set of entries alphabetically and I don't get a working and clean solution.
Taking this documentation entry, I am doing it as follows:

  {% set fromAtoF = craft.entries.section('shops').type('shops').order('title').search('title:a* OR A* OR b* OR B* OR c* OR C* OR d* OR D* OR e* OR E* OR f* OR F*') %}
  {% set fromGtoL = craft.entries.section('shops').type('shops').order('title').search('title:g* OR G* OR h* OR H* OR i* OR I* OR j* OR J* OR k* OR K* OR l* OR L*') %}
  {% set fromMtoR = craft.entries.section('shops').type('shops').order('title').search('title:m* OR M* OR n* OR N* OR o* OR O* OR p* OR P* OR q* OR Q* OR r* OR R*') %}
  {% set fromStoZ = craft.entries.section('shops').type('shops').order('title').search('title:s* OR S* OR t* OR T* OR u* OR U* OR v* OR V* OR w* OR W* OR x* OR X* OR y* OR Y* OR z* OR Z*') %}

Problem 1: I get entries starting by 'A' like 'Amazon' in the fromStoZ group, and 'Walmart' in fromGToL...etc
Problem 2: It's not clean nor elegant. There must be other ways to query this but I haven't found the good one yet.

I also tried:

  {% set fromAtoF = craft.entries.section('shops').type('shops').order('title').search('title:a* OR b* OR title:c* OR title:d* OR title:e* OR title:f*') %}
  {% set fromGtoL = craft.entries.section('shops').type('shops').order('title').search('title:g* OR title:h* OR title:i* OR title:j* OR title:k* OR title:l*') %}
  {% set fromMtoR = craft.entries.section('shops').type('shops').order('title').search('title:m* OR title:n* OR title:o* OR title:p* OR title:q* OR title:r*') %}
  {% set fromStoZ = craft.entries.section('shops').type('shops').order('title').search('title:s* OR title:t* OR title:u* OR title:w* OR title:x* OR title:y* OR title:z*') %}

But neither it works; entries like 'Best Buy' and 'JC Penney' don't get into any group, but 'Best Buy2' goes correctly into fromAtoF

Not exactly sure what you are trying to do with this data, but it sounds like you could use the group filter

{% set alphaEntries = craft.entries.section('shops').type('shops').all() | group('title | slice(0, 1)') %}

{% for letter, entries in alphaEntries %}

{{ letter }}

        {% for entry in entries %}

{{ entry.title }}

        {% endfor %}

{% endfor %}


How can I get contact form added information on the control panel? I'm using the contact form plugin to implement the contact form on the front, now I want to see all the contact information on the control panel, So how can I get that in the control panel?

You can find the Contact Form Extensions plugin in plugin store. It’s free to use.

Install it and then fill the setting form as you need it. After that settings completed you will see the new option “Form Submisson” in your side bar menu in control panel. You will get all filled contact form records in it from now on.


Logging in Every Minute - Craft Admin Sessions (on Heroku) I have Craft installed on Heroku using Memcached for sessions. Craft is kicking me out of the admin area every minute or two. It's deriving me crazy. I've also set the user session duration in general.php:

'userSessionDuration' => 'P2W'

Still kicking me out.

If I set it to dev mode, I get this error:

Undefined variable: _SESSION

I know that the session does work, because I can login. I can also check the currentUser variable and see people signed in. The thing is, it isn't lasting long and makes the admin area nearly unusable.

My composer file is really simple. Nothing complicated.

{
  "require": {
    "ext-mbstring": "*",
    "ext-imagick": "*"
  },
  "require-production": {
    "ext-memcached": "*"
  }
}

EDIT:

Also, here are my Memcached settings in the /public/.user.ini file (as recommended by Heroku):

session.save_handler=memcached
memcached.sess_binary=1
session.save_path="PERSISTENT=myapp_session ${MEMCACHIER_SERVERS}"
memcached.sess_sasl_username=${MEMCACHIER_USERNAME}
memcached.sess_sasl_password=${MEMCACHIER_PASSWORD}

SOLUTION:

For anyone interested, the Memcached extension in my composer.json file wasn't being picked up by Heroku on deploy. So I updated my composer.json file like this:

{
  "require": {
    "ext-mbstring": "*",
    "ext-imagick": "*",
    "ext-memcached": "*"
  }
}

Then ran composer update to update the composer.lock file.

When deploying to Heroku, the composer.lock file is very similar to the Gemfile.lock in Rails - telling Heroku exactly what to install with the deployment. Now the Memcached extension is being installed by Heroku and my session problem has been solved.

My own answer... for anyone interested, the Memcached extension in my composer.json file wasn't being picked up by Heroku on deploy. So I updated my composer.json file like this:

{
  "require": {
    "ext-mbstring": "*",
    "ext-imagick": "*",
    "ext-memcached": "*"
  }
}

Then ran composer update to update the composer.lock file.

When deploying to Heroku, the composer.lock file is very similar to the Gemfile.lock in Rails - telling Heroku exactly what to install with the deployment. Now the Memcached extension is being installed by Heroku and my session problem has been solved.


How to use the native datepicker ui in custom fieldTypes? I would like to impliment the native craft datepicker ui in my custom fieldType. From looking at the native date template (craft/app/templates/_includes/form/date.html) I can see that it inserts javascript using includeJs, which I have followed exactly. Here is my template code:

        <input type="text" autocomplete="off" value="" size="10" id="trial_end" data-stripe="trial_end" class="text hasDatepicker">

{%- set js %}
    var $datePicker = $('#{{ 'trial_end'|namespaceInputId|e('js') }}');
    $datePicker.datepicker({
        constrainInput: false,
        dateFormat: '{{ craft.i18n.datepickerJsFormat }}',
        defaultDate: new Date(),
        prevText:   '{{ "Prev"|t|e('js') }}',
        nextText:   '{{ "Next"|t|e('js') }}',
    });
{%- endset %}
{%- includeJs js %}

I have confirmed that the js output is identical to the other native date fields, and that the namespaced id matches between the js selector and the html input field id. But no datepicker. Is there a piece missing?

Update: Perhaps my question needs some clarification. My field type includes additional 'dummy' fields that will never get stored in the database, but rather are only used to collect information from the user that will be sent via ajax to a 3rd party service, with the result customerId being stored in the database. One of those dummy fields is a date field that I would like to use the native datepicker for. Here is an image:

Yes. That is all one field! that only stores a customerid from a third party service (Stripe), and loads all of the customer account info via ajax. The actual field 'customerID' is never exposed to the client, as it generated automatically.

Here’s what your field type’s getInputHtml() method should look like:

public function getInputHtml($name, $value)
{
    // If $value['trial_end'] is set, make sure that it's a DateTime object
    if (!empty($value['trial_end']))
    {
        $value['trial_end'] = DateTime::createFromString($value['trial_end']);
    }
    else
    {
        $value['trial_end'] = '';
    }

    return craft()->templates->render('myplugin/input', array(
        'id'    => craft()->templates->formatInputId($name),
        'name'  => $name,
        'value' => $value,
    ));
}

Then your plugin’s input.html template would be responsible for showing the Datepicker input.

The easiest way to create a Datepicker input is to either include the _includes/forms/date.html template directly into your template, or use the date() macro from _includes/forms.html.

{% from "_includes/forms" import date %}

{{ date({
    id: id ~ '-trial_end',
    name: name ~ '[trial_end]',
    value: value.trial_end
}) }}

However if you need to tweak the HTML, such as adding that ata-stripe="trial_end" attribute, you can just copy the HTML from the _includes/forms/date.html template directly into yours.

In your case, it’s probably not working because you have that hasDatepicker class on your <input>, which tells the Datepicker JS that a datepicker instance has already been assigned to that input, so the new datepicker initialization is getting skipped. Remove that class and you should be good to go.

When an entry is saved, you will need to convert the user-submitted date value into a DateTime object, which you can do using DateTime::createFromString().

On a normal field type you would want to put that code within prepValueFromPost(), like this:

public function prepValueFromPost($value)
{
    // Convert trial_end to a DateTime object
    $value['trial_end'] = DateTime::createFromString($value['trial_end']);

    return $value;
}

However in your case, if your field type isn’t storing any data and its defineAttributeConfig() method is returning false, a better place to put it would be in onAfterElementSave():

public function onAfterElementSave()
{
    // Get the raw POST value for this field
    $value = $this->element->getContent()->getAttribute($this->model->handle);

    // Convert trial_end to a DateTime object
    $value['trial_end'] = DateTime::createFromString($value['trial_end']);

    // ...
}

If you’re looking for an example third party field type that works with dates, check out our Store Hours plugin. It’s using timepickers rather than datepickers, but those both work exactly the same.


How are the Craft docs created? The Craft documentation on Section Types state that they themselves are created using a Structure. Can someone explain the method they used here?

What I'd really like to see is the Twig code for the left hand navigation. Are there multiple Structures here (to account for the headings) and if not, how are the headings set?

Thanks!

There is a Documentation structured section with three entry types.

Heading Only
Page
Link

The Getting Started, Core Concepts, etc. headers are the Heading Only entry type. The only field is has is a title.

The majority of the docs are using the Page entry type.

The Link entry type is used for the entries like Full Templating Reference and Plugin Development that open into a new window, and those are their own separate structured sections.


Text that is conditional on date I have set up a structure that allows me to display events with some information.  I'd like to know if there's a way that I can set a date that will automatically change certain  it's a text from being future tense to be in present tense during the event and past tense after the event i.e.  I'll be, I am, I was.

Thanks to everyone in advance!

I guess you could do something like this. I'm assuming the events have eventStart and eventEnd date variables, and I'm here comparing the dates with the built in now variable on the format year-month-hour-minute:

{# When eventStart is bigger than "now", the event is in the future #}
{% if event.eventStart|date('YmdHi') > now|date('YmdHi') %}
  I will attend this event!

{# When eventStart is in the past, and eventEnd is in the future, the event is ongoing #}
{% elseif event.eventStart|date('YmdHi') <= now|date('YmdHi') and event.eventEnd|date('YmdHi') > now|date('YmdHi') %}
  I am at this event RIGHT NOW!

{# When none of the above, the event is in the past #}
{% else %}
  I was at this event
{% endif %}

Depending on your use, you could build on this to create a variable for "past/present/future" or similiar. To be even more sure on your validation, the last endif could also specifically test that the endDate is in the past, instead of just being a catch-all else.


Can I set the same relation in a field multiple times? My customer wants a videoplaylist for users.

Idealy I'd like to have a assets relation field for the playlist and relate all the videos in said playlist.

The problem is if a user wants the same video several times in the playlist.
( like in a loop ).

As far as I know it's only possible to relate an entry/asset once in the same relation field.

The solution for me would be to add a matrix-block for each video in the playlist, but since there are thousands of playlists the db grows way more than expected.

Without matrix field: around 30MB
With matrix blocks: around 200MB.

The site slowed down quite a bit and the searchindex table grew to about 80MB.

Is there another way to implement this or a ideally a way to relate an entry several time in one field?

You're right, this can only be accomplished with a Matrix field.

That said, you could probably accomplish what you need via a custom field type. You'd need to create a custom plugin (obviously), but you could probably build something that simply stores an array of asset IDs:

[12,33,42,10,10,10]

I won't diver deeper into what the mechanics of that plugin & field type should be... that's a bit beyond the scope of this question.


Building a Class Schedule I am building a site for a martial arts school. I want to add a repeating schedule to the site from Monday through Saturday so the user can edit classes and times when needed. What would be the best way to do this? Should I use a global, structure or something else?

Thanks.

For the field type you could use a Super Table field, with columns for the times, the class and the teacher. For the class and teacher column you could consider using an Entries or Categories field, this makes sure the classes are named consistently and you could have links to the classes' description or the teacher's about page.

I would probably create one of these Super Table fields for each weekday and just list them one below the other in your entry type or global set. Is there mulitple rooms or any other reasons to create multiple schedules, than have them in a channel section (ordered by title) or a structure. This could also be handy in case you want to store schedules for each year or season. The user could create the upcoming schedule and it automatically becomes active with the start or the new season (set an expiry date and always pick the latest entry).

Here's an example for school classes:


favicon.ico throwing 404 TemplateLoader exception This is my first Craft site, I inherited it. I've manually set a link tag to my favicon in my templates/_layouts/_header.twig file:

Everything else in that /dist/img folder renders fine - .png, .jpg, .gif. Everything inside the other /dist subdirs renders fine - /css, /js, /pdf... What am I missing? Going directly to the favicon.ico url, I get a blank page with this:

"Unable to find the template â€œ_layoutâ€."

I do not understand the routing - but that feels like a red herring here anyway. I don't have any routes set up in the cms, and everything else in the /dist directory renders fine when I link directly to it. Thanks for any ideas.

I don't think you can open a .ico file with the browser directly, that's why the request 404s.

There's two ways to make it do its thing:

simply place it in the web root, e.g. public/favicon.ico
use this link tag in your document head: <link rel="icon" href="{{ url('dist/img/favicon.ico') }}" type="image/x-icon">


Why do Image transformations rename the image? I noticed that when performing an image transition on an image, the resulting image name is computer gibberish. How can I maintain the original name of the image? Keeping the original name is important for SEO value.

EDIT
When viewing a transformed image for first time, the url shows as  http://aed.dev/cpresources/transforms/3?x=pEYIdgIMS ... but! I have discovered that this url only appears the first time I view the page. every other page view will display the image with original file name

Craft will use the original file name of the asset after the first request.

The first time an asset is requested, the url for the asset will not include the original file name


How to check structure type has any entries/children from anywhere on my site? I have a section with a "Structure" section type. I've called it "structure_casestudies".

I'd like to create a navigation bar that links to that page, but only if there is at least one entry within it.

hasDescendants() or similar EntryModel functions work fine, for structure pages only. But how can I perform the same check, from anywhere on the site?

I hoped doing a specific query would do the trick... but this just isn't right.

{% if craft.entries.section('structure_casestudies').hasDescendants() %}Case Studies{% endif %}

Any ideas?

To do a check if a structure has content you could do

{% set structureNav = craft.entries({ section : 'structure_casestudies' }).first() %}

{% if structureNav != "" %}
    I exist.
{% else %}
    I don't exist.
{% endif %}


Craft 3: Preventing Element from Saving in Plugin I had a simple Password Confirmation validation function in Craft 2. In porting the function to Craft 3, I'm struggling to figure out how to handle the same thing. In Craft 2, all events were consistently handled by setting $event->performAction = false but in Craft 3, only a subset of events have a similar isValid option.

Here is my previous Craft 2 version, triggered on onBeforeSaveUser...

public function confirmPassword($event)
{
    // Only do anything if it is a front end submission
    // Only validates against passwordConfirm if field is present
    if (craft()->request->isSiteRequest()) {
        $password = Craft::$app->request->post('password');
        $passwordConfirm = Craft::$app->request->post('passwordConfirm');
        if (isset($passwordConfirm) && strcmp($password, $passwordConfirm) !== 0) {
            $event->user->addErrors(array('passwordConfirm' => Craft::t('Passwords do not match.')));
            $event->performAction = false;
        }
    }
}

In my attempt to port to Craft 3, right now, I'm listening for EVENT_BEFORE_SAVE_ELEMENT and then doing...

public function confirmPassword(ElementEvent $event)
{
    // Only do anything if it is a front end submission
    // Only validates against passwordConfirm if field is present

    if (Craft::$app->request->isSiteRequest) {

        $password = Craft::$app->request->getBodyParam('password');
        $passwordConfirm = Craft::$app->request->getBodyParam('passwordConfirm');

        if (isset($passwordConfirm) && strcmp($password, $passwordConfirm) !== 0) {

            $event->element->addErrors([
                'password' => 'Passwords do not match.'
            ]);

            // WHAT DO I DO HERE TO PREVENT USER ELEMENT FROM SAVING?

        }
    }
}

When I print out $event->element->errors, it correctly shows the errors. But the element is still saved. Am I missing a step here? Or is there a better way to handle this simple/custom validation?

The event fired by element service is not cancellable, as that is a bit too broad to be controlled like that. Instead, you should be listening to the EVENT_BEFORE_SAVE on the User element as that supports the isValid property.

use craft\events\ModelEvent;
use craft\elements\User;
use yii\base\Event;

Event::on(User::class, User::EVENT_BEFORE_SAVE, function(ModelEvent $event) {
    $event->sender->addErrors([
        'password' => 'Passwords do not match.'
    ]);
    $event->isValid = false;
});


How do you rename a tag globally in the Craft Control Panel? Is there a way to rename a tag, globally, within the Craft CP?

If not directly, would the Find and Replace tool include tags?

As of Craft 2.0 you can rename tags by double-clicking on them.


Trouble getting an asset bundle registered I have searched for a couple hours for help on this. No luck.

Following the docs here.

My first two passes were unsuccessful so I deleted everything and started over.

1) I created a plugin scaffolding with a single controller and successfully registered that plugin. I did not edit anything in that plugin.

2) I created the file "FooBundle.php" in the following folder structure:

recoveryfinder
--myPlugin
  --src
    --FooBundle.php

3) I edited the contents of FooBundle.php to be exactly the docs:

<?php
namespace ns\prefix;

use craft\web\AssetBundle;
use craft\web\assets\cp\CpAsset;

class MyPluginAsset extends AssetBundle
{
    public function init()
    {
        // define the path that your publishable resources live
        $this->sourcePath = '@ns/prefix/resources';

        // define the dependencies
        $this->depends = [
            CpAsset::class,
        ];

        // define the relative path to CSS/JS files that should be registered with the page
        // when this asset bundle is registered
        $this->js = [
            'script.js',
        ];

        $this->css = [
            'styles.css',
        ];

        parent::init();
    }
}

Lastly I added the following line after my {% extends "base.html" %} in my index.html. My first two lines of index.html look like this:

{% extends "base.html" %}
{% do view.registerAssetBundle("ns\\prefix\\FooBundle") %}

When I refresh my site index page I get:

  ReflectionException

  Class ns\prefix\FooBundle does not exist

Because your FooBundle has the classname MyPluginAssetrename your class to FooBundle and it should work (if your namespace is correct, since your information are not really detailed as always)

The docs are not supposed to be a place for copy paste but a source for information.


Display category entries based on Segment? I'm really struggling to display entries of a category, based on the segment. In other words, I have 1 category template, so the category needs to be determined dynamically (*we still  do this by segment, right?? or is that not the best practice?)

I was trying something like this, but I can't seem to get it right:

{% for category in craft.categories.group('typeOfPack').find() %}
     {% set active = (
        craft.request.Segment(2) == category.slug
     ) %}

    {% for entry in entry.typeOfPack.search('active').find()  %}
        <h3>{{ entry.title }}</h3>
    {% endfor %}

{% endfor %}

Apologies if this offensively bad. As I try to get my head around Twig, I'm wondering if there are some high level errors, for instance:
1. Does the {% for entry... %} need to be inside the {%for category... %}? Do I even need to do the {% for category...%} stuff if I'm just needing entries, or is the ".search(...)" sufficient?

Thank you so much.

Big Mike

How do I list the entries related to a category? article on the Craft site should get you headed in the right direction.

  You can fetch the entries related to a given category with a little
  help from craft.entries and the relatedTo param.

{# Fetch all of the entries related to this category #}
{% set entries = craft.entries.relatedTo(category) %}

{# Output them #}
{% for entry in entries %}
    {{ entry.title }}
{% endfor %}


Pagination: Next/Previous related to author I'm having trouble limiting next/previous links in one channel to articles by the author.

next/previous links are working correctly on the regular blog but when included on the DJ blog I get unknown property errors in the template.

If I remove the merge line below pagination appears to work, but includes DJ posts not by the current Dj.

url looks like https://domain.com/djs/503/firstName-lastName where 503 is the author.id

{# Set parameters for prev/next elements list #}
{% set params = craft.entries.section(channel).orderBy('title asc') %}

{# if djs channel limit to author based on url segment 2 which is author id #}
{% if craft.app.request.segment(1) == 'djs' %}
  {# get dj to relate and limit next/prev #}
  {% set author = craft.app.request.getSegment(2) %}
  {# {% set dj = craft.users.id(author).one() %} #}

  {# {% set params = craft.entries.section('djBlog').relatedTo(author).orderBy('title asc') %} #}

  {% set params = params | merge({ relatedTo: author }) %}

{% endif %}

Below code is working on all other templates except the DJ blog where I need to restrict pagination to posts by the current author. Only including here in case it may be relevant though I don't think so.

 {# grid-container #}

      {% if prevEntry %}

          {##}
          {{ macros.icon("next", "icon-blue", "40", "40") }}
           Previous

      {% else %}

          {##}
          {{ macros.icon("next", "icon-blue", "40", "40") }}
           Previous

      {% endif %}

      {% if backTo == 'true' %}

          Back to {{ backToTitle }}
          {#  #}

      {% endif %}

      {% if nextEntry %}
        Next{{ macros.icon("next", "icon-blue", "40", "40") }}
      {% else %}
        Next{{ macros.icon("next", "icon-blue", "40", "40") }}
      {% endif %}

You are trying to merge an object of type ElementQuery with an array so your object will be transformed as an array and merged with the new array. Of course you'll end up having an array instead of a query so you can't execute it in order to fetch the entries.

Instead of merging it, why not setting the parameter directly?

{% do param.authorId(author) %}

Furthermore authors are not related to entries  (except you set them in an additional field)


'Create a new entry' CP is blank if matrix field exists I set up an matrix field and put it into section type.

If I am trying to create new entry a kind of broken 'Create a new entry' CP is shown up. Only title 'Create a new entry' and an broken 'save' button. Also rest of header seems not to rendered nice. Horizontal scrollbars appear.

If I change same field to other type, all works as expected.
It really only happens if I am using matrix field.

All happens on fresh setup:
No plugins installed. (Just this one task tried and failed).
Mac, Mamp Pro.
Craft (version 2.5.2757)

Console in Browser says nothing.

What I tried:
 + Fresh installation with user permissions for all craft folders read&write.
 + PHP memory config on 128mb. (Mamp Pro).

UPDATE: SOLVED It had something to do with php error settings in Mamp Pro. Once disabled, all is working, also with Matrix.

Solution: Do it as in craft instructions asked 'PHP 5.3.0 or later with safe mode disabled' and all works perfect like a charm.

This problem came from settings in Mamp Pro. The debugger was active. And all other 'what to log' too. After uncheck - no problem any more.


Changing Redactor settings doesn't work I'm trying to change Redactor's settings by editing craft/config/Standard.json (and Simple.json) but it doesn't seem to have any effect at all. I logged out, emptied Craft's and browser cache and still don't see any changes.

Is this feature broken in the current Craft version or am I missing something? I edit the file by removing/adding buttons, like this:

{
    "buttons": ["html","formatting","bold",],"plugins":["fullscreen","video"],
    "toolbarFixed": true
}

Thanks!

You have to select that config file you edited in your Richtext field's settings. See the settings options for "Rich Text fields" in the Craft Docs.


Get entries after a certain time I am trying to get all entries from my events section in Craft 3 that occur after 17:00.

My current code is:
{% set events = craft.entries.section('events').eventStartTime('>= ' ~ '17:00'|time ).all() %}

The >= is being ignored as far as I can tell. The query just returns all events.

The eventStartTime field is a Date/Time field that is set to just show the time (I know that behind the scenes Craft still treats this as a DateTime object but I was hoping that the |time filter would help with that.

When I have created similar queries on a DateTime field but looking at the date rather than time, they have worked as expected - maybe I am missing something when it comes to the time portion of the object?

Any help would be appreciated.

That will give you all entries, from today (so not past entries) starting after 5PM:

{% set startAfterTime = '17.00'|date('U') %}
{% set today = now|atom|date %}

{% set events = craft.entries()
    .section('events')
    .status(['live', 'pending'])
    .postDate('>=' ~ today )
    .eventStartTime('>=' ~ startAfterTime)
    .all() %}


How do I force a 301 http status code using the redirect tag? Using Craft's redirect template tag creates a redirect with a 302 (Moved Temporarily) http status code. How can I force a 301 (Moved Permanently) status code?

Although it is (as of today) not yet documented, looking through the redirect twig extension revealed that the redirect tag can accept a second parameter for the http status code. So forcing a 301 is done as follows:

{% redirect 'pricing' 301 %}

I've sent a request to P&T to add this to the docs.


Caching not working on page with asynchronously loaded asset transforms I'm using PictureFill on a large page, containing many image transforms, that doesn't seem to be caching despite most of the page being wrapped in {% cache %} tags. When I view the page after several refreshes with Dev Mode enabled, the Profiling Summary Report is reporting Total Queries at 174, and the HTML source still contains many examples of image urls that contain something like /cpresources/transforms/XX.

I read in this answer that Craft won't cache a page with unresolved transforms, which might explain why this page isn't being cached. But then the question is, why aren't these transforms resolving?

Seems to be the case that Craft won't attempt to resolve these /cpresources/transforms/ URLs until the asset is actually requested, which can mess with a setup like PictureFill where there is no guarantee that the transformed assets will ever be loaded.

Solution in my case was to to set 'generateTransformsBeforePageLoad' => true, in your Craft config array as mentioned here

After doing this, all transform URLs resolve and the page is properly cached.


Emoji mb_detect_encoding() error when updating to latest Craft 2.6.x I updated a Craft 2.6 installation to the latest 2.6.x and suddenly I get an error when saving a user's profile on the frond end:

mb_detect_encoding() expects parameter 1 to be string, array given
/data/sites/web/boumaticdevbuthostcom/subsites/corporate-web.boumatic.dev.buthost.com/craft/app/vendor/elvanto/litemoji/src/LitEmoji.php(108)

However, nowhere on that page has an emoji been inserted in any input fields or anything.

I hope somebody can help me with this as it is an urgent issue.

UPDATE

I just tracked down the problem to this input field:

<input type="hidden" name="fields[gdprPermissionsList][permissionSales][type]" value="permissionInfo">

Which is quite weird as it does the exact same thing as 3 other fields on that page which work fine.

Solved it. The problem was with this field:

<input type="hidden" name="fields[gdprPermissionsList][permissionSales][fields][lastChangedDate][date]" value="{{ now|date("m/d/Y") }}">

The [date] part was to much and it saved the value in Craft as a literal string: {"date":"07\/11\/2018"} instead of the formatted date.

In one of the Craft updates that throws an error, maybe because it ses it as an object/array due to the curly brackets or maybe because that string has an emoji shortcut in it?


How to query in MySQL all entries with related categories I have a custom product grid not associated with Craft Commerce. I am wondering, how can I query, in the SQL database, all entries and their related categories?

The relations table holds all of the information about relations between Craft elements (entries and categories in your case).

So you would use the sourceId and targetId columns of the relations table and join on the id columns of the entries and categories tables in your example.


How to remove a Super Table row on the front end? Is it possible to remove a Super Table row?

I got it to work to add a new row but it would be great if I can remove it later.

Thanks for any help! :)

I got a solution!

<input class="remove" type="hidden" name="fields[{{ fieldHandle }}][{{ row.id }}][type]" value="{{ blocktype }}">

So the output will be "1" if you change it to "0" and safe your page the row is deleted! Really simple.


Perform "inclusive" relatedTo query with multiple categories I want to be able to return all entries that are related to 1 .. n categories:

{% set resources = craft.entries.section('resources').relatedTo('and', categories) %}

in this example, categories contains two categories category1 and category2, and the query returns all entries that have either category1 or category2.

How do I change the syntax to return entries that are related to both category1 and category2?

I thought 'and' would do it, but seemingly not.

That and argument only applies to the other top-level relatedTo arguments. If one of those arguments targets multiple elements (e.g. categories), those will still be glued together with “OR”.

You would need to set it up like this instead:

{% set resources = craft.entries.section('resources').relatedTo(
    'and',
    { targetElement: category1 },
    { targetElement: category2 }
) %}

If you don’t know all of the categories ahead of time, you can create the parameter value dynamically like this:

{# Get the category IDs #}
{% set catIds = craft.categories[...].ids() %}

{# Create the relatedTo param value #}
{% set relatedTo = ['and'] %}

{% for id in catIds %}
    {% set relatedTo = relatedTo|merge([id]) %}
{% endfor %}

{# Now find our entries #}
{% set resources = craft.entries.section('resources').relatedTo(relatedTo) %}

Update

This is significantly easier in Craft 2.5 (currently in beta), as the relatedTo param’s element, targetElement, and sourceElement sub-properties can now begin with 'and', which tells Craft to only return elements that are related to all of the following element IDs.

Here’s a quick example:

{# Start with a list of category IDs that must be included #}
{% set catIds = [1, 2] %}

{# Find the entries #}
{% set resources = craft.entries({
    section: 'resources',
    relatedTo: {
        targetElement: ['and']|merge(catIds),
    }
}) %}


What is the appropriate way to query and Hard Delete existing Soft Deleted Elements for a Custom Element? I have a Custom Element where the Soft Delete functionality is not necessary. Right now, existing users of this plugin may have thousands of Soft Deleted Elements in their Elements table that don't need to be there.

I am writing a migration that removes those, and, making some other updates so that when they get deleted in the first place, they get hard deleted.

Where I'm not clear on what the appropriate path forward is how to delete the existing Soft Deleted Elements. As far as I can tell, running the Garbage Cleanup hardDelete method is not really the right way to do this as I can't target a specific Custom Element of my choosing - it's all or nothing. I don't want to delete Soft Deletes that may be important for users, I just want to delete the ones in our plugin.

Next,it seems I can't use deleteElementById as it doesn't give me a way to indicate I want to Hard Delete, so I need to use the deleteElement method called by the deleteElementById method and recreate any code necessary to convert the ID into an actual Element class that I can pass to the deleteElement method. Something like:

foreach ($results as $key => $elementInfo) {
    $element = Craft::$app->elements->getElementById($elementInfo['elementId'], MyCustomElement::class, $elementInfo['siteId']);

    if ($element && !Craft::$app->elements->deleteElement($element, true)) {
       // Fail
   }

   // Success
}

However, this doesn't appear to work either because getElementById returns null, I expect because it's excluding Soft Deleted items from what it's retrieving.

I figured this while posting so I thought I'd just add it here anyway for others to reference.

To retrieve a Soft Deleted Element using the getElementById method you can pass the fourth argument to the getElementById method and define $criteria setting trashed to true, which will include Soft Deleted items in your results:

$element = Craft::$app->elements->getElementById($elementInfo['elementId'], MyCustomElement::class, $elementInfo['siteId'], [
    'trashed' => true
]);


confused by inconsistent behavior of matrix Here's my code block:

{% extends "_layout" %}

{% block content %}

{{ entry.title }}

TEST EDIT 8

        {% for block in entry.blogPost %}

heading - {{ block.heading }}

sub heading - {{ block.subHeading }}

accolade- {{ block.accolade }}

        {% endfor %}

Posted on {{ entry.postDate.format('F d, Y') }}

        {{ entry.body }}

{% endblock %}

And here's the error message I am getting on an inconsistent basis:

  Craft\MatrixBlockModel and its behaviors do not have a method or closure named "heading"

I've tried to remove the other Matrix fields from the template, and just isolate on the 'block.heading' field, and I get really strange behaviors. Sometimes the template renders fine, and the dynamic value gets rendered by the page. Sometimes, with a different content entry, the same template gives the above error message.

I'm brand new to CraftCMS. Is there an obvious syntax mistake I'm making?

Since you have 3 block types in your Matrix, you need to check for the block type before trying to call an inner field.

{% block content %}

{{ entry.title }}

TEST EDIT 8

        {% for block in entry.blogPost %}
            {% if block.type == 'imageCaption' %}

heading - {{ block.heading }}

sub heading - {{ block.subHeading }}

            {% elseif block.type == 'WhateverTypeAccoladeIsIn' %}

accolade- {{ block.accolade }}

            {% endif %}
        {% endfor %}

Posted on {{ entry.postDate.format('F d, Y') }}

        {{ entry.body }}

{% endblock %}

You should add that check before block.accolade as well for whichever block type accolade is in.


How can I create a simple loop through entries in a category? I have a category set up and have added entries to it. How do I loop through these entries, and output just the title of each entry?

Serious noob here but trying to learn, any help would be gratefully received.

This example assumes you have your Category Group setup to use custom URLs.  In the template used to display your categories, the category variable will be available and represent your CategoryModel for that page.

The key is to pass the CategoryModel (in our example below category) to the relatedTo parameter of the Entries tag.

{{ category.title }}

{% paginate craft.entries
    .section('articles')
    .relatedTo(category)
    .limit(10)
    as entries
%}

    {% if entries|length %}

        {# Content #}
        {% for entry in entries %}
            {{ entry.title }}
        {% endfor %}

        {# Pagination #}

    {% else %}

No items have been added to this Category yet.

    {% endif %}

{% endpaginate %}


Is there a way to get supportedSites for a category page? I'm working on a site that is available in multiple languages and I would like to build a language switcher that will work for both category pages and single entries.

In Craft v2 that was possible but once I switched to Craft v3, I can't find a way to do get the current category page.

For single entries I do the following (simplified):

{% for siteForEntry in entry.getSupportedSites %}
    {% set site = craft.app.getSites.getSiteById(siteForEntry.siteId) %}
    {% if site.id == entry.siteId %}

           {{ site.language }}

    {% else %}
        {% set entryForOtherSite = craft.entries.id(entry.id).site(site).one() %}

                {{ site.language }}

        {% endif %}
 {% endfor %}

Is there a way to do the same thing for categories?

It turns out that getSupportedSites() returns different results for categories and standard entries so an additional check needs to take place.

The solution below has been tested with a single group with multiple languages, and it works, although I hope there's a better solution than this one:

If the current page is a category then assign it to the entry variable

{% set entry = category %}

Then:

{# Retrieve all supported sites for the current entry #}
{% set supportedSites = entry.getSupportedSites %}

{% for siteForEntry in supportedSites %}
  {% if siteForEntry | length == 1 %}
    {# category #}
    {% set site = craft.app.getSites.getSiteById(siteForEntry) %}
    {% set entryForOtherSite = craft.categories.id(entry.id).site(site).one() %}
  {% elseif siteForEntry | length == 2 %}
    {# standard entry #}
    {% set site = craft.app.getSites.getSiteById(siteForEntry.siteId) %}
    {% set entryForOtherSite = craft.entries.id(entry.id).site(site).one() %}
  {% endif %}

  {% if site.id == entry.siteId %}
      {# This is the current language, mark it as active and don't retrieve its url #}

{{site.language}}

  {% else %}
      {# if it's not the current site, get the entry for this site #}

{{site.language}}</a

  {% endif %}

{% endfor %}


Live Preview not working in some sections Live preview works in some sections, but not ones that use routes and have "entries in this section have their own urls" deselected.

Is this expected behaviour?

Is there any way to use live preview on these sections?

It is expected behavior.  Live Preview is meant to show you what that entry will look like on the front-end of your site with the template specified in that section's setting.

If that entry doesn't have a URL as defined in the section settings, then there is nothing to preview.


Matrix Field Conditional I'm trying to attach a custom header image for each entry, if none is selected then the default one will be displayed.

contentBuilder is the Matrix field.
imgHeader is an assets block type.
img is the actual field

{% for content in entry.contentBuilder.type('imgHeader') %}

    {% if content.img|length %}
        {{ content.img.first.url }}
    {% else %}
        default jpg
    {% endif %}

{% endfor %}

However this doesn't work. Please advise :)

Image are returned as an array so could use either of the following:

{{ content.img[0].url }}

Or set a variable which fetches the asset to then output its fields

{% set asset = content.img.first() %}
{{ asset.url }}

Related: Looping through images in a Asset field type

UPDATE: The line {% if content.img|length %} will always be true because you are checking for existence of the field. You need to instead check that the field has a value using one of the methods below:

{% for content in entry.contentBuilder.type('imgHeader') %}

    {% if content.img[0]|length %}
        {{ content.img[0].url }}
    {% else %}
        default jpg
    {% endif %}

{% endfor %}

or

{% for content in entry.contentBuilder.type('imgHeader') %}

    {% set image = content.img.first() %}

    {% if image|length %}
        {{ image.url }}
    {% else %}
        default jpg
    {% endif %}

{% endfor %}


Dynamic Macro Variable We're using the Digital Products plugin from Pixel and Tonic to sell 6 different types of products. I've set up a macro with matching icons for each of the product types (image, video, etc). On our user account page, I want to show recent purchases with the icon of the product type underneath it.

Usually, I would write {{ icons.image }} or {{ icons.video}} to call the icon macro. But the variable needs to be dynamic if I want to display it under a dynamic list of products.

In order to make it dynamic, of course, I need to be able to inject different macro variables image, video, etc when they're called.

I found the {{ attribute() }} function, which looks like the preferred way of accessing dynamic attributes.

So I tried this:

{{ attribute(icons, license.product.type) }}

And get this error:

Illegal offset type in isset or empty

So I researched a bit and found that I could try {{ attribute(icons, license.product.type[0]) }}

But that led to this error: Property "Craft\DigitalProducts_ProductTypeModel.0" is not defined.

So, basically now I'm stuck. My lack of PHP knowledge may be holding me back here.

The better approach would be to pass the icon as a parameter to your macro. So I would do something like

{% macro renderIcon(type) %}
    {% switch type %}
        {% case 'video' %}
            {% include 'video.twig' %}
        {% case 'audio' %}
            {% include 'audio.twig' %}
        {% default %}
            {% include '_generic.twig.twig' %}
    {% endswitch %}
{% endmacro %}

And in your template you can do

{% import 'macro.twig' as icon %}
{{ icon.renderIcon(product.getType().handle) }}


Cart - only one item at a time In my cart on Commerce, I only get to have one item at a time. If I try to add another item, it replaces the item that was already in the cart.

I have used {% set cart = craft.commerce.getCart() %} and the for item in cart.lineItem to loop through the items, to no avail.

That would happen if you are using Commerce Lite. You will need Commerce Pro if you want the 'full' cart functionality.


Get excerpt of entry from search query If I enter a query into the search bar I would like to see an excerpt (let's say 140 characters) of each entry that is related to the query.

Here is what I use on the search result page to display the results.

{% set query = craft.request.getParam('q') %}
{% set entries = craft.entries.search(query).order('score') %}

{% if entries|length %}

{{ entries|length }} results:

    {% for entry in entries %}

{{ entry.title }}

    {% endfor %}

{% else %}

Your search for “{{ query }}” didn’t return any results.

{% endif %}

How do I add entry excerpts like: https://craftcms.com/search?q=entry

Have a look at the slice filter. To return 140 characters max. you would do something like this:

{% if entry.body %}
    {{ entry.body|slice(0, 140) }}
{% endif %}

See this other question on a similar topic if you want to apply this on a rich text field. Because this solution only works with plain text.


Unable to register adjuster in module Following https://docs.craftcms.com/commerce/v2/adjusters.html I am unable to register an adjuster in my module.

in my Module.php file I have placed the following inside init() alongside other stuff being registered (that are working)

use craft\events\RegisterComponentTypesEvent;
use craft\commerce\services\OrderAdjustments;
use modules\mymodule\adjusters\DiscountAdjuster;

Event::on(OrderAdjustments::class,
    OrderAdjustments::EVENT_REGISTER_ORDER_ADJUSTERS, function(RegisterComponentTypesEvent $event) {
    $event->types[] = DiscountAdjuster::class;
});

And in src/adjusters/DiscountAdjuster.php I have

namespace modules\mymodule\adjusters;

use Craft;
use craft\base\Component;
use craft\commerce\base\AdjusterInterface;
use craft\commerce\elements\Order;
use craft\commerce\models\OrderAdjustment;

class DiscountAdjuster extends Component implements AdjusterInterface
{

    public function adjust(Order $order): array
    {
        $adjustments = [];

        foreach ($order->getLineItems() as $item) {
            $adjustment = new OrderAdjustment;
            $adjustment->type = 'discount';
            $adjustment->name = '$2 off';
            $adjustment->description = '$2 off everything in the store';
            $adjustment->sourceSnapshot = [ 'data' => 'value']; // This can contain information about how the adjustment came to be
            $adjustment->amount = -2;
            $adjustment->setOrder($order);
            $adjustment->setLineItem($item);

            $adjustments[] = $adjustment;
        }

        return $adjustments;
    }
}

This should take 2 off of every line item when I add items to the cart, no? Nothing happens though. And if i put something like die() in public function adjust, that isn't registered either.

What am I missing?

I also tried adapting this example: Demo repo for an Adjuster module for Commerce 2? However I'm faced with the same issue.

I had the same issue, turns out I had Craft Commerce Lite installed when the feature requires the Pro version.


Category list not returning all related entries Here's my code:

{% for category in craft.categories.group('artistLocation') %}

    {% set entryCount = craft.entries.relatedTo(category).total() %}

    {% if entryCount %}

            {{ category.title }} ({{ entryCount }})

    {% endif %}

{% endfor %}

For some reason, this is only returning the first six categories with entries associated.

https://www.dropbox.com/s/a2ut7j48acnq1g0/Screenshot%202016-05-06%2010.49.34.png?dl=0

Nothing in the error logs that are shedding any light on it for me.

Any ideas would be awesome!

How many categories do you have in that locations group? A criteria model returns the first 100 elements only by default, so any category falling behind that wouldn't be listed, no matter if there's related entries or not.

Add limit(null) to your craft.categories criteria model to make it return all categories.


DB Queries in Craft Commerce 2 with large data Currently working on an e-commerce site, which currently has over 4000 products with a mass of variants (averaging 3 variants per product) - and hit a few hurdles on the way...

At present, craft.products.hasVariant({hasSales: true}) takes over 4 minutes to return the data of items on sale. And again running a product count against the brand (category) is a similar issue.

Now I understand the sheer amount of queries for the above is getting a little ridiculous around 300 are showing in the Logs each time this is run - so running these queries from twig is next to impossible with the overheads.

So now turned to use a plugin with a public function in order to try and ease the pressure from the front end...

Anyone any ideas on how get the same results with a craft\db\Query...

Thanks in advance...

I hope this makes sense...

Okay for anyone who runs into issues with Craft Commerce and has large amounts of products (over 4K) with 8K's worth of variants...

You'll need to create a plugin and execute a function in the variables.php like so...

public function getClearanceProductIds() {
      $rows = (new \craft\db\Query())
      ->select('craft_commerce_variants.productId')
      ->from('craft_commerce_sale_purchasables')
      ->join('JOIN','craft_commerce_variants','craft_commerce_variants.id = craft_commerce_sale_purchasables.purchasableId')
      ->where(array(
        'like',
        'craft_commerce_sale_purchasables.saleId',
        '2'
      ))
      ->column();

      $rows = implode(",", $rows);

      return $rows;

    }

And then query the products in the normal way with the ids array

{% set products   = craft.products.id(saleItems).all() %}

Otherwise, every your resources and CPU will overload by doing things the craft way i.e.

{% set products = craft.products.hasVariant({hasSales: true}).all() %}

I hope this helps someone with a similar issue!


Deleted matrix block means deleted data? If I delete the Matrix block content (while editing an entry) does the associated is deleted as well or only the block but its data still remains in db?

Any content or relationships that belong to the Matrix block will also be deleted, when you save the entry. If there were any relationships, the target elements won’t be deleted, though.


Login test for user's group? I want to display some content only if a user from a certain group (wholesalers) is currently logged-in. The following syntax seems to work - but is there something more shorthand than the nested conditionals I'm using?

{% if currentUser %}
    {% if currentUser.isInGroup('wholesalers') %}
        Do something here...
    {% endif %}
{% endif %}

You could use a switch statement or an if statement using getGroups().

Instead of me taking all the credit, here is a great thread along with an example of using getGroups at the template level.

Here is what that might look like within a plugin.

To get the actual ID of the group - I'm sure there is a more scientific way, but If I'm always going to know what the ID is, I'll just hover over the handle and look at the url. It will be something like /settings/users/groups/2.

Hope this helps!


Adding second user to user field in plugin brings server to its knees I'm building a plugin which needs to add users to a users-type field when they edit the entry on the front-end. It works well when the post is created, adding the original author to the field, and again when the same user edits the post. However, when another user edits the post everything comes to a standstill for a minute and users are taken not to the landing page, but to a page containing nothing other than a "1". Checking the back-end, it has added the second user to the field, though.

Can anyone suggest to me from the code below why adding a second (haven't tested any more than that yet) user brings things the server to its knees?

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

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

        $entry = $event->params['entry'];
        $user = craft()->userSession->getUser();
        $notifyMe = craft()->request->getPost('notifyme');

        // CHECK THIS IS THE FORUM SECTION
        if ($entry->sectionId == 16) {
            craft()->notifier->addAnotherUserToNotify($entry, $user, $notifyMe);
        }
    });
}

And here is the function:

// ADD ANOTHER USER TO A POST'S NOTIFICATION LIST
public function addAnotherUserToNotify($entry, $user, $notifyMe)
{
    if ($notifyMe == "yes") {

        // GET IDs OF USERS ALREADY LISTED TO BE NOTIFIED
        $usersToNotify = $entry->usersToNotify->ids();
        if ( ! in_array( $user->id, $usersToNotify ) ) {
            // ADD THE CURRENT USER TO THE ARRAY OF USERS TO BE NOTIFIED
            $usersToNotify[] = $user->id;
        }

        // UPDATE THE ENTRY'S FIELD WITH THIS UPDATED ARRAY
        $entry->getContent()->setAttribute('usersToNotify', $usersToNotify);

        // SAVE ENTRY
        craft()->entries->saveEntry($entry);

    }

}

The code is inspired by Update User "Field Type" for Entry in Plugin

You've created an endless loop with calling saveEntry within the entries.saveEntry event listener. You can fix it with implementing a static variable.

craft()->on('entries.saveEntry', function(Event $event) {
    static $recursionLevel = 0;

    if ($recursionLevel == 0) {
        $recursionLevel++;

        // `saveEntry` in `addAnotherUserToNotify` triggers another
        // `entries.saveEntry` event
    }
});


Error when outputting assets from a field within a Neo field Anyone with Neo experience had issues with outputting an assets field with multiple images?
I am not using a dynamic field, as I saw there are issues with that.

Code

{% for asset in block.serviceGallery %}

{% endfor %}

Error:
Key "index" for array with keys "entry, ... " does not exist.

You'll need to reference the field handle within asset.
For instance > {{ asset.imageHandle.getUrl('square') }}.
I'm guessing you aren't seeing {{ asset.title }} either?


Getting Commerce Products using Element API in Craft 3 I am trying to get Products using the Element API plugin. I set the 'elementType' to Commerce_Products, CommerceProducts, etc.., but the endpoint keeps returning:

  Endpoint has an invalid elementType

This is my endpoint:

use craft\commerce\elements\Product as ProductsModel;

return [
    'endpoints' => [
        'api/search' => [
            'elementType' => 'ProductsModel',
            'paginate' => false,
            'pretty' => true,
            'criteria' => [
                'limit' => 15,
                'search' => (Craft::$app->request->getParam('keyName')) ? 'title:'.'*'.Craft::$app->request->getParam('keyName').'*' : ''
            ],
            'transformer' => function(ProductsModel $product) {
                return [
                    'title' => $product->title,
                    'url' => $product->url
                ];
            },
        ],
    ]
];

How do I fix it?

You're so close! Just one change (see the elementType key, and the added comment)…

use craft\commerce\elements\Product;

return [
    'endpoints' => [
        'api/search' => [
            'elementType' => Product::class, // This provides Element API the fully qualified Element namespace + class.
            'paginate' => false,
            'pretty' => true,
            'criteria' => [
                'limit' => 15,
                'search' => (Craft::$app->request->getParam('keyName')) ? 'title:'.'*'.Craft::$app->request->getParam('keyName').'*' : ''
            ],
            'transformer' => function(Product $product) {
                return [
                    'title' => $product->title,
                    'url' => $product->url
                ];
            },
        ],
    ]
]

  Note: I'd recommend leaving the use statement as just Product, as I've done above. What you're importing is a class that inherits from the Craft Element class… “Model” has some other specific connotations in Craft + Yii, and even though at a lower level, Elements are still models, I think it's a good idea to leave them named as-is… after all, this is the Element API!


How to create a secondary menu to filter entries? I have a page where by default it lists all of the entries inside the section 'work'. I'd like to have a secondary menu where I can filter these entries by the field 'projectCategories'.

        {% for entry in craft.entries.section('work').find() %}

                {% for asset in entry.mainProjectImage %}

                {% endfor %}

{{ entry.title }}

                    {% for option in entry.projectCategories %}

                        {% if loop.last %}
                            {{ option }}

                        {% else %}
                            {{ option }} +

                        {% endif %}

                    {% endfor %}

        {% endfor %}

My current solution is a secondary menu above the entries that links to a url where it filters the entry for just for that project category with:

{% for entry in craft.entries.section('work').search('projectCategories:Packaging') %}

This works but isn't DRY and unfortunately because of AJAX the secondary menu fades out and back in again when you change the URL.

Is there a way to filter entries by a field without changing the url? Or alternatively is there a way of making the secondary menu not reload with AJAX when on a url that begins with 'work'?

Ok so if you are showing all of the entries by default, lets say you have 10 entires in your "work" section.

I am assuming that you have a category group(s) that each entry belongs to.
From there I would assign the category in a data attribute. This would give you a hook that you could talk to for filtering.

twig

{# Get all entries within the work section #}
{% set entries = craft.entries.section('work').find() %}

{% if entries|length %}

    {% for entry in entries %}

{{ entry.title }}

    {% endfor %}

{% endif %}

{# data-category="{{ entry.category }}" could be data-category="my-category" #}

Then I would have a drop-down, or a set of links that represented each of my categories.

twig

{# Get all categories within the work category group #}
{% set category = craft.categories.group('work') %}

<select id="workFilter" name="workFilter">
    <option value="">Select Location</option>
    {% for cat in category %}
        <option value="{{ cat.slug }}">{{ cat.title }}</option>
    {% endfor %}
</select>

On the javascript side, you could either listen for a click - and hide whatever nav items did not have the same data-category value.

For example:

html

Use a click event to check the data value, and hide whatever nav elements did not have "my-category" as the data-category attribute.

Or, a drop-down like above.

jquery

$('#workFilter').change(function (event) {
    // get the value of the drop-down. Hide all list items that do not have the same data-category value.
});

You shouldn't need any ajax or anything like that since all of your entries are already on the page. You just need a hook to show/hide them.

Hope this helps!

EDIT

Sure - give fadeOut a look.

If you are using a button/link you can listen for the click event. Then fadeOut the element. That will fade it out, then set the display to none which should remove the empty gaps for you.

Something like this...

jquery

$('nav-element').click(function(event){
    $('all-things-not-matching).fadeOut('fast', function() {
        // Animation complete.
    });

    event.preventDefault();
});

Each element that is now hidden has the css values of:

opacity: 0;
display: none;


Trigger Update Asset Index from url endpoint Is it possible to trigger an update of the asset indices from an url endpoint? I guess not, but is it planned to provide some kind of API?

Not natively, but you could easily write a plugin with a controller that exposes the AssetIndexingService.


Use a Twig macro to set a variable Is there any way to use a macro in twig to define a variable outside that macro?

For example, say you want to use a macro to set a variable that stores an entry's parent (I know you can do this much simply, but I have my reasons to want to do it like this), I would intuitively want to do something like this:

{% macro getParentEntry(thisEntry) %}

    {% import _self as self %}

    {% if thisEntry.parent|length %}

        {% set parent = thisEntry %}

    {% else %}

        {% set parent = false %}

    {% endif %}

{% endmacro %}

{% import _self as self %}
{% set parent = self.getParentEntry( entry ) %}

But this clearly isn't quite right.

Am I missing something, or is this just not possible. (I couldn't find any mention of anything like this in the twig documentation.)

Many thanks!

I think the issue with trying to set a variable in a macro is that the variable is limited to the scope of the macro you are triggering, so {% set parent = thisEntry %} is available within the scope of your macro, but doesn't define it for the rest of your template.

  Macros are comparable with functions in regular programming languages. They are useful to put often used HTML idioms into reusable elements to not repeat yourself.

  Macros differs from native PHP functions in a few ways:

  Default argument values are defined by using the default filter in the macro body;
  Arguments of a macro are always optional.
  But as with PHP functions, macros don't have access to the current template variables.

Taken from the Twig docs

So due to the limitations in scope and the nature of macros, they are meant to be used to just output reusable code, not set and define logic in your templates. So everything is just rendered as a string (models have their __toString() method called)

The way you could get this to work for you is to just output whether or not the logic in your macro is true or null, then do the rest of the logic in your template, something like:

{% macro hasParentEntry(thisEntry) %}

 {% import _self as self %}

 {% if thisEntry.parent|length %}

   {# would output 1 #}
   {{ true }}

 {% else %}

   {# or just output null #}
   {{ null }}

 {% endif %}

{% endmacro %}

Then in your template do something like:

{# This will either be true or null #}
{% set parent = self.hasParentEntry( entry ) %}

{% if parent %}

 {# this will set your parent variable to the entry model or leave the variable as null #}
 {% set parent = entry.parent %}

{% endif %}


Using Mailgun with Craft Is it possible to use the Mailgun SDK with Craft at this point?

If not, is it OK to just the composer autoloader as a second autoloader (I'm about to test it, I'm just curious whether it's kosher or there's a different way of doing it that doesn't involve writing another plugin)?

The asker was able to solve their question and confirm that MailGun can be used with Craft. In the comment they state:

  Just FYI: requiring vendor/autoload.php (from my plugin) worked and
  correctly loads Mailgun. So I guess it works, it's just (more than a
  little) ugly

We have had success integrating Craft with MailGun in our plugins as well.  While we have not released our integration publicly, we have a Sprout Email MailGun integration used by our direct customers and we were able to successfully integrate with Email Lists and Campaigns, and allow users to build Emails using Craft templates with Live Preview and send them through the MailGun API.


Can't remove index.php from my URLs I edited .htaccess as described here http://buildwithcraft.com/help/remove-index.php and added this 'omitScriptNameInUrls' => true, to craft/config/general.php, but it doesn't work.

Image:

I also have my .htaccess file set up:

    RewriteEngine On
    # Send would-be 404 requests to Craft
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} !^/(favicon.ico|apple-touch-icon.*.png)$ [NC]
    RewriteRule (.+) index.php?p=$1 [QSA,L]

This file is inside public folder and I also tried putting in in the directory that contains the public folder.

What happens is this: whether 'omitScriptNameInUrls' => true is added or not, the home displays fine without the index.php, but the internal pages require index.php to display.

The only thing that happens when I add 'omitScriptNameInUrls' => true is that the navigation spits out links without the index.php, and so the navigation breaks.

The good people at Craft said that my site (which is a retooling of the Happy Lager demo site) has been changed to a multi-environment config, which is why my config file looks the way it looks. Not sure if there's anything else that needs to me added to a multi-environment config to get the thing to work.

I have not been able to get any more clarification from Craft about this issue yet.

These are the settings I have in place for config.php and .htaccess file.


Different template for an entry in section If I have a Section called "Pages" that uses the "page.html" Entry Template.

How do I override that template for a single page in this Section?

I thought I would be able to use Craft Routing but the Entry request (#4) is picked up before the Dynamic Routes (#5).

Is there a nicer solution to this rather than a bunch of if statements in the template?

{% if craft.request.getPath() == "about" %}

    {% include '_includes/about.html' %}

{% endif %}

I also found this solution, but not sure if it's overkill if I only want to override 1 Entry?

Zuccs, have a look at this plugin: https://straightupcraft.com/craft-plugins/template-select


Craft Commerce: Calculating (Product + Shipping) + Tax? There is an option when setting up Tax Rates to apply the tax to "both (item + shipping costs)" however when testing on the front end the shipping cost is added after tax is applied to the product and no tax percentage is applied to the shipping cost.

The total amount payable is (Product + Tax) + Shipping. I want (Product + Shipping) + Tax.

Is there more configuration needed so that the adjustments show correctly at checkout and the customer is charged the right amount?

Currently there is a caveat, that order level shipping costs can not have tax applied to them.

This means if you have any 'base shipping costs' applied  to the cart the tax engine can not see them because they are not on a line item. Currently the tax adjuster system only adds tax to line items.

This is an issue that will be fixed in a future release but will mean there needs to be a change to the way the adjustment system works. We would need to allow tax to be added to adjustments.

If you want tax on shipping cost you would need to make all shipping rules only add tax to line items. Let me know if you have further questions and I will update my answer.

UPDATE: see other answer for the final solution.


Replace core login function I want to replace the login function with a custom one validating against Office 365 oAuth.  I already have the connection to MS coded, but I can't find a way to replace the core login function.  I can see the "before login" hook, but that would still display the login screen.  Is there any way to accomplish via plugin, or do I have to alter the core code to accomplish what I want?

I believe what you're trying to accomplish can be done with a plugin.

Perhaps this OAuth plugin could at least offer some boilerplate for you: https://dukt.net/craft/oauth/

dukt's github also has some provider-specific plugins: https://github.com/dukt


Check if we're the second or last sunday of the month today How can I check if today is the second or last sunday of this month?
My effort:

{% set now = now|date('U') %}
{% set monthyear = now|date('F Y') %}
{% set secondSunday = now|date_modify("#{monthyear} second sunday")|date('U') %}
{% set lastSunday = now|date_modify("#{monthyear} last sunday")|date('U') %}

{# check if now is second or last sunday #}
{% if now == secondSunday or now == lastSunday %}
   {# YES, today is the second or the last sunday #}
{% else %}
   {# NOPE #}
{% endif %

But I keep getting the following error:

DateTime::modify(): Failed to parse time string (juni 2017 second sunday) at position 0 (j): The timezone could not be found in the database

Maybe it doesn't work because the monthyear variable is formed in dutch and not english? (juni = june) If this is the case, how can I modify this to english in order to get it to work?

Also, my timezone is correctly set to UTC+2 (CEST) - Europe/Brussels via Settings > General

Thanks!

Maybe it doesn't work because the monthyear variable is formed in dutch and not english?

Yes that's part of the problem. Have a look at PHP's relative formats page to see what it supports.

You can actually pull off what you're doing with the this keyword.

{% set secondSunday = now|date_modify("second sunday of this month")%}
{% set lastSunday = now|date_modify("last sunday of this month") %}

You also don't need to define (or override) now since Craft will always set that to a DateTime object for you.


Randomly getting the "Integrity constraint violation" sql error on saving entry Randomly getting the "Integrity constraint violation"  sql error on saving entry from backend.  There no apparent cause of this at least not that I can see, because the same post saves without errors when I try again.

Craft version is : 2.6.3017

Here is the error and Stack trace:

[error] [system.db.CDbCommand] CDbCommand::execute() failed: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`db_production`.`craft_relations`, CONSTRAINT `craft_relations_targetId_fk` FOREIGN KEY (`targetId`) REFERENCES `craft_elements` (`id`) ON DELETE CASCADE). The SQL statement executed was: INSERT INTO `craft_relations` (`fieldId`, `sourceId`, `sourceLocale`, `targetId`, `sortOrder`, `dateCreated`, `dateUpdated`, `uid`) VALUES (:row0_col0, :row0_col1, NULL, :row0_col3, :row0_col4, :row0_col5, :row0_col6, :row0_col7), (:row1_col0, :row1_col1, NULL, :row1_col3, :row1_col4, :row1_col5, :row1_col6, :row1_col7), (:row2_col0, :row2_col1, NULL, :row2_col3, :row2_col4, :row2_col5, :row2_col6, :row2_col7), (:row3_col0, :row3_col1, NULL, :row3_col3, :row3_col4, :row3_col5, :row3_col6, :row3_col7), (:row4_col0, :row4_col1, NULL, :row4_col3, :row4_col4, :row4_col5, :row4_col6, :row4_col7), (:row5_col0, :row5_col1, NULL, :row5_col3, :row5_col4, :row5_col5, :row5_col6, :row5_col7).

[error] [exception.CDbException] CDbException: CDbCommand failed to execute the SQL statement: SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (`db_production`.`craft_relations`, CONSTRAINT `craft_relations_targetId_fk` FOREIGN KEY (`targetId`) REFERENCES `craft_elements` (`id`) ON DELETE CASCADE) in /var/www/mysite.com/craft/app/framework/db/CDbCommand.php:358

Stack trace:
#0 /var/www/mysite.com/craft/app/etc/db/DbCommand.php(370): CDbCommand->execute(Array)
#1 /var/www/mysite.com/craft/app/services/RelationsService.php(74): Craft\DbCommand->insertAll('craft_relations', Array, Array)
#2 /var/www/mysite.com/craft/app/fieldtypes/BaseElementFieldType.php(291): Craft\RelationsService->saveRelations(Object(Craft\FieldModel), Object(Craft\EntryModel), Array)
#3 /var/www/mysite.com/craft/app/services/ElementsService.php(1608): Craft\BaseElementFieldType->onAfterElementSave()
#4 /var/www/mysite.com/craft/app/services/EntriesService.php(176): Craft\ElementsService->saveElement(Object(Craft\EntryModel))
#5 /var/www/mysite.com/craft/app/controllers/EntriesController.php(462): Craft\EntriesService->saveEntry(Object(Craft\EntryModel))
#6 /var/www/mysite.com/craft/app/framework/web/actions/CInlineAction.php(49): Craft\EntriesController->actionSaveEntry()
#7 /var/www/mysite.com/craft/app/framework/web/CController.php(308): CInlineAction->runWithParams(Array)
#8 /var/www/mysite.com/craft/app/framework/web/CController.php(286): CController->runAction(Object(CInlineAction))
#9 /var/www/mysite.com/craft/app/framework/web/CController.php(265): CController->runActionWithFilters(Object(CInlineAction), Array)
#10 /var/www/mysite.com/craft/app/framework/web/CWebApplication.php(282): CController->run('saveEntry')
#11 /var/www/mysite.com/craft/app/etc/web/WebApp.php(836): CWebApplication->runController('entries/saveEnt...')
#12 /var/www/mysite.com/craft/app/etc/web/WebApp.php(287): Craft\WebApp->_processActionRequest()
#13 /var/www/mysite.com/craft/app/framework/base/CApplication.php(185): Craft\WebApp->processRequest()
#14 /var/www/mysite.com/craft/app/index.php(73): CApplication->run()
#15 /var/www/mysite.com/public/index.php(15): require_once('/var/www/mysite...')
#16 {main}
REQUEST_URI=/admin/entries/blog/new
HTTP_REFERER=https://mysite.com/admin/entries/blog/new

Anyone ever faced this error? is this a Craft bug?

It's not a Craft bug.

The error means that the data in your craft_relations table is out of sync with the data in the your craft_elements table.  i.e. an ID exists in craft_relations.targetId that doesn't exist in craft_elements.id or visa-versa.

How it got that way is hard to say, but here are some common causes:

Someone manually edits database data without realizing the implications.
A database was imported into a MySQL box that only supported the MyISAM storage engine, which doesn't support foreign keys, so all of the foreign keys that Craft relies on to keep data consistent between tables are silently dropped.  If this is the case, you can use https://github.com/pixelandtonic/craft-fixfks to try and restore Craft's foreign keys.
A botched import/export script.
A plugin behaving poorly.

In the context of these two tables, if you want to find all rows that have a value in craft_relations.targetId that doesn't exist in craft_elements.id, the SQL would be similar to:

SELECT * FROM craft_relations r
LEFT OUTER JOIN craft_elements e
ON r.targetId = e.id
WHERE e.id IS NULL


How to update different parts of the same Entry by different Users I'm trying to work out the best way to administer this. The point of the system I'm building is as follows:

A front-end system which contains Events, Partners and Users
Each User is associated with one Partner
Each Event allows each Partner a certain number of places (guestAllocation)
Each User must be able to log in via the front end and update the names of the people who are going to the event (limited by guestAllocation) associated with their Partner.

Structure:

Currently, SuperTable lists the Partners invited to that event and their allowed guestAllocation

At the end of all this I need to export a Guest List which should be generated by the names of people who are attending the Event (if there are missing names and spare guestAllocation, there will be default value).

What's the best way to structure this in the database? Should I have one Event that gets updated by multiple users somewhow, or an Entry for each Partner related to an Event?
Is it possible to update a single Entry by multiple Users who can only add the correct number of names to the guest list for their Partner?

Definitely multiple ways to do this but I think you're close. I wouldn't want to have multiple users hitting the same entry. Use Craft's power of relations to help here.

I'm guessing you're trying to great some kind of "rotary" or networking registration system?

You need 2 more sections: Guest Names and Guest List (name these whatever you want).

Guest Names is straightforward, it basically is going to be a list of every guest name available. You just need 1 field: the name. Craft's user ownership will take care relating this back to the User who created it and the Partner it contains.
Guest List is going to hold the master list. You need a couple more relational fields, one to relate back to tell which which event it's for (in your Events section) and another to "hold" the names of the guests attending.

Now it's just a matter of wiring it all up. You're going to want users to post to the Guest List and Guest Names sections. It's up to you how you want to handle the validation on the front end as to whether a guest already exists that's "owned" by the User.

The beauty here is also if you do multiple events and the same people attend the events, when someone registers, you can simply pull up their prior Guests and offer those up as guest choices too. Again, I'm just speculating.

When it's time to pull out a guest list, just query your Guest List section based on the Event you want, loop through the event, and grab the names for each attendee.


Merge element type errors? (title + hard-coded field) My plugin has a custom element type. The element type uses a standard "title" field, implemented by MyElementType::hasTitles() returning true.

In addition, my element type contains a few hard-coded fields. The whole plugin has been built out and working great, I'm very happy with how all of the components interact.

However, I'm trying to refine the validation of when an element is saved. It's easy to make a field required by simply adding 'required' => true when defining the field in my Record. And when a user attempts to save an element without filling in that field, the proper error message will be triggered and displayed in my template.

But here's the catch...

If the user leaves empty both the title field and my hard-coded field, only one of them will display an error message at a time. Specifically, only the hard-coded field will display the error message first. Once that has been filled in, the title error message will be triggered on the second submission.

What am I missing? Is there a specific way to merge these error messages together so that they are both returned to the template at the same time?

You can pass the element off to ContentService::validateContent() in the event that it doesn't pass the record’s validation, just to get those  errors mixed into the element as well.

if (!$record->validate())
{
    // Copy the record's errors over to the element model
    $element->addErrors($record->getErrors());

    // Might as well validate the content as well,
    // so we get a complete list of validation errors
    if (!craft()->content->validateContent($element))
    {
        // Copy the content model's errors over to the element model
        $element->addErrors($element->getContent()->getErrors());
    }

    return false;
}


Countries Field for Freeform The Freeform docs say there is a predefined option for Countries, but I do not see it anywhere in the Field types or existing fields. How does one access this? Using the latest version of both Craft and Freeform.
Thanks!

The answer: after you create a "select field", name it whatever you want - in this case country - and then add it to a form. Once you have done that, select that field within the form and edit in the properties column. Under Option Editor > Source, select "Predefined Options", then under > Target, select the option set you want, e.g. Countries, States, etc.
Seems to me that this should be part of the field creation process, rather than doing it in the form, but once you understand how to do it, it works great.


How do I control order of output using Seomatic plugin When I use the {% hook 'seomaticRender' %} tag in my template, I expected that it would output the data in the position where it's located. For example, I have the following in my template:

{% hook 'seomaticRender' %}
<meta name="msapplication-TileColor" content="#ffffff">

But when the template is rendered, the Seomatic data is output after the "msapplication-TileColor" meta tag. I don't suppose it matters much, but I like to keep a specific order for tags in my header.

I'm quite sure the answer is somewhere in the documentation, but it would be great to have a comprehensive example template.

I this for the Craft 2 version of SEOmatic, or the Craft 3 version of SEOmatic? The Craft 3 version does not have a {% hook 'seomaticRender' %} tag at all.

Instead, the metadata is automatically added where it should go to various parts of the document. I wouldn't recommend changing where this is output without a good reason, but if you really want to:

https://nystudio107.com/docs/seomatic/Using.html

Disable automatic rendering:

{% do seomatic.config.renderEnabled(false) %}

Then where you want each container's output, you'd need to manually do:

{{ seomatic.jsonLd.render() }}
{{ seomatic.link.render() }}
{{ seomatic.script.render() }}
{{ seomatic.tag.render() }}
{{ seomatic.title.render() }}

In the appropriate places in the DOM. The reason it's not recommended that you do this is that SEOmatic puts things where they should go already, and there's no real benefit in moving them around.


File upload error. Cannot upload .key (keynote) files I am trying allow users to upload keynote and powerpoint files. Powerpoint works fine. Keynote fails. I do not have any asset type restrictions in place. Why am I unable to upload asset type .key?

It looks like .key files are not included in the default allowed file extensions. But you can manually add it with the extraAllowedFileExtensions setting in your config/general.php file:

'extraAllowedFileExtensions' => 'key'


Are private S3 assets possible? Is it possible to have an asset source pointing to a non public S3 bucket? Maybe also with expiring link urls?

Private buckets can be used, but files uploaded to them via the Craft CP will be given public read access. Expiring URLs are not built into Craft because the files being public.


Plugin only saving one column in database I'm having trouble saving some data into the database with my plugin. I am able to save content only if an index is defined on that column, but only if unique=>true is set, which causes some problems because I need repeated values in column b. My function that runs after plugin install works, as I am able to save all the correct content in column A. Data is saved in column b if I set a unique index on it, otherwise the column fills with Null. Any help is greatly appreciated!

Model:

namespace Craft;

class Plugin_MyModel extends BaseModel
{
    public $a = "";
    public $b = "";

    protected function defineAttributes()
    {
        return array(
            'a' => AttributeType::String,
            'b' => AttributeType::String,
        );
    }
}

Record:

<?php

namespace Craft;

class Plugin_MyRecord extends BaseRecord
{
    public function getTableName()
    {
        return 'my_table';
    }

    protected function defineAttributes()
    {
        return array(
            'a'     => AttributeType::String,
            'b' => AttributeType::String,
        );
    }

    public function defineIndexes()
    {
        return array(
            array('columns' => array('a'), 'unique' => true),
        );
    }
}

Service that gets data from API call and attempts to save in DB:

<?php

namespace Craft;

class Plugin_MyService extends BaseApplicationComponent
{

    protected $myRecord;

    public function __construct($myRecord = null)
    {
        $this->myRecord = $myRecord;
        if(is_null($this->myRecord))
        {
            $this->myRecord = Plugin_MyRecord::model();
        }
    }

    public function saveItem(Plugin_MyModel &$model)
    {
        if ($id = $model->getAttribute('id')) {
            if (null === ($record = $this->myRecord->findByPk($id))) {
                throw new Exception(Craft::t('Can\'t find item with ID "{id}"', array('id' => $id)));
            }
        } else {
            $record = $this->myRecord->create();
        }

        $record->setAttributes($model->getAttributes());
        if ($record->save()) {
            // update id on model (for new records)
            $model->setAttribute('id', $record->getAttribute('id'));

            return true;
        } else {
            $model->addErrors($record->getErrors());

            return false;
        }
    }

    public function loadAllItems()
    {
        $items = $this->api();

        foreach($items['Items'] AS $item)
        {
            $new_item = new Plugin_MyModel();
            $new_item->a = $item['a'];
            $new_item->b = $item['b'];
            $this->saveItem($new_item);
        }
    }

    private function api(){
        //Returns API Data
    }
}

I had a similar problem, ended up using multiple setAttribute() calls instead of setAttributes().

I created an array of attributes separately and then looped through them and called setAttribute for each one, seemed to do the trick.

if ($id = $model->getAttribute('id')) {
    if (null === ($record = $this->myRecord->findByPk($id))) {
            throw new Exception(Craft::t('Can\'t find item with ID "{id}"', array('id' => $id)));
        }
    } else {
        $record = $this->myRecord->create();
    }

    /* Not this: */
    $record->setAttributes($model->getAttributes());

    /* This instead: */
    $attributes = array(
        'column1' => $col1,
        'column2' => $col2
    );
    foreach($attributes as $k => $v) $record->setAttribute($k,$v);
}


How do I display tags comma separated with "and" between the last two tags? I would like to output a tag-list like this:

foo, bar and baz

I know how to elegantly output a tag list with no comma after the last tag:

{% for tag in tags %}
    {{ tag }}{{ not loop.last ? ', ' }}
{% endfor %}

Is there a similarly elegant solution for getting the tags to display the way I want?

Not very elegant, but... :)

{% for tag in tags %}
    {{ tag.type }}{{ loop.index < loop.length-1 ? ', ' : loop.index < loop.length ? ' and' }}
{% endfor %}


amforms: display form field I'm trying to output an amform in a template that has been selected from a Form field. From the amform docs, it says:

{{ craft.amForms.displayForm('formHandle') }}

My matrix fieldname is called myFormField:

so:

{{ craft.amForms.displayForm('{{block.myFormField}}') }}

But it doesn't look like craft is parsing {{block.myFormField}}:

No form exists with the handle “{{block.myFormField}}”.

Any thoughts?

Solution:

{% if block.myFormField|length %}
    {{ block.myFormField.first().displayForm() }}
{% endif %}


Does a Craft Editor's Guide exist? I'm just coming over to Craft from Other CMSes Which Shall Not Be Named. Something I typically do for clients is create custom videos showing how to use the CMS. Now that I'm diving into Craft I'm thinking about creating a general Editor's Guide to show all the nice features of this lovely CMS. (realizing that Craft will be customized to each site's needs)

I've looked around and haven't yet found any similar attempt at showing Craft from an editor's perspective. Do you know of one?

The Features section on the Craft site already has some useful videos that may be of interest:

https://buildwithcraft.com/features/matrix


Query to find users who are in more than one user group I'm working with a site that has a few thousand user accounts. With the exception of core accounts with CP access, each user account exists for the purpose of access to event URLs which eventually expire.
But, although the vast majority of users belong to only one event-specific user group, a select few belong to more than one.
For the purposes of housekeeping, I'd like to be able to easily find such user accounts, so I can exclude them from a periodic account deletion process.
What query could serve this purpose for a report of multi-user-group users?

If you're looking for a SQL query (as opposed to an element query), then you can use this:
SELECT userId FROM craft_usergroups_users GROUP BY userId HAVING COUNT(*) > 1;

This only gets the userId.


Custom Shipping Method Availability in Commerce - User Messages I have multiple custom shipping methods, each with rules which determine whether or not they will be available to the user. Basic things like minimum order cost and their address which would determine if a certain shipping method is available.

There are some scenarios where a shipping method wont be available and the reason could depend. I need to be able to tell the user what exactly caused it to be unavailable.

So for example:

public function matchOrder(\Craft\Commerce_OrderModel $order){

    // If this is true, do not enable shipping method.
    if($scenario_1) { return false; }

    // If this is true, do not enable shipping method.
    if($scenario_2) { return false; }

    return true;

}

In the event that one of those is true, the shipping method is not available to the user. On the shipping page, I can check if it is enabled or not like this:

{% if 'myShippingMethod' not in craft.commerce.availableShippingMethods|keys %}{% endif %}

But that only does me good in simply whether or not it's available - not for knowing why it isn't available. Is there a way I could somehow 'pass' information to the templates for the shipping methods that didn't return true? That way I could tell user "This shipping method isn't available because of $scenario_1" or "This shipping method isn't available due to $scenario_2."

Does this make sense? Trying to think of a good way to go about this. Any thoughts about how I should go about this would be super appreciated.

100% untested, but I think one way to go would be to use addError on one of the Commerce_OrderModel's attributes (in the defineAttributes method).

Then your template could do something like:

{% if 'myShippingMethod' not in craft.commerce.availableShippingMethods|keys %}
    {% for error in order.getErrors('theAttribute') %}
        {{ error }}<br />
    {% endfor %}
{% endif %}


Is it possible to create a 3 month membership instead of a subscription using Charge 2 for Craft CMS? Here is the scenario: I'm trying to create a gift membership subscription for 3 or 6 months of site access that you can send to somebody. Since the most common scenario is that someone else will be paying & sending this to someone as a gift, we obviously don't want the charge their card again at the end of the period, and the membership access should end unless they update their card details & renew with one of our regular subscription plans.

Charge 2 handles subscriptions (which recurring by definition) and it also handles 1-off charges. It's well documented how to create a membership site that is tied to subscriptions. What I’m trying to figure out is how to provide 3 or 6 months of membership, that does not renew at the end.

The Subscription Model offers planInterval and planIntervalCount, but I don't see an option for something like 'endAfterCount' or something similar.

The one-off charges (1 time charge of $39 for 3 months of access, for example) I don't think have a time interval attached to them.

I feel like I'm probably missing something obvious here... any help is greatly appreciated.

You could have them make a one-time payment, then generate a gift code that can be redeemed when a user fills out the subscription payment form.

I did that by creating a plugin and utilizing the charge.onCharge event, it makes sure it was a gift code purchase, then generates a code that is stored in the charge's coupon code table and you can either have it send an email with the code to person who is to redeem it or just display it on the screen.


Commerce & PayPal - What does "Solution Type" mean? Our site is using the Craft Commerce plugin, and within that we've enabled the PayPal Express gateway. However, there is a very cryptic dropdown menu on the gateway settings page...

So my question is, what is the "Solution Type"?

What does that even mean? And what is the difference between the "Sole" and "Mark" options?

Ignore the terminology, it really makes no sense. What it should say is this...

Require customers to use a PayPal account?

[Sole] No, a PayPal account is optional. Customers can still choose to pay with a credit card instead.
[Mark] Yes, a PayPal account will be required to complete a purchase.

Here's a screenshot of the documentation...

So why did PayPal decide to call this particular choice "Solution Type"?

And what do "Sole" and "Mark" actually mean?

The world may never know.


Displaying gallery when viewing category page or entry with related categories - code review I have a gallery in my site's  with images that are defined in a matrix field on each of my categories. If I'm viewing a category page or an entry with related categories I want to display this image gallery in the footer.

What I currently have is this:

{% if category is defined %}
    {% if category.actionBilder.exists() %}

            {% for block in category.actionBilder.limit(3).orderBy('RAND()').all() %}
                {% if block.type == "actionImg" %}

                {% endif %}
            {% endfor %}

    {% endif %}
{% endif %}

{% if entry is defined %}
    {% set categories = craft.categories.relatedTo(entry) %}
    {% for category in categories %}
        {% if category.actionBilder.exists() %}

                {% for block in category.actionBilder.limit(3).orderBy('RAND()').all() %}
                    {% if block.type == "actionImg" %}

                    {% endif %}
                {% endfor %}

        {% endif %}
    {% endfor %}
{% endif %}

While it's working fine, I don't think that this is the best solution.

How would you change my code to make it better?

Some "problems" I see with your solution:

You're repeating yourself twice there - it would be much better if you had your actionBilder loop in there only once. When writing code, try to use the DRY principle: Don't Repeat Yourself (obviously exceptions to that rule but this is one case where you could simplify).
Not sure why exactly you're using exists() to check you matrix block's presence. I've actually never seen that method in use before and had to look it up to see what exactly it does. Based on the docs, looks like you would use it to check if there are any related categories (but don’t need to fetch them). But like I said, I've never heard of exists() so could be I'm wrong... Fwiw, here's a great answer by Brandon Kelly on what you should use to check if a field is empty or non-existent.
This may not be a problem in your current setup but at the moment you're fetching three blocks from your matrix field and only displaying them if they are a particular type. This means if you were to ever add another block to your matrix you could end up with two, one, or even no images at all (because the three blocks you queried for are all of a different type). It would be better to grab three blocks of that particular type and then loop through them.

Here's what I'd recommend doing:

{# are we dealing with an entry page? #}
{% if entry is defined %}

    {# if so we create an array of related categories #}
    {% set categories = craft.categories.relatedTo(entry) %}

{# otherwise we'll check if this is a category page #}
{% elseif category is defined %}

    {# if so we create an array with our one category #}
    {% set categories = [ category ] %}

{% endif %}

{# make sure we actually have categories in the array #}
{% if categories | length %}

    {# start the `for` loop #}
    {% for category in categories %}

        {# does the matrix field exist and does it contain any blocks? #}
        {% if category.actionBilder | length %}

                {# get 3 `actionImg` blocks randomly #}
                {% for block in category.actionBilder.limit(3).type('actionImg').orderBy('RAND()').all() %}

                    {# get the block's first image's url #}

                {% endfor %}

        {% endif %}

    {% endfor %}

{% endif %}

Hope that's helpful!


If loop contains id `X` Is it possible to check a matrix array for an ID?

I created a entries field which functions as a navigation.
Now if the user decides to remove one entry I want the specific template to return a 404

I thought something like (Assuming we are in the "Journalismus" template):

{% for navi in navigation.navi %}
    {% if '4' not in navi.id %}
        {% exit 404 %}
    {% endif %}
{% endfor  %}

But that does pass the 404 always.

Or is there a better way to do this?

{% if '4' not in navigation.navi.ids() %}
    {% exit 404 %}
{% endif %}


Can you relate entries from more than 1 section? Can you relate an entry to entries in two or more different channel/sections?

Yes, you can. When creating an entires field the Sources option is where you select which sections you'd like to be able to select entries from. See Entries Fields in the docs.