Querying Entries by Month and Year Good morning, If have have a URL that passes parameters: http://url?month=January&Year=2018, how would I go about querying all entries in section where the postDate equals January 2018?

I can get the parameters by using: craft.app.request.getParam('month') and craft.app.request.getParam('year') but I can seem to figure out the correct way to only show me entries based on these parameters.

Thanks in advance.

I noticed a post that had the following answer and the response was that it worked. I tried it, and received the error:
Object of class DateTime could not be converted to string.

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

{% set firstDayOfMonth = now | date_modify('first day of ' ~ month ~ ' ' ~ year ~ ' 00:00:00') %}
{% set lastDayOfMonth = now | date_modify('last day of ' ~ month ~ ' ' ~ year ~ ' 23:59:59') %}

{% set entries = craft.entries.section('yourSection').postDate('and', '>= ' ~ firstDayOfMonth, '<= ' ~ lastDayOfMonth) %}

Jon's answer is excellent, but if you want to keep the same month and year URL query params, I offer this.

The problem is that firstDayOfMonth and lastDayOfMonth are PHP class objects and can't be inlined as text. They need to be formatted as text with a date() or atom filter.

Here's your code with the filters added:

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

{% set firstDayOfMonth = now | date_modify('first day of ' ~ month ~ ' ' ~ year ~ ' 00:00:00') %}
{% set lastDayOfMonth = now | date_modify('last day of ' ~ month ~ ' ' ~ year ~ ' 23:59:59') %}

{% set entries = craft.entries.section('yourSection').postDate('and', '>= ' ~ (firstDayOfMonth|atom), '<= ' ~ (lastDayOfMonth|atom)) %}

You can make it extra readable by using the after and before methods since your query is based on Craft's postDate parameter.

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

{% set firstDayOfMonth = now | date_modify('first day of ' ~ month ~ ' ' ~ year ~ ' 00:00:00') %}
{% set firstDayOfNextMonth = firstDayOfMonth | date_modify('+1 month') %}

{% set entries = craft.entries
    .section('yourSection')
    .after(firstDayOfMonth|atom)
    .before(firstDayOfNextMonth|atom)
    .all()
%}

I'm sure you're aware, but it's worth noting for anyone finding this answer later: This is a bit fragile. If the URL query string does not have a valid month name and four-digit year number, it'll chuck errors.


Asset Field: Select a folder instead of all images Is there a way to pick a folder from an asset field?

The goal is to render a dynamic gallery from an asset folder (which is on S3) instead of selecting all images inside a folder by hand.

Use case:
In an asset field, I select folder 'XYZ' and render a gallery from all images which are inside. If a user uploads a new image to the folder 'XYZ', the gallery will be updated automatically.

Problem:
Currently, I can only handpick the images from a folder. If someone uploads a new image, he/she also has to pick the new image in the asset field. So it is not dynamic.

Thanks in advance!

You can create a new field with these functions. Note: this is a very basic example, you would usually want to do this with a template but I don't have much time

class FolderAssetField extends Field {
    // Static Methods
    // =========================================================================

    public $folderId;

    /**
     * Returns the display name of this class.
     *
     * @return string The display name of this class.
     */
    public static function displayName(): string{
        return 'Folder';
    }

    /**
     * @param $value
     * @param ElementInterface|null $element
     * @return string
     */
    public function getInputHtml($value, ElementInterface $element = null): string
    {
        $allFileModels = \craft\records\VolumeFolder::find()->all();
        $string = 'select a folder
<select name="' . $this->handle .  '">';
        /** @var VolumeFolder $folder */
        foreach ($allFileModels as $folder){
            $selected = ((int)$value === $folder->id)? 'selected="selected' : '';
            $string .= '<option ' . $selected .  ' value="' . $folder->id . '">' . $folder->name .  '</option>';
        }
        $string .= '</select>';

        return $string;
    }

}

Your field will then contain the folderId of the selected folder. You can then  get all assets for this folder with

/** @var AssetQuery $assetQuery */
$assetQuery = \craft\elements\Asset::find();
$assets = $assetQuery->folderId($value)->all();

or in Twig

{% set assets = craft.assets.folderId(entry.fieldHanlde).all() %}
{% for file in assets %}
    {{ file.title }}

{% endfor %}

You could also use the normalizeValue function to prepare this Query. The Redactor plugin has some good examples here


When redirecting to HTTPS from www, index.php appears in URL I have a redirect setup for www, it successfully redirects to https:// but it includes /index.php?p= in the URL. I'm not convinced by htaccess file is configured correctly.

Here's my htaccess file:

RewriteEngine On

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

RewriteBase /
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]

Help much appreciated.

There are docs for removing index.php from your URLs here: https://craftcms.com/support/remove-index.php

There are also docs for enforcing SSL for all CP requests here: https://craftcms.com/support/force-ssl

Note that they mention the the SSL rewrite should happen before the index.php rewrite in your .htaccess file.


Photo demographic targeting in Craft? We will be creating a website for a large clinical trial. The catch is that this trial will have study sites in many different areas of the world. We want to appeal to use user depending on their demographic. For example, when a user from one of our Thailand sites visits the website, we want them to see photos of Asian study participants (from photos we provide). Is this a possibility? It would sort of be like text translation but with photos instead.

If I'm understanding you correctly, this is possible using the standard Craft Pro "locale" stuff. In addition to making text translatable, you can make Assets translatable - in which case you can upload a different image for each translated region. The appropriate asset will be used. This assumes you target each region by having a dedicated URL prefix for each (mysite.com/thailand, mysite.com/japan etc)

https://craftcms.com/docs/localization-guide


Can you batch-change all authors in the CP? Context: When we insert content for clients on full-service projects, sometimes we leave the original author. This author is usually from my shop and has admin-level permissions. When we turn the site over to clients, many times they can't override an admin due to their own (appropriate) permissions.

Question: Is there a way to batch-change all authors to either another author or null? Forethought is obviously the best thing in this case, but it's a pain to go into each entry and remove/change authors, and I'm lazy. I wasn't able to find a workaround or plugin. This question shows what to do in the database, but I'm wondering about the CP.

There's currently no way to do so natively in the CP, but there is a round-about way to do it using a CSV file with a pair of indispensable plugins from Bob Olde Hampsink:

Import
Export

Do the export/import 2-step

Use the Export plugin to spit out just the Title and Author from the section you want. Open up the resulting CSV file in whatever editor you want, you don't necessary have to use Excel or OpenOffice in this case since it's just text.

Do a find/replace on the author with the new author. Save the file.

Open up in the Import plugin, and again, tell it what section you want and to replace the data. On the next screen, confirm Title and Author are already selected for you. Title should be checked as how to match up the data. Run the import.

You're basically telling the plugin to leave everything alone except to replace the Author and use the Title (which we exported before) as the source.
Rinse and repeat with as many sections you have.


Using Craft CMS with Foundation 6 (for Sites) So I finally am climbing on board the Craft CMS train, but I have a quick question about how some of you more seasoned Craft-users do things.

I do a lot of my work using the Foundation framework (by ZURB) for a lot of reasons, but I want to know if there is a "best way" to include the front-end framework with Craft. I've never really used a CMS before, so this isn't really a familiar territory for me at all. I haven't found any good guides online as of yet detailing how to do this with Foundation 6, so I figured this would be the next best place to turn! If someone who knows more than me could walk me through the process to mesh these two awesome elements together, that would be much appreciated!

Craft is completely "BYO HTML", so there is no magic in making Foundation work with Craft, unlike lesser CMSes that force their own HTML on you.

Just add your stylesheet links and script tags to your main base HTML wrapper and have fun building!


Freeform Checkbox Group Field only returns one value I need a scenario where users can select multiple options within a checkbox group.  Unfortunately Freeform only returns the last value selected and ignores the rest?  I might be missing the point but I expected to see all (and only) the values selected represented in the submissions area?

Any ideas?

Thanks

Ok, Solspace support cam through via email with the answer...  Put square brackets after the field name!  Simple :)

<input type="checkbox" name="MyFieldName[]" value="Item1">
<input type="checkbox" name="MyFieldName[]" value="Item2">
<input type="checkbox" name="MyFieldName[]" value="Item3">


Applying changes from your project config files ... No site settings exist for section 20 Deploying on production is giving me this error.
Applying changes from your project config files ... No site settings exist for section 20
Deploying to stage is working no problem. Production isn't live yet. It uses the same database copied from stage.
Any ideas?

If it's a new environment with your staging database, then run this on your new production environment:
./craft project-config/rebuild
This will force-dump the config into the project-config YAML files from scratch, and include any small changes that might have happened to make way for the new environment, including pesky caches.


Making a dynamic {{ siteUrl }} for local mobile testing I'm developing a site using a mobile first approach, connecting the phone via USB and using Safari's Web Inspector on iOS8.

On my local machine, the url for all CSS, JS and href links is http://localhost:8888/ (running MAMP) but on the phone it's my IP or http://00.00.00.00:8888/

Right now, this issue is breaking the entire site when testing on a device. All links are broken.

How can I make the Craft variable {{ siteUrl }}... well variable?

Hey Jeremy you can actually make siteUrl work using Multi-Enviroment Configs and your general.php file will end up looking something like this.

return array(
'*' => array(
    // ...
),

'example.dev' => array(
    // ...

    'environmentVariables' => array(
        'basePath' => '/users/brandon/Sites/example.dev/public/',
        'baseUrl'  => 'http://example.dev/',
    )
),

'example.com' => array(
    // ...

    'environmentVariables' => array(
        'basePath' => '/storage/av12345/www/public_html/',
        'baseUrl'  => 'http://example.com/',
    )
)

);


Craft 3 image asset getUrl() not showing I came across an interesting issue. I'm using Craft CMS 3.0.0-RC14 and non of my image paths are showing but the title and the file name does.

{% set image = nav.navLogo.one() %}
{{image.title}} // works
{{image.fileName}} // works
{{image.getUrl()}} // no output, not even error

Any ideas ?

The solution is to enable "assets for this source have public URLs" in the volume settings.


Filter Entries by Category fields & refresh URL and list with AJAX I'm finding myself stuck with filtering entries that are related to categories using a category field. I'm looking to build a sub-navigation on a page, where I can select from a select field or from a dropdown nav.

I tried following this but no luck. It doesn't work for me.
How to load entries via ajax when a filter is clicked?

I also would love to have 2 or 3 category fields. In the end, I am trying to create something very similar to crafts partner page filtering.
https://craftcms.com/partners/category?locations=&partnerCapabilities=

If anyone could share their filtering snippets, I would greatly appreciate it :)

First you need some HTML/Twig logic to display your categories

    {% for category in categories %}
        <input data-id="{{ category.id }}" data-slug="{{ category.slug }}" type="checkbox" class="category-filter">{{ category.title }}
    {% endfor %}

    Submit

Then some Javascript logic to make an ajax request, keep in mind you need some variables for csrf protection

window.csrfTokenName = "{{ craft.app.config.general.csrfTokenName|e('js') }}"
window.csrfTokenValue = "{{ craft.app.request.csrfToken|e('js') }}";
window.siteUrl = '{{ entry.getUrl() }}';

$(document).ready(function () {
    $('#submit').click(function (e) {
        e.preventDefault();
        var checked = $('.category-filter:checked');
        var ids = [];
        var slugs = [];
        $.each(checked, function (index, item) {
            ids.push(item.dataset.id);
            slugs.push(item.dataset.slug);
        });

        var data = {
            action: 'plugin-id/controller-id/action-id',
            ids: ids
        }
        data[window.csrfTokenName] = window.csrfTokenValue

        var newUrl = siteUrl + '?location=' + slugs.join();
        $.ajax({
            url: '/',
            data: data,
            type: 'POST',
            dataType: 'json',
            success: function (response) {
                console.log(response);
                history.replaceState({}, '', newUrl);
            }
        });
    })
});

And finally your Controller

public function actionIndex()
{
    $ids = Craft::$app->getRequest()->getBodyParam('ids');
    $entries = Entry::find()
        ->relatedTo($ids)
        ->asArray()
        ->select(['elements.id', 'title'])
        ->all();

    return $this->asJson([
        'entries' => $entries
    ]);
}


Select Related Entries from a specific category in CP I'm creating a site which has a products section.

I have created an entries section called 'Products'.

I have set up some categories, i.e. 'Category One, 'Category Two', 'Category Three'

I have also created a related entries field so I can related products to each other.

When the client adds a new product in 'Category One', they should only be able to relate entries that are in 'Category Two' or 'Category Three'.

Is there a way that I can restrict the results returned in an entries field in the Control Panel to a specific category?

There is no native functionality for this at the current time.

You could write a plugin to extend the Products field-type (which itself extends the base entries field-type) - to provide this filter functionality.  That is you'd add a categories chooser to the field type and then filter the available products using that category in your plugin.

https://pluginfactory.io would get you started on the plugin scaffolding, and I'd look at /craft/plugins/commerce/fieldtypes/Commerce_ProductsFieldType.php and the native Craft categories field type to get started.


Do "update cart" and "complete cart" as one action I am developing a site which has "normal" shop stuff that is added to cart and bought through the checkout process. But it also has to support submitting requests for food catering jobs. This is a slightly different workflow. I want to do this by creating a "catering product", which has a number of line items which represent the food items the customer wants supplied on the day.
So I can setup a custom product page with all the line item fields etc on it. But now I am wanting to combine "add to cart then complete checkout without payment" into one action, so that this all happens in one go when they submit the catering request form. (The client will then get in touch with the customer, confirm the catering job details, then the customer will pay for the job once everyone is happy.) So really I need to combine two actions - "update cart" and "complete cart".
Any suggestions on the best way to do this? Do I have to write my own module? Any advice/tips greatly appreciated!

There's a few moving parts here but Commerce 3.3, which was recently released, just introduced support for partial or deferred payments which should help get this done easily.
I'm not sure what your checkout looks like but one way to handle it would be to post via ajax. Basically anything that updates on-the-fly (addresses, line items, etc.) needs to to get pushed to update-cart first.  You don't really need to write a plugin for this.
Then when you ready to complete the order, you could also make one final push to update cart. Then when a user wants to finalize, they then hit the commerce/cart/complete endpoint.
You could also have a separate "confirm your order" screen which could give the user time to check over their catering before it gets sent.
Either way, you want to have the new allowCheckoutWithoutPayment setting set to true.
It's also possible to grab a partial payment (say if your client wants to do a deposit).


Required fields in the user profile how to make required plane text fields or required firsrtName and lastName fields in users profile? I want to during the registration and profile changes were required. Maybe there is any plugin for this?

For custom fields that you add to users under settings>users>fields, you can control whether the field is required by clicking on the small gear icon and selecting make required. With built-in fields such as firstName and lastName, make required cannot be controlled. Within the CP, at least, you would need to look for a plug-in solution.

On the front-end, I would suggest a writting javascript solution that simply validates that the fields are not empty before submitting the form (or before enabling the submit button). Have a look at jquery's .on('click') or .on('change') functionality for more info.


Admin pages request a broken version of the craft.css file We’re using Craft over SSL and everything is working fine apart from the admin fonts:

This is due to a mixed content, because craft.css is requesting the fonts from non-ssl URLs:

The CSS file requesting these non-ssl assets is:

/admin/resources/css/craft.css?d=1478612388

When I clear caches, everything works for one page load, then reverts to broken fonts on the next page load. This is because for one page load after clearing caches, the CSS file is requested with a different query string:

/admin/resources/css/craft.css?x=EVPBt6yJn

This file uses the correct SSL URLs for font files, as does any other variation on the query string.

I’ve tried completely emptying the storage directory.

I can’t find anything in the docs about how Craft generates these CSS files, or the query strings. Can anyone give me any pointers?

The fix in this particular case was to modify and save /craft/app/resources/css/craft.css — this revs the timestamp in the query string.


Calling Craft Console Commands from Plugin? I am in the process of building a plugin that has a controller that accepts a HTTP request. If the token and request are valid, I would like to call a Craft Console Command from within the plugin (e.g. gc/run or resave/entries).

The equivalent would be using the CLI for call the command ./craft gc/run but from a controller.

How would I call the command from my plugins HTTP controller?

Since Yii treats console commands like requests, you need to perform the following steps to execute a Craft console command from within a plugin:

Within your plugin, set the namespace to match the commands namespace
Call a run action from your plugin, and pass the route name/params

    MyPlugin::$plugin->getInstance()->controllerNamespace = 'craft\console\controllers';

    $command = MyPlugin::$plugin->getInstance()->runAction('gc/run');


Override admin local name I changed the language locale to Hungarian, but the translation for the singles looks a bit funny. Is there an easy way to override it with my version?

Singles are translated to "Egyedülállók" but that 99% of the time here means a single person and not a single something.

You can add your own translations by placing a region-specific translation file in a craft/translations folder. The filename should be named after your locale and return an array of translations.  In your case this may look like a file named:

craft/translations/hu.php

And within that file, returning an array like so:

<?php

return array(
    "Singles" => "Something Better than Egyedülállók"
);

All strings that are identified as translatable in your front-end templates and the Craft Control Panel files, will be checked against these translations when loading a page in your particular locale. Craft's help doc on Static Translations discusses what this could look like in your templates.

If the phrase is really off in your language, you may want to reach out to Pixel & Tonic and let them know as well. I believe they welcome recommendations from community members on how language translations can be improved.


Craft 3 Plugin not returning custom field value I am trying to get the value of a custom field in entries, but I can't seem to get it to grab that value. I'm assuming I'm pulling it too early or too late, otherwise I have no idea.

I can pull the value the of the lightswitch enabled

Event::on(Elements::class, Elements::EVENT_AFTER_SAVE_ELEMENT, function(Event $event)
    {
        $request = Craft::$app->getRequest();

        // will successfully send email if enabled lightswitch is on
        if($request->getBodyParam('enabled') == 1)
        {
            $html = $request->getBodyParam('enabled');
            $subject = "testing";
            $mail = "example@gmail.com";
            return $this->sendMail($html, $subject, $mail);
        }
    });

The below doesn't return anything at all for the custom field fields[sendEmail]

Event::on(Elements::class, Elements::EVENT_AFTER_SAVE_ELEMENT, function(Event $event)
    {
        $request = Craft::$app->getRequest();

        // will not send email no matter what position the lightswitch is in
        if($request->getBodyParam('fields[sendEmail]') == 1)
        {
            $html = $request->getBodyParam('fields[sendEmail]');
            $subject = "testing";
            $mail = "example@gmail.com";
            return $this->sendMail($html, $subject, $mail);
        }
    });

I tried changing the event handler to EVENT_BEFORE_SAVE_ELEMENT but it made no difference.

Found my answer here

// get $_POST['foo']['bar'], if it exists
$bar = Craft::$app->request->getBodyParam('foo.bar');

or inserting it into my code

Event::on(Elements::class, Elements::EVENT_AFTER_SAVE_ELEMENT, function(Event $event)
{
    $request = Craft::$app->getRequest();

    if($request->getBodyParam('fields.sendEmail') == 1)
    {
        $html = $request->getBodyParam('fields.sendEmail');
        $subject = "testing";
        $mail = "example@gmail.com";
        $this->sendMail($html, $subject, $mail);
    }
});


Bypass server memory_limits for Cloud Asset resources I’m building a site that needs to upload large video files to Amazon S3. We have run into limitations with our host where they will only increase the memory_limit to 512mb and it’s likely that there will be video files in excess of this. It seems that Craft stages the video file on the server before sending it to S3. Is there a way around this so we can bypass the hosting limits on file uploads and memory and not make the user use an FTP client to upload bigger files?

I don't think there is anything native in Craft that is going to help you here.

FTP is probably the best bet.  Only images get downloaded from external sources during indexing, so it's a simple as FTP'ing up the files and rebuild the asset source indexes (which could be automated via cron job).


Check for number less than x in array I want to check if there is a number less than 10 in an array.

{% if 10 in [0, 30, 50, 10, 9, 200]  %}
  {# checks only if there is a 10 in it. not if there is anything below 10. #}
   yep. there is a number 10
{% endif %}

That's close, but I want to find find out if there is any number below 10 in it, disregarding how many.

Not possible: {% if 10 > in [0, 30, 50, 10, 9, 200] %}

Also not possible: {% if > 10 in [0, 30, 50, 10, 9, 200] %}

Twig isn't very well equipped to deal with more than basic logic and comparisons, but you can accomplish some of these tests with a bit of extra juggling:

{% set constraintMet = false %}

{% for value in [0, 30, 50, 10, 9, 200] %}
  {# Here’s where you get to set up your advanced comparison criteria: #}
  {% if not constraintMet and value < 10 %}
    {% set constraintMet = true %}
  {% endif %}
{% endfor %}

Constraint {{ constraintMet ? "was" : "wasn't" }} met.

Alternatively, you can build the conditional into your for loop…

{% set constraintMet = false %}

{% for value in [0, 30, 50, 10, 9, 200] if not constraintMet and value < 10 %}
  {% set constraintMet = true %}
{% endfor %}

Constraint {{ constraintMet ? "was" : "wasn't" }} met.

…but this is a little more difficult to read, in my opinion, as it obscures the critical test. One improvement this offers, though, is that it prevents the loop from running after the constraint is met, unlike the first option, which runs/renders the body of the if block for every element in the array—even if it finds a match early on.

Whenever possible, I'd recommend stashing this kind of logic in a custom Twig extension. If you haven't built a plugin or module before, Pluginfactory can set you down the right path!

  Heads up! map, filter, and reduce functions have come to Twig (and Craft, as of 3.2), which make this possible to collapse this into a one-line statement: {% set hasMatchingValue = [0, 30, 50, 10, 9, 200] | filter(v => v < 10) | length > 0 %}. This just iterates over the array, and filters out anything that is 10 or greater with the implicitly returned value from the “arrow function,” then checks if the new array includes “more than zero” values.


How do you insert the site name into a default asset path? Multisite question.... how do I output the site into the assets path? currentSite won't work because its the admin panel, so the current site is always the default site.
Using the below, I will always get /default/footer-content with this, regardless of which site is having its field edited.

Try using {site.handle} instead of {{currentSite.handle}} and it should work ok.


Why is craft adding a rel attribute with inline styles in my textarea? It looks like redactor is adding a rel attribute to images as they are added to content via the RTE. Removing the rel attribute and then switching views adds it back in again.

How can I remove the rel attribute as it's affecting validation: https://validator.w3.org/nu/?doc=http%3A%2F%2Fgrowthwise.com.au%2Fnews%2F2015%2Fgetting-organised-for-tax-sucks-is-there-an-easier-way

Looks like this was a Redactor bug they fixed back in 10.1.

The latest version of Craft (2.4.2684) is currently running Redactor 10.2.2, so make sure you're Craft installation is up-to-date.


Group looped entries into blocks and wrap in markup every x number of loops I am trying to loop through all the entries in a section and "group" them into items which are in blocks of 9 then wrap them with some html markup so there will be the following code:

{% set selectedWork = craft.entries.section('selectedWork') %}

    {% for item in selectedWork %}

      {{ item.title }}

    {% endfor %}

The outer
 and
 tags need to wrap round the first 9 items then then next 9 etc. etc. Also the panel--1 needs to increment so that each panel goes in order so panel--1 holds 1-9 items then panel--2 holds 9-18 items etc. Is this possible using some kind of array splice or something?

The array slice something you are looking for is Twig's batch filter. Here's how you'd set up the groups and use loop.index to generate the class name.

{# Use the `find()` method to return an array of EntryModels #}
{% set selectedWork = craft.entries.section('selectedWork').find() %}

{# Group entries using the `batch` filter #}
{% set selectedWorkGrouped = selectedWork|batch(9) %}

{% for group in selectedWorkGrouped %}

    {# Set class using the loop index from outer loop #}
    {% set panelClass = 'panel--' ~ loop.index %}

        {% for entry in group %}

                {{ entry.title }}

        {% endfor %}

    </div

{% endfor %}


Craft Commerce Required Address fields I need to make the address fields in craft commerce required, as well as the phone number, etc. I tried to add the 'required' tag to the input element, but it breaks the form so you can't submit it -- at least in chrome. The submit button just stops working.

Is there any way to make these fields required without a plugin? Seems that this should be a feature included (or something optionally set in the code).

Thanks!

You can make address fields required in two ways - at the front end using your own js form validation or html techniques (and note that the Commerce example templates are not at all intended  for use with live stores, they're just examples to get you going with your own development).

The second approach is in a plugin -

Craft Commerce: Validation on Address Fields

...the ideal approach is probably to use both methods.

Currently (Dec 16) there isn't another way.  I presume this is to give maximum flexibility with checkout and perhaps (and hopefully) pending the time when addresses become proper element types with custom field support.  That would be nice.


How to check if a user has any entries they're an author of... in a plugin? This seems pretty simple in a template; along the lines of

if( craft.entries.authorId(10) | length ){ ... }

But how do I do that from a plugin?

craft->entries->authorId(10)

doesn't seem to exist and I've been banging my head against the docs not knowing what I'm actually looking for...

[EDIT]

I now have the following code:

$entryCriteria = craft()->elements->getCriteria(ElementType::Entry);
$entryCriteria->authorId = $existingUser->id;
$existingPages = $entryCriteria->find();

if ($existingPages) {
    AutoUserEntryPlugin::log('User already exists and has a page belonging to them; aborting.', LogLevel::Info);
    throw new Exception(Craft::t("You already have an account and a page created for you. Aborting. You have not been charged."));
} else {
    AutoUserEntryPlugin::log('User with ID ' . $existingUser->id . ' does not seem to have a page.', LogLevel::Info);
}

But with a user I know for a fact has an Entry for which they are the author, it's returning "User with ID 1198 does not seem to have a page".

Getting entries in plugins is slightly different from within templates and you should read the details on Working with Elements in a plugin in the Craft docs.

Taking that as a guide, you need to create an ElementCriteriaModel instance which selects the entries you are interested in:

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->authorId = 10;

Note that the ElementCriteriaModel won't pull disabled entries by default. If you want to pull both enabled and disabled entries, you can add the status parameter to your query:

$criteria->status = null;

Finally, you need to call find() on the ElementCriteriaModel to fetch the entries matching your criteria:

$entries = $criteria->find();


Gallery block inside a Matrix What's the best solution for having a 'gallery' block inside of a Matrix? By 'gallery block' I mean an ability to have multiple images, with captions, alt, and link, presented as a gallery on the front-end, but as part of a parent Matrix (the user needs to control the location of the gallery within the page content, so the page content is a Matrix).

What I really need is a Matrix within a Matrix, but that's not possible with Craft at the moment. I'd thought using a Table type inside the Matrix might work, but Craft doesn't offer Asset as a type for use inside a Table (makes sense, this would be a hacky use of 'table').

Another work-around might be to just have 'singular image' blocks and have the Template code notice when multiple Image blocks occur as siblings, and convert those into gallery mark-up - but I've no idea how to code that, if it's even possible.

Do you have better solutions?

I guess it depends on what information each Asset needs to contain. As you mentioned, a Matrix within a Matrix is not possible, so you will need a different method to attach additional information to each Asset.

One method that may work is to create Asset Meta Fields for Assets. This way, you can define additional things on each image on the Asset level. For example, you could have custom fields for things like title, description, copyright, etc.

With Asset Meta Fields in place, you could define one "Gallery" Matrix block that allows for multiple files to be selected. The order could be controlled by drag/dropping each of the selected Assets.


How to get user's information when registering or logging in via ajax form I did search for this but was unable to find the documentation for getting user's data on a return when logging them in from a front-end facing login form (I need to do the same for a registration as well).

I need to get a return of the user's Id and their email.

This is my code for the form. It works fine,  I just cannot seem to find the user's info in the data return so if anyone has an example or suggestion it would be greatly appreciated.

$('#workshop-registration-user-login-form').submit(function (e) {
  e.preventDefault();
  var data = $('#workshop-registration-user-login-form').serialize();

  $.ajax({
    type: 'POST',
    url: '/users/login',
    data: data,
    headers: {'Content-Type': 'application/x-www-form-urlencoded'}
  })
  .success(function(data) {
    console.log(data.currentUserId);

    ...

    // get data populate the fields
  })
  .error(function(data) {
    console.log('error');
  });

Not sure what other user info you're looking for, but Craft's UsersController will only return two things in the JSON response of a successful login for an AJAX request.

A success key set to true and a returnUrl key set to where the login redirect should go to.


Asset field empty in graphql query response I have a problem with a graphql query which includes an asset field. The asset field is always an empty array. There are no errors in the graphiql tool.

The graphql api is not public unfortunately but if anyone has any ideas on how I could troubleshoot that would be appreciated.

The query itself is pretty simple:

{
   entries(section: "posts") {
        title
        ... on posts_posts_Entry {
            testText
            imagetest {
                id
            }
        }
    }
}

Response:

{
  "data": {
    "entries": [
      {
        "title": "Headline",
        "testText": "testing",
        "model": [ ]
      }
    ]
  }
}

Check that the schema you're querying has permissions to access the asset volumes that your asset field is pulling from.

For images to be returned, the schema you are querying must have permissions for every asset volume that your asset field can pull from. If there are any assets selected in the field which the schema does not have permission to access, then the field will return an empty array.


Ajax post request front-end csrf token I'm trying to make a simple post request with ajax to a controller in plugin.
The problem I'm having is that I always get a 400 Bad request because I don't send a valid CSRF Token.

But I can't figure out how to get this in javascript. I found multiple examples saying you get it by calling

Craft.getCsrfInput();

but this only works in "CP mode", on the front-end the Craft object is not available. I also found that importing it is not a good idea.

So anyone who can tell me how to do this?

You can take a look at the guide Enabling CSRF Protection

<script type="text/javascript">
    window.csrfTokenName = "{{ craft.app.config.general.csrfTokenName|e('js') }}";
    window.csrfTokenValue = "{{ craft.app.request.csrfToken|e('js') }}";
</script>

var data = {
    // ...
};

// Add the CSRF Token
data[csrfTokenName] = csrfTokenValue;

$.post('/some/url', data, function(response, textStatus, jqXHR) {
    // ...
});


Where is this spam message sent using the Contact Form plugin? I've noticed all of my Contact Form spam has a referrer that matches the form's location. Building a module is out of my comfort zone for now (not really a developer). I am currently using the Honeypot plugin, though, so I have a simple conditional in my contact page which compares the referer to the URL and if it's the same, fills the Honeypot field with a value.

The Honeypot plugin will set the isSpam flag to true, which prevents the message from being delivered. Then the form redirects to its default "Thank You" template.

What I want is for this template to display a message that the submission was flagged as spam and not delivered. I can see that /craft/vendor/craftcms/contact-form/src/Mailer.php has code that sets a message when isSpam is set to true:

if ($event->isSpam) {
   Craft::warning('Contact form submission suspected to be spam.', __METHOD__);
   return true;
}

…but for the life of me I can't find how to access Craft::warning or to have it output into a template. Any pointers are greatly appreciated. Thank you!

Currently not possible without forking the Contact Form plugin and changing the logic to do what you're looking for.

There are other form builder/contact form plugins that might have more options when dealing with SPAM you might want to look at as well: https://plugins.craftcms.com/search?q=contact%20form


Need no search engine tracking option in Craft websites Can you let me know what the process would be? I heard there was a no track tag we can put in the site header so the sites won't show up in search engines.

If you're used to another CMS such as WordPress, you're probably used to using a Discourage search engines from indexing this site option. As Robin's answer mentions, the training wheels are off.

However, that doesn't mean you can't replicate WP's functionality.

When you tick that box, there's a few things that happen behind the scenes:

If robots.txt file is requested, WP auto generates a version that tells google to skip indexing the site.
A <meta name="robots" content="noindex,follow"> is added to each page.
XML-RPC pinging is disabled (so WP won't "ping" services like ping-o-matic when you update pages on the site).

Craft doesn't automatically ping any services so you don't have to worry about the last option but the first 2 are pretty straightforward to setup.

Global Lightswitch / templates

Create a Global called siteSettings and add a Lightswitch with a field handle of disableIndexing so you can reference throughout the site.

In the <head> section of your templates, it can be as simple as:

{% if siteSettings.disableIndexing %}
    <meta name="robots" content="noindex,follow">
{% endif %}

robots.txt

The second piece is some Craft magic. If you don't already have a robots.txt file, create one inside Craft's templates folder or remove it/move it if it exists in your public root folder.

Craft is smart enough to parse your robots.txt file as Twig code and even output the proper mime type. This allows you to dynamically change it as it is requested.

When robots.txt is requested, instead of serving the file directly as your web server would, Craft will instead take the request and because there is a file that matches robots.txt inside templates folder, it'll use it.

Put this in your robots.txt file:

User-agent: *
Disallow: {% if siteSettings.disableIndexing %}/{% endif %}

We're basically telling search engines not to index anything when the Lightswitch is ticked. That's a pretty basic robots.txt file but it gets the job done for this example. There's a ton more options.

Wrap up

That's really it.  The only thing to remember is to UNTICK the box when your site goes live or when you want search engines to revisit.

Lots of people in WP land get burned because they forget to turn it back on so this isn't really a great thing to do in the first place but this answer goes into some basic Craft concepts.

If you want more control, instead of a Global lightswitch, you could setup one up on a per entry basis much like Yoast does. This is pretty common for landing pages used for PPC so they don't get indexed to begin with. Just remember not to include them in your sitemap as well.  Also consider the SEOMatic plugin which can do all of this and more.


Fields Missing. Gone from Database as Well as Control Panel Recently the organization I work for started a podcast and wanted to add a section on the site where people could find some information about the podcast, some links to subscribe, and more details about each individual episode.

So I created some fields, a field group, and a couple of sections and created migration files using the Migration Manager plugin. Everything was fine for over a month, I am not sure if it was the deployment of some other work or a bug but one day I was alerted to the fact that the podcast episodes on the site were missing information. I went into the control panel to add the data back and was surprised to see those fields were no longer available on the entry. I check the field layout and they were missing there too as well as in the list of fields. So I went back to my local dev environment and created new migration files using Migration Manager. After another deployment that restored the fields. I added the data back and went on with my life. It happened again shortly after and I repeated the process of creating new migration files for the missing fields.

That was a couple weeks back. It happened this morning and I decided that not only was recreating migration files not a sustainable solution but it may be causing more issues.

I logged into the database using Sequel Pro and can see that the fields and the field group no longer exist there, but it looks like the data that was previously entered still exists in the content table as it looks like a new column is created for each field in the system. Additionally, I can see duplicate fields that were almost definitely the result of my multiple migration files. Those fields have their names appended with what looks like some encoded information (ex: field_episodeTeaser_Z9E6Zcu6PN).

Has anyone run into an issue like this? At this point, I am nervous to implement any solution as I have no idea what has caused/is causing this issue. Any help would be greatly appreciated.

It sounds like something/someone is updating which could be causing the migrations to run and then subsequently fail... that could cause data loss but that's hard to say or know exactly.

When this sort of thing happens, you should be reverting to a last known good backup and then figuring out what went wrong.

That's going to be the only sane way to debug this. I wouldn't try to push something locally onto a bad state on production unless you overwrite everything (which is a hail mary move to restore to a good state).

Are you using Craft 3? The Migration Manager plugin is now called Migration Assistant. Make sure you're using updated versions of the software, as old versions can cause weird issues.


Notify users when item is back in stock Is it possible to let customers enter their email on individual product pages if the stock is 0, and then automatically send them an email when the stock goes above 0 again?

This is not currently possible out of the box with Commerce at time of writing (Sept 2016).

You could write a custom plugin to do it, which would basically keep a table of these people-to-contact, and run a task (or use a controller you trigger by cronjob) -> to send out the emails at such a time the product is re-stocked.

It wouldn't be spectacularly difficult to implement.  Here's a rough sketch:

A form on the site to accept the email addresses -> that form posts to a controller in your plugin - which stores a record of the product, customer email, and date emailed (date emailed is initially null).

You then have a task that periodically runs and checks these records - for each record, if there is no date emailed, check the stock of the product - if greater than zero, send an email and log when it was sent.


Problem with IF conditional not working I have 2 sections, events and activities, that share many fields. But activities doesn't have an eventLevel field as there isn't a level. eventLevel is a radio fieldtype. So I want to insert the eventLevel when it exists and if it doesn't just insert the text "Activity". I've tried various tests on if eventLevel is defined, is null, and length. If there is an eventLevel it displays, but if it's an activity I end up with an empty cell.

{% set events = craft.entries.find({section:'events,activities', eventDate : ">= " ~ now.w3cDate() , order:'eventDate'}) %}
{% if events %}
    {% for entry in events %}

        {{ entry.eventDate.format('D j M') }}
        {{ entry.eventName }}
        {{ entry.nearestTown }}
        {% if entry.eventLevel is defined %}{{ entry.eventLevel }}{% else %}Activity{% endif %}

    {% endfor %}
{% endif %}

I've also tried the twig default filter with the same result:

{{ entry.eventLevel|default('Activity') }}

To test if a field exists, you'll have to use brackets notation, i.e.

{% if entry['eventLevel'] is defined %}
   ...
{% endif %}

When the field exists, but there isn't a selected option, the Radio FieldType returns an empty string, so you also need to test for entry.eventLevel != ''.

Putting it together, I believe a ternary conditional would perhaps be the most succinct solution in your particular case:

{{ entry['eventLevel'] is defined and entry.eventLevel != '' ? entry.eventLevel : 'Activity' }}

What the above does is to first check if the entry has a property 'eventLevel' – the brackets notation is needed here, to avoid Twig throwing an exception if the entry variable doesn't have the property – before checking if the attribute's value is not an empty string. If both of those statements evaluate to true, then the attribute's value is printed; if not, the string Activity outputs.

This is a bit beside the point, but if you're wondering about the syntax here, the so called ternary operator (e.g. {{ variable ? 'yes' : 'no' }}) is just a kind of a short-hand way to write conditionals. Ternary operators are supported in many programming languages (including JavaScript and PHP).

If you wanted to, you could write out the full conditional and it would work exactly the same:

    {% if entry['eventLevel'] is defined and entry.eventLevel != '' %}
       {{ entry.eventLevel }}
    {% else %}
       Activity
    {% endif %}

I'd argue that a ternary operator is more readable, shorter and also makes it easier to deal with potential whitespace issues etc. when inlined in markup like this, though.


URI with multiple URL formats (after slug) Is it possible to have a URI like this: /artist/{slug}/news
to create an overview of all news articles of this particular artist?
I tried to set it up with Routes and with a section Entry URI, but I get a 404

You can achieve this by writing a module and using the UrlManager::EVENT_REGISTER_SITE_URL_RULES event.
Basic example:
<?php

use craft\elements\Entry;
use craft\events\RegisterUrlRulesEvent;
use craft\web\UrlManager;
use yii\base\Event;

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

        Event::on(
            UrlManager::class,
            UrlManager::EVENT_REGISTER_SITE_URL_RULES,
            static function (RegisterUrlRulesEvent $event) {
                $artistEntries = Entry::find()->section('artists')->all();

                foreach ($artistEntries as $artistEntry) {
                    $event->rules[$artistEntry->uri] = ['template' => '_pages/artists/news'];
                }
            }
        );
    }
}

Then, in the _pages/artists/news.twig template, you'll need to extract the artist's slug from craft.app.request.url and use it to get the Entry corresponding to your artist.


How to set multi-lingual image paths in a css file for different environments? Not sure how to do this. I'm setting up a multi-lingual site with a couple of locales and I have 3 different environments set up. I've set up some environmentVariables for assets store and assets path these work fine in the templates.

However how do you deal with background images in the CSS file? Can you include the Twig code? i.e. add {{ craft.config.environmentVariables.sitePath }} to the image path I'm assuming not as CSS uses the curly braces. I know I can add the full URL to the image but this is no good when trying to work within different environments where the overall domain path will be different each time.

Anyone come across this problem and have any ideas?

Many thanks.

The easiest option is probably to use inline styles in your markup for the relevant element(s):

{% set sitePath = craft.config.environmentVariables.sitePath %}


Is is possible to add a bespoke Twig template loader? Twig lets you provide alternate (or multiple) template loaders. I'd like to take advantage of this to do use a bespoke loader to pull in components from a pattern library using a shorthand syntax like {% include '*mycomponent' %} or similar.

Does Craft expose the environment used for loading templates in a way that I can append/overwrite the default filesystem loader with my own custom implementation?

Any pointers in the right direction would be much appreciated!

When you call Craft's TemplatesService->getTwig()  (craft()->templates->getTwig()), the first parameter you can pass in is your custom template loader classname.

i.e. craft()->templates->getTwig('\My\Awesome\Plugin\TemplateLoader, array('my' => 'options')


Is there a way to format the Asset Size variable to Mb, Kb, etc.? I'm trying to display the file size of a file uploaded in Assets. I can get it to display the number of bytes in the file. https://craftcms.com/docs/templating/craft.assets#size

Is there a way to format that number to Mb's?

This should do it:

{% set bytes = asset.size %}
{% set kiloBytes = (bytes / 1024)|round(2) %}
{% set megaBytes = (kiloBytes / 1024)|round(2) %}

bytes = {{ bytes }}
kiloBytes = {{ kiloBytes }}
megaBytes = {{ megaBytes }}

You can look at Twig's number_format filter if you want to get fancy with how to display the numbers.


Get all elements (entries) where a field exists I'm developing a plugin and I'm searching a way to get all entries where a field exists (by id or handle).
I'm trying to get all the entries even if the value of the field is null, empty or text.

I can't find a way to that. Can somebody help ?

Fields are related to entry types via their field layout.

You need to find all field layouts your field is attached to then find entry types using these field layouts. Once you have that, fetch all your entries by types.

If you already know your field's id, you don't need this but to find the id of your field by its handle:

$fieldId = Craft::$app->getFields()->getFieldByHandle('yourfieldHandle')->id;

Get all field layouts using that field:

$fieldLayouts = (new Query())
    ->select(['layoutId'])
    ->from(['{{%fieldlayoutfields}}'])
    ->where(Db::parseParam('fieldId', $fieldId))
    ->column();

Get all entry types using the field layouts you've just fetched:

$entryTypes = (new Query())
    ->select(['handle'])
    ->from([Table::ENTRYTYPES])
    ->where(Db::parseParam('fieldLayoutId', $fieldLayouts))
    ->column();

Or you can do both the above at once (get entry types by field id):

$entryTypes = (new Query())
    ->select(['entrytypes.handle'])
    ->from(['{{%entrytypes}} entrytypes'])
    ->innerJoin('{{%fieldlayoutfields}} fieldlayoutfields', '[[entrytypes.fieldLayoutId]] = [[fieldlayoutfields.layoutId]]')
    ->where(Db::parseParam('fieldlayoutfields.fieldId', $fieldId))
    ->column();

Once you have your entry types, get all entries matching:

$entries = Entry::find()->type($entryTypes)->all();

Altogether:

use Craft;
use craft\db\Query;
use craft\elements\Entry;

...

// Fetch your field by its handle, if you know the id, just manually set it here
$fieldId = Craft::$app->getFields()->getFieldByHandle('yourFieldHandle')->id;

// Find all entryTypes using the fieldLayouts your field is attached to
$entryTypes = (new Query())
    ->select(['entrytypes.handle'])
    ->from(['{{%entrytypes}} entrytypes'])
    ->innerJoin('{{%fieldlayoutfields}} fieldlayoutfields', '[[entrytypes.fieldLayoutId]] = [[fieldlayoutfields.layoutId]]')
    ->where(Db::parseParam('fieldlayoutfields.fieldId', $fieldId))
    ->column();

// Find all entries by entryType
$entries = Entry::find()->type($entryTypes)->all();


Can I cache an include for use elsewhere in a template? I have an include that is doing a DB query (it generates a menu of entries) and that's used more than once on a template.

Is there a way I can cache the first parse for later use to cut down on DB hits?

You would wrap the code in your include in cache tags and use the keyword globally with it.

{% cache globally for 3 years %}


Craft 3 entries "before" not working I have a Craft 3 site. For some reason the before filter isn't working when pulling entries from a channel, but after does. This is not a data issue.

{% set start = "2 months ago"|date() %}
{% set end = "next week"|date() %}

{% set listings = craft.entries({
    section: "tvListings",
    limit: null,
    with: "channel",
    before: end
}).all() %}

For clarity the dates result in:

Start: Feb 4, 2018
End: Apr 9, 2018

And one of the example entries is definitely in that date range (April 2nd).

If I ditch the "before" and go "after: start" it does work. If I try to say "give me all entries before Apr 9, 2018", the "Thunderbirds are go" (or any other listings) do not show.

Surely I'm not doing something super stupid right?

I'm running Craft 3.0.2.

Thanks.

EDIT: I've started pulling apart the CMS to debug. EntryQuery->beforePrepare() builds the query that filters by date. Although the props before and after are set, once they're passed through Db::parseDateParam() it mutilates the dates and somehow comes out with "2017-12-31 11:00:00" for both - so no bloody wonder it's not working. If this is a date format thing for those props I'll update the answer.

This is down to lacking documentation. Before/after are supposed to take  "DateTime|string" as a parameter in the ElementQuery. The format is not documented.

Use "Y-m-d H:i:s"

{% set start = "2 months ago"|date("Y-m-d H:i:s") %}

Behind the scenes in building the query the CMS was replacing any dates I sent through with "2017-12-31 11:00:00" (no idea where this came from). After realising this I spelled out the before/after in format "Y-m-d H:i:s" and the dates started working.

Pixel and Tonic - Can you please update the docs to include the available date formats - or at least throw an error if it's not valid.


Need help: Multiple Listing channels with one template. DRY I have several Listing channels that all use the same templates:

E.g.

Templates:

/templates/view/overview.html
/templates/view/detail.html

Channels

News
Research Updates
Upcoming Events

How can I only list the entries for each channel at their respective URL without having to duplicate the templates?

E.g.

"http://mysite.com/news" should only list the the latest 20 news stories with links to the detail page.

{% for entry in craft.entries.section('news', 'research', 'events').limit(20).find() %}

{{ entry.title }}

{{entry.postDate|date('M j, Y')}}

{{ excerpt|length > 250 ? excerpt|slice(0, 200) ~ '...' : excerpt  }}

Read More

{% endfor %}

A good option here is to make use of craft.request. As long as the URL is the section handle, you can do something like this:

{% current_section = craft.request.firstSegment %}

{% for entry in craft.entries.section(current_section).limit(20).find() %}
...
{% endfor %}

If the url is mysite.com/news, firstSegment will return 'news', which you can use in your craft.entries call.

UPDATE:

If your URLs need to be different than the section handles, make use of Twig's include with tag. For each section, you will need an index.html template with the following:

{% set current_section = 'thisSectionHanle' %}
{% include listPage.html with current_section %}

listPage.html can be the template that has the actual fetch and display logic. Using include with, listPage.html will have access to the current_section variable.

So not perfectly dry, but the main logic chunk will not have to be repeated.


What are the options for taking membership subscriptions via Craft? In addition to ‘What is the current landscape regarding e-commerce plugins for Craft?’, I’m looking for current options for setting up membership subscriptions.

I have a site in development that was using the ‘Commerce’ and ‘Membership’ plugins from Dukt (private beta) but unfortunately they no longer appear to be available.

The basic requirements would be for a user to signup, pay for membership (ideally through Stripe in this case), which then automatically assigns users to different membership groups depending on their subscription level/status when appropriate (e.g. full, trial, expired, etc).

I don't think that there currently is a plugin option right now, but keep an eye on the craft plugin page. However, given your requirement to "automatically assign users to different membership groups", I think you would need to write your own regardless. That is pretty specific and would require that you have your user groups set up to match the subscription plans.

I recently did something similar for a project. Saving for a few issues with javascript and learning the API for stripe it was fairly straightforward. It is currently a bit hard-wired to the specific project, however — I still need to abstract it so that it's more portable. I would be glad to share some tips, if you are up for writing your own.

The process that I'm using is to store the StripeCustomerId in the custom fieldtype. As far as craft is concerned that's all just 1 field, that is auto-generated and never exposed to the client (i.e. they can't edit the 'stripeCustomerId').

Whenever an 'account' (could also be 'user') is created, I use the onSaveUser event to generate and store a StipeCustomerId. The rest of the field just sends calls to stripe to add card, delete card, create subscription, cancel subscription, etc. via service methods, and then refresh itself with the most up-to-date customer data from Stripe (doesn't ever store this info, just the customerId).

Besides this the only thing that you would need to add is to reassign the userGroup based on the plan selection. However, if you want to ensure that the userGroup is always synced with the Stripe account (i.e. if the client, for example, canceled the subscription directly from their Stripe account), you would probably need to create a webhook to trigger the userGroup re-assignment. Or instruct them to always re-save the user in craft afterwards.


Auto enable/install plugin through config Is it possible to auto enable/install a plugin through config (or another way) rather than having to do this through the database?

The short answer is no. The long answer is sortof, if you’re running Craft 3.

Since plugins are technically modules in Craft 3, you should be able to bootstrap a plugin onto the application just like any other module.

To do that, update config/app.php with these modules and bootstrap sub-arrays:

return [
    'modules' => [
        'contact-form' => function() {
            $plugin = Craft::$app->plugins->createPlugin('contact-form');
            $plugin->setSettings([
                'toEmail' => 'foo@bar.baz',
            ]);
            return $plugin;
        }
    ],

    'bootstrap' => [
        'contact-form',
    ],
];

Using Contact Form as an example. For a different plugin, replace all of the 'contact-form' strings with the right plugin handle, and change the settings array to whatever the plugin is expecting. (You can find which settings keys the plugin supports by checking its Settings model – usually either src/Settings.php or src/models/Settings.php.)

Some caveats off the top of my head, though:

Craft won’t know that the plugin is installed, so it will still look like an uninstalled plugin in Settings → Plugins.
You won’t be able to edit the plugin’s settings in the Control Panel; only from config/app.php.
You won’t be able to update the plugin from the Control Panel; only via composer update.
If the plugin has an install migration, you will need to manually duplicate it as content migrations. And whenever you update the plugin, you’ll need to check if it added any new migrations, and manually duplicate those as content migrations as well. (Any migrations that were there at the time you first installed the plugin, besides the Install migration, can be ignored.)

EDIT

If you just want to be able to install a plugin programmatically, but don’t mind if the plugin ends up getting a row in the plugins DB table, that’s easy. Just create a new content migration, with the following safeUp() function:

public function safeUp()
{
    Craft::$app->plugins->installPlugin('plugin-handle');
}

Then you just need to run the migration on each of your environments. You can either do that from Utilities → Migrations in the Control Panel, or by running the following CLI command:

./craft migrate/up

Maybe worth noting that you can also install plugins directly from the terminal, using this command:

./craft install/plugin <plugin-handle>


How do I toggle list/grid view on section index page without affect category filtering I have a section "projects" with entry type (projectPage) with and an index page set up displaying a grid view of entries.  I have also set up category filtering via links to the {{category.url}} which point to the projects/index template.

I want to add another entry type (projectList)  that will have entries that
1. have only title and category relationships defined
2. do not have their own url.

I want to add a toggle button to the page that will change the display from a grid view to a list view combining the (projectPage) entries and (projectList) entries, but I want it to remain in effect as you cycle through the categories, until it is deselected.

I had some success setting  up a route to projects/list  that filtered the entry types based on the url with   {% if craft.request.getSegment(2) == link %}

but the relationship brakes when I click on a category link.  I'd prefer to have everything in the same template file and not add the "list" to the url if possible.

Currently I'm think that to hide the (projectList) entry URL's I'd have to set up another section "projectListings"  and set up routes  for project/list to point to the new index template and add routes for each category for project/list/{{cat}}  but I'm hitting a roadblock as to if this is the best way to go about it, and how exactly to implement it.

Hopefully this is not too broad a question, as I could use a little direction.  Thanks.

If I don't misunderstand anything from your question, you're basically looking for a way to pass data with a link, in your case the toggle state, which is responsible for the grid / list view.

There's multiple ways to do that. See Brad's short but precise answer on an related question.

You said that you're preferably looking for a way that doesn't reveal the toggle state in the URL. I can understand the thinkings behind that, but keep in mind, that this is the only way one could save the site or post a link to someone else with the information included.

Another idea: Most sites probably use Javascript for such a toggle (I've seen many Wordpress themes with such a feature). But you'd still need to save the state somehow or completely AJAXify the relevant pages.


FeedMe Direct Feed Link not showing in CP The FeedMe docs state that there is a Direct Feed Link for cron usage. I'm not seeing it. All I see is the Debug, Status and Delete icon. Or is this a PRO feature?

I'using Craft 2.6.x and FeedMee 2.0.6

Cheers,
Martijn

Apologies for the confusion, this was updated in the latest Feed Me version, but not reflected in the docs (we're currently re-working them a little).

The direct feed link icon is no more - its not accessible on the first page where you set the name and URL.


Failed to instantiate component or class error I have a site with a custom module that was working fine until just recently but I tried to do a plugin update via CLI and it returned Failed to instantiate component or class "modules\exifreturn\ExifReturn", even though the update did actually complete. But after that, the front and backend of the site were displaying the same error.
I've seen a similar question already about this but the suggested fix in that question isn't working for me. I've also seen some discussion in Discord and have been looking at how NY Studio set up their Devmode repo and as far as I can tell, I've got things set up the same, so not sure why it's not working.
In config/app.php I have:
return [
    'modules' => [
        'exifreturn' => [
          'class' => \modules\exifreturn\ExifReturn::class
        ]
    ],
    'bootstrap' => ['exifreturn'],
];

In composer.json I have:
"autoload": {
  "psr-4": {
    "modules\\exifreturn\\": "modules/exifreturn/src/"
  }
},

and on the server I have this in the modules folder:

Can anyone see what I might be missing?

Make sure you have the correct namespace in your modules/exifreturn/src/ExifReturn.php class. From what you show, you should have:
namespace modules\exifreturn;

Right at the top, after <?php. With that in place, run composer dumpautoload.


Is it possible to execute ./craft via cron? I'm trying to execute Craft 3.3.X CLI commands via cron. I can execute ./craft from ssh no problem, but the same type of commands triggered via cron do not execute.

These command works via SSH:

# cd /home/USERNAME/CRAFTROOT
# ./craft backup

# /home/USERNAME/CRAFTROOT/craft backup

These commands do nothing via cron:

cd /home/USERNAME/CRAFTROOT;./craft backup

/home/USERNAME/CRAFTROOT/craft backup

Any ideas?

Explanation for answer
Since the craftcms supplied CLI file aka ./craft uses the following to identify it's location:
// Set path constants
define('CRAFT_BASE_PATH', __DIR__);
// the above finds out the file path where the ./craft file is stored in

There's no need for any cd commands in your crontab, so all you have to do, is make sure that you either have your ./craft file marked as executable (chmod +x path/to/craft) or explicitly call it with php or usr/bin/env php
Since according to your observations /home/USERNAME/CRAFTROOT/craft backup doesn't work in cron, I'd suggest using the following instead
TLDR: (solution)
/usr/bin/env php /home/USERNAME/CRAFTROOT/craft backup
Potential causes of issue
Now I won't guarantee that this was the cause, but it might just be the case.

The User running the cronjobs was different compared to the one you used in ssh => different permissions => somehow broke execution through cron.
The /home/USERNAME/CRAFTROOT/craft file was not marked as executable (fix -> chmod +x /home/USERNAME/CRAFTROOT/craft), though in that case one of your ssh commands should've also failed.
The different environment in Bash/Shell (for example, a different $PATH or the .bashrc not being read) in cron compared to ssh may also have been the cause behind this issue.

Other than that I'm not sure what could've caused the issue...
Q: But just to be sure, (please add a comment as answer), you ran your ssh commands without the # infront of them, right? Otherwise it'd make sense that your ssh commands wouldn't output any failures since your commands would simply be read as comments. [A in comments]
How to figure out what the cause was
Adjust your non-working crontabs by adding  >> /home/USERNAME/CRAFTROOT/cron.log to the back of the cronjob, this'll store the output of your command into the file located at /home/USERNAME/CRAFTROOT/cron.log, this would help in identifying what caused your issue in the first place.


Does Craft/Twig help with cache-busting js/css? Usually, I would use PHP to append the filetime of a file provide cache-busting. Does Craft or Twig do anything that can help with this?

No, Craft/Twig itself doesn't really do anything in regards to cache busting your assets. Bust is one tool, and you'd also want to take a look at the awesome Minimee plugin port.


Set status in a plugin I was wondering if it's possible to modify the status of an Entry within a plugin?

I've tried setting the status property but I get a readonly error.

$entry->status = $status

Not directly, but you can indirectly change it. An entry's status is defined by several attributes.

An entry is considered "live" if it is enabled (both on a per-locale and global basis), it has a post date in the past and an expiration date that doesn't exist or hasn't been met yet.

If the entry is enabled and the post date is greater than the current date, then the entry's status is "pending".

If it is enabled and the current date is past the expiration date, then it has a status of "expired".

If an entry is not enabled at all, it has a status of "disabled".


Understanding migrations and CLI commands Can someone please help explain some basics regarding migrations and the associated CLI commands to help troubleshoot when things fail? Specifically,
How does craft know which migrations have been applied and which are new?
I.e. Is it by comparing the craft_migrations table to the migration files found in '/vendor/craftcms/cms/src/migrations' folder (or plugin folders)?
Where does the information from running 'php craft migrate/new' and 'php craft migrate/history' come from? I ask because, when running php craft migrate/all and a migration fails, if I reload the previous DB and run migrate/new it says "No new migrations found", which is clearly wrong. Likewise running migrate/history displays "No migration has been done before." But when running migrate/all again it does attempt to run the migrations again. So clearly something is out of sync (or is terribly wrong in this project).
How are version numbers and migrations associated with each other? I.e. Is it simply based on whatever migration files happen to currently exist in the 'migrations' folder based on the last composer update?
What determines the order that migrations are run? I.e. Are they simply run alphabetically, based on the file names in the 'migrations' folder?
Finally, if a migration fails, is there something else that should be done besides restoring the DB to reset the craft state, before attempting to run migrate/all again?
Appreciate the help. Thanks.

How does craft know which migrations have been applied and which are new? I.e. Is it by comparing the craft_migrations table to the migration files found in '/vendor/craftcms/cms/src/migrations' folder (or plugin folders)?

Exactly!

Where does the information from running 'php craft migrate/new' and 'php craft migrate/history' come from?

migrate/history purely checks the migrations table in the database for a list of migrations that have already run.
migrate/new grabs the same list of migrations from the database that migrate/history does, then compares it again the migrations folder on the file system to find any newer migrations (using the timestamp in the filename) that haven't run yet and returns that list.

So clearly something is out of sync (or is terribly wrong in this project).

Something does sound out-of-sync to me.

How are version numbers and migrations associated with each other?

Craft's (and a plugin's) version number is independent of migrations. Both have a separate concept called a schemaVersion, and when that number gets incremented, that tells Craft that a plugin (or itself) that there are new migrations that need to run.

What determines the order that migrations are run?

They are sorted, but since timestamps are embedded in the migration names, they will run from the oldest unapplied migrations to the newest unapplied migrations.

Finally, if a migration fails, is there something else that should be done besides restoring the DB to reset the craft state, before attempting to run migrate/all again?

Nope - restore from a pre-update attempt database back, fix whatever caused it to fail, then try again.


Get an Asset's Filename Without the Extension How do I get an asset's filename without the extension? So if my filename is my_cool_photo.jpg I want to return my_cool_photo. Using {{ entry.assetsField.one.filename }} returns the name of the file with the extension included.

A simple method would be to trim the extension from the filename (see this fiddle):

{{ assetsField.filename|trim('.' ~ assetsField.extension, 'right') }}


How to build a navigation from sections I've went through several examples related to my issue, but I quite couldn't find What I'm looking for.

Well, there was one, but with pre-defined array.
What I'm looking for is to only output all my sections, with link and title +  at the matched section's URL, display all entries belonging under relevant section.

I've found here one snippet of code, which logic sounds about right to me, but it's like there's missing something.

{% set sections = [] %}
{% for section in craft.sections.getAllSections() %}
{% if section.type == 'channel' %}
{% set sections = sections|merge([section]) %}
{% endif %}
{% endfor %}

Any help, or direction would be appreciated and I believe, it would help those, Who are like me at the beginning of this journey.

Thank you

There is not really a very simple way to do this. One thing to keep in mind is that channels and structures do not have an 'index' page defined by default. Essentially there are no uri's for channels and structures as a whole, only for the entries within them. You need to create index pages yourself, using:

Singles (one for each of your index pages), or
a Structure (using different EntryTypes for the different levels and/or page types), or
Template files (placed directly in your templates folder)

The other problem is that you may have channels that do not represent pages at all, but are just collections of data to be used elsewhere; likewise, sections do not really have a way to define order. Overall not really a good mechanism to generate nav.

There are, however, other ways to do this.

One solution is to use a dedicated Structure specifically for navigation (called 'primaryNav' for example) with a related entries field that links to other entries and a custom url field to link to other pages as needed. You can then loop through that structure to generate your nav.

Another option is to define all of your top level pages (what might normally be considered singles) within a structure using EntryTypes to differentiate the various page types and define the field requirements (i.e. a structure called 'pages' for example). You can then loop through this structure to generate your nav, using the EntryType to determine which template code to display.

Either of these techniques can be used with other channels and or structures as needed to generate lower level pages where there are many of the same type (i.e. news, blog, articles, projects, etc.).

There are a lot of good examples of this on the exchange site. Also have a look at craft's nav tag in the documentation.


Adjust all date/times to users current timezone I've done a bunch of research and I can't seem to find a suitable answer for this issue without hacking which I'd like to avoid.

My client needs the entries in the DB to always assume they're relative to the users current timezone. So content set to display at 9am on Monday morning will display at 9am Monday in every timezone.

The locale options in Twig only adjust the UTC timestamp to the users current timezone but it's still displaying content based on UTC timestamp in the DB.

Through MySQL I can use the following command per session to accomplish what I'm looking for:

SET SESSION time_zone = '+10:00';

This appropriately offsets the MySQL time to match a users timezone +10 hours ahead of UTC, in this case Australia.

Reading this article it seems that "initSQLs" might be the answer but it's a Yii article that talks about adding that command to the db array within the protected/config/main.php file which I'm unsure of how to tie into.

Nevertheless, I'm hoping someone might have some insight into how I can bootstrap the DB calls per user session or another solution potentially utilizing a plugin.

We're doing timezone lookups by IP address, I realize the potential issue, so the option will need to work for both logged in and logged out users.

I wouldn’t recommend hacking the MySQL timezone, since that would happen on a global basis, not just for the current user, and will result in some weird race conditions whenever two people are using the site/CP at the same time.

Getting an entry to go live at a certain time based on their time zone is a fundamentally different thing than the feature provided by entry Post Dates. So your best bet here is to code the functionality yourself, rather than trying to bend Post Dates into something they’re not.

To do that, you should create your own custom Date/Time field to hold the post dates. Give it a handle that’s different than “postDate” so you don’t run into naming conflicts in your templates - let’s say it’s “liveDate”.

In your templates, you can query against your liveDate field like so:

{% set timezone = 'Europe/Paris' %}
{% set localDate = date()|date('Y-m-d H:i:s', timezone) %}
{% set entries = craft.entries.section('blog').liveDate('<=' ~ localDate) %}

That will only give you entries where the liveDate field is before or equal to the current date/time, in whatever timezone you’ve passed in.

Couple gotcha’s:

Twig’s |date filter requires that you specify the timezone using one of PHP’s supported timezone names, not a numeric offset. Your script that is determining the timezone based on the user’s IP will need to account for that.
The built-in Post Date fields will still be enforced, so you will need to get in the habit of making sure those are set at least 14 hours before the custom liveDate field is set (UTC-14 is the earliest time that “tomorrow” begins). That’s assuming you’ve left your system timezone set to UTC in Settings > General.


How do I test if Craft CSRF Protection is properly enabled? Craft supports enabling CSRF protection on our front-end forms.  They even have a nice, easy-to-follow, help page called "How do I enable CSRF protection?"

Let's say we pull that all off without a hitch. Our forms output the csrfTokenName and csrfToken and the browser cookie is generated just as expected.

Now, how do we test if it is actually working?  Are there any steps an average, not-very-technical developer can take to see if CSRF protection is behaving as expected?

After the page loads with the form loads, delete the CSRF cookie, then submit the form.  It should fail CSRF token validation.


Insert a url segment without creating sections I have a very simple site split into sections. All pages use just one template.

The previous site had sections such as /section/subject.  I had thought I could have all entries in just one section and then alter the URL on each entry to include a 'pretend' section /section/{slug}, but this defaults to /section-subject.

Is there a way to have /settings/subject/ without creating new sections?

Many thanks

Martin

From what I gather from your question you want some sort of sub-categorisation of your entries.

Such that one entry can have the URL as:
    siteUrl/section/subject-1/entry-slug

while another entry can have a URL as:
    siteUrl/section/subject-2/entry-slug

If that is what you want to achieve then you have to look into Structures instead of Channels

Here is the link: http://buildwithcraft.com/docs/sections-and-entries#sections

You can basically have multiple entries with sub-urls in the same structure section.


Trouble finding the correct path to template in custom module and getting the "Unable to find the template" error I've created a custom module trying to implement new field types. I'm using How to create custom field type in Craft 3 and https://github.com/mmikkel/IncognitoField-Craft3
as reference on how to structure the module.

However, with a barebones version, I cannot seem to get the correct path to my templates. My module structure has the templates at:

SalesteamModule/src/templates/_components/fields/_input.twig

And the main function is:

public function getInputHtml($value, ElementInterface $element = null): string
    {
        // Get our id and namespace
        $id = Craft::$app->getView()->formatInputId($this->handle);
        $namespacedId = Craft::$app->getView()->namespaceInputId($id);

        // Render the input template
        return Craft::$app->getView()->renderTemplate(
            'salesteam-module/_components/fields/_input',
            [
                'name' => $this->handle,
                'value' => $value,
                'field' => $this,
                'id' => $id,
                'namespacedId' => $namespacedId,
            ]
        );
    }

App.php

return [

    // All environments
    '*'       => [
        'modules'   => [
            'site-module' => [
                'class' => \modules\sitemodule\SiteModule::class,
            ],
            'salesteam-module' => [
                'class' => \modules\salesteammodule\SalesteamModule::class,
            ],
        ],
        'bootstrap' => ['site-module', 'salesteam-module'],
    ],

    // Live (production) environment
    'live'    => [
    ],

    // Staging (pre-production) environment
    'staging' => [
    ],

    // Local (development) environment
    'local'   => [
    ],
];

The module is registered as "salesteam-module" in the app config, so I don't think it's a module id thing. And the path I copied the structure of the Incognito plugin I posted above. Although that repo is a plugin, not a module if that makes any difference.

Not sure where to go from here since I've tried a whole slew of different path combinations.

Thanks

If this is a module and not a plugin, you might need to declare your base template directory in the Module's __construct using:

Event::on(View::class, View::EVENT_REGISTER_CP_TEMPLATE_ROOTS, function (craft\events\RegisterTemplateRootsEvent $e) {
    if (is_dir($baseDir = $this->getBasePath() . DIRECTORY_SEPARATOR . 'templates')) {
        $e->roots[$this->id] = $baseDir;
    }
});

See Andrews's article on the subject.


Is there a tag to get the parents url like {{entry.url}}? Is there a tag that can shorten the following:

{% set parentPage = entry.getParent() %}
{% if parentPage %} {{ parentPage.title }}
{% endif %}

Something like {entry.getParentUrl}?

The shortest way, still checking if the parent exists, is to use (not tested):

{{ entry.parent ? entry.parent.link }}

entry.link, or entry.getLink() gives you the {{ entry.title }} part.


What is the best way of managing multisite propagation post setup phase? I have a multisite setup with a pages section.
In the future we want to add additional sites but there seem to be some caveats.
When we first setup pages we set the section propagation to 'all other sites in this group'. This creates the pages we want in another site without having to recreate the content. Great :)

Once this has been done, I then change the section settings to 'only save sites they were created in'. Otherwise the content edited overwrites each site page.
However, I am trying to achieve a cookie cutter approach going forward that lets us set up a new site and then allows us to copy initial pages in the section rather than recreate the existing pages for the new site.

However there is an inherent danger in swapping propagation methods as this seems to sometimes remove content and or create failed tasks where I can't tell what craft is trying to do (maybe a bug - I'll check github later)

Is there a better way of achieving this process over time when adding sites or is best to just complete initial setup then leave and add new site and content from scratch?

It sounds like perhaps the problem you've got is that you're not making fields translatable? That would explain what you said about "Otherwise the content edited overwrites each site page ". The idea is that pages should stay set to propagate to other sections (to the group in your case), and the fields store the translation data.

Assuming that's the case, I think your problem would be solved if you didn't change that to "Only save entries to the site they were created in' and set up the fields themselves to be translatable. That would allow you to create new sites and propagate the pages.


Getting a 'ReflectionException' error, "Class modules\Module does not exist' when I change the namespace of my module in Craft 3 First attempt at making a module. So far all I've done is try to change the namespace of the template that was included with my freshly installed craft 3.0.23.1 project.

Was following the official docs (https://docs.craftcms.com/v3/extend/module-guide.html#set-up-the-basic-file-structure) and spend a few hours trying to figure this out on various searches here and elsewhere.

So in the file '/modules/Module.php' I changed

namespace modules;

to

namespace banana\modules;

, then in '/composer.json' changed:

  "autoload": {
    "psr-4": {
      "modules\\": "modules/"
    }
  },

to

  "autoload": {
    "psr-4": {
      "banana\\modules\\": "modules/"
    }
  },

Then in Terminal, ran the command 'composer dump-autoload -a' in the project folder. Reload the page and I get the error. Other than just doing the setup wizard, i haven't touched any other files in the project.

It's a bit difficult without seeing all of your code, but I'm going to guess that you also need to make changes in your config/app.php to make the namespace changes you're making.

So two things I'd recommend... first, you can generate your module's framework here: https://pluginfactory.io/

...and second I wrote up a tutorial on creating a module in the Enhancing a Craft CMS 3 Website with a Custom Module article.


Excluding Array of Entry Ids Not Busting Cache -- UPDATED --

My understanding of how the cache busting works is to make sure the query is within the {% cache %} tag. When looking into how it works I may not really be understanding the ins and outs of using the cache tag properly. Correct me if I'm wrong.

The goal with this example is to show posts on the index and any category page that excludes cateogry-one unless a user is viewing the category one page.

If I have an entry that is initially not tagged with category-one and it will output as expected as well as when I tag that entry with that category. However if I were to again edit that entry and remove category one the cache doesn't bust and won't output the entry.

Blog Index Code:

{# Get all the categories you want to INCLUDE #}
{% set categoryIds = craft.categories()
    .group('categories')
    .slug('category-one')
    .ids() %}

{% set excludeIds = craft.entries()
    .relatedTo({
        targetElement: categoryIds
    })
    .ids() %}

{% cache globally using key craft.app.request.pathInfo ~ '/p' ~ craft.app.request.pageNum %}

    {% set blogEntriesCriteria = craft.entries({
        section: 'blog',
        id: ['not']|merge(excludeIds),
        with: ([
            ['image', {
               withTransforms: ['medium']
            }]
        ])
    }) %}
    {% set isFirstPage = craft.app.request.pageNum() == 1 %}
    {% set limit = 10 %}
    {% paginate blogEntriesCriteria.limit(limit) as pageInfo, blogEntries %}

    {% if blogEntries %}

        {# Loop through this page's News entries #}
        {% for entry in blogEntries %}

            {% include 'includes/components/_news-card' %}

        {% endfor %}

    {% else %}

Sorry, no posts found.

    {% endif %}

{% endcache %}

Blog Category Code:

{% set catIdCheck = false %}

{# Get all the categories you want to INCLUDE #}
{% set categoryIds = craft.categories()
    .group('categories')
    .slug('category-one')
    .ids() %}

{% set excludeIds = craft.entries()
    .relatedTo({
        targetElement: categoryIds
    })
    .ids() %}

{% if category.id == categoryIds[0] %}
    {% set catIdCheck = true %}
{% endif %}

{% cache globally using key craft.app.request.pathInfo ~ '/p' ~ craft.app.request.pageNum %}

    {% if catIdCheck == true %}
        {# If true show category-one entries
        on Category One Page #}
        {% set blogEntriesCriteria = craft.entries({
            section: 'blog',
            relatedTo: category,
            with: ([
               ['image', {
                   withTransforms: ['medium']
               }]
            ])
        }) %}
    {% endif %}

    {% if catIdCheck == false %}
        {# If false show all posts that
        do not include category-one on all other
        category pages #}
        {% set blogEntriesCriteria = craft.entries({
            section: 'news',
            relatedTo: category,
            id: ['not']|merge(excludeIds),
                with: ([
                    ['image', {
                        withTransforms: ['medium']
                    }]
                 ])
          }) %}
    {% endif %}

    {% set isFirstPage = craft.app.request.pageNum() == 1 %}
    {% set limit = 10 %}
    {% paginate blogEntriesCriteria.limit(limit) as pageInfo, blogEntries %}

    {% if blogEntries %}

        {# Loop through this page's News entries #}
        {% for entry in blogEntries %}

            {% include 'includes/components/_news-card' %}

        {% endfor %}

    {% else %}

Sorry, no posts found.

    {% endif %}

{% endcache %}

I have had success with the busting the cache for the category page when I use the following code, which does not include id: ['not']|merge(excludeIds)

Any insight about the cache tag and if the id not array would be really helpful.

NOTE:
I have updated my Blog Category file to have the if statements outside of the cache tag recommended by @RitterKnight but this did not fix the cache issue related to excluding entry ids.

The cache tag is somewhat misunderstood and it tends to trip up even the most seasoned Crafters.

The best way to explain about the {% cache %} tag is to think of it as a snapshot in time.

The first time the template runs, Craft saves the output to the database. It does not actually save queries.  On subsequent runs, Craft simply grabs the output from the cache. Again, it doesn't save state or variables, it simply saves the output.

Specifically, I see you have {% if %} tags inside {% cache %}. Those conditionals will only run once. The {% if %} tags won't re-execute and the output is going to be the same.

What you can do is something like:

{% if whatever %}
      {% cache %}
         {{ do some output stuff }}
      {%endcache%}
{% endif %}

For more info, check out Straight UP Craft as well as Andrew Welch's great piece on the subject.


Set SuperTableFields programatically I'm trying to setup some Global fields in a migration.

I'm using the SuperTable Field from verbb which is similar to a matrix field.

I'd like to add several rows during migration but can't seem to get the combination right in order to set the field values.  Can someone help me out, what I've got so far is the following:

   $globalSet = Craft::$app->globals->getSetByHandle("myGlobals");

   $globalSet->setFieldValues([
            'siteName' => "The Website",
            'siteCustom' => [
                'new1' => [
                    'type' => 'superTableBlockType',
                    'fields' => [
                        'firstField' => "some value",
                        'secondField' => "some other value"
                    ]
                ]
            ]
        ]
   );

   Craft::$app->globals->saveSet($globalSet);

So it looks like you must get the correct block type in order for this to create new rows in the SuperTable.

First get the block type using the SuperTable service:

       //you'll need to reference this in your code
       use verbb\supertable\SuperTable;

       $field = Craft::$app->getFields()->getFieldByHandle('siteCustom');
       $blockType = SuperTable::$plugin->service->getBlockTypesByFieldId($field->id)[0];

Then use that same blockType id to set the type field:

       $globalSet = Craft::$app->globals->getSetByHandle("myGlobals");

       $globalSet->setFieldValues([
              'siteName' => "The Website",
              'siteCustom' => [
                   'new1' => [
                          'type' => $blockType->id,
                          'fields' => [
                              'firstField' => "some value",
                              'secondField' => "some other value"
                           ]
                   ]
               ]
       ]);

       Craft::$app->globals->saveSet($globalSet);

If you need to add more than one value to siteCustom you can do so with the same syntax, just make sure you increment the number after new each time (so new2, new3, and so on).


Run a localized site using one Craft install on 2 servers Is it possible to share one craft install across 2 servers?  Say I have a US site (en only) hosted in the US and a Canadian site (en and fr) hosted in Canada.

E.g.

usa-site.com (english)
ca-site.ca (english)
ca-site.ca/fr (french)

Craft has exceptional locale functionality, which would cater for your different languages.

See here for relevant answer...

Besides the above, I understand that:

Multi-location/domain installation is not possible at the moment.
the licence for Craft applies to a domain. So for your example, each domain would require a separate Craft licence.


Does Craft have any default keys for flash messages? Does Craft have any default keys for flash messages like logging in or updating a profile?

Not particularly.

UserSessionService has setNotice() and setErrors(), which are just wrappers for Yii's setFlash() where we pass in an 'error' or 'notice' for the key.

Yii will take than and prepend the FLASH_KEY_PREFIX const which we set to Craft.UserSessionService.flash..

So an error's key will end up being Craft.UserSessionService.flash.error and a notice will be Craft.UserSessionService.flash.notice.


Responsive background images in carousel I have a homepage carousel using http://flickity.metafizzy.co/ and the images are set as background images and lazyload.

What I need to do is to make them into responsive images, so that different images are served up for mobile, tablet and retina screens. But am struggling on how to do it in the code. Can anyone help?

{% if entry.carouselImage1.first() %}

{% endif %}

{% if entry.carouselImage2.first() %}

{% endif %}

{% if entry.carouselImage3.first() %}

{% endif %}

It's not really a Craft CMS question, but...

I don't remember Flickity supporting what you describe. You could try listening for screen size on pageload (and resize), assigning the correct image to the cell, and then creating the slideshow (destroying it first if it's a resize).

But half the point of lazy loading is to avoid loading images until they're needed anyway, so I'd question whether serving different images for different sizes is the right approach. Probably the easiest method would be to forget lazy loading and use an inline <style> element with media queries targeting each cell.


Include user information in html block I need to pass the logged-in user's email address as a variable to a embedded javascript form. I think the easiest way for me to do this is to dynamically embed the user's email address in the embed code URL.

Within the javascript snippet in the HTML block would be a URL "form=http://www.formsite.com/formname?email=XXXX@XXX.COM" -- how can I pass the logged in user's email into that?

I'm not a web developer nor do I have a lot of experience with craft other than as an admin level user. I'm trying to accomplish this without enlisting the services of a web developer to do any custom work.

There is a currentUser global variable that is available to all Twig templates.

If there is a currently logged in user, it will return that user's UserModel class.

From there, it's just a matter of:

{% if currentUser %}
    form=http://formsite.com/formname?email={{ currentUser.email }}
{% endif %}

Of course, what's inside the if block will look different depending on how you're generating the embedded code URL.


How to pass dynamic arguments into Wordsmith chop parameters I have a use case where I need to set a maxChars variable to pass into the Wordsmith plugin’s chop parameters.
So I know I can do this (with the Empty Coalesce plugin):
{% set maxChars = matrixBlock.maxChars ??? null %}
{% set intro    = entry.intro ??? null %}

{% if intro and maxChars %}
    {% set intro = intro|md|chop(limit= maxChars, unit='c', allowedTags='
') %}
{% endif %}

…

    {{ intro|raw }}

But maxChars might be null and I might want the allowedTags string to be a variable too, so it would be handy to be able to set the chop parameters as a hash and pass them in.
The following doesn’t seem to work, but is there something that does?
{# Default tags permitted #}
{% set chopArgs = { allowedTags: '
' } %}

{# Custom tag list #}
{% set tagList = matrixBlock.tagList ??? null %}

{% if maxChars %}
    {% set chopArgs = chopArgs|merge({ limit: maxChars, unit: 'c' }) %}
{% endif %}

{% if tagList %}
    {% set chopArgs = chopArgs|merge({ allowedTags: tagList }) %}
{% endif %}

…

{% if intro %}
    {% set intro = intro|md|chop(chopArgs) %}
{% endif %}

Your only problem here is limit but would something like this work for you?
{# Default tags permitted #}
{% set defaultTags = "<p>" %}

{# Concatenate default + custom tags #}
{% set allowedTags = defaultTags ~ matrixBlock.tagList ?? null %}

{# Limit - use if provided or set to unlimited using a huge number #}
{% set limit = matrixBlock.maxChars ?? 1000000000000000 %}

{% if intro %}
    {% set intro = intro|md|chop(limit= limit, unit='c', allowedTags=allowedTags) %}
{% endif %}