What's the best approach to building a photo gallery in Craft? I'm thinking about the best way to implement a photo gallery in Craft.

A channel section with an assets field should do the job, but would like to hear how other devs have approached this problem.

Craft is so flexible there are many ways to do most things, it is up to you to determine what is best for your needs.

As far as photo galleries go, there are two main ways that I normally approach this:

Method 1:

Define asset fields for the images, where you define the photo title and description, etc.  These fields are accessed by double clicking the image, which will pull up a form with the fields you have defined.  This method associates these fields directly to the assets themselves, and the data will be available site-wide, not just in the gallery.

While this is simplest to code, it does have the drawback that clients will often skip over the asset fields and add images to the gallery that have not been assigned all of the data needed for the gallery.

Method 2:

Use a matrix block to define the gallery and create matrix fields for the assets and associated fields.  This is much easier for clients as they can see each bit of data they need to enter, and you can even make the fields required so they do not avoid entering them.

While much simpler for the client, this method does has several drawbacks. First, the data entered into the matrix block will only be available in the context of the gallery and not anywhere else in the site. Second, a gallery built from matrix blocks can become quite lengthy in the back end and take up a lot of space on the edit page. And lastly, this method is a bit more complex to code than just a simple assets loop. Once you get the hang of it it is no biggy, but you will need to work through nested matrix/asset loops the first time.

Here is the code I use for a very simple matrix based gallery w/o titles or descriptions, best of luck :)

{% set vertParams = {
  height: 800,
  mode: 'crop',
  position: 'center-center',
}
%}
{% set horzParams = {
  width: 800,
  mode: 'crop',
  position: 'center-center',
}
%}
{% set thumbParams = {
  width: 120,
  height: 120,
  mode: 'crop',
  position: 'center-center',
}
%}
{% set images = contentBlock.galleryImages %}
{% if images | length %}
  {% if contentBlock.galleryTitle | length %}

{{ contentBlock.galleryTitle }}

  {% endif %}

    {% for image in images %}

      {% if image.getHeight() > image.getWidth() %}

      {% else %}

      {% endif %}

    {% endfor %}

{% endif %}


How do I adjust the page title for different Section and Entry pages? Inside the default template that comes installed with Craft, the title of a page is set as:

<title>{% if title is defined %}{{ title }} - {% endif %}{{ siteName }}</title>

This works perfectly for the homepage and on pages where the {{ title }} variable is set. However for individual entries inside a channel, only the site name is used for the title.

I've tried to use the {{ entry.title }} variable instead, however in that case the title of the homepage is rendered as 'Homepage - {{ siteName }}'.

What's the best way to achieve the following page titles for the different sections?

Homepage: {{ siteName }}
Page: {{ title }} - {{ siteName }}
Entry: {{ entry.title }} - {{ siteName }}

The title var can be set in the child templates, that way you can fine-tune it for each section of your site.

Take a look at these default templates:

news/index.html:

{% set title = "News" %}

news/_entry.html:

{% set title = entry.title %}

_layout.html:

The main layout just checks if it has been defined or not:

{% if title is defined %}{{ title }} - {% endif %}{{ siteName }}

.

P.S. Embed templates might be confusing at first, but are really great, check out the docs.


Twig issue with divisibleby() First sorry for my bad english.

What i want to do: display comments on a page, one at the right one at the left.

My code look like this:

{% for i in 0.. NbComment %}
   {% if  (i is divisibleby(2)) or (i == 0) %}

       <!--Right comment-->

   {% else %}

       <!--Left comment-->

   {% endif %}
{% endfor %}

It works perfectly except when I only have one comment: it display nothing.
Thanks for your help.

Instead of divisableby I think using Twig's built-in odd/even test might be easier in this case:

{% for i in 0.. NbComment %}

   {% if i is odd %}

   {% else %}

   {% endif %}

{% endfor %}

And, just to suggest some minor improvements to your Twig, assuming the only difference between your comments is their alignment (left/right), you could do something like this, which would probably be a bit more DRY:

{% for i in 0.. NbComment %}

{% else %}

No comments to display

{% endfor %}

With the above code, your comments will have either the class .is-odd or the class .is-even – making it easy to e.g. float comments either left or right in your CSS. There's really no need to have a full if/else conditional.

Also, note the {% else %} statement in the above for loop. The contained markup will output if there are no comments – which is good practice, and will save you yet another conditional :)


Deleting unused tags Tags are used to categorize blog post topics.

How can I delete or manage unused tags?

For example, one user created a "Success Factors" tag and another created a "SAP SuccessFactors" tag. The goal is to remove one of these to keep the categories tight.

There currently isn't any Tag management in Craft, but if you think there should be, consider voting for this feature request.

In the meantime, there is a 3rd party plugin called Tag Manager that will let you delete tags, although it won't show you which ones aren't in use.

There is a help article that shows how to select all of the tags that are in use.  From there you could diff it with the full tag list to see the ones that aren't in use.


How can I select channel index/root pages from an Entries Field Type? This seems like a somewhat overlooked feature. When I use an "Entries" field type with "All" sources selected. I don't have the option to select the root link for any of the channels. I can select the individual entries for the channels, just not the actual channel itself.

Is this intentional? Or is there a way to include channel index pages as a selectable option too?

Having thought about it a bit more, this doesn't really make much sense. Obviously the entries will only link to... entries. I got a little confused as to why it also allowed me to select "single" pages.

I still think it's worth including the option to add channel index/root pages. In the meantime, because I'm using this as a crude navigation maker, I've just created an additional single section. I then directed the Entry Template to the same directory as the index.html page. This then gives me the option to add it in my entry field, without messing any links up.


List most recent items combined from Channel and Structure sections If we pass through an array of Channels & Structure sections we find that Channels entries tend to be listed first. So the first 15 will comprise of ChannelOne and ChannelTwo and then start listing the Structure section.

{% set homepageEntries = craft.entries({
    section: ['channelOne','StructureOne',channelTwo','StructureTwo'],
    limit: 15
}) %}

{% for item in homepageEntries %}
{{ item.title }}
{% endfor %}

All we want is a list of the 15 most recent items from a number of sections.

It does not look to be as straightforward as it seems. Creating multiple arrays of ids and merging still seems to produce the same results.

I was presuming that the default Order for Channels and Structure was postDate desc. But it turns out the default for Structure is sortOrder

{% set homepageEntries = craft.entries({
    section: ['channelOne','StructureOne',channelTwo','StructureTwo'],
    order: 'postDate desc',
    limit: 15
}) %}

Explicitly stating the order seems to fix this issue


Changing Content-Type on Sprout Forms custom endpoint I'm using Sprout Forms 3.3.7 and have created a custom endpoint integration to post the form data to Pardot. The integration fires successfully, but Pardot was rejecting the request.

I used Guzzle Middleware to inspect the request (right around here https://github.com/barrelstrength/craft-sprout-forms/blob/v3/src/integrationtypes/CustomEndpoint.php#L83) and it tells me that the Content-Type is application/json but Pardot only accepts application/x-www-form-urlencoded.

Is it possible to change the Content-Type when using a custom integration? Either in the CP or in the form.twig code?

The Custom Endpoint integration currently is sending JSON as the request, but we could consider adding additional options there. I've opened a Feature Request if you'd like to add any more details there:
https://github.com/barrelstrength/craft-sprout-forms/issues/319

In general, the Custom Endpoint is best used when you control the other end of the request and control how you are receiving the data there. While it's possible that the Custom Endpoint can work with specific platforms, there may be several other considerations that will need to be addressed as you work toward a successful request such as authentication and the format of the fields being sent in the request - and in several cases, it may not be possible at all with the default settings or may require some additional configuration updates to get those things working.

For integrations with a specific platform that may require specific settings, it's Sprout Forms does have an Integrations API where you can add your own custom Integration for an editor to select and use.

In your case, that could mean that you create a Pardot Integration, configure your Pardot API credentials within your Craft and Integration module settings, and have the integration call out to the Pardot API to present the user fields or options that are retrieved from your Pardot account directly.


Fetch Craft Commerce purchasable element type How should I retrieve a purchasable element criteria in Craft Commerce ?

To get entries, I just do

craft()->elements->getCriteria(ElementType::Entry);

I have tried the following without any success to get purchasables

craft()->elements->getCriteria(ElementType::Purchasable);
craft()->elements->getCriteria(ElementType::Purchasables);
craft()->elements->getCriteria(ElementType::Product);

By default, Commerce only provides 3 custom element types to Craft... products, orders and variants.

My guess is you're looking for products, in which case the syntax you're looking for is:

$productsCriteria = craft()->elements->getCriteria('Commerce_Product');


Is there a way to programatically add a user when no one is logged in In my controller, I can add new users when a user with the right privileges is logged in via craft()->users->saveUser(), but this doesn't work when no user is logged in.

Is "users/saveUser" the only service method I can use? I would prefer to be able to use my custom one.

EDIT:
code below works fine when I'm logged in as an admin user, otherwise it redirects me to login form, after form submission. Have I missed something in here?

public function actionAddPartner()
{
        $content = craft()->request->getPost();
        $companyId = explode("@", $content['email']);
        $user = new UserModel();
        $user->username         = $content['email'];
        $user->email            = $content['email'];
        $user->unverifiedEmail  = $content['email'];
        $user->firstName        = $content['firstName'];
        $user->lastName         = $content['lastName'];
        $user->pending          = true;
        $success = craft()->users->saveUser($user);
        if ($success) {
            // Assign them to the Partner Admin user group
            craft()->userGroups->assignUserToGroups($user->id, 1);
            // Update the Element Index
            craft()->search->indexElementAttributes($user);
        }
}

Oh well, totally forgot to allow anonymous access at the top of the controller.
I guess I can leave this answer here in case somebody is as forgetful as me:

protected $allowAnonymous = true;


.dev local development I'm getting SSL errors when developing using .dev as a domain name. I believe it's because browsers are now automatically forwarding these to HTTPS://.

Any ideas how to get around this with Craft? I can change the extension but Craft requires .dev for local development I believe.

This seems missing from the other answers, so I feel the need to emphasize it here...

Craft does not require .dev for local development.

Your local URL can be anything you want, Craft does not care. There is no requirement whatsoever on using a .dev domain. That being said, it is recommended that you use a "dev-sounding" URL, in order to avoid the licensing nag warning. And even if you're getting the warning, it won't have any negative impact on the capabilities your site.

The other answers already address what to do if you do use a .dev URL, so I won't cover it here. You may also want to read this helpful answer on a related question.


Get entries by month, but not restricted by year I'm building a calendar functionality and I need to get entries by month, but they cannot restricted by year (as, for example, the calendar might have entries that fall on both Jan 2017 and Jan 2018).

At the moment, I'm doing a for loop and incrementing to get the next 5 years:

{% set categoryParam = craft.request.getParam('month') %}

{% if categoryParam %}
  {% set allDates = [] %}

  {% for i in 0..5 %}
    {% set year = now|date('Y') + loop.index0 %}
    {% set combinedDate = '1970-' ~ categoryParam ~ '-01' %}

    {% set startDate = year ~ '-' ~ combinedDate|date('m') ~ '-01' %}
    {% set dayCount = startDate|date('t') %}
    {% set endDate  = year ~ '-' ~ combinedDate|date('m') ~ '-' ~ dayCount %}

    {% set courseDates = craft.entries({ section: 'courseDates', limit: null }).order('courseStartDate').courseStartDate('and','>= ' ~ startDate, '<=' ~ endDate) %}

    {% for courseDate in courseDates %}
      {% if courseDate not in allDates %}
        {% set allDates = allDates|merge([courseDate]) %}
      {% endif %}
    {% endfor %}
  {% endfor %}

{% else %}
  {% set allDates = craft.entries({ section: 'courseDates', limit: null }).order('courseStartDate').courseStartDate('and','>= ' ~ now) %}
{% endif %}

I'm just wondering if there is a better way of doing this that doesn't rely on the year?

I think a better way would be to add a Preparse field to your Course Dates’ field layout that stores only the month.

https://github.com/aelvan/Preparse-Field-Craft

The code for the preparsedMonth field.

{{ entry.courseStartDate|date('m') }}

With that in place you can drastically simplify your template code and reduce database queries.

{% set categoryParam = craft.request.getParam('month') %}

{% set allDates = craft.entries({
    section: 'courseDates',
    courseStartDate: '>= ' ~ now|date('c'),
    preparsedMonth: categoryParam ? '%02d'|format(categoryParam) : null,
    order: 'courseStartDate',
    limit: null,
}) %}


Getting adjustment amount in a plugin I need to get the amount of a discount from orders to write that data into a json file (on EVENT_AFTER_COMPLETE_ORDER) which then will be consumed by an inventory management system and now am stuck with discount amounts. Currently I have:

"price": ' . $order->adjustment->one->type('discount')->amount . ',

which does not work. Could anyone help on how to do this and maybe point me to the documentation where I could read up on it?

Thanks
m

Got it:

"price": ' . $order->totalDiscount . ',

^^


The requested URL was not found on this server. Apache/2.4.18 (Ubuntu) Server at localhost Port 80 The frontend just work fine. But when I call the backend http://localhost/craft3/web/admin/dashboard/ or http://localhost/craft3/web/admin/ I get the error
requested URL was not found on this server.
Apache/2.4.18 (Ubuntu) Server at localhost Port 80.
The admin-folder doesn't exist in web-folder.
I searched here for this problem, but they had problem with frontend.

This worked just fine.
https://craftcms.stackexchange.com/a/35846/10953
I did all steps execpt steps 3. and 4.
Thanks all!


How to use a global variable in a conditional statement if an entries relation field is empty? {% if entry.fieldHandle %}
  {{ entry.fieldHandle}}
{% else %}
  {{ global.fieldHandle}}
{% endif %}

Doesn't seem to be rendering for me. The entry field shows up when it's true, but the global field doesn't in the cases it needs to.

The reason it wasn't rendering is because my original entry field is an Entries Field (see templating examples in the docs). The relationship fieldtypes (Entries, Assets, Users) require that you include the length filter in your conditional like so:

{% if entry.fieldHandle |length  %}
  {{ entry.fieldHandle}}
{% else %}
  {{ global.fieldHandle}}
{% endif %}

Thanks to Keith Mancuso @keithmancuso for the fix!


I am unable to render new entries on the browser (demo version) I just started using craft and am still exploring the Happy Lager demo version. I can create new sections, fields and entries. However, when I try to render the entry on my browser by clicking on the globe icon, the URL takes me to "Page not found" error.

Am I not allowed to create new entries on the demo? or am I missing something?

I figured it out. I went with the default template file which did not exist, hence the error.


How to get rendered image paths from the ElementAPI? I'm wanting to return HTML content via the ElementAPI. I seem to be able to do this with the following elements.php:

'endpoints' => [
    'api/trials.json' => [
        'elementType' => 'Entry',
        'criteria' => ['section' => 'trials'],
        'transformer' => function(EntryModel $entry) {
            return [
                'summary' => ($entry->summary ? $entry->summary->getRawContent() : false),
                ...
            ];
        },
    ]
]

It's just that the getRawContent() returns the following in the JSON:

"summary": "
<img src=\"{asset:46:url}\"…

When I'm expecting:

"summary": "
<img src=\"/images/myimage.png"…

Should I be using a different method to get to the content, or do I need to run the content through some kind of transformation?

Thanks in advance,

James

Rather than calling getRawContent(), just explicitly cast your Rich Text field data into a string:

'summary' => ($entry->summary ? (string) $entry->summary : false),


Display entries for each month I created html template using radio buttons as tabs as you can see in the picture. When user click on any of the tabs the relevant entries for that month display and the rest hidden.

I created matrix field to group the calendar field and other text fields but my question is how to dynamic display all entries for each month? So that I can use CSS to hide other entries and show entries when tab are selected.

You could do this multiple ways.

One you could create a category with each month and an input for your entries and assign that month to each category.  Then it would be a matter of calling that categories relatedTo param using each Month Category ID.

{% set monthIds = craft.categories.group('months').ids() %}

{% for monthId in monthIds %}

        {# group each months entries #}
        {% for item in craft.entries.section('sectionName').relatedTo({targetElement:monthId}) %}
            {# content for each entry. #}
        {% endfor %}

{% endfor %}

Two you could use your eventStart field.

{# 1 == January #}
{% set months  = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"] %}
{% for month in 1..12 %}

        {# group each months entries #}
        {% set idx = month - 1%}

{{ months[idx] }}

        {% for item in craft.entries.section('blog') if item.eventStart|date("n") == month %}
            {# content for each entry. #}

{{item.title}}

        {% endfor %}

{% endfor %}


Error clearing a field via migration script I'm using a migration script to clear out the values for a field on one of my entries. The field is an Entry Field and is not required.

So I do this:

$product->components = [];
Craft::$app->elements->saveElement($product);

But I get this error:

  Argument 1 passed to craft\fields\BaseRelationField::_all() must
  implement interface craft\elements\db\ElementQueryInterface, array
  given, called in
  /var/www/html/vendor/craftcms/cms/src/fields/BaseRelationField.php on
  line 382

I can clear out other fields, even entry fields, just fine. But this particular one gives me this error every time.

I've also tried the following:

$product->components = null;
Craft::$app->elements->saveElement($product);

And:

$product->components = false;
Craft::$app->elements->saveElement($product);

Any ideas?

I figured it out. I'm not sure understand the why of it. But here is the how:

$product->setFieldValue('components', []);
Craft::$app->elements->saveElement($product);

I guess setFieldValue() does some other stuff in it that the magic methods do not.

The more you know! :)


Register custom REST routes while building a plugin for Craft 3 I am building a custom plugin for Craft and I am hitting some REST APIs in my backend service to fetch some data using Ajax calls in JS. What I would like to do when the AJAX calls complete and come back with data, is to store some data in Craft. I know I can use projectConfig to store and retrieve plugin based data and settings but how to call those Craft functions through my JS files. The way I figured is to call it using REST routes that I can define via my plugin.

But I am not sure how to register routes using my plugin and how to setup controllers for the same.

Main plugin file:

Event::on(UrlManager::class, UrlManager::EVENT_REGISTER_CP_URL_RULES, function(RegisterUrlRulesEvent $event) {
            $event->rules['poptin/signup'] = 'poptin/default/signup';
        });

DefaultController.php

<?php
/**
 * poptin plugin for Craft CMS 3.x
 *
 * Create advanced website popups and forms, and improve your website's conversion rate within a few minutes.
 *
 * @link      poptin.com
 * @copyright Copyright (c) 2020 Poptin
 */

namespace poptin\poptin\controllers;

use poptin\poptin\Poptin;

use Craft;
use craft\web\Controller;

/**
 * Default Controller
 *
 * Generally speaking, controllers are the middlemen between the front end of
 * the CP/website and your plugin’s services. They contain action methods which
 * handle individual tasks.
 *
 * A common pattern used throughout Craft involves a controller action gathering
 * post data, saving it on a model, passing the model off to a service, and then
 * responding to the request appropriately depending on the service method’s response.
 *
 * Action methods begin with the prefix “action”, followed by a description of what
 * the method does (for example, actionSaveIngredient()).
 *
 * https://craftcms.com/docs/plugins/controllers
 *
 * @author    Poptin
 * @package   Poptin
 * @since     1.0.0
 */
class DefaultController extends Controller
{

    // Protected Properties
    // =========================================================================

    /**
     * @var    bool|array Allows anonymous access to this controller's actions.
     *         The actions must be in 'kebab-case'
     * @access protected
     */
    protected $allowAnonymous = ['index', 'signup'];

    // Public Methods
    // =========================================================================

    /**
     * Handle a request going to our plugin's index action URL,
     * e.g.: actions/poptin/default
     *
     * @return mixed
     */
    public function actionIndex()
    {
        $result = 'Welcome to the DefaultController actionIndex() method';

        return $result;
    }

    /**
     * Handle a request going to our plugin's actionDoSomething URL,
     * e.g.: actions/poptin/default/do-something
     *
     * @return mixed
     */
    public function actionSignup()
    {
        $result = 'Welcome to the DefaultController actionSignup() method';

        return $result;
    }
}

I see this error:

Your code is almost there, Craft allows registering routes for the Control Panel and the front-end of the site. You need to change EVENT_REGISTER_CP_URL_RULES to EVENT_REGISTER_SITE_URL_RULES.

You are listening for an event on EVENT_REGISTER_CP_URL_RULES which will only register routes inside the control panel. This is useful for plugins that want to add controllers for settings and custom logic.

  The event that is triggered when registering URL rules for the control panel.

https://docs.craftcms.com/api/v3/craft-web-urlmanager.html#events

However, in the scenario where access is needed outside of the control panel, Craft triggers the EVENT_REGISTER_SITE_URL_RULES. This allows access for users that do not have control panel access (e.g. site guests and regular users).

  The event that is triggered when registering URL rules for the front-end site.


Entry Search Unbearably Slow Anyone have any tips on speeding up entry searches? Ours are currently taking about 90 seconds per search.

Some stats about our Craft database:

Entries: 336,000
Relations: 4,390,000 (!!!)
Search Index Records: 320,000

It used to be fast. But the more data we get into it, the slower it goes. It's basically unusable now. We removed indexing on every field except for title, slug and item number. But that didn't help much.

Nothing to see here. We had a corrupt index.

Running this command in the DB brought our searches down from 90 seconds to 1 or 2 seconds. I'd still love it to be faster. But we can live with 2 seconds:

optimize table searchindex;


Do 404s get access to variables set with setRouteVariables? I have a plugin with nothing but the following in the init() method other than the basics (just for testing purposes):

craft()->urlManager->setRouteVariables(array(
    'foo' => array('bar' => 'baz')
));

From all of my routes I can access this just fine. It's working for static templates, dynamic entries, etc. To access it I'm using the following code in my main base template /_layouts/base.twig:

{{ foo.bar }}

The output is as expected: baz

However, I cannot access this from a page that does not exist, i.e., a 404. If I go to my-site.com/doesnt-exist I receive the following:

Twig_Error_Runtime

Variable "foo" does not exist in "_layouts/base" at line 1

My 404 template is extending base as well.

What am I doing wrong?

It's probably worth noting that the reason I'm trying to do this is because I want to include a form on the 404 page (that I also include in other areas, so it's setup as a partial) and I'm having trouble passing error validation back and forth with setRouteVariables, but only for 404 pages. I know I could do this with a session and that is my current work around, but I wanted to see if there was a better way.

The simple answer is: no, error handling templates don’t have access to the variables that would be available to the template when the request resolves normally. And we won’t be making it possible.

Technically you could get access to them by creating a plugin that has a template hook which is capable of adding those variables:

craft()->templates->hook('mergeRouteVariables', function(&$context)
{
    $routeParams = craft()->urlManager->getRouteParams();

    if (isset($routeParams['variables']))
    {
        $context = array_merge($context, $routeParams['variables']);
    }
}

404.html:

{% hook "mergeRouteVariables" %}
{# ... #}

  It's probably worth noting that the reason I'm trying to do this is because I want to include a form on the 404 page (that I also include in other areas, so it's setup as a partial) and I'm having trouble passing error validation back and forth with setRouteVariables, but only for 404 pages. I know I could do this with a session and that is my current work around, but I wanted to see if there was a better way.

While I understand your use case, it's pretty weird that you would have a form that intentionally submits to a 404 page (even though it’s the same page).

Here are a couple alternatives you might want to consider:

You could create a dedicated page for the form, and have the form submit to that page’s URL in the event that it’s coming from a 404.
You could handle the form submission and validation with Javascript/Ajax.


Simple Craft htaccess Help I have a Craft site where I need to redirect any traffic to www (including dev.lakesideohio.com). The rule seems to be working but for some reason the url gets changed to using index.php with query string which I am not using.

For example https://mysite.com/news goes to https://www.mysite.com/index.php?p=news/ instead of https://www.mysite.com/news.

<IfModule mod_rewrite.c>
RewriteEngine On

# Redirect to www
RewriteCond %{HTTP_HOST} !^www\.mysite\.com$ [NC]
RewriteRule ^(.*)$ https://www.mysite.com/$1 [R=301,L]

# 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]

Check out: Removing “index.php” from URLs


Is there a way to filter calendar results by location? My current calendar plugin has filters by category, location and a date selector. Is this all achievable in solspace calendar?

Yes, you can achieve this by using the search parameter on calendar.events just like you would with regular Craft Searching.
search: "customField:myvalue*"

It might also look something like this in your template:
{% set eventOptions = {
  rangeStart: 'now',
  rangeEnd: '3 months',
} %}

{% set events = craft.calendar.events(eventOptions).search("location:test") %}

{% for event in events %}
   ...
{% endfor %}


Hook into rendered templates? I am hoping to write a plug-in to cache pages as static HTML. Is there a hook that would give me access to the full rendered HTML of a page?

Currently, no.  But it is on our radar and we've got some ideas on how we'd want to implement it.


How can I install modules with Composer? Installing a Craft 3 plugin via Composer is pretty simple. You require the package, update Composer, and install it via the CMS.

My circumstances require that our company use a private Module on all projects. But installing the package via Composer always puts the Module into the default vendor directory.

So how can I install a module into the modules folder?

Craft Plugins require that a "type":"craft-plugin" property is defined in each composer.json file. Composer refers to this to help manage and install the plugin. Craft Modules do not currently have this support.

You can see all package types that Composer Installer supports here. There is still a way to achieve what you're trying to do though...

Composer Installers Extender allows you to create your own custom package type. So we could create craft-module ourselves. Just make sure your module has this "type":"craft-module" in it's composer.json

Now we can define some extra settings that tell Composer to put the modules into the modules directory. Incorporate the following into your projects composer.json file:

"require": {
  "oomphinc/composer-installers-extender": "^1.1",
  "vendorname/modulename": "dev-master"
},
"autoload": {
  "psr-4": {
    "modules\\": "modules/",
    "modules\\modulename\\": "modules/modulename/module/"
  }
},
"extra": {
  "installer-types": ["craft-module"],
  "installer-paths": {
    "modules/{$name}": ["type:craft-module"]
  }
},

Note: Make sure your module no longer exists in your vendor directory as you may be hit with some potential conflict warnings.


How do I setup a password administration workflow using setPasswordPath and a forgot password page? I have a couple of issues regarding administering users passwords from the front-end of my site.

Firstly, I'm trying to implement the Set Password form as listed at https://craftcms.com/docs/templating/set-password-form.

I have created a single pointing to the path specified in the setPasswordPath config entry, using a template containing the above form. However, when I navigate to the setPasswordPath page it is erroring saying that 'Variable "code" does not exist'. When I remove the hidden code field, the id variable errors in the same way.

Secondly, the forgot password form listed at https://craftcms.com/docs/templating/forgot-password-form works great, except for when the user navigates to the link in the e-mail, and then enters their new password, they are redirected the Craft dashboard login, which a lot of the end users should never really see. Is it possible to redirect people  to my home page login form on the front-end?

The form that lives at setPasswordPath assumes that the user arrived there by clicking on the link in the validation email that was sent to the provided email address.  That link includes a code=somelongid querystring parameter in the URL that the form is looking for.

If you're just loading that URL directly, then you'll get the "Variable 'code' does not exist" error.  You could always do something like this to guard against it:

{% set code = craft.request.getParam('code') %}

{% if not code %}
    {% exit 503 %}
{% endif %}

Regarding the forgot password form, upon successfully setting their new password, Craft will check to see if the user has control panel access.  If they do not, it will check the setPasswordSuccessPath config variable and redirect there.  If they do, Craft will send them to the dashboard (which will redirect to the login page if you don't have autoLoginAfterAccountActivation set.


Loading specific products I have lots of products and I want to filter them a certain way.
I want to retrieve all products that have stock = 1 or where product.myField = checked.

I don't know how to do this exactly. This is what I have for now

{% for prod in craft.commerce.products({
    search: 'myField:0 or hasVariant:{hasStock:true}'
}).type(myType).order(sort ~ ' ' ~ order).limit(35) %}

Thanks in advance!

I haven't tried Commerce myself but I think something like this should work:

{% set products = craft.commerce.products.type(yourType) %}

//make an empty array
{% set filteredProducts = [] %}

{% for entry in products %}
    //check for your conditions
    {% if (entry.checkboxFieldhandle) or (entry.hasStock) %}
        //add each entry to your products array
        {% set filteredProducts = filteredProducts|merge([entry]) %}
    {% endif %}
{% endfor %}


How To Accept Payments By Check I have a client that will only be accepting payments by check at this time.  It is a larger company that has same clients and they bill the client and check is mailed.  However they want to be able to take orders online and I really wanted to try Craft Commerce.  What I need to do is somehow bypass the payment step.  I would like to be able to send them an invoice, but not one that says paid.  Any suggestions.

A pure ghetto method would be to just go into the pdf template and remove the "paid" markup.

I can't remember off hand, but I think it is just a div. Inspect the element to find the hook (id, class). Then either comment out the css rules or remove that element.

EDIT

It looks like this is the file you need to modify:

/craft/templates/commerce/customer/order.html


Setting the position of a Smart Map marker on the front end I'm using Smart Map in a front end entry form and trying to set the position of a marker as the user enters their address.
I can get the lat/lon lookup working but I'm stumped with the marker itself.
Here's my JavaScript that's doing the lookup and filling in the lat/lon
$.post('/actions/smartMap/lookup', data, function(response) {
    if(response.status = 'OK'){
        // get lat/lng and populate hidden fields
        $('.js-address-lat').val(response.results[0].geometry.location.lat);
        $('.js-address-lng').val(response.results[0].geometry.location.lng);

        // update map (add marker)
        smartMap.map['smartmap-mapcanvas-1'].setOptions({styles: styles});

        var lat = parseFloat(response.results[0].geometry.location.lat);
        var lng = parseFloat(response.results[0].geometry.location.lng);
        var newLatLng = new google.maps.LatLng(lat, lng);

        smartMap.marker['smartmap-mapcanvas-1.{{ property.id }}.location'].setPosition(newLatLng)

        smartMap.refreshMap(smartmap-mapcanvas-1);

    } else {
        alert('No address could be found');
    }
});

The docs say to reference the marker as
smartMap.marker['<MAP ID>.<ELEMENT ID>.<FIELD HANDLE>']

With the <ELEMENT ID> being the ID of the marker's parent element. But what would be? Is that the ID of the entry? I'm trying that but it just seems to lock the browser up and the fields don't save.

Turns out my code was pretty much working but there was another issue in there that was stopping the map marker updating. I've since resolved it.
The original form is huge so here's a cut down snippet of the part that does the marker update in case anyone needs it. This cut-down version isn't tested but should be good.

Incidentally, the "parent element ID" to which I referred is the id of the entry in which your map resides.

Basic location update form (my entry is 'property')

<form id="property-edit__form" method="post" accept-charset="UTF-8" enctype="multipart/form-data">
    {{ getCsrfInput() }}
    {% if property is defined %}
        <input type="hidden" name="action" value="entries/saveEntry">
        <input type="hidden" name="entryId" value="{{ property.id }}">
        <input type="hidden" name="sectionId" value="{{ property.sectionId }}">
        <input type="hidden" name="enabled" value="{{ property.enabled }}">
    {% else %}
        <input type="hidden" name="action" value="entries/saveEntry">
        <input type="hidden" name="sectionId" value="3">
        <input type="hidden" name="enabled" value="0">
        <input type="hidden" name="redirect" value="me/property/saved">
    {% endif %}

            Street Address
            <input class="js-address-part" type="text" name="fields[location][street1]" value="{{property.location.street1 ?? ''}}">

            City
            <input class="js-address-part" type="text" name="fields[location][city]" value="{{property.location.city ?? ''}}">

            County
            <input class="js-address-part" type="text" name="fields[location][state]" value="{{property.location.state ?? ''}}">

            Post Code
            <input class="js-address-part" type="text" name="fields[location][zip]" value="{{property.location.zip ?? ''}}">

            Country
            <input class="js-address-part" type="text" name="fields[location][country]" value="{{property.location.country ?? ''}}">

        <input class="js-address-lat" type="hidden" name="fields[location][lat]" value="{{property.location.lat ?? ''}}">

        <input class="js-address-lng" type="hidden" name="fields[location][lng]" value="{{property.location.lng ?? ''}}">

<button class="js-address-lookup">Lookup address</button>

        {% if property is defined and property.location.hasCoords %}

            {% set options = {
                height: 300,
                width: '100%',
                zoom: 11,
                markerOptions: {
                    icon: '/images/map-marker.png'
                    },
                }
            %}
        {% else %}
            {% set options = {
                height: 300,
                width: '100%',
                zoom: 4,
                center: { 'lat': 51.499998 , 'lng': -0.1166662},
                markerOptions: {
                    icon: '/images/map-marker.png'
                    },
                }
            %}
        {% endif %}

        {% if property is defined %}
            {{ craft.smartMap.map(property.location, options) }}
        {% endif %}

    <input type="submit" value="Save">
</form>

And some Javascript to do the business (using jQuery here).


Show time ordered entries from midnight at end of loop I'm creating a line up listing page for a festival, across 4 nights. Acts are listed, per day, sorted by a date field in order of a start time field.

The issue I'm having is that midnight until 3am is still considered the night of an event but my time field obviously considers it otherwise.

e.g. an act is performing on the Friday morning at 1am but I need to list this at the end of the Thursday acts.

So the user adds it to the CMS on the Thursday but it appears at the start of the day instead of the end.

Essentially, I just need any acts that appear between 00:00 and 03:00 at the top of a list e.g

Thursday

Act 1 - 1am - 2am
Act 2 - 12am - 1am
Act 3 - 11pm - 12am
Act 4 - 10pm - 11pm

etc

This is the code I have so far

whatDateAreTheyPerforming is a date field

startTime and endTime are time fields

{% set entryIds = craft.entries.section('lineUp').ids() %}
{% set categories = craft.categories.relatedTo({ sourceElement: entryIds }).find() %}

{% for category in categories %}

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

  {# Group entries by date and order by start time #}
  {% for date, entries in entries.order('whatDateAreTheyPerforming', 'time(startTime) desc')|
  group('whatDateAreTheyPerforming') %}

DAY HERE - {{ date | date('l') }} {{ date | date('jS') }}

        {% for entry in entries %}

{{ entry.title }}
              {{ entry.whatDateAreTheyPerforming | date('l') }} - {{ entry.startTime | date('G:i') }} - {{ entry.endTime | date('G:i') }}

        {% endfor %}

  {% endfor %}

{% endfor %}

I hope this makes sense, any guidance will be appreciated.

I -think- one of the neatest ways to go about this is to introduce a "Show as last in list" lightswitch-field.

I'm currently working on a similar project (festival line-up) where I also needed this; here's the approach I went with.

Basically, I'll be going for two fields: eventTime (date/time-field) and showAsLastInList (lightswitch-field)

{% set events = craft.entries.section('events').showAsLastInList('NOT 1').orderBy('eventTime ASC').all %}

{% for date, eventsByDate in events|group('eventTime|date("Y-m-d")') %}
    {% set additionalEvents = craft.entries.section('events').eventTime(date).showAsLastInList('1').orderBy('eventTime ASC').all %}

{{ date|date('l j. F')|capitalize }}

    {% for event in eventsByDate|merge(additionalEvents) %}
       {# PRINT YOUR HTML HERE #}
    {% endfor %}
{% endfor %}

It's not exactly pretty, but I can't really think of another way to achieve this without creating a custom plugin for it.


Sprout E-mail: 400: HTML Content URL Required - Campaign Monitor I'm getting the following error when trying to send a campaign with Campaign Monitor through the Sprout E-mail plugin:

400: HTML Content URL Required

I used the example templates provided by Sprout. The Api connects well (I get the list my subscription list from Campaign Monitor in Sprout). I make a new campaign and I can preview the mail in both html and text. The preview looks fine (just some hardcoded stuff). But when I try to send the mail I keep on bumping on that issue. I figured it had to do something with the template url, so I played around with the setting in the campaign:

Entries of this type have their own URLs

I tried pointing it to the template (sproutemail/newsletter) or the name of the entry (sproutemail/{slug}), both without any luck.


What's the best way to make sure external URLs aren't interpreted as relative links? I have a field where the client can enter a URL, and then that field's value is put into the 'href' of a link in the template. The client will sometimes prepend it with "http://", sometimes with "www.", and sometimes with nothing. Unless it's prepended with "http://" or "https://", the link is interpreted as relative and tries to go to "http://mysite.com/www.otherlink.com", which is obviously not what I want.

What's the best way of automatically handling different URL formats?

Using Craft, you could go two ways:

Make your own field-type, that handles the url in PHP and appends http:// if needed (Create a plugin for that)
Check the url for 'http' in your template, and if needed prepend it:

{% set url = entry.url | slice(0,4) == 'http' ? entry.url : 'http://' ~ entry.url %}

Be sure to use the {% cache %} tag if you use option 2, so the check only has to be done once.

Edit: You could use this plugin to pre-validate your urls.


Pulling blog entries related to a structure entry field type fairly new to craftCMS. I've wrestled with this now for hours and exhausted all research avenues.

I have three main "service pages" (Web Design, Digital Marketing, Hosting & Analytics) These are top level Structure pages, each with 5 entries - for example Web Design/Web Development, Web Design/User Experience, Digital Marketing/Inbound, Digital Marketing/SEO, etc. etc.

I have set up an 'entries'field type called 'blogServices' that uses the three main service pages as the parent source, and allows me to select the child pages with no issue. So for instance, if I write a post about Web Development, I can select the 'Web Design/Web Development entry with no problem and have it show up as a related service on the blog post.

Where I am running into a roadblock is I want to pull up 3 most recent blog posts on my 'Web Design' index page. However, I want to be sure that the three most recent posts fall under one of the five 'Web Design' child service entries (side note: Each blog post can also fall under multiple services as well).

Any help with showing me how to filter out only these posts on the index page is of course greatly appreciated. I've been trying the 'relatedTo()' function with no luck at all.

Thank you in advance.

You can run a related to query, passing in all of the descendants of the 'parent' structure entry like so (assuming you are on the 'parent' entry page, else you'll need to query that entry first)

// Get the index pages children
{% set descendants = entry.descendants.all() %}

{% set recentBlogPosts = craft.entries({
  section: blog,
  relatedTo: descendants,
  limit: 3,
  orderBy: 'postDate desc'
}).all() %}

Or, if you don't mind getting blog posts related to the parent page also, you can use the fact that in order to be related to a child page, a blog post must also be related to the parent:

{% set recentBlogPosts = craft.entries({
  section: blog,
  relatedTo: entry,
  limit: 3,
  orderBy: 'postDate desc'
}).all() %}


How do I limit entries retrieved except those with a sticky lightswitch on the entry? I have a list of "meetings" as entries and I want to show only the last two ordered by meetingDate, and show any other meetings marked as sticky, without doubling up.

What I have so far is:

{% set stuck = craft.entries.section('meetings').relatedTo(subcategory).sticky('1').order('meetingDate desc').find() %}
{% set entries = craft.entries.section('meetings').relatedTo(subcategory).order('meetingDate desc').limit(2).find() %}
{% set entries = entries|merge(stuck) %}

Now this works except that if an entry marked as Sticky is one of the first two, then it shows twice. I understand it is bad practice to try and manipulate data using Twig, and that rather I should aim on getting the right data out of the entries first up.

One method is to check to see if item is not in array before merging. The downside is that the entries will just be appended vs sorted by meetingDate.

{% set stuck = craft.entries.section('meetings').relatedTo(subcategory).sticky('1').order('meetingDate desc').find() %}
{% set entries = craft.entries.section('meetings').relatedTo(subcategory).order('meetingDate desc').limit(2).find() %}

{% for stuckEntry in stuck %}
    {% if stuckEntry not in entries %}
        {% set entries = entries|merge([stuckEntry]) %}
    {% endif %}
{% endfor %}

The other method is to grab the ids from the 2 queries and then merge them together, and perform a new query which can be sorted.

{% set stuckIds = craft.entries.section('meetings').relatedTo(subcategory).sticky('1').ids() %}
{% set entryIds = craft.entries.section('meetings').relatedTo(subcategory).limit(2).ids() %}

{% for id in stuckIds %}
    {% if id not in entryIds %}
        {% set entryIds = entryIds|merge([id]) %}
    {% endif %}
{% endfor %}

{% set entries = craft.entries.id(entryIds).order('meetingDate desc') %}


Recovering (or creating a new) admin account Our developer hasn't been able to recover his password for the account he used to setup the site, and now he's non-responsive. The site is on my server and I have full access, but his account is the only one we setup.

We're not able to add new companies until we can either recover the account or setup a new one.

Download and install a fresh copy of Craft from http://buildwithcraft.com somewhere (doesn't matter if it's the same computer your existing site is on or not).
During installation, remember the password you entered when setting up the user.
Open the database and look in the craft_users table. Copy what's in the password column for the user that the installer created over to the password column in the craft_users table for the site you're trying to recover.
If the locked, suspended, pending or archived columns have 1 in them, set them to 0.
If lockoutDate and/or lastInvalidLoginDate have values in them, delete them.
Login to the site you're trying to recover with the password you created in #2.


nesting variables in twig I have 3 sets of globals, which use the same fields handles.

{{ firstGlobalHandle.aFieldHandle }}
{{ secondGlobalHandle.aFieldHandle }}
{{ thirdGlobalHandle.aFieldHandle }}

In a child template, I set a variable corresponding to the handle of the global group which I need to call

{% set globalHandle = "secondGlobalHandle" %}

Now in the In the parent template, I would like to do the following :

{{ '{{ globalHandle }}'.aFieldHandle }}

Is there any way to do so ?

OK, my bad, this was answered here

Here is the solution :

{{ _context[ globalHandle ].aFieldHandle }}


Custom field type that has multiple fields to extend the default field types Ok scenario that I'd like to create.
Create a custom field type lets call it videos. In this field type you would have 5 separate fields title, description, caption, link, thumb. This would make up the field type which could then be selected from the field type when creating a new field in the CP.

The objective is that this grouped field type could then be re-used within separate matrix fields or as a field in it's own right.

I know you can create field types for plugins but is there a way to create the above?

I would say you can do this yeah, it just take a little figuring out is all.

Your input template could look something like:

<input type="text" name="{{ name }}[title]" value="{{ value.title is defined ? value.title }}">
<input type="text" name="{{ name }}[description]" value="{{ value.description is defined ? value.description }}">
<input type="text" name="{{ name }}[caption]" value="{{ value.caption is defined ? value.caption }}">
<input type="text" name="{{ name }}[thumb]" value="{{ value.thumb is defined ? value.thumb }}">

Then in your fieldtypes main class, something like:

public function getInputHtml($name, $value)
{

    // If value is null, we set it to an array to prevent template errors
    if(!$value)
    {
      $value = array();
    }

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

public function prepValueFromPost($value)
{
    return json_encode($value);
}

public function prepValue($value)
{
    return json_decode($value, TRUE);
}

So basically you are settings the fieldtype value to an array of pluginHandle[field] which then you json_encode so it can all go into database without any issues.

Then when you retrieve the value from the DB, its a string, so you json_decode it into an array. The TRUE part states you want an associative array, rather than a stdClass object.

Thats pretty much it at a basic level :)


How to remove category link from redactor links but leave assets and entry link This is a follow up from How to remove Link To Category from Redactor.
I've been able to setup the module and remove all links with this:
Event::on(
  RedactorField::class,
  RedactorField::EVENT_REGISTER_LINK_OPTIONS,
  function(RegisterLinkOptionsEvent $event) {

          $event->linkOptions = [];
  }
);

Which removes all Craft links, but how do I remove the categories links only?

At the moment, your are overriding $event->linkOptions which contains an array with all options to an empty array with $event->linkOptions = [].
First, add the below to your module and refresh any page on your site so you see what you are working with:
Event::on(
  RedactorField::class,
  RedactorField::EVENT_REGISTER_LINK_OPTIONS,
  function(RegisterLinkOptionsEvent $event) {

    Craft::dd($event->linkOptions);
  }
);

In the array you saw above, you want to remove the object containing a 'elementType' => 'craft\\elements\\Category'.
You can do this by searching $event->linkOptions for craft\\elements\\Category, remove it but still returning the rest of the options.
Here's one way of doing so:
Event::on(
    \craft\redactor\Field::class,
    \craft\redactor\Field::EVENT_REGISTER_LINK_OPTIONS,
    function(\craft\Redactor\events\RegisterLinkOptionsEvent $event) {
        $defaultOptions = $event->linkOptions;

        // Search for category element
        $categoryLink = \craft\helpers\ArrayHelper::where($defaultOptions, 'elementType', 'craft\\elements\\Category');

        // If present, remove the option and return the rest
        $event->linkOptions = \craft\helpers\ArrayHelper::without($defaultOptions, key($categoryLink));
    }
);


Calling onSaveEntry event only for one section Using the entries.onSaveEntry event, how would I ensure it's only applied to entries in a particular section? Or is there a way to make a distinction between an entry saved from the control panel and an entry created on a front-end form?

You would compare against the entry's section / entry type in a conditional. The entry modal is available from the event params $event->params['entry'].

craft()->on('entries.onSaveEntry', function(Event $event)
{
    $entry = $event->params['entry'];

    if($entry->section['handle'] == 'mySection' && $entry->type['handle'] == 'myEntryType')
    {
        // Execute for mySection / myEntryType entries only!
    }
}


Getting a single, random, related entry within a plug in Given a Matrix with each row containing a text field and a multi relationship field. And I am picking 1 Matrix row based on the value in the text field. How would I go about selecting a single, random, related entry for that row?

I've tried to do this a couple of ways but I'm not really getting anywhere.

I'm selecting the Matrix row and getting the related entries using

$matrixRow = $entry->matrixField->textField($stringToMatch)->first();

$relatedEntries = $matrixRow->relationshipField;

But how can I now pick one of those related entries at random?
Is the only way to create an array and shuffle it?
Or is there a way I can do it when fetching the Matrix row?

I've tried adding the following in an attempt to get all the related entries associated with the Matrix row. Figuring I can then modify this query by adding a limit and ordering randomly to get my 1 related entry. But it's coming back empty.

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section         = 'videos';
$criteria->relatedTo       = array(
    'targetElement'   => $matrixRow,
    'field'     => 'relationshipField'
);

$entries = $criteria->find();

foreach($entries as $entry){
    var_dump($entry->title);
}

$matrixRow->relationshipField returns an ElementCriteriaModel pre-configured to query for the related elements. You can add / override additional criteria and then query for a matching element using the first() method.

$randomEntry = $matrixRow->relationshipField->order('RAND()')->first();

This is basically the same as what you’ve tried with your custom ElementCriteriaModel. It should also work once you have fixed the mistake in the relatedTo param, as the entry that holds the field is the “sourceElement” of a relation.


Creating on-demand Sprout Fields I have a situation where a form needs to have the ability add additional fields on the fly. For example, if the user clicks "add cat" a new section/tab appears with the fields to add a new cat. So if the user wanted to add 10 cats to the form they would have that ability without issue.

My first thought was that we could use a matrix field to dynamically add fields, but the field type is unsupported. Any help or ideas would be appreciated.

Example:

Sounds like Matrix is the right field for your situation. The harder part is how you decide to implement this on the front-end.

While your question doesn't say it explicitly, it is tagged plugin-sproutforms so I'm going to base my answer on how to approach this using Sprout Forms.

Option 1: Custom HTML

If you only have a single form, building things out in Custom HTML might be worth considering.

You can grab the SproutForms_FormModel using the form tag:

{% set form = craft.sproutForms.form('formHandle') %}

Or use the displayTab and displayField tags to output parts of your form that you don't need additional control over.

You would need to build out support for the Matrix Field manually, but Sprout Forms can receive data for a Matrix Field that is built in the proper format.

Option 2: Matrix Custom Field Plugin

If you need to reuse your form in multiple places, or have the need to reuse Matrix fields on the front-end, you might consider building a Custom Field for Sprout Forms that adds front-end Matrix support.

There are several examples in the Sprout Fields plugin of how to add front-end Custom Field support for Sprout Forms, it would just require a bit more work to take into account all the scenarios that a Matrix field could present.  Depending on your scenario, you might be able to simplify things and just add support for the fields you need to start off, and add more complexity as the need arose.


Cannot update Craft, only download the zip Recently I cannot update Craft on a server. From versions 2.6.2778 and 2.6.2779. I only can download the zip to install it myself. What could be wrong here?
Thanks in advance.

PHP: 5.6.16-1byte1

Alert on iconv (older version)

You can do manual installs easily, all you really need it's the app folder inside the craft folder. but don't just replace it.
I would rename the new app folder to something like "app-new" move it next to the other app folder inside craft folder. once it is all done copying. I would rename the "app" folder into "app-old" and rename the "app-new" into "app" again. Then go to your admin URL and craft should do the automatic database changes that it needs. It has worked for me in the past and it's quick and easy and less error prone.


Display all related entries in a table I'm building a site that contains a listing of products and distributors. I have a channel for each, and each entry in the distributors channel contains a relationship field to tie it to any number of entries in the products channel. There are about 20 entries in each channel.

I need to set up a page with a table that includes all of the products across the top, and all of the distributors in the left column, with a check box in each cell where there is a relationship between the two.

I know how to just use standard related entries tags to output the distributors and list out the related products for each, but is there a way get it into the table format, without a ridiculous number of queries?

Let me show you the quickest solution I could think of.
If you put it in {% cache %} tags, you should be fine. You could also create a little plugin that returns the required data from one big-ass query, if you're into building plugins. If you have any plugin experience, then building a plugin is what I would do.

{% set distributors = craft.entries.section('distributors').limit(null) %}
{% set allRelatedProducts = craft.entries.section('products').relatedTo(distributors).limit(null) %}

            Distributor
            {% for product in allRelatedProducts %}
                {{ product.title }}
            {% endfor %}

        {% for distributor in distributors %}
            {# Get ids for all products related to distributor #}
            {% set productsForDistributor = craft.entries.section('products').relatedTo(distributor).limit(null).ids() %}

                {{ distributor.title }}
                {% for product in allRelatedProducts %}
                    {#
                     # Check if product ID is in array containing this distributor's products
                     # and display value accordingly
                     #}
                    {{ product.id in productsForDistributor ? 'yes' : 'no' }}
                {% endfor %}

       {% endfor %}


Combing an If Statement with Pagination I'm trying to pull all the entries in a category that have a multi-selection selected and then paginate it.

If I just do the below, it works perfectly fine.

{% set entriesRed = craft.entries.section('eventRentals').relatedTo(category) %}
{% for entry in entriesRed if entry.rentalColor.contains('red') %}
            {{ entry.title }}
{% endfor %}

But now I want to paginate it and I can't quite get the right syntax. To be clear, it's the top part I can't get a hold of, I'm modifying an already working existing pagination so I'm not including the bottom half.

{% paginate craft.entries.section('eventRentals').relatedTo(category).limit(12).order('title') as entries if entry.rentalColor.contains('red') %}
{% for entry in entries %}
    {{ entry.title }}
{% endfor %}
{# blah blah blah rest of the pagination ul li stuff #}

doesn't work, neither does

{% paginate craft.entries.section('eventRentals').relatedTo(category).limit(12).order('title') as entries %}
{% for entry in entries if entry.rentalColor.contains('red') %}
     {{ entry.title }}
{% endfor %}

Any tips?

To get the pagination to work as expected, you need to incorporate the if into your craft.entries query. There may be a more elegant solution to do this, but looking at the database, the selected choices is saved as an array-like string:

["blue","red"]

This means that you can search for the value in the field like this:

craft.entries.section('eventRentals').rentalColor('*"red"*').relatedTo(category).limit(12).order('title')


Fields not displaying for some entries in control panel Since I updated to Craft 2.5, I have a weird bug in my entry edition window. Some entries work just fine, and other gives me this :

Like if there was nothing (actually there is something, this single in particular has two tabs and many fields in each..)
Any fix ? Thanks !

If you have xDebug installed on your server, you're probably running into this.

If you don't, you're probably running into this.


Setting User field type from a front end form I am moving a site from EE to Craft and trying to figure out the best Craft approach to something I did with lots of php and url parameters in EE.

The overview: the site is a Family Counseling Clinic.  As part of their program, they have parents register as users on their site.  The parents create a profile for each of their children and then, for each child, they fill out a number of questionnaires.

The basic issue is how to set up these relationships, given that I am using front end forms.

Since the parent is a registered user and is creating the child profile(s) (as a channel entry), the relationship can be based on entry.authorId(theParent).  No problem there.

The relationship between child and forms is where I am looking for a Crafty solution.  One obvious approach is to use Structure for the child profiles and have the questionnaires as a "child entries".  The other possibility that occurs to me is to use an Entries field in a Questionnaire channel that is tied to Child channel entries.

In both cases the question is whether it is possible to do either one of those using a front end form, which would either require setting the parent entry for the Structure solution or the Entry field for the other.

Hope this is clear, and thanks for any suggestions!

Maybe I don't quite get your problem, but I actually don't see any difference between posting child entries (the patients) related to a parent user and posting questionair entries related to a child entry.

You need a hidden field like this for the child registristration.

{% parentId = entry.authorId %}
...
<input type="hidden" name="fields[parentUsersField][]" value="{{ parentId }}">

You can now link to the child entry and allow the parent to enter the questionair form.

{% set childId = entry.id %}
...
<input type="hidden" name="fields[childEntriesField][]" value="{{ childId }}">

Keep in mind that relation fields can hold multiple elements, even if set a limit in the field settings; so you need to post an array using the syntax show above. There's other more  complete code examples here on Stack Exchange for having relational fields in a from (i.e. "Creating comments via a related section").

And yes, using a channel for the questionairs is a very flexible and clean way to structure the relation in my opinion.


How to load a template based on the first segment (and ignoring the second) So I have my dinnermenu at example.com/dinnermenu but I want to show specific content for the next week if someone asks for it via example.com/dinnermenu/nextWeek but it should still use the entry data from dinnermenu ...

how can I achieve that ?

There are a lot of ways to go about this depending on how you have your sections and templates set up, and where you are getting your content from for both 'dinnermenu' and 'nextweek'.

Using routes

If you just want 'dinnermenu/nextweek' requests to be directed to the 'dinnermenu' template, then one option would be to set up a dynamic route with a '*' token as the last segment (i.e. dinnermenu/*). This would route example.com/dinnermenu/any-uri-segment to your 'dinnermenu' template ('dinnermenu.html' or 'dinnermenu/index.html' or whatever you called it).

In the dinnermenu template you can then test for the uri segment and display custom 'nextweek' content, in addition to (or instead of) your dinner menu content.

{% if craft.request.segments(2) == 'nextweek' %}
    // display content for next week
{% endif %}

See craft.request for more info.

Using a structure

For more dynamic nav you could also use a 'structure' (with 2 levels). In the template you can then test for the level and include the parent content as needed.

{% switch entry.level %}
    {% case "1" %}
        {% set dinnermenu = entry %}
    {% case "2" %}
        {% set dinnermenu = entry.parent %}
{% endswitch %}

{{ entry.intro }}     // dinnermenu's or nextweek's 'intro' field
{{ dinnermenu.body }} // with dinnermenu's body field

Using ElementCriteriaModel

If on the other hand, you want to pull your 'dinnermenu' entry into your 'nextweek' template (no matter where it is), then you can use an EntryCriteriaModel to retrieve and display the 'dinnermenu' entry.

{% set dinnermenu = craft.entries.slug('dinnermenu').first %}
{{ dinnermenu.body }}
etc.

You could also just include the whole 'dinnermenu' template in the 'nextweek' template.

{% set entry = craft.entries.slug('dinnermenu').first %}
{% include 'dinnermenu.html' %}

Lot of options.


How to load entries via ajax when a filter is clicked? I have a page that lists all entries from the section 'work'. I would like the user to be able to filter these entries by category but via ajax so I don't have to go to a new page.

{% set entries = craft.entries.section('work').limit(null).search('categories:hotel') %}

This works but each category has to have its own page. Is it possibly to load the filtered entries by ajax? Something using {% if craft.request.isAjax %}?
Here is the relevant html:

Categories

All

Hotel

Bar

Club

Restaurant

Retail

    {% set entries = craft.entries.section('work').limit(null) %}

            {% for entry in entries %}

                        {% for asset in entry.mainPhoto %}

                        {% endfor %}

{{ entry.title }}

{{ entry.address }}

            {% endfor %}

There's a ton of ways to pull this off, but in my opinion setting up pages/URLs for each category is probably a good idea, for SEO and sharing reasons. It's not something that requires a lot of work and would make implementing the AJAX part a breeze. Another win is that you're going to have a solution which will actually work without AJAX or JavaScript, too – which is always a plus :)

To start, make sure the template path for your category group points to the same template that you use for your work index listing page (e.g. work/index), and that the URL pattern is work/{slug}.

Then, amend the listing template like this – the idea is to add the category filter to the craft.entries query only when one of the category URLs are requested.

{# Your basic work entries query #}
{% set query = {
    section : 'work',
    limit : null
} %}

{% If a category URL is requested, Craft will have populated your template with a global `category` variable #}
{% if category is defined %}
    {% set query = query|merge({
        search : 'categories:'~category.slug
    }) %}
{% endif %}

{# Fetch entries #}
{% set entries = craft.entries(query) %}

        {% for entry in entries %}

                ...

        {% endfor %}

For the AJAX part, here's a super simple implementation – this example uses jQuery, and the concept is basically that we'll have the category URLs load using AJAX, and then just swap out the contents of the .projects DOM element with the returned HTML – no need for a separate AJAX template, JSON or even a craft.request.isAjaxRequest test. It's probably also a good idea to use the HTML5 History API to update the browser's address bar:

// Check if the browser supports HTML5 history
var historySupport = !!(window.history && history.pushState);

// Add an event listener for filter clicks
$(function () {
    $('body').on('click', '.filters a', onFilterClick);
});

// Event handler for the filter click
function onFilterClick (e)
{
    e.preventDefault();
    var $filter = $(e.currentTarget);
    var href = $filter.attr('href');
    if (historySupport) {
        // Update the browser's address bar
        history.pushState(null, null, href);
    }
    $.ajax($filter.attr('href), {
        dataType : 'html',
        success : function (response) {
            refreshProjects(response);
        }
    });
}

function refreshProjects (html)
{

    // Update the <title> tag
    document.title = $(html).filter('title').text();

    // Update the .projects DOM element with new HTML
    var $html = $('
').append(html);
    $('.projects').html($html.find('.projects').html());

}


pulling in an image from another section within a matrix loop I am trying to loop through a matrix to output three blocks but also I want to pull in 3 images from 3 different sections. The images are asset fields in 3 other sections. should i loop through those sections using craft.entries or craft.assests? below is an example of what i have been trying out. thanks in advance for any help

{% for block in entry.homeMatrix %}
        {% if block.type == "homeMatrix" %}

                    {% for image in craft.assets.kind('image') %}
                    <picture class="box-image">

                            <source srcset="{{ entry.lTopBannerImg.first().url('gridImages480X340') }}" media="(min-width: 45em)">
                            <source srcset="{{ entry.lTopBannerImg.first().url('gridImageOdd559X315') }}" media="(min-width: 28.4375em)">
                            <source srcset="{{ entry.lTopBannerImg.first().url('gridImages560X520') }}">

                    </picture>
                    {% endfor %}

{{ block.url }}

Click to see more information

        {% endif %}
    {% endfor %}

I'm not sure what {% for image in craft.assets.kind('image') %} is all about in your code since the image variable isn't being used anywhere.

But here's the basic structure on how you could loop through 3 separate Asset fields in 3 different single sections inside of a Matrix block:

{% for block in entry.homeMatrix %}
    {% if block.type == "homeMatrix" %}

        {% set firstSingle = craft.entries.section('myFirstSection').first() %}
        {% set secondSingle = craft.entries.section('mySecondSection').first() %}
        {% set thirdSingle = craft.entries.section('myThirdSection').first() %}

        {% if firstSingle.myAssetField|length %}
            {% for image in firstSingle.myAssetField %}
                {{ image.url }}
            {% endfor %}
        {% endif %}

        {% if secondSingle.myAssetField|length %}
            {% for image in secondSingle.myAssetField %}
                {{ image.url }}
            {% endfor %}
        {% endif %}

        {% if thirdSingle.myAssetField|length %}
            {% for image in thirdSingle.myAssetField %}
                {{ image.url }}
            {% endfor %}
        {% endif %}

    {% endif %}
{% endfor %}


Merging params PostDate limits errors I'm attempting to merge in postDate restrictions based on the url segment. However I get twig errors with my code.

So for a link of domain.com/news/archive/2016 I want to see all entries with a postDate in 2016.

current code:

{% set params = { section: 'news', limit: 5 } %}

{# check for annual archive in the url #}
{% if craft.app.request.getSegment(2) == "archive" %}
    {% set year = craft.app.request.getSegment(3) %}

    {% set start = date( year ~ '-01-01') %}
    {% set end = date( year ~ '-12-31') %}

    {% set params = params | merge({
      postDate(['and', ">= " ~ start, "< " ~ end])
     }) %}
{% endif %}
{# end check for annual archive #}

And the Error I get

A hash key must be followed by a colon (:). Unexpected token "punctuation" of value "(" ("punctuation" expected with value ":").

Also not working
I tried a couple of variations - this gets no errors, but also no entries are output

{% set params = { section: 'news', limit: 5 } %}

{# check for annual archive in the url #}
{% if craft.app.request.getSegment(2) == "archive" %}
    {% set year = craft.app.request.getSegment(3) %}

    {% set start = date( year ~ '-01-01') %}
    {% set end = date( year ~ '-12-31') %}

    {% set params = params | merge({
      postDate: "['and', '>= ' ~ start, '< ' ~ end]",
     }) %}
{% endif %}

try:

{% set params = params | merge({
    postDate:['and', '>= ' ~ start.date, '< ' ~ end.date]
}) %}


Issue with Craft license not validating I've recently built a site on Craft, and while developing it locally I had purchased a license for Craft Client. After publishing the website to the production server the administration panel is showing a modal window with the text "You're running Craft Client with a Craft Personal license."

I've checked and made sure the license.key file is where it's supposed to be, and that the file is accessible. I've built a couple of websites on Craft before and have not had this issue until now.

I've tried re-uploading the site to a different server/domain, and it said in the admin panel that the license didn't belong to this domain, but the other domain it was originally uploaded under. So it obviously is reading the license file. I clicked to transfer the license to the new domain, and the same issue started occurring (modal window the the message "You're running Craft Client with a Craft Personal license. What would you like to do?").

As Craft initially read the license file (otherwise how would it know that the site didn't belong to the domain?), it means the license file exists and is valid, so I suspect it's an issue on Craft's side. Unfortunately their support is taking a little long so I thought I'd come to the community to hopefully get some help.

Thanks, Ben.

Edit: From what I remember from a year ago, this was entirely my own fault. I had purchased the license on the staged version of the site. My bad.

You can try clearing your cache, and/or emptying the contents of the /craft/storage/runtime/ folder. If it's just some cached data causing a problem, that would fix it.

Otherwise, I'd recommend waiting for P&T to get back to you... they're really the only ones who can verify and correct your licensing issues.


getSegment matching category title I'm trying to match the 2nd part of the slug with the category title to then place a 'current' class on the link.

Something like:

{% nav category in craft.categories.group('blogCategories') %}

    {{ category.title }}

{% endnav %}

You might do something like this, concerned that you want to set current on active category.

{% set categorySlug = craft.request.getLastSegment() %}

{% nav category in craft.categories.group('blogCategories') %}
    {% set current = (category.slug == categorySlug) %}
    <a class="button button--outline-blue
       {% if current %} current{% endif %}
       href="{{ category.url }}">
       {{ category.title }}
    </a>
{% endnav %}


'Could Not Find Your Craft/ Folder' After Updating I updated to the latest version of Craft, and I am getting this error:

  Could not find your craft/ folder. Please ensure that $craftPath is set correctly in /storage/xxxxxxx/www/public_html/index.php

I have updated the same way each time. This is the first time I am seeing this error.

The files are setup like this:

Server

www/

craft/
public_html/

index.php

This is what the index.php file has always been:

https://cl.ly/281K2H3a3r1y

Permissions are the same as the previous app folder: 775

Any ideas about what may be causing this? As I said, I have updated Craft several times before without any problems. I've also read other threads on this and didn't find a solution that works for me. I am wondering why this would be a problem now, when it hasn't been an issue during previous Craft updates?

Thank you for any help you can give!

Actually, the permissions have been 774, not 775 as mentioned in my post. I think that was messed up somehow during the upload, and I missed that it wasn't the correct setting. I had also cleared my firewall cache earlier and it hadn't worked. When I cleared again just now after resetting permissions, everything seems ok.


Craft Migration fails (SuperTable propagationMethod) I'm trying to upgrade Craft from 3.3.1.1 and I'm getting an error. I am updating via Composer and get the following error when I run the migration script after upgrading:

Unknown Property: Setting unknown property: verbb\supertable\fields\SuperTableField::propagationMethod

Migration: craft\migrations\m190913_152146_update_preview_targets

I received a similar error when I tried to run the save entries script from the CLI as recommended in the upgrade documentation.

- Resaving test (10554) ... error: Setting unknown property: verbb\supertable\fields\SuperTableField::propagationMethod

I'm running the upgrade on my local server via Valet. Restoring the database brings me back to the migration screen...

Any suggestions would be helpful.

On the chance that anyone is having this same issue, here is what I needed to do to fix the issue (based on help provided by Craft's Support -- many thanks to them):

The Super Table plugin was out of date. The admin panel didn't show the issue and a composer update didn't either. I had to manually update the composer.json file to reflect the current Super Table version, "verbb/super-table": "2.4.9". Then I was able to clear the composer cache and run an update. The migration then worked just fine.


How to install plugin - Non-developer I am not a developer and I hope someone can help me. I had purchased a Mailchimp Commerce plugin via the plugin store but I don't know how to install it or find any documents on how to.

I do see the license on my ID but it says "Craft License Not attached to a CMS license."

Do I need a developer to install the plugin? any instructions I can look over?

Any help is really apprecited

Plugins can be installed through the Craft control panel.

When you log in to your Craft install, you'll see Plugin Store in the left-hand menu. From there you can find and install (labelled 'Try' as you're first installing as a trial) the MailChimp Commerce plugin.

Once installed go to Settings > Plugins and enter the license you purchased.


When clicking blogposts it redirects me to localhost I've installed CraftCMS on my localhost in a subfolder called blog, when creating a new blogpost and clicking on the link it redirects me to my localhost instead of the blogpost.

This video should show what happens.
https://gfycat.com/DemandingBitterGoldenmantledgroundsquirrel

My index php looks like this:

<?php

// Path to your craft/ folder
$craftPath = '../../craft';

// Do not edit below this line
$path = rtrim($craftPath, '/').'/app/index.php';

if (!is_file($path))
{
    if (function_exists('http_response_code'))
    {
        http_response_code(503);
    }

    exit('Could not find your craft/ folder. Please ensure that
$craftPath is set correctly in '.__FILE__);
}

require_once $path;

Could someone please advise me on how I can get the posts to upload correctly?

You need to create an 'entry.html' file which lists the title, description etc.. within it. The link to the post should then direct you to the entry.html file.

/blog/entry.html


Dynamic Image Variant in Template I'm keen to set my image variants dynamically from content editor and not quite sure how I do this in twig.

I have three variants. They are named imageVariantsThumb, imageVariants16by9, and imageVariants3by2 in craft.

To render the variant on the image I use the following.

{% set optimizedImages = item.itemImage.one().imageVariantsThumb %}

Depending on the dropdown selected in the editor (say the values are thumb, 16by9 and 3by2) I want to change the variant name in this line of code. How do I use the value from my drop-down field to change the variant name on the end of the code above?

I have tried defining a variable using the value and replacing imageVariantsThumb above but it doesn't work:

{% if block.listImageRatio == '16by9' %}
  {% set imageRatio = 'imageVariants16by9' %}
{% endif %}

{% set optimizedImages = item.itemImage.one().imageRatio %}

So instead of using the dot syntax ., this would be a good place to use the subscript syntax [].

{# dot syntax #}
{{ foo.bar }}

{# subscript syntax #}
{{ foo['bar'] }}

When you use the subscript syntax to access a variable's attributes, you can safely use variables (by just removing the single quotes surrounding the attribute).

{% set bar = 'helloWorld' %}
{{ foo[bar] }}
{# functions just like foo.helloWorld #}

So for your example, you would do this:

{% if block.listImageRatio == '16by9' %}
    {% set imageRatio = 'imageVariants16by9' %}
{% endif %}

{% set optimizedImages = item.itemImage.one()[imageRatio] %}

(Twig docs)


Prevent direct access to a web page except redirect I have redirect to a web page upon successful form submission using guest plugin. The redirected page is in announcement tone so I'd like to prevent it from direct access with exception that comes from form submission.

Is there something Craft can do?

Add a Preparse field to the entry type you're posting to and make it generate a random string on entry save.
Then make the Guest Entries plugin redirect to a URL with that Preparse field's value in the query string.

<input type="hidden" name="redirect" value="success?id={id}&key={preparseField}">

You should now be able to get that entry model in your template and test against that Preparse field's value.

{% set query = craft.request.getQuery() %}
{% set entry = craft.entries.id(query.id).preparseField(query.preparseField).first() %}

{% if not entry %}
    {% exit 404 %}
{% endif %}


What, if any, are the dangers to modifying users directly in the database? Is it dangerous for the longterm stability of the Craft database to modify user privileges (i.e. suspend users or change user group) at a database level?

Example scenario:

Somebody has gone into the database and suspended specific users and didn't use the Craft CP. Would doing this action in Craft CP modify more tables than just "craft_users"?

Manually modifying anything in the database inherently comes with risks.  The biggest is that you risk corrupting data by getting it in an inconsistent state across tables, which can cause foreign key constraint violation errors later on.

In the case of suspending/un-suspending a user, that risk is pretty low since it's limited to just the craft_users table, but in the case of changing user groups, it's higher because now you're talking about craft_users, craft_usergroups, craft_usergroups_users.

In both cases, you also need to take into account any plugins that might be using that data as well.


Optimizing website menu I have created a global menu for my website and there I have a label and an entry section selection that I use for directing when clicking.

However, I just need the URL of that section and loading the whole section data is way too much overhead that its not needed.

I have 4-5 menu items so I am loading 4-5 sections for no reason.  Imagine the overhead.

Can I somehow use the section selector in CMS but get only the section URL without loading all the section data?

Are you experiencing performance issues? If not, is this overhead really an issue?

If it is, how about caching the global menu for a really long time? https://craftcms.com/docs/templating/cache


Custom registration User validation I'm building a custom registration process in which a set of entries and a user are created at the same time.

Currently I'm not able to pass back my errors in my controller into the front-end template.

(The following code should error out on purpose to test this functionality)

In my plugin controller:

$user = new UserModel;
$wasSaved = craft()->users->saveUser($user);

if ($wasSaved) {
     $was_assigned = craft()->userGroups->assignUserToGroups($user->id, array(1));
} else {
     $user->addErrors($user->getErrors());
     var_export($user->getErrors());
     return false;
}

In my template

{% macro errorList(errors) %}
{% if errors %}

     {% for error in errors %}

{{ error }}

      {% endfor %}

{% endif %}
{% endmacro %}

{% if account.getErrors is defined %}
    {{ _self.errorList(account.getErrors()) }}
{% endif %}

With the var_export($user->getErrors()); in my controller, I can see the errors at the top of the page:

array ( 'username' => array ( 0 => 'Username cannot be blank.', 1 => 'Username cannot be blank.', ),
'email' => array ( 0 => 'Email cannot be blank.', 1 => 'Email cannot be blank.', ), )

but these errors are not making it back into the actual template.

Any ideas?

It looks like you're not returning the user model back to the template.

You need something like this in your controller.

craft()->urlManager->setRouteVariables(array(
    'account' => $user
));


How do I use offset in Craft 3? In Craft 2 I used:

{% for image in entry.imageGallery.offset(1) %}

to exclude the first image, as that is shown higher up in the template.
I get the depreciation error of:

  Looping through element queries directly has been deprecated. Use the
  all() function to fetch the query results before looping over them.

So I changed it to:

{% for image in entry.imageGallery.all() %}

But I can't find any example of how to apply an 'offset' in the Craft 3 docs.

{% for image in entry.imageGallery.offset(1).all() %}

Don't search for an example "how to apply offset". All properties work the same - there is nothing special/ no difference between offset, limit, a field value or anything else.


Query two sections filtered by different custom fields, then order them Two channels:
1) exhibitions, which have a startDate and EndDate
2) events, which have a date

I need to grab the current exhibitions, future exhibitions and future events, which I do using this:

{% set allOccurrences = craft.entries.section('exhibitions').startDate('<= ' ~ now | date("U")).endDate('>= ' ~ now | date("U"))
    | merge(craft.entries.section('exhibitions').startDate('> ' ~ now | date("U")))
    | merge(craft.entries.section('events').date('>= ' ~ now | date("U"))) %}

Now what I need to do is order them, by the startDate (if an exhibition) and the date (if an event). In other words, having already fetched the entries, I need to order them by two different fields.

I'm not sure this is possible without a plugin - could anyone give me any pointers?

There's this super useful SuperSort plugin that would make this possible.

{% set sortAsTemplate = '{{ object.section == "Exhibitions" ? object.startDate|date("U") : object.date|date("U") }}' %}
{% set sortedOccurrences = allOccurrences|supersort('sortAs', sortAsTemplate) %}


How to make URLs translatable in Craft 3 I am trying to make the URLs translatable according to the language selected for the site.

To give this an answer, the URI can be set on a per-site basis, so it is simply a matter of setting the URI for the English site to about-us and the URI for the Dutch site to over-ons on the section's settings page.


Can I add an enabled-by-default lightswitch field to existing entries? I've created a lightswitch field that defaults to "On", and it works fine for new entries, but for all existing entries it is set to "Off". I'm keen to avoid having to manually go through all existing entries switching it to "On" - is there a way of making existing entries respect the default value of this new field (rather than treating the absence of a value for it from when they were created as "Off")?

(Or alternatively: is there an easy way to set a field to "On" for all existing entries?)

If there was no default set beforehand, then your previous elements will have a value of null for that field. You should be able to include those in your "on" queries by querying for that null value as well as the "on" value in your templates:

{% set onEntries = craft.entries.yourLightswitch([null, '1']).find %}

This won't actually change the value of your previous elements though. One way to do that would be using a SQL query against the craft_content table to update rows (elements) that have null in that column:

UPDATE `craft_content` SET `field_yourLightswitch` = 1 WHERE `field_yourLightswitch` IS NULL;


How to improve unexpectedly poor Craft performance? We have a seasonal website which gets very popular around this time of year. This year we ported it from ExpressionEngine to Craft, for all the obvious reasons. We were very surprised to discover that the Craft version of the site is using considerably more resources than the old EE one. I'm looking for any advice on how to get this load down.

For info; both sites used the same dedicated Virtual Server, a quad core Xeon (minimum 800Mhz, burst to 2Ghz) with 8Gb RAM.

This weekend the Craft site was dealing with around 500 simultaneous visitors but pushing the CPU load to 7. By judicious use of the {% cache %} tags I dropped the queries per page from 200 to 20, and the load dropped to around 4-5.

Once the site is seeing 700 simultaneous visitors the CPU load is going into double digits and rapidly starts to spiral.

We had to switch out to a static scrape of the site. At the peak last year we were dealing with 1000 simultanious visitors and did not need to switch out to a static site.

I should point out that both sites are loading all their assets off Amazon S3, so none of those files are having an impact. This is purely about Craft being able to deal with the number of requests it's getting.

Why might Craft be performing so poorly in comparison, and how can I fix this?

This is a great resource on improving performance as it's a multi-pronged attack:

Native craft caching {% cache %} which you mentioned you have done
CDN and Browser caching
Varnish and other tools, including plugins like Cache Warmer

I concentrated on cache as this is usually where the bottleneck seems to happen in Craft. Apologies if you've addressed all these already!


Craft 3: query matrixBlocks and eager load its owner? Does anybody know if it's possible to load matrixBlock and eager load the entries (=owner) the matrixBlocks belong to in Craft 3?

I tried:

{% set blocks = craft.matrixBlocks.type('eventDate').fieldId(4).with('owner') %}

but this does not work. Leaving out the .with('owner') works perfectly and then access its owner by block.owner.<fieldname>

Currently no, but I suppose since Craft 3 added the craft.matrixBlocks() template function, it would make sense to make this possible.

Just created a FR about this: https://github.com/craftcms/cms/issues/1820


Passing variables into twig components Based on this interesting article: DRY templating with Twig and Craft CMS. I found myself trying to update the approach with include instead of macro following reading I had about twig 2 and craftcms 3.

So basically there is my component

_hero-banner.twig

{# Defaults #}

{% set defaults = {
    heroTitle : title is defined ? title : 'Title not set',
    titleColor : color is defined ? color : null,
    heroImage : image is defined ? image : null,
    heroButton : button is defined ? button : null,
    heroClasses : classes is defined ? classes : null
  }
%}

{# Options #}

{% set options = options is defined ? defaults|merge(options) : defaults %}

{# Variables #}

{% set imageMobile = {
    mode: 'crop',
    width: 640,
    height: 500,
    quality: 75,
    position: 'focus-point'
} %}

{# Output #}

      {# Display the entries #}

{{ options.heroTitle }}

            {% if options.heroButton %}
              <button type="button" class="o-button o-button--primary"> {{ options.heroButton }} </button>
            {% endif %}

And there is my include

index.twig

{% set heroBannerOptions = {
    title : homepage.mainTitle,
    image : homepage.heroBanner,
    color: true
  }
%}

{% include 'components/_hero-banner.twig' with { options : heroBannerOptions } %}

Somehow I cannot pass the variables into the component and I cannot figure out why...

I forgot to post the solution:

_hero-banner.twig

{% set defaults = {
    heroTitle : options.title is defined ? options.title : 'Title not set',
    titleColor : options.color is defined ? options.color : false,
    heroImage : options.image is defined ? options.image : null,
    heroClasses : options.classes is defined ? options.classes : null,
    heroButton : options.button is defined ? options.button: null
  }
%}

{# Options #}

{% set options = options is defined ? defaults|merge(options) : defaults %}

{# Variables #}

{% set imageMobile = {
    mode: 'crop',
    width: 640,
    height: 500,
    quality: 75,
    position: 'focus-point'
} %}

{# Output #}

      {# Display the entries #}

{{ defaults.heroTitle }}

            {% if defaults.heroButton %}
              {% include "components/_buttons.twig" with options %}
            {% endif %}

I wasn't calling my variables properly...


How to check if an entry is enabled for a particular site? Is there a way to find out if an entry is enabled for a particular site?

I know there's the enabledForSite property, but it doesn't look like it accepts any arguments. Ideally I'd like to do something like {% if entry.enabledForSite(2) %} or {% if entry.enabledForSite('siteHandle') %}.

Thanks!

Based on the anyStatus and site query parameters, it should work like this:

{% set entries = craft.entries()
    .site('foo')
    .enabledForSite(true)
    .all() %}


What's the best place to store and load static data for plugins? I have static data that my plugin requires as an array (multidimensional with 100s of items), it doesn't need to change and it seems overkill to store in a database and not appropriate as just arrays in my code.

Options I have considered:

Json files - load them in
In the config file

Which is best and is there a more appropriate way to store access?

What format is the source data in?  If it's already in a multidimensional PHP array, then it might be as simple as having a data.php file in your plugin and doing a require_once in your plugin's init() method and you're good to go.

Even if it's in a different format, loading it from init() and parsing it into the multidimensional array is a good option.


Change default status of entry publication (Lightswitch 'Status') When I write an article and save it, I want to verify my text.
I don't want publish my article immediately.
If I'm tired, I sometimes forget to disable the Lightswitch 'Status'.
So, how can I disable it by default?

If you're using a Craft Client or Craft Pro, you can save your entry as a draft and review it later.

This isn't foolproof either. If you wanted to really try to restrict yourself, you could set up another user account that doesn't have privileges to "Publish live changes."

But again, this would require either a Craft Client or Craft Pro license.


How can I add field content to an asset in code? I'm trying to upload an asset based on this code https://gist.github.com/sathoro/8178981
which works fine, but how can I add additional content fields during the upload? I would like to set the caption an additional fields like credit during the upload?

It propbably works to store the custom field directly with your new element model:

$assetFileModel->setContentFromPost(array(
    'captionFieldHandle' => $myCaption,
));