How to limit number of entries returned from a group filter? I'm wondering how I would go about limiting the number of results returned from a set using the group filter? I only want four to show, but using the limit() method seems to throw errors wherever I put it. Here's my template code:

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

{% for category, catEntries in entries | group('cuisineType.first().title') %}

    {% for entry in catEntries %}

       // I only want four entries shown here

    {% endfor %}

{% endfor %}

The reason limit() isn't working is that is a method on the ElementCriteriaModel you get from craft.entries.

Because you're actually dealing with a standard array when you access catEntries, what you want instead is Twig's |slice(start, length) filter:

{% for entry in catEntries|slice(0, 4) %}

   // You'll only get four entries shown here

{% endfor %}


How do I stop my relative links to stylesheets breaking? When I navigate to [home]/news/2014/poster my relative links to stylesheets break. I am using:

<link href="css/myStylesheet.css" rel="stylesheet">

How do I stop these links breaking in this scenario?

The links aren't working because that's a relative URL, from whatever the last "directory"-looking segment in your page's URL is.

To resolve this, you can either make your URLs root-relative:

<link href="/css/myStylesheet.css" rel="stylesheet">

Or relative to the site URL:

<link href="{{ siteUrl }}css/myStylesheet.css" rel="stylesheet">

The drawback to root-relative URLs is, it makes your site a little less portable - you'll only be able to install the site in a web root (no subfolders) without having to update all URLs.

If this is a localized site with multiple site URLs, then both solutions could have issues. In that case it might make sense to define your own custom config setting in craft/config/general.php:

'baseResourceUrl' => "http://example.com/",

Then call glad from your templates instead of siteUrl:

<link href="{{ craft.config.baseResourceUrl }}css/myStylesheet.css" rel="stylesheet">


How do I output image in the loop for an entry? I've run into an unexpected situation, where ElementCriteriaModel could not be converted to string.

{% set news = craft.entries.section('news').limit(3) %}
{% for news in news %}
    {% set cover = news.promotionNewsImage %}
    {% if cover|length %}
        {{ cover.getUrl('gtLg') }}
    {% endif %}
{% endfor %}

Any thoughts on that please?

Your image input returns and array so you need to reference the first item, even if you only allowed one to be selected.

{% set news = craft.entries.section('news').limit(3) %}
{% for news in news %}
   {% set cover = news.promotionNewsImage %}
   {% if cover|length %}
       {{ cover[0].getUrl('gtLg') }}
   {% endif %}
{% endfor %}


Craft 3 / Sprout Forms Bootstrap field classes How can I add a css class directly to the INPUT tag generated by {{ input|raw }} from the accessible template of the sprout form plugin? I do not wish to add the class to a surrounding div.

I ended up looping through the form fields, which works almost but lacks the field types:

This is my field.html. It seems I cant get the field.type thus it defaults to text for all fields.

{%- do craft.sproutForms.addFieldVariables(_context) -%}

{%- set label            = field.name ?? null %}
{%- set name             = field.handle ?? null %}
{%- set type             = field.type ?? 'text' %}
{%- set required         = field.required is defined and field.required ? true : false %}

{%- set id               = renderingOptions.id ?? name %}
{%- set class            = renderingOptions.class ?? name %}
{%- set value            = entry is not empty ? entry.getFieldValue(name) : null %}
{%- set errors           = entry is not empty ? entry.getErrors(name) : null %}

{%- namespace field.getNamespace() -%}
    {%- if field.isPlainInput() -%}

        {{ input|raw }}

    {%- else %}

        {% if label -%}

                {% if label -%}

                            {{- label|raw|t('sprout-forms') -}}

                {%- endif -%}

        {% endif -%}

                <input type="{{type}}" name="{{name}}" class="{{class}}" {%- if required %} required{% endif -%}>

        {% include "errors" with {
            errors: errors,
            name: name
        } %}

    {%- endif -%}
{%- endnamespace -%}

In the tab.html which calls uses the field.html:

{%- for tab in tabs -%}

    {%- set layoutFields = tab.getFields() %}

    {% set fieldOptions = {
        "class": "form-control",
        "errorClass": "has-error",
        "data": {
            "hidden": "false",
        }
    } %}

    {% for field in layoutFields -%}
        {{- craft.sproutForms.displayField(form, field, fieldOptions) }}
    {%- endfor %}

{%- endfor -%}

This is all based on the default "accessible" template from the plugin. While I know I could put the fields manually in the template, I would prefer to learn how this is actually done "nicely". Thanks!

In Craft 3, you can do this by overriding the field inputs directly, and you shouldn't have to add any logic to the form, tab, or fields templates. We're still working on getting the docs updated to properly show this.

Custom Form Templates

To override field inputs in Sprout Forms, you can enable Form Overrides in your settings.

  Sprout Forms->Settings->General->Default Form Templates->Custom

Here you can define an override folder in your front-end templates. Let's say you set your default templates to _forms. This means your override templates will exist in templates/_forms.

Once you have that in place, you can place a fields folder within that folder that contains a field override:

templates/_forms/fields/dropdown/input.html
templates/_forms/fields/email/input.html

You can do this for all the fields where you wish to modify the base input HTML.

A good place to start may be to copy the code for the specific field you wish to override from Sprout Forms itself:

https://github.com/barrelstrength/craft-sprout-forms/tree/v3/src/templates/_formtemplates/fields

Making Your Form Templates into a Plugin

If you like the templates you've created and wish to reuse them on more than one project, you can take what you've done above and wrap it in a plugin.

Creating a Form Template integration will display your Form Templates in the dropdown list of Templates to choose from. The template files themselves would then be managed in your plugin instead of in your project.

You can see an example of how to create an integration in Sprout Forms with the AccessibleTemplates Form Templates:

https://github.com/barrelstrength/craft-sprout-forms/blob/v3/src/integrations/sproutforms/formtemplates/AccessibleTemplates.php

The integration is really just a way to tell Sprout Forms where your form templates are and makes it easier for content editors to select in the Craft UI.


Populate select input via static values on plugin settings page I am attempting to populate a select input on my settings page for a plugin I am working on.

_settings.html

forms.selectField({
    'label': "myLabel",
    'instructions': "My Instructions"|t,
    'required': true,
    'id': 'myInput',
    'name': 'myInput',
    'options': craft.myPlugin.settings.getOptions
})

I am getting the select to render, but it's just not getting any values.

craft.myPlugin.settings.getOptions links to my variable file for my plugin.

MyPluginVariable.php

public function getOptions()
{
    error_log(__FUNCTION__);  // Never gets executed
}

I thought maybe I could just return a name|value array in my getOptions method.

return array('one'=>'one', 'two' =>'two');

The value(s) that this select will have are literally that easy and will never change. That's why I was going this route vs. a db lookup.

I get errors that the value needs to be a string, so I know I can't just have an array right in the settings file. Not exactly sure where to go from here.

Thank you!

EDIT

Well, I may have a solution, i'm curious if there is a better way though.

MyPlugin.php

public function getSettingsHtml()
{
    $options = array(
        '' => 'Select',
        '1' => '1',
        '2' => '2',
        '3' => '3',
        '4' => '4',
        '5' => '5',
        '6' => '6',
        '7' => '7',
        '8' => '8',
    );

    return craft()->templates->render( 'myPlugin/_settings', array(
            'settings' => $this->getSettings(),
            'options' => $options
        ) );
    }

_settings.html

forms.selectField({
    'label': "myLabel",
    'instructions': "My Instructions"|t,
    'required': true,
    'id': 'myInput',
    'name': 'myInput',
    'options': options
})

If your first attempt – using a variable method – failed, it was probably because you had the "path" to that variable method wrong. If your variable method is called getOptions() and resides in a variable class called MyPluginVariable, the path should be

craft.myPlugin.getOptions

not

craft.myPlugin.settings.getOptions

Anyway, your current solution is fine. The ideal, "Craft-y" way to do stuff like this would probably be to keep the input options in a plugin config file and use a service + variable method to expose the data to the template – but for such a simple case there's really no need to over-engineer things. If you have more fields/options later, or need the data to be dynamic or stored in a database, deal with it then. Don't optimize too early.

Personally, I'd consider just hard coding the options in the template:

forms.selectField({
    'label': "myLabel",
    'instructions': "My Instructions"|t,
    'required': true,
    'id': 'myInput',
    'name': 'myInput',
    'options': {
        '' : 'Select',
        1 : '1',
        2 : '2',
        ...
    }
})


How to link to controller actions in a Craft 3 plugin? I cannot find any documentation that specifies how to link to controller actions which return a rendered template in CP.

Let's say I have a plugin called waffles and my namespace is Very\Waffles. I have a controller named SyrupController and it's residing in Controllers directory (note the capitalized directory name). So the namespace for it would be Very\Waffles\Controllers.
An action actionPour() - how can I register a route that would call this action if I land on the /admin/waffles URL?
I've walked through the steps with a debugger and It's trying to check if a SyrupController exists but how can it, if only Very\Waffles\Controllers\SyrupController exists? Thus it fails to register that route and fails.

Any help much appreciated!
Here's some code:

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

It shouldn't be possible to link to a controller by using this string, so I'm guessing an array that specifies the SyrupController::class, but there's no documentation about it.

Thanks!

Apparently I figured it out. Would still like a better way of doing this, but here's the solution I found to be working:

In your Plugin class, you have to add a public $controllerMap array. For my example plugin above, here's what I would have to add to that $controllerMap array:

use Very\Waffle\Controllers\SyrupController;

class Plugin extends \craft\base\Plugin
{

    /** @var array */
    public $controllerMap = [
        'syrup' => SyrupController::class,
    ];

    // other code here, obviously
}


How do I convert a date stored in UTC to the user's current locale in PHP? I have a date stored in the database in UTC.

2016-01-13 09:01:16

I can query the database and output this date just fine. But it outputs in the date in the wrong timezone.

How do I adjust a date from the database into the current user's locale?

I believe this involves using craft()->timezone at some point, with some method, but I have not had any luck. I'm retrieving the date with the query builder:

$rows = craft()->db->createCommand()
         ->select('dateCreated')
         ->from('mytable')
         ->queryAll();

Bonus points: sometimes I have multiple dates, so I need to modify all dates I get back into the right timezone.

More bonus points: at what point in the process is the best point to modify the date into the right timezone? In MySQL query? In PHP? In Twig?

Here is some code used in the past.

$timezone = new \DateTimeZone(craft()->getTimeZone());
$newdate = \DateTime::createFromFormat(DateTime::MYSQL_DATETIME, $mysqlDate, $timezone);

I have typically done this before assigning to a model.


Switch Twig condition Case with OR condition (two values in the case) I got a Twig switch in a template like:

{% switch bodyClass %}

    {% case 'A' %}
        ...

    {% case 'B' %}
        ...

    {% default %}
        ...

{% endswitch %}

I would like to add another possible value for the first case.
So I would have case 'A' or 'C'.

Is it possible in Twig syntax?

=================================
EDIT CRAFT BUG ?
OK lets try to rephrase, sorry for my english not easy to explain for me sometimes :)
So when the or syntax is added, then the 2nd and 3rd cases B or default (after 'A1' or 'A2' case) are never reached anymore.
The switch always say TRUE to 1st case (even if it is wrong...).

{% switch bodyClass %}

    {% case 'A1' or 'A2' %}
        ...

    {% case 'B' %}
        ...

    {% default %}
        ...

{% endswitch %}

This currently isn't a supported syntax for the Twig switch statement.

Craft will take that line and compile it down to:

case ("A1" || "A2"):

Which will always evaluate to true, which is why you always get the first result.

In order for it to work, it would need to be either:

case "A1":
case "A2":

To take advantage of PHP's fall-through support or the more ugly:

case ($context["bodyClass"] == "A1" || $context["bodyClass"] == "A2")


What is the best way to test if a file exists without knowing which file extension a Craft install is using for templates? Craft allows users to use whatever template extension they prefer: .html or .twig or something custom.

We can check if a file exists like so:

IOHelper::fileExists($filePath)

Is there any way to know which extension we want to be testing for?  By default Craft supports both html and twig in the supported extensions config setting.

Right now, I have the following which feels a bit clunky:

foreach (craft()->config->get('defaultTemplateExtensions') as $extension)
{
    if (IOHelper::fileExists($template . "." . $extension))
    {
        ...
    }
}

That's exactly how I'd do it.

It doesn't make much sense, but there's nothing stopping a user from having both extensions for a template like:

/index.html
/index.twig

And your existing code would cover both cases.


Why can't I set the 'type' of my Asset source? When I try to add an asset source under Admin > Settings > Assets, I can't see the type-field on the 'Create a new Asset source'-page. Why not?

The problem you are having is with your Craft edition... as in, which level of Craft did you pay for: Personal, Client, or Pro? If you didn't buy Craft Pro, then you can't save assets to a cloud service. And since you can't save to the cloud, all of your assets will be automatically saved to a Local Folder. The Type menu is only shown in Craft Pro.


Craft routing with extra attributes I am Craft newbie, and am trying to use PayPal express checkout but am stuck on a confirmation route.

How do I register a route like this:

localhost:8888/app/confirm?token=EC-5UA33446UB5625646&PayerID=8RB74GZ8ASWGQ

What I have done so far:

Registered route confirm on the plugin but when PayPal adds the token and payerId, Craft doesn't understand the route anymore.

public function registerSiteRoutes()
{
    return array(
        'app/confirm' => array('action' => 'app/confirm')
    );
}

Any help will be appreciated.

Craft actually has its own built-in support for tokenized requests, which is activated if there's a "token" param. if that param is set, Craft will refer to the craft_tokens table for instructions in how to route the request, ignoring the normal routing steps.

The name of that param can be customized using the tokenParam config setting, but you should probably just have PayPal use a different query string param if you can.


Removing index.php strange issue I already had this question posted but I didn't include enough relevant information so I deleted it and here I go again...

I have a weird issue currently on my Craft setup. I have removed index.php from my URLs, so all my single-page links are loading via www.siteurl.com/about-us etc...

The issue I'm having now is that when I created a new single page section, index.php isn't being removed from the URL. It's the only section doing this on the entire site, and everything is perfectly the same as the other sections.

I'm going to run through my setup in case anyone can spot what the issue is.

I currently have a .htaccess file within my project foot folder. The contents of that are here:

RewriteEngine On
RewriteBase /
RewriteRule ^(.*)$ /public/$1 [L]

Then inside my public folder, (which is the same level as the Craft folder) I have another .htaccess, with the contents from https://craftcms.com/support/remove-index.php.

<IfModule mod_rewrite.c>
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]
</IfModule>

This setup works perfectly for the entire site, except the new section I created. Does anyone know what the issue could or might be?

I've went into my Apache http.conf file and made sure the

 LoadModule rewrite_module modules/mod_rewrite.so

is enabled.

and

AllowOverride All

is set.

Also inside my general.php file I have added,

'omitScriptNameInUrls' => true,

But when I push this up to my staging server, the same issue is there. So I assume the default Apache configuration is correct.

The really weird issue is why it works across the entire site except the one new section.

Could you double check your General Settings (Settings > General) to make sure there's no "/index.php" in the Site URL field?


Possible to change locale in PHP? I've got a plugin which is defaulting to English during AJAX calls, but I need it to stick to whatever the current language is. I can send the current locale through via AJAX data, but I'm not sure how to change the locale in PHP.

It's possible to get the current locale like this...

craft()->getLanguage()

Is there a way to set the current locale in PHP?

I think I got this resolved the proper way... looks like you just need to make sure that your AJAX calls are localized.

In my main _layout template:

<script type="text/javascript">
window.siteUrl = "{{ siteUrl }}";
</script>

Then in my JS, I have this:

$.post(
    siteUrl + 'actions/myPlugin/myAction',
    ...
);

As long as your siteUrl is being localized properly, it should trickle down into the JS... and the localized AJAX path can then load a properly localized template.


Date fields saving the wrong date from front-end form I have a front-end form with two date fields. After upgrading to Craft 3 and implementing what I believe to be all the changes concerning front-end forms in Craft 3 I am experiencing some odd behavior.

The odd behavior

When I enter manually or use jQuery UI Datepicker plugin to enter a desired date into any of the date fields associated with this front-end form (this is the only front-end form on the site currently), the date gets saved one day behind. E.g. if I enter 2018-05-01 it gets saved as 2018-04-30. However, if I go to the admin area and add a new block to this matrix field it saves correctly.

What I changed when upgrading from Craft 2 to 3 is the following:

{{ getCsrfInput() }}
<input type="hidden" name="action" value="entries/saveEntry">

to

{{ csrfInput() }}
<input type="hidden" name="action" value="entries/save-entry">

I also checked and confirmed that I am using the most up-to-date version of jQuery UI to rule out the datepicker as the culprit.

Here is a gist of the form: https://gist.github.com/swthate/08152aefe2c481cd792fc156a9ea1bc6

Note: fields/inputs in question are on line 38 and line 49 of the gist (lotMixDate and lotExpireDate).

Thanks!

You need to include a timezone parameter to your form in order to get the correct one.

<input type="hidden" name="postDate[timezone]" value="America/Los_Angeles">

If you don't include something like this in your frontend chances are high you'll receive the wrong time because it adds/subtracts a certain amount of hours. As soon as you include a valid timezone it will calculate the correct time. Otherwise it will be set to the default system timezone which may differ from your local


index.php in url for just channel pages I have followed the instructions for removing index.php and it works on all pages with the exception of pages with channels. So I would see http://www.example.com/index.php?p=news/2016/news-title.

I also added the 'omitScriptNameInUrls' => true, in the general.php file.

Here is what I have in my .htaccess file

<IfModule mod_rewrite.c>
    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]
</IfModule>

<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/text text/html text/plain text/xml text/css application/x-javascript application/javascript image/svg+xml
</IfModule>

<IfModule mod_headers.c>
    <FilesMatch "\.(eot|otf|tt[cf]|woff2?)$">
        Header set Access-Control-Allow-Origin "*"
    </FilesMatch>
</IfModule>

Options +FollowSymLinks
RewriteEngine on
RewriteCond %{HTTP_HOST} ^example.com [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L]

So it turns out I needed to have the "Options +FollowSymLinks" block above the craft rewrite rule in my htaccess. See comments above.


How can multiple fieldtype instances without a content column be attached to the same entry type and still be uniquely identifiable? We have a custom fieldtype that can be attached to an entry type multiple times and everything works just fine. This fieldtype has multiple input fields (shortUrl, longUrl) and they have been properly namespaced to make them unique (via the fieldtype handle) and when the data is saved, it gets saved to a table that defines the necessary columns (id, elementId, shortUrl, longUrl) since the defineContetAttribute() method has been set to false.

As previously mentioned, this fieldtype has been properly namespaced and is taking advantage of the Craft JS buffer to avoid naming conflicts.

The issue comes up when we try to retrieve the data from our custom table via preValue($value) because $value will be null and all the other values we have access to in this context  ($field->model->id, $field->model->handle, $field->element->id) are not unique enough to fetch a record.

I've tried a couple of workarounds but have not found a clean way to do this yet.

The prepValue() method provides the entry id ($field->element->id) which we can use to fetch the content (record) for each field since we have a relationship set but beyond that, I haven't found any other way to identify each record individually so that I can attach it to the right field instance within the input html.

There might be something simple that I'm missing and thought I would ask: )

Since you're saving your data in a separate table, you basically need two fields within your custom table to help you identify which field & element originally saved the content:

The element id (which you're already storing)
The field id (missing from your current setup)

You could even create an index on your custom table that would be a combo of those two fields.

In theory, you should be able to retrieve your data with a combination of the $field->model->id and $field->element->id.

When saving:

$attr['elementId'] = $field->element->id;
$attr['fieldId']   = $field->model->id;

$fieldRecord->setAttributes($attr);

When retrieving:

$fieldRecord = MyPlugin_FieldRecord::model()->findByAttributes(array(
    'elementId' => $field->element->id,
    'fieldId'   => $field->model->id,
));


List entries without specific tag I am trying to output a list of entries from a channel section that DO NOT have a certain tag.

I am able to output the entries that have the tag assigned by setting the tag as a variable and using relatedTo to filter the entries out. For example:

{% set tag = craft.tags.search('All-Stars').first() %}

{% if tag %}
{% set relatedEntries = craft.entries.section('news').relatedTo(tag) %}
{% endif %}

What is the best approach to output entries without the tag?
I've tried the following:

{% set tag = craft.tags.search('All-Stars').first() %}
{% set allEntries = craft.entries.section('news') %}
{% set taggedEntries = craft.entries.section('news').relatedTo(tag) %}
{% set untaggedEntries = allEntries|without(taggedEntries) %}
{% for feedItems in untaggedEntries.limit(5).offset(1) %}

This however doesn't work and throws out some errors, the first being:

array to string conversion

craft/app/vendor/twig/twig/lib/Twig/Template.php(525)

$message = sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object);

I tried many other ideas like .relatedTo('not' ~ tag) and |without with no avail.

Is it something obvious I am missing or more advance than that?

Thanks in advance

You could try something like following reducing the tagged entries into IDs that you then filter against (see this thread):

{% set tag = craft.tags.search('All-Stars').first() %}
{% set allEntries = craft.entries.section('news') %}
{% set taggedEntries = craft.entries.section('news').relatedTo(tag).ids %}
{% set omitIds = 'and, not ' ~ taggedEntries|join(', not ') %}
{% set untaggedEntries = craft.entries.section('news').id(omitIds) %}


Help with Printmaker Plugin Has anyone had any success with Printmaker PDF plugin?

I’m not sure where to put the tags?  The only way I can get the template to actually load is to add the Printmaker tags at the end of the document.  In which case, the "Download CV" link further up the page doesn’t work.  It seems {{ pdf.url }} HAS to appear AFTER the Printmaker tags.  If I move the Printmaker tags further up I get the error "Internal Server Error - Requested HTML document contains no data.”.

Also, i’ve linked to a print stylesheet and when I do get a document to be created the print.css is ignored?

Thanks

We've used it successfully to generate PDF tickets for orders. It may/may not help in your case.

On our order page, we simply have:

Download PDF Tickets

Then, our order/tickets template:

{% set html %}
    {% set orderId = craft.request.param('orderId') %}

    // HTML/CSS to generate ticket

    <meta http-equiv="content-type" content="text/html; charset=utf-8" />

        // Ticket HTML

{% endset %}

{% set settings = {
    compress: true,
    orientation: 'portrait',
    size: 'letter',
    cacheDirectory: 'cache/tickets',
    filename: 'TICKET-' ~ craft.request.param('orderId') ~ '.pdf'
} %}

{% set pdf = craft.printmaker.pdfFromHtml(html, settings) %}

{{ pdf.output }}


Recreate deleted orders? The client has unfortunately deleted some orders from the Craft Commerce plugin. Does anyone know if it's possible to recreate deleted orders?

Your best bet would be to find a database backup that has the order information that was deleted and write a script that re-inserts that order info into your existing database.


How do I fix a deprecation error for DateTime::year? I am trying to work through deprecation warning. I have not touched Craft in a few months, so I am a bit rusty.

The Deprecation Message is:

  DateTime::year is deprecated. Use the |date('Y') filter instead.

The offending line is:

  {% for year in now.year .. firstEntryEver.postDate.year %}

Here is the context:

{% set firstEntryEver = craft.entries.section('posts').orderBy('postDate asc').one() %}
{% for year in now.year .. firstEntryEver.postDate.year %}

 date_range {{ year }}
 {% endfor %}

So, how do I fix this?

This is how you fix this:

{# Old code #}
{% for year in now.year .. firstEntryEver.postDate.year %}

{# New code #}
{% for year in now.year .. firstEntryEver.postDate |date('Y') %}


Rename a file using onSaveEntry event craft()->on('entries.saveEntry', function(Event $event)
{
    // entry slug, will be used as image name
    $EntryTitle = $event->params['entry']['slug'];

    // Get attached image
    $entry = $event->params['entry']['imgdir'][0];

    craft()->assets->renameFile($entry, $EntryTitle);
    $entry->setAttribute('filename', $EntryTitle);
    craft()->assets->storeFile($entry);

});

This init() code gets the current entry title right after it was saved, and is supposed to use it to rename an attached file.
I used a method given by another developer in the context of a saveAsset, but it doesn't seem to work in this new context (→ see Change asset name on upload).

I'm not sure i've set the $entry variable to correct data. Fact is I'm able trough the path you see above, to get access to the asset.
Please tell me where this code is wrong.

You probably just confused the entry model and the asset model, see if the code below works for you.
I guess the entries.onBeforeSaveEntry event is a better match in this case, and I also added some conditionals to
only do something for a specific entry section and type, and if there's exactly one asset selected. I hope this helps (code is untested)!

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

    if (($entry->section['handle'] == 'friends') && ($entry->type['handle'] == 'friends'))
    {
        $title = $entry->slug;
        $assets = $entry->imgdir;

        if (count($assets) != 1)
        {
            $event->params['entry']->addError('imgdir', Craft::t('Exactly 1 asset has to be selected.'));
            $event->performAction = false;
        }
        else
        {
            $filename = $title.'.'.$assets[0]->getExtension();

            craft()->assets->renameFile($assets[0], $filename);
            craft()->assets->storeFile($assets[0]);
        }
    }
});


Imagick installation passed with warnings I have installed imagick on my amazon lightsail lamp instance like so:

apt-get install imagemagick
apt-get install php5-imagick

Unfortunately craft tells me that the ImageMagick extension has Passed with warnings. See this image:

What am I missing? How do I make sure imagick is working correctly?

Click on the "i" graphic and it will probably tell you that GD is installed, but Imagick isn't and it is recommended.

You can verify that Imagick is installed and available to PHP/Craft by going to yoursite.com/admin/utils/phpinfo and searching for "imagick".  If it's not there, then it has not been installed properly.


Plugin Settings UI for saving an array of values I'm making a plugin where I'd like a user to be able to add values to a list, then have that list saved as an array.  Are there any smart ways of doing this? My current solution is to have a textarea, then make values out of each line but that's not ideal at all. Does Craft already have a built-in UI pattern for this?

Thank you!

You can use the EditableTable template component (i.e. the same UI component that Table fields use).

Note that this will only work inside the Control Panel – not on the front end. The title of this question says "Plugin settings", so I'm assuming that's your actual use case.

Here's how:

{% import "_includes/forms" as forms %}

{{ forms.editableTableField({
    label: 'Some setting',
    instructions: 'Some instructions here',
    id: 'someSetting',
    name: 'someSetting',
    cols: [
        {
            heading : 'Some column',
            type: 'select',
            options: [{label: 'Foo', value: 'foo'}, {label: 'Bar', value: 'bar'}]
        },
        {
            heading : 'Some other column',
            type: 'singleline'
         },
    ],
    rows: settings['someSetting']
}) }}

As long as the setting you use with the table (someSetting in the example above) has AttributeType::Mixed, Craft will automatically handle serialization for you (the rows you input in the table will be stored as a simple JSON object in the database, just like Table fields are stored).

Note that each column entry can have a type of singleline, multiline, number, select or checkbox. If you don't declare a type, the column will render as a PlainText field.

Also note that the variable settings (which is passed to the rows parameter) refers to an array of your plugin's current settings – meaning you'll need to pass those to your settings.html template like this (the following method should go in your plugin's primary class):

public function getSettingsHtml ()
{
    return craft()->templates->render('yourpluginhandle/settings', array(
        'settings' => $this->getSettings(),
    ));
}

Of course, you can pass additional variables to the settings template – such as a pre-populated array of label/value pairs to use for any dropdown (select) fields inside the table.

If you're unfamiliar with Twig macros, I recommend taking a look at the official docs on the subject (if only to understand the syntax used, and the import statement).

Also, here's the source for the editableTableField macro, which could prove useful.


Using RedisCache Class & Methods How would I access the available RedisCache class and it's properties/methods in PHP/plugins? (https://buildwithcraft.com/classreference/etc/cache/RedisCache)

I'm just starting to learn Redis and can't seem to find more information about how to start using the available class. I have set cacheMethod to redis, and created a rediscache.php file in craft/config/.

I want to explore connecting to db, inserting my own keys/values and retrieving data for my other plugins, but can't seem to find the right path path. I tried things like:

echo craft()->redisCache->hostname;

But that returns CExeption errors. What am I missing?

You put your Redis connection information in your craft/config/rediscache.php config file.  You can see the default here, and your file will override any matching set keys.

From there you can use craft()->cache->set(), craft()->cache->get() and any other cache methods on Yii's CCache class.


How do you get memcached working? I'm trying to get our Craft CMS install to use a memcached cluster we created in AWS. I am able to telnet to the memcached server on port 11211 from the server that will be connecting to it. I did a tcpdump (packet trace) on the web server's interface and it did not try to connect to the caching server at all over a period of 12 hours.

I have the caching method in config/general.php set to use "memcache" and have the useMemcached set to true in config/memcache.php as well as the memcached server info all filled out correctly.

Is there something I am missing? It should have at least attempted to connect at least once in that amount of time. I was wondering if my web server was missing some sort of php plugin. I found libphp5-memcached wasn't installed so I installed it, but still no connection out.

The documentation on getting Craft CMS to work with a caching server don't appear to have much more than the config stuff, so not sure what we're missing.

Thanks for the help in advance!

If this memcache cluster is purely for craft caching you could consider using redis instead.

I've found both the old and newer memcache implementations in php to be flaky, but those are personal experiences without any scientific proofs backing them.


Get only enabled variants of a product I would like to get all enabled variants for a product. I refer to the following question, where a method for limiting a for-loop is given:

Disabled product variant still shows in {% for %} loop

In the comments Andreas provides a way to get all enabled variants for a product:

{% set variants = craft.commerce.variants({ product: product, enabled: true }) %}

However, in my case this does not return any variants, while there are two active. Instead, it returns the following object:

object(craft\commerce\services\Variants)#2364 (3) {
  ["_events":"yii\base\Component":private]=>
  array(0) {
  }
  ["_eventWildcards":"yii\base\Component":private]=>
  array(0) {
  }
  ["_behaviors":"yii\base\Component":private]=>
  NULL
}

How can I get all the active variants for a product?

If you already have the product

PHP

$product = Product::find()->one();
$variants = ArrayHelper::filterByValue($product->variants, 'enabled', 1);

Twig

{% set product = craft.products.one() %}
{% set variants = product.variants|filterByValue('enabled', "1") %}

If you don't have the product

Twig

{% set variants = craft
    .commerce
    .variants
    .productId(x)
    .all()
%}

PHP

$variants = Variant::find()
    ->productId(x)
    ->all();


Is there a way to prevent uploading assets into a parent level folder? Say that I have a folder structure like this:

/images
  /products
  /employee-photos
  /user-photos
  /advertising

Is there a way that I could define the single asset source of /images while only allowing uploads to its children?

I would like to do this so that I could simply add new children w/o having to define them as assets sources separately.

The only way I know how to do this would be to create a different asset channel for each child directory.


How do I set up a section of text on my home page to rotate through, rather than stay static? I am a site owner who's new to Craft and whose site is nearing completion. I now realize I would like to have multiple versions of text rotate through in the box on the top of my home page, rather than having one "fixed" paragraph of text that doesn't change, unless I change it manually. (Think of scrolling testimonials, even though I don't plan to use it for that ...)

Will this change in setup require major surgery on the developer's part, minor surgery, or just a simple plugin, for example? Or might this functionality be built into Craft already? What's the upper limit on how many chunks of text I can have cycle through for the viewer to see?

Many thanks for your help and input!

This should be relatively simple to implement, although depending on how the page was designed may require reworking some of the existing page layout and css.

As far as craft is concerned the data could be stored in a few different ways; perhaps in a separate channel, table, or matrix field. Setting this up on the craft-side is trivial, and would not require any special plugins.

On the front-end content could all be loaded when the template is initially rendered (by simply adding a few lines of code to the template), or loaded as needed using javascript and ajax (by creating a separate template used to render just the text segments as requested). Although if it's truly only text, I would opt for loading it all at once on initial page load. Transitions would normally be done using some fairly simple javascript and/or css transitions.

There shouldn't be any technical limit on the number of items you could display; but there probably are some practical limits where it would start to get clumsy for one reason or another.

If you need more specific code examples, please leave a comment, and I can add more detail.


Getting logged out of admin area when refreshing site The problem seem to be that the session file in /craft/storage/runtime/sessions is getting removed any time I refresh the actual page, so that I have to do a new login everytime I've changed content, looked at the site, and then want to add more content.

This i running on Apache, PHP 5.3.29, locally through MAMP on Yosemite.

Is there some config setting I'm missing here?

The problem was actually Chrome using iOS emulation when viewing the site, thus spoofing the UA string into something different than the usual Chrome UA string when logging into the admin area.

Solution (as suggested by @craftcms on Twitter) was to set:

'requireMatchingUserAgentForSession' => false

In

craft/config/general.php

For whatever environment you are having the issue.


Building my first Sprout Form and need ability to add Tags input I'm building my first Sprout Form and I need a tags relational field, but where the user filling in the form can add their own tags, but if similar/matching tags exist then they can select them, like the tags field behaves within the control panel.

Anyone know if that's possible? If not in Sprout Forms, another way?

Short answer: yes it's possible. Longer answer: it will probably require some custom development during your implementation to get in place what you're looking for.

Sprout Forms has a Tags Field in the Relations Field section of the Form Builder. On the CP side, it's just a wrapper around Craft's Tag Relations field and will work the same way for Content Admins.

By default, this field just outputs a list of tags in a dropdown for a user to choose from.

But, does the field support submitting new tags? I don't know! As the Form is just receiving POST data I'd start by taking a look at how Craft's Tags field is sending new Tags when entries are saved in the back end and try to update the front end tag input to submit data in the same way and see if it works.

If it does work, the main problem here would then be that you'd like to update your front-end UI. You can do that using Form Template Overrides and override the input field for the Tags field to behave as you wish. As long as you are submitting the POST data in the same format, Sprout Forms doesn't care which field type you use or if you use javascript or a Vue Component to guide your user toward preparing the input for submission.

If it doesn't work, then we could consider that a Feature Request or you could address the problem by building out a custom Tags Field that behaves as you need it to using the Form Field API. You're more than welcome to use Sprout Form's Tags Field as a starting point.


Frontend form with relation to an entry I have a field called "assetId" from Entry "A" with Field Type "Entries" and Source "B". How can I build a form so that a relation between these two entries will be established.

In the craft backend I can add a new entry in Entry "A" and can use the Button "Add an entry" to select the suitable Entry from "B". This works fine. A record is written in the Table craft_relations.

How can I build a user form in the frontend to get this. I tried following form with a hidden field "fields[assetId]" which is set to the id of the suitable content:

<form method="post" accept-charset="UTF-8" enctype="multipart/form-data" class="send-form" id="send-form">
    <input type="hidden" name="action" value="entries/saveEntry"/>
    <input type="hidden" name="sectionId" value="34">
    <input type="hidden" name="enabled" value="1">
    <input type="hidden" name="fields[assetId]" value="1478" id="hidden-assetID">
    [... some more fields ...]
     <input class="btn-vote" type="submit" value="send">

</form>

The entry is saved correctly, but without the assetId. There is no relation between targetId 1478 and the new entry in the Table craft_relations established. What am I doing wrong?

After research with lots of trail & error I found the solution. I just had to add [] to my hidden field to establish the relation:

<input type="hidden" name="fields[assetId][]" value="1478" id="hidden-assetID">

The leading hint was here: Setting User field type from a front end form


Bootstrap Craft from another app Is there any known way to bootstrap Craft to use the core functions inside another application? For example, in Magento anyone can include a file, initialize the app and use all the functions from there.
This is exactly what i am trying to achieve but in Craft.
Thank you!

Craft’s bootstrap file in located at craft/app/index.php. Importing that will get you 99% of the way there.

The only problem is, index.php not only loads Craft, it also runs it. In doing so, Craft is going to insist that it completely resolves the request, with a response to the browser.

I’m thinking we should move most of that code into a new bootstrap.php file, with the only exception being the last line:

$app->run();

Then index.php would simply import bootstrap.php and call $app->run() itself. That way you could import bootstrap.php rather than index.php, and do whatever you want with the app, like fetch entries, without losing control over the whole request.

In the meantime, you could copy the contents, sans $app->run(), of index.php into your own file and import that instead. You’d need to go through it and update all of the paths, too.

Another option would be to make Craft think the page should be a 404, and catch the 404 exception:

// Make it look like a 404
$_GET['p'] = "some/invalid/path";

// Import Craft, catching the 404
try
{
    require 'path/to/craft/app/index.php';
}
catch (\Craft\HttpException $e){}

// ...

Little hacky, but that may be your cleanest option until we give you a bootstrap.php file to import instead.

UPDATE

As of Craft 2.2, Craft now ships with a bootstrap.php file which handles all of the app initialization stuff with the exception of actually calling run().

When you include bootstrap.php(), a new Craft application will be returned.

$craft = require 'craft/app/bootstrap.php';


How can I search for a user id in a custom field in my entries loop? In my template I have the user id variable pulled out of the URL and then I want to search through my entries for posts where that user id is included in a custom field with a users field type as well as the default "author" field.

Here's what I've got working for the author field, and I just want to include my custom "coAuthors" field type as well...

With a url like "/author/joyce"

{% set username = craft.request.segment(2) %}
{% set author = craft.users.username(username).first() %}
{% set entries = craft.entries.section('blog').authorId(author.id) %}

That works great, but how can I also include entries where that author id is set in the coAuthors custom field?

I can't even seem to find it separately. This turns up nothing

{% set entries = craft.entries.section('blog').search('coAuthors.username:author.id') %}

You would want to use the relatedTo() method of elementCriteriaModel.

{% set username = craft.request.segment(2) %}
{% set author = craft.users.username(username).first() %}
{% set entries = craft.entries.section('blog').relatedTo(author) %}

If you need both then you may need to merge the results.

{% set username = craft.request.segment(2) %}
{% set author = craft.users.username(username).first() %}
{% set authorEntries = craft.entries.section('blog').authorId(author.id).find() %}
{% set coAuthorEntries = craft.entries.section('blog').relatedTo(author).find() %}

{# merge authorEntries and coAuthorEntries #}
{% set entries = authorEntries|merge(coAuthorEntries) %}

Not tested. But should be close. Update: added .find() which will convert the elementCriteriaModel to an array so that the merge filter works properly.


500 Error on AWS bitnami instance I have a fresh LAMP instance based on a bitnami image on AWS. All server requirements are met for Craft 2, but I'm getting a 500 error when trying to hit the site:

  site.com is currently unable to handle this request. HTTP ERROR 500

Seeing this in the error log:

  Uncaught Error: Call to a member function run() on integer

I've done separate db tests for pdo and mysqli -- connectivity seems fine. Permissions all look correct (774). Any thoughts on what could be causing?

So, turns out the issue was with the $app = require 'bootstrap.php'; line in app/index.php.  There was another directory for smarty template engine that was getting pulled from for the bootstrap file.  After removing that conflicting file, the issue was resolved.  Strange issue, but hopefully can help if anyone bumps into this in the future...


Displaying Entries That Are Not Related I have two channels set up, the first creates entries called "databytes" the second is a channel for relating certain databytes to each other called "databyteSeries". In my template I want to output all databytes but if they are related just show the first in the series. I have the following code which is displaying the first in the databyteSeries no problem (sectionId 8):

{% paginate craft.entries.section(['databytes','databyteSeries']).limit(6) as entries %}

{% for entry in entries %}

  {% if entry.sectionId == 8 %}

  {% for series in entry.relatedDatabytes %}
    {% if loop.first %}
      {# TEMPLATE CODE FOR ENTRY HERE #}
    {% endif %}
  {% endfor %}

  {% else %}

    {# THIS NEEDS TO DISPLAY ALL DATABYTES THAT ARE NOT RELATED #}

  {% endif %}

{% endfor %}

{# PAGINATION CODE HERE #}

{% endpaginate %}

It's the second part where I now only want to display the databytes that have NOT been related where I am struggling. I guess it needs some kind of reverse relationship where I have put the {# THIS NEEDS TO DISPLAY ALL DATABYTES THAT ARE NOT RELATED #} but I am not sure.

Any help would be appreciated.

Your question is just about entries without relationships but your code example is attempting to display both items with a relationship and without a relationship.  I think your example is making things a bit more complicated than this needs to be.  Rather than looping through both sections (databytes and databyteSeries), I believe you only need to loop through one section.  The databyteSeries section, as you've described it, has a relation field for databytes, so all the info you need to know about databytes should be available to you in the relation field.

Let me know if the following example gets at what you are going for.  It simplifies your loop to just the databyteSeries section, and then uses Twig's length filter to test the entry.relatedDatabytes field to see if it has any entries. If there are related databytes, it displays one output, and if there are not, it displays an alternative output.

I've also updated the method in which you were using to output the first item in the series.  Rather than loop through the entire entry.relatedDatabytes field and just output the first item using a loop.first conditional, I've updated the code to use entry.relatedDatabytes.first().  Using the first() method on an EntryModel will just grab the first item, and then you can output it as you wish with whatever variable you assign it to.  Below, I've assigned the first item to the firstInSeries variable.

{% paginate craft.entries
     .section('databyteSeries')
     .limit(6)
     as entries
%}

    {# Loop through databyteSeries entries #}
    {% for entry in entries %}

        {% if entry.relatedDatabytes|length %}

            {# Display the first item in a Databyte Series that has a relationship #}
            {% set firstInSeries = entry.relatedDatabytes.first() %}
        {{ firstInSeries.title }}

      {% else %}

        {# Display the Databyte Series name that has no relationships #}
        {{ entry.title }}

      {% endif %}

    {% endfor %}

{% endpaginate %}

UPDATE

Based on your clarification in the comments and your potential solution, here's another method to consider using Craft's without filter:

{# Get all databyteSeries and databytes #}
{% set databyteSeries = craft.entries.section('databyteSeries').limit(null) %}
{% set databytes = craft.entries.section('databytes').limit(null).indexBy('id') %}

{# Determine which databytes already have a relationship to a databyteSeries #}
{% set alreadyUsedDatabytes = craft.entries.section('databytes').relatedTo(databyteSeries).indexBy('id') %}

{# Use the without filter to remove all 'alreadyUsedDatabytes' from the complete 'databytes' result, so you are left with only 'unusedDatabytes'  #}
{% set unusedDatabytes = databytes|without(alreadyUsedDatabytes) %}

{# Output the unusedDatabytes #}

{% for entry in unusedDatabytes %}

{{ entry.title }}

{% endfor %}

I have not tested this code so let me know if you run into any issues to troubleshoot.


Need help trying to pass a variable of a related entry On my page, I have a form which is using Freeform (Solspace).

I'm attempting to setup a custom redirect URL for the form. The form will apply to numerous entries in a channel and some will require different redirect URLs. The main channel in question (Animals) has a relation field which relates it to another channel (Adoption Price). This channel contains a URL field which ideally, I would like the user to be redirected to upon submitting the form. Below is what I have tried so far but with no luck.

  //Setting the variable

  {% for priceBracket in entry.relatedAdoptionLink %}
      {% set priceURL = priceBracket.adoptionPriceLink %}
  {% endfor %}

  //The Form

    {% set form = craft.freeform.form("animalAdoptionForm", {
        labelClass: "form-label",
        inputClass: "form-control",
        instructionsBelowField: true,
        overrideValues: {
          animalToAdopt: entry.title,
        }
    }) %}

    {{ form.renderTag({returnUrl: "{{priceURL}}"}) }}

Can anybody help me out with this? Setting the variable directly via the entry would be more straight forward but I'm trying to pull the information I need from a relation in another channel.

Thanks

This is how it could look like from Twig point of view. I don't know if the Solespace part is correct

{% set priceBracket = entry.relatedAdoptionLink.one() %}
{% set priceUrl = priceBracket !== null? priceBracket.getUrl() : '' %}

{{ form.renderTag({returnUrl: priceURL}) }}


Feed Me - importing Commerce variants from Google Sheets? Is there a way to automagically create variants from a Google Sheet when importing via Feed Me?

The docs at https://docs.craftcms.com/feed-me/v4/guides/importing-commerce-variants.html#setup-your-feed only mention JSON and XML

Thanks :)

EDIT FOR CLARITY: I can't figure out how to relate a Variant row in the spreadsheet to the parent Product row, I guess this is inherent in XML/JSON because of the nested structure...

The solution at https://github.com/craftcms/feed-me/issues/368#issuecomment-555710613 works just fine.

(Mentioning this in the docs would be good :)

I didn't bother with step 7 as it seems the first line automatically becomes the default variant if one isn't set.

1. Create a new custom field e.g. "Import ID" and add it to the product type that has variants
2. Create new line for each product variant.
3. Make sure "Import ID" is the same for variants of the same product (But unique for each product).
4. Under "Import Strategy" of Feed Me check both: "Create new elements" and "Update existing elements".
5. Under "Set a unique identifier to match against existing elements" check the field you created in step 1: eg. "Import ID".
6. Map all other fields as you would normally do with a non-variant import.
7. Make sure you have an extra column for the "Is Default" field and that only one of the variants has that value to set to 1


Regex to remove trailing slash not working I am trying to remove the http:// and trailing slash from a string, so my replace filter looks like this:

website|replace({ 'http://': '', '/\\/$/': '' })

The http:// part works, the trailing slash one doesn't. Why not?

I think you are getting the twig replace filter (which does not have the regex capability) instead of the Craft replace filter (which does).

So this is a bug in Craft, in that their filter is masked by the twig one.

You could use the trim filter to remove trailing /s:

website|replace({'http://':''})|trim('/')

Or you could use one of Victor's Twig PCRE Filters.


Create Matrix Block via Module I'm having an issue creating a matrix block from a module. I'm currently doing the following:

Calling an API using Guzzle
Getting that request and iterating over a media block.
Trying to create a new Matrix Block with each iteration.
Adding data from the request into each Matrix Block.

** EDIT **

I got this working using the following code:

                $data = json_decode($json, true);
                $number = 1;

                foreach($data['media'] as $element) {
                  $matrixData = array();
                  $matrixData["new$number"] = array(
                    'type' => 'media',
                    'enabled' => true,
                    'fields' => array(
                      'mediaDescription' => $element['likes'],
                    )
                  );
                  $user->setFieldValue('recentPosts', $matrixData);
                  $number++;
                }

Example JSON

"media": [
        {
            "media_id": "2053313765945828720",
            "instagram_user_id": "1",
            "shortcode": "Bx-1f2_nuVw",
            "created_date": "1558994096",
            "caption": "",
            "comments": "7077",
            "likes": "1131719",
            "media_url": "https://www.instagram.com/p/Bx-1f2_nuVw",
            "media_image_url": "https://scontent-lhr3-1.cdninstagram.com/vp/8e6c054cec7d3c3657bc73d49dae0fd9/5D7B651B/t51.2885-15/e35/c0.134.1080.1080/s150x150/61993210_834852143539503_2474404095511077560_n.jpg?_nc_ht=scontent-lhr3-1.cdninstagram.com",
            "type": "IMAGE",
            "mentions": [],
            "hashtags": [],
            "date": "2019-05-28 02:44:09",
            "last_check_date": "2019-05-28 20:25:24"
        },
...

Unfortunately, now my forloop isn't saving new matrix blocks.

Fixed using the following code. Also includes fetching an API via Guzzle and parsing it into Craft CMS. Thought I would post here so that if anyone else is having trouble they can decipher bits from this.

                // Set a base URI
                $baseUri = 'http://domain.com';
                // Build the Guzzle Client and use the Base URI
                $client = Craft::createGuzzleClient([
                  'base_uri' => $baseUri,
                ]);
                // Send a Request!
                $response = $client->request('GET', '/mytestendpoint/');
                // Parse the Response
                $json = $response->getBody();
                // Decode it
                $data = json_decode($json, true);

                // Set some values from it!
                $user->setFieldValue('userTotalFollowers', $data['followers'] );
                $user->setFieldValue('userEngagementRating', $data['details']['total_likes'] );
                $user->setFieldValue('verified', $data['is_verified'] );

                $number = 0;
                $matrixData = array();

                foreach($data['media'] as $element) {
                  $number++;
                  $matrixData["new$number"] = array(
                    'type' => 'media',
                    'enabled' => true,
                    'fields' => array(
                      'mediaDescription' => $element['likes'],
                      'mediaLikes' => count($element),
                    )
                  );
                }
                $user->setFieldValue('recentPosts', $matrixData);


getVersionsByEntryId is deprecated. Can't find the new method? We are using getVersionsByEntryId in our XML sitemap to return the number of times an entry has been saved, then comparing that with todays date and the date the entry was created to determine the changefreq over that time:

{% set revisions = craft.app.entryRevisions.getVersionsByEntryId(element.id)|default(1)|length %}

Looking at the docs however, this is now deprecated:

  DEPRECATED

  Deprecated in 3.2. Use an entry query instead.

I can't seem to find anything in the docs for an entry query? Could someone point me in the right direction?

You can use the revisionOf parameter (docs).

{% set revisions = craft.entries.revisionOf(element.id).all|default(1) %}


Determine Entry based on URL Parameters? I have a bit of code that checks if a page's title has been manually set in a parent template, and if it has to use that, otherwise to use entry.title. This is what that bit looks like:

{% set activeTitle %}
     {% if pageTitle is defined %}
         {{ pageTitle }}
     {% else %}
         {{ entry.title }}
     {% endif %}
{% endset %}

I however have some pages like so:
http://example.com/foo/text.html?sectionId=6&handle=bar&entryId=170&slug=somethingclever

How do I get the entry based on the parameters that are defined in the URL? And then use this entry's entry.title to set my page title?

This is a longer version answer (code wise) to the one Douglas already posted. He did a very nice job of explaining how to get a URL parameter and what to pay attention to handling the results.

I will try to show you how to build a query from multiple unknown params, so any of these combinations is possible and potentially return a single (and unique) Entry Model:

http://example.com/foo?sectionId=6&entryId=170&slug=somethingclever
http://example.com/foo?sectionId=6&slug=somethingclever
http://example.com/foo?entryId=170

This also tries to handle the case, the page already comes with an entry variable pre-populated or there's already a pageTitle set. So you don't do all the requests / logic on all of your pages.

{#
 # Only try parsing the params, if this page doesn't come with an `entry`
 # var pre-populated and we don't already have `pageTitle` set.
 #}
{% if not entry and pageTitle is not defined %}

    {# Get URL params #}
    {% set entryId = craft.request.getParam('entryId') %}
    {% set entrySlug = craft.request.getParam('slug') %}
    {% set sectionId = craft.request.getParam('sectionId') %}

    {# Default query #}
    {% set query = craft.entries %}

    {# Add params to the query if they are not empty #}
    {% set query = not entryId ? query : query.id(entryId) %}
    {% set query = not entrySlug ? query : query.slug(entrySlug) %}
    {% set query = not sectionId ? query : query.sectionId(sectionId) %}

    {# Now try to get that entry and set our own `entry` var #}
    {% set entry = query.first() %}

{% endif %}

{# Set the entry title. Also handle the case our query didn't find anything #}
{% set entryTitle = entry ? entry.title : 'Title for a page that doesn’t exist' %}

{# Set the page's title #}
{% set activeTitle = pageTitle is defined ? pageTitle : entryTitle %}

Useful links for this code: craft.request and Ternary operator in Twig.


SOLVED: Best way to deploy Craft 3 to webserver? I want to deploy a local craftCMS 3 website to a server, but I didn't manage to get answers to some of the questions I have rightnow on Google search. So I hope you can help me with this and can help me finding the right / a better workflow to do these things instead of me reinventing the wheel.

I have the website build locally and want to deploy it. I installed composer on the webserver via SSH by putty (Win) and installed Craft 3 on the server with composer and the craft webinstaller whithout any problems. But that's obviously just an empty craftcms and not the locally build cms.

These are the questions I have right now:

1) What's the preferred way to install a build craft website on the server? Do you use the craft installer or just copy all local files of the project to the server by FTP?

When creating a new craft project with composer the 'public' files are in 'web'. So if I install a new craft project with composer on the webserver inside public_html, the public files will be in domain.com/project/web or in domain/web if I use public_html as a path.
But in both cases some critical files, like the config files with passwords and all, will be in the public_html folder.

Of coarse I use htaccess to protect things, but I'm not sure this is the right and secure location to have this folderstructure on the server as meant to be and wonder if the project should go on a higher folder instead with only 'web' exposed on public_html.

2) What's the right location on the server to install the craft project to to keep everything secure, like having config, vendor and all 'out of sight'? Do you guys install craft directly in the public_html folder, or on a higher parent folder? And in case of the latter do you only have the 'web' folder inside public_html somehow (how to do that?)? So what's the right/preferred way/location to install Craft3 in a secure way?

With an older CMS/framework I used I just copied local files by ftp to deploy. But it seems like using composer is a better way to do this and like to improve my workflow.

3) If you make changes to the website locally, how do you deploy them once the website is setup on the server? Do you just use ftp to upload your changed files (and update the database) or is there a better way to do this with composer?

I like to do things in a way that works best and the CMS is meant for instead of reinventing the wheel and do things differently than the 'standard'. Hope you guys can help. Thanks in advance!

At the risk of "link" answers, we talk about different deployment strategies here:

Website Deployment without Tears

...and there's a writeup of deploying Craft CMS here:

Setting up a New Craft CMS 3 Project

It's hard to do a TL;DR on this, because it's fairly involved, but essentially ignore your vendor/ directory, and do a composer install on your production/staging server to install the vendor/ directory there, synced up with your composer.lock

Using some kind of deployment tool like Forge or Buddy.works will also make your life easier.


Show 2 random entries based on checkbox in Super Table I have a Super Table field (entryType) with a checkbox field "featuredIn" and some values.

This is how it looks when creating a entry:

I can't figure out how to mix "slice" and "orderBy RAND" with filtering by that field.

This does show me 2 random entries from all:

{% set entries = craft.entries.section('blog').orderBy('RAND()').all() %}

{% for entry in entries|slice(0, 2) %}
  {{ entry.title }}
{% endfor %}

This shows me only the entries where "showInRandom" is checked (but not random and not only 2):

{% for entry in craft.entries.section('blog') if entry.entryType.featuredIn.contains('showInRandom') %}
  {{ entry.title }}
{% endfor %}

The question is pretty confusing so this answer assumes the following:

You have a Super Table field named entryType with the following cells:

featuredIn (checkbox)
showInRandom (checkbox)

And that you are trying to:

Only show rows where showInRandom is checked
Randomize the order of the rows that are returned
Limit the returned results to 2

Unfortunately Super Table doesn't support searching based on a block's value, which I see you already know, so you'll have to do it in steps.

First, you need to pull in every Super Table row. Then you need to check if each row has showInRandom checked (side note: a lightswich field would be easier), and add its ID to an array if so. Then you randomize the array and run a Super Table query with those IDs and limit the results to 2.

{# create an array to store the returned IDs #}
{% set randomRows = [] %}

{# add only the rows with showInRandom selected to the array #}
{% for row in entry.entryType.all %}
    {% if row.showInRandom.options[0].selected %}
        {% set randomRows = randomRows|merge([row.id]) %}
    {% endif %}
{% endfor %}

{# randomize the array and run a super table query, limiting to 2 #}
{% for row in craft.superTable.blocks({
    owner: entry,
    fieldId: 123,
    id: shuffle(randomRows),
    fixedOrder: true,
    limit: 2
}).all %}
    {{ row.someField }}<br>
{% endfor %}


Freeform email notifications going to spam Hi does anyone know how to keep the email notifications from going to spam folder?

Email that is sent from your server is often marked as spam, this is not anything to do with either Craft or Freeform but with the fact that the server you use may not be trusted by email providers. Read the article Brad recommended for some background info. Then do yourself a favour and use a transactional email service to deal with all the hassle for you, sending email from their servers. A lot of them are free for smaller use. I use Postmark, you can easily implement it in Craft, see https://postmarkapp.com/support/article/1019-use-postmark-to-send-emails-from-craft
I've also used Sendgrid in Craft with succes (with a little help from this page https://mediasurgery.co.uk/video-episodes/craft/make-sure-those-crucial-emails-get-delivered-with-craft-cms-and-sendgrid). Others include Mailgun, Sparkpost, or just Google 'transactional email service' for others.


Using $model->validate() with AttributeType::Url I have a basic model defined:

protected function defineAttributes()
{
    return array(
        'id'        => array(AttributeType::String, 'required' => true),
        'url'       => AttributeType::Url,
        'info'      => array(AttributeType::String, 'required' => true, 'maxLength' => 4000),
        'title'     => array(AttributeType::String, 'required' => true, 'maxLength' => 65, 'minLength' => 15),
        'message'   => AttributeType::String,
    );
}

And when checking if the model is valid:

if (!$my_model->validate())
{
    return false;
}

Almost any string for 'url' is passing the validation, even without a '.com'

So if someone inputs sdfsdfsfsdfsdf in the input field, it'll pass as a valid URL and return as http://sdfsdfsfsdfsdf

I've also tried using AttributeType::UrlFormat but I run into the same problem. Am I not understanding what this attributetype does, or should it be validating that it's an actual URL string?

Craft extends Yii's CUrlValidator to add support for protocol-less URLs as well as URLs without a TLD (such as your example of http://sdfsdfsfsdfsdf).

If you need other behaviors for your URL validation, you can always write a custom URL validator.


Outputting SVG from an asset field inside a matrix field with svg() I've set up an asset field inside a matrix field where a user can upload SVG icons, but I'm having trouble outputting them using the svg() function.
{# Correctly shows the path #}
{{ callout.icon[0].url }}

{# Correctly displays the SVG within an image tag #}
<img src = "{{ callout.icon[0].url }}" alt=""  />

{# No output #}
{{ svg(callout.icon[0].url) }}
{{ svg(callout.icon) }}

Can anyone see what I'm doing wrong with the svg() function? Other than being inside a matrix field, what I'm doing doesn't seem to differ from the example in the documentation. I'm trying to avoid using any plugins if at all possible.

Ok, think I know what's wrong – you want to select the first asset, but not its url. E.g.
{{ svg(callout.icon.one()) }}


Changing the asset url for the Control Panel I'm attempting to get the Control Panel assets to load from a CDN instead of locally from Craft.

Going through the config options here and here I can't seem to find a way to change the asset URL.

Is there any way to change the asset url (in this case for control panel)?

I can't think of a way to do this.

Problem #1: the URLs generated for control panel resources are based on the Craft install's Site URL (whether that's defined in Settings->General or via the config setting and that is taken into account when creating all links in Craft, not just for control panel resources requests.

Problem #2: in Craft 2, all control panel resources are actually served through PHP, not the web server.  I suspect even if you found a way around #1, this would cause separate issues.


Can Garnish be extended to allow plugins to use custom keyboard shortcuts? For example, when editing an entry cmd + s saves the entry. Is there an easy way to extend Garnish to allow for my plugin to listen for custom keyboard shortcuts?

I'm not sure if there's an "official" way yet but I've looked through the source a little bit and I think the most Craft-like way I would do it, following plugin conventions, is to extend Garnish.Base with a new object that attaches the listener.

(function($) {

        var PluginName_KeyCapture = Garnish.Base.extend({

            init: function()
            {
                this.addListener(Garnish.$doc, 'keydown', function(ev)
                {
                    if ((ev.metaKey || ev.ctrlKey) && ev.keyCode == 66)
                    {
                        ev.preventDefault();
                        console.log('You hit CTRL + B! Good work.');
                    }
                });
            }
        });

        Craft.PluginName_KeyCapture = new PluginName_KeyCapture();
    })(jQuery);


How do I add a value to a tag field type using the entries service saveEntry method? I am updating an entry using the entries service, I want to add a tag value into a tag field type (classifiedTags).

$entry = craft()->entries->getEntryById(120);
$entry->getContent()->classifiedTags = 'tagtest';
$entry->title = 'Updating title to this';
$entry->getContent()->description = 'this is the new description';
craft()->entries->saveEntry($entry);

It runs and updates everything except the tag field (classifiedTags).

If I change it from a string to array like below:

$entry->getContent()->classifiedTags = array('tagtest');

It gives me this error:

  CDbCommand failed to execute the SQL statement: SQLSTATE[23000]:
  Integrity constraint violation: 1452 Cannot add or update a child row:
  a foreign key constraint fails (ggmg_craft.craft_relations,
  CONSTRAINT craft_relations_targetId_fk FOREIGN KEY (targetId)
  REFERENCES craft_elements (id) ON DELETE CASCADE). The SQL
  statement executed was: INSERT INTO craft_relations (fieldId,
  sourceId, sourceLocale, targetId, sortOrder, dateCreated,
  dateUpdated, uid) VALUES (:row0_col0, :row0_col1, NULL,
  :row0_col3, :row0_col4, :row0_col5, :row0_col6, :row0_col7). Bound
  with :row0_col0='43', :row0_col1='31823', :row0_col3='tagtest',
  :row0_col4=1, :row0_col5='2016-07-14 21:16:04', :row0_col6='2016-07-14
  21:16:04', :row0_col7='d2228ed9-cc60-478d-929c-98efd776b63c'

Which leads me to believe I am getting warmer.

Craft CMS v 2.6.2796
PHP v 5.6.13

The Tags field classifiedTags needs an array of tag IDs, not slugs/titles. Also, if this is an existing entry and you want to retain tags already added to the field, you'll need to pull the existing tag IDs using $entry->classifiedTags->ids() and merge with those.

$tag = craft()->elements->getCriteria(ElementType::Tag, [
    'groupId' => 1,
    'slug' => 'tagtest',
])->first();
if ($tag) {
  $existingTags = $entry->classifiedTags->ids();
  $entry->getContent()->setAttribute('classifiedTags', array_merge($existingTags, [$tag->id]));
}

Note that if the tag doesn't already exist, you'll need to create it using the TagsService:

$tag->groupId = 1;
$tag->getContent()->title = 'tagtest';
$success = craft()->tags->saveTag($tag);


Twig sometimes breaks JavaScript or CSS Sometimes when your javascripts or stylesheets are formatted a certain way, twig seems to try and render those snippets (whom always include curly brackets in some way).

For example, if you end you're CSS stylesheet with something like this;

@media only screen and (max-width: 600px) {
  body {
    background-color: lightblue;
  }
}

(I can't remember the exact case off the top of my head, but I believe this is it)

The stylesheet won't render, as twig throws an exception giving you a 500 error. It seems to be that the curly brackets (two next to each other in the flow) gets interpreted as twig.

The same goes for JavaScript, where a concrete example is instafeed.js if you import and compile with Parcel or Webpack or the likes, there's a line of code in that library that makes the .js file throw a 500 error because twig interprets the file. Specifically this line;

pattern = /(?:\{{2})([\w\[\]\.]+)(?:\}{2})/;

Again the curly brackets breaks the loading of the .js file.

I actually haven't gotten around to simply loading the javascript and css though basic tags in the html, so it might be that the issue is only present when loading through {% do view.registerCssFile(url) %} or {% do view.registerJsFile(url) %}.

Any simple workaround for this (maybe just loading with html like <script src="{{ path-to-file }}">)?

Don't put your CSS and JS files in the /templates folder. Store them on the front-end in the /web folder.

If they're not in the templates folder, Twig won't try to parse them.


Smart Map - Setting single map with multiple pins I have a Smart Map field in a section and am trying to output multiple results (pins) to a single map.
This code will output multiple maps (one map per pin)
{% for mapEntry in craft.entries.section('markets') %}
{% set options = {
    height: 500,
    zoom: 14,
    draggable: false,
    markerInfo: '_includes/mapInfoBubble',
    markerOptions: {
        icon: 'http://maps.google.com/mapfiles/ms/icons/green-dot.png'
    },
    infoWindowOptions: {
        maxWidth: 200
    }
} %}

{% set locations = craft.entries.section('markets').marketAddress.find() %}

{{ craft.smartMap.map(locations, options) }}

{% endfor %}

So essentially I am trying to get the {{ craft.smartMap.map(locations, options) }} outside the for loop.
{% set locations = '' %}
{% set options = '' %}
{% for mapEntry in craft.entries.section('markets') %}
{% set options = {
    height: 500,
    zoom: 14,
    draggable: false,
    markerInfo: '_includes/mapInfoBubble',
    markerOptions: {
        icon: 'http://maps.google.com/mapfiles/ms/icons/green-dot.png'
    },
    infoWindowOptions: {
        maxWidth: 200
    }
} %}
{% set locations = craft.entries.section('markets').marketAddress.find() %}
{{ craft.smartMap.map(locations, options) }}
{% endfor %}

But this only results in a single pin (most recent entry).
Can't get my head around this. Any assistance most welcome.

According to the docs, locations has to be an array of elements or an ElementCriteriaModel
if you want to display multiple markers.
{% set mapEntries = craft.entries.section('markets') %}
{{ craft.smartMap.map(mapEntries, options) }}


How to fetch Category of current Entry and build "Next / Prev" urls My original question here helped me figure out how to build my URL structure but now the site has introduced two categories: design and photo.

I want the "Prev" and "Next" buttons to navigate back and forth within the category of the current entry.

I know how to get the category of the current entry here:

{% for category in entry.category %}
   {{ category.title }}
{% endfor %}

...but I don't know how to put category.title into a variable to build my params. This is my best shot at the solution but it's broken and I've given up spinning on it myself :) Any help would be much appreciated.

{% set category = "craft.categories.relatedTo(entry)" %}

{% set params = craft.entries.section('projects').order('title asc').relatedTo(category) %}

{% set prevEntry = entry.getPrev(params) %}
{% set nextEntry = entry.getNext(params) %}

{% if nextEntry %}
    {% set nextEntryUrl = nextEntry.url %}
{% else %}
    {% set firstEntry = craft.entries.section('projects').first() %}
    {% set nextEntryUrl = firstEntry.url %}
{% endif %}

{% if prevEntry %}
    {% set prevEntryUrl = prevEntry.url %}
{% else %}
    {% set lastEntry = craft.entries.section('projects').last() %}
    {% set prevEntryUrl = lastEntry.url %}
{% endif %}

A category is an element. So is an entry, and an asset, and a tag, and user. When you relate one element with another you get returned an ElementCriteriaModel in the template. So you need to use its methods to actually get the element data. In this case first().

So if you know for sure that you only have (and care about) one category in an entry, then you can try this for your params.

{% set params = craft.entries.section('projects').order('title asc').relatedTo(entry.category.first()) %}

You could also set category way up at the top of the template if you know you'll
use it multiple times in the template. That way you are only making one database query.

{# At the top of the template #}
{% set category = entry.category.first() %}

{# Somewhat lower to display the category #}
{{ category.title }}

{# even lower to pull the other entries. #}
{% set params = craft.entries.section('projects').order('title asc').relatedTo(category) %}


After transferring local to server, Twig Runtime Error: Impossible to invoke a method all() on an array I transferred site from MAMP to Arcustech server and the Admin panel works fine, I even updated to 3.6.6, but the front-facing site throws an error:
Twig Runtime Error: Impossible to invoke a method all() on an array.
This is the code, but it throws it anywhere all() is used:
{% set myEntryQuery = craft.entries()
    .section('informationPages')
    .all() %}

{% set entries = myEntryQuery.all() %}

I'm new to Craft so I'm probably doing something dumb, but the site works fine in MAMP so I'm not sure where to start in running this down.
I checked all the file/folder permissions, updated all the .env and config items, etc.

You can't call .all() twice. In myEntryQuery you have converted the result into an array, you are then trying to call .all() again, but at this point you have an array, so .all() can't be used as it's not an entry query anymore.
entries will now be an array, at this point you can loop through this array and output what you need.


Element API CORS issue I'm running into this effectively https://github.com/pixelandtonic/ElementAPI/issues/4 and I'm not quite sure how I'd integrate this change with https://gist.github.com/stevieg83/85dd058dc77a3b46764165975b17bb76 adding it as the first part of my function errors out for me

syntax error, unexpected '=>' (T_DOUBLE_ARROW)

What's missing?

100% untested, but try this:

return [
    'endpoints' => [
        'api/jobs.json' => function() {
            HeaderHelper::setHeader([
                'Access-Control-Allow-Origin' => 'http://example.com'
            ]);

            return [
                'elementType' => 'Entry',
                'criteria' => ['section' => 'jobs'],
                'transformer' => function(EntryModel $entry) {
                    return [
                        'title' => $entry->title,
                        'url' => $entry->url,
                        'jsonUrl' => UrlHelper::getUrl("jobs/{$entry->id}.json"),
                    ];
                },
            ];
        },
        'api/jobs/<entryId:\d+>.json' => function($entryId) {
            HeaderHelper::setHeader([
                'Access-Control-Allow-Origin' => 'http://example.com'
            ]);

            return [
                'elementType' => 'Entry',
                'criteria' => ['id' => $entryId],
                'first' => true,
                'transformer' => function(EntryModel $entry) {
                    return [
                        'title' => $entry->title,
                        'url' => $entry->url,
                        'entryId' => $entry->id,
                        'postDate' => $entry->postDate,
                    ];
                },
            ];
        },
    ]
];


List child categories which have entries based on the current categories I am looking to output the child categories of a parent category.
I only need to show the categories which have entries related to them.

I have done this to show all categories using

{% set entryIds = craft.entries.section('stories').ids() %}
{% set categories = craft.categories.relatedTo({ sourceElement: entryIds }).groupId(2).orderBy('title').all() %}

What is the best way to do this for subcategories.

Use the descendantOf parameter to select just the subcategories, then run an entries query to check if that category has any entries assigned to it.

    {# loop through the subcategories #}
    {% for subCategory in craft.categories({
        groupId: 2,
        descendantOf: parentCategoryObject,
        orderBy: 'title'
    }).all %}
        {# check if this subcategory has at least one entry assigned to it #}
        {% set subCatEntries = craft.entries({
            section: 'blog',
            relatedTo: subCategory,
            limit: 1
        }) %}

        {# display a link to the subcategory page if entries are assigned to it #}
        {% if subCatEntries|length %}

{{ subCategory.title }}

        {% endif %}
    {% endfor %}

You'll need to provide the parentCategoryObject yourself based on however your templating works.


Sprout reports options can't find form fields I'm getting an error on my options template when I run the report, the sprout from can't find the form fields template and I get this error

  Unable to find the template “_includes/forms” in
  "__string_template__1e75d07f7afb92cfc030941cdd0c214a5067c25743f143e36dcfc3dd77a06f62"
  at line 1.

When I remove the import I get this error

  Variable "forms" does not exist in
  "__string_template__68fd366166a1d3cc8e58752e3634a261ca9faaa526e284d487e82cc2434316c9"
  at line 2.

Here is my options.twig

{% import '_includes/forms' as forms %}

{% set limitByDateRange = settings.limitByDateRange ?? false %}

{{ forms.lightswitchField({
    label: 'Filter By Date Range'|t,
    name: 'limitByDateRange',
    on: limitByDateRange,
    value: 1,
    toggle: 'toggle-dateRangeFields',
    first: true
}) }}

    {{ forms.date({
        label: 'Start Date'|t,
        id: 'datetimeStartDate',
        name: 'datetimeStartDate',
        value: settings.datetimeStartDate is defined ? settings.datetimeStartDate : now|date_modify('-1 month')
    }) }}

to

    {{ forms.date({
        label: 'End Date'|t,
        id: 'datetimeEndDate',
        name: 'datetimeEndDate',
        value: settings.datetimeEndDate is defined ? settings.datetimeEndDate : now
    }) }}

{%- js %}
    $('#options-datetimeStartDate-date').datepicker($.extend({
        defaultDate: new Date({{ now.year }}, {{ now.month-1 }}, {{ now.day }})
    }, Craft.datepickerOptions));

    $('#options-datetimeEndDate-date').datepicker($.extend({
        defaultDate: new Date({{ now.year }}, {{ now.month }}, {{ now.day }})
    }, Craft.datepickerOptions));

    $('#modify-options-panel').attr('style', null);
{%- endjs %}

I also already tried to copy the examples templates from the plugin folder and I get the same error.
Does anyone have an idea what could be wrong? I appreciate any help, thanks.

As Ben Parizek pointed out in the comments this was a bug that was fixed on Sprout Reports 1.2.8.

I couldn't see Sprout Reports update because my Craft CMS installation was below v3.3.7, I updated Craft CMS and then updated Sprout Forms to v1.2.8 which fixed the bug.


FeedMe Import XML feed with HTML I'm trying to migrate an existing blog into Craft using the FeedMe plugin. The old blog has an XML RSS feed that I'm importing and for the most part, everything works fine but the content section of the XML element contains HTML tags. When importing these tags are not removed or displayed properly.

Is there a way using the FeedMe plugin (Free or Pro version) to strip these tags or have them display properly?

Probably need a little more information (as in, an example of your feed), but if you're trying to import HTML content in an XML-based feed, you'll want to wrap that with CDATA, so its escaped properly.

<![CDATA[
This is bold
]]>


What will happen if we change the field type in the fields (settings -> fields) in Craft 3? I am a beginner in Craft CMS. I just want to know, what will happen if we change the field type in the fields (settings -> fields) in Craft 3?

It depends on the field type. Many of them you can change without problems, while others would make no sense. If you are, for instance, changing a text field to an image field, Craft obviously wouldn't know what to do with it. But if you change an Email field to a Plain Text field, it would keep the value.

The dropdown will have a warning icon when it's unsafe to change the field type. Sometimes it may work, even though the results are unpredictable. For instance, if you change a Plain Text field to a Multi-Select field, the text will be the value of the field (I think), but there is no guarantee that it is a valid option for the Multi-Select.

Also, the other way, changing a Number field to a Plain Text field causes no problems. If you change a Plain Text to a Number field, you have no guarantee that the text actually represents a number. But I think it will keep the value, but that you will get a validation error on trying to save it the next time, if the value is not valid.


Postpone sending activation codes; Creating a user as "Inactive" I'm finding the user activation process a bit confusing...

I was trying to create a handful of users, but I didn't want to send out the activation emails yet.

I incorrectly assumed if I unchecked "send activation email" when creating, it would create the user and I would be able to send the activation later.

Instead, Craft creates the user as "active" with no password, and the "Resend activation email" isn't available.

At this point I'm stuck, as you can't set a user to inactive. I'm left with these choices:

having to set a dummy password, require reset, and manually email my users
email my users the control panel url, and instruct them to click "Forgot password" and enter the same email I've created their user with.

Neither options are great, unless I'm missing something.

Thoughts?

Good point, not a very good UX there. We’ll have to come up with something better.


Is it possible to create a fieldtype that creates a many to many relationship between two entry sections? So, for example:

Say I have two sections:

- Recipes
- Ingredients

Recipes can have many ingredients. Ingredients can have many recipes.

If I'm editing a Recipe, I can edit the ingredients. This updates the relationship so that when I edit ingredients it can show the associated recipes (and they are editable from the ingredients as well).

Is this possible with Craft?

Thanks!

====== EDIT ======

Just to make this more clear. What I'm trying to do is create a Many to Many relationship between two Sections of Entries so there is an association between the two that works both ways.

Another example of this would be if you have a User with many Roles. I can manage which Users belong to which Roles from the Roles section, and/or I could manage which Roles a User belongs to from the Users section.

There's still a few kinks to work out, but I developed a plugin that solves this problem using Craft's native Many to Many relationship that already exists.

Basically, I've created a field type that links the relationship from the other side of things and allows you to add entries to it.

You can find it here:
https://github.com/page-8/craft-manytomany

Thanks @Brandon Kelly for the help and guidance.


Additional criteria to filter status of field passed into RelatedTo I'm trying to save all the images related to an entry in a variable. I need the images that are added through a matrix field in the entry. I'm using the following code, but am then also getting images associated with disabled matrix blocks. I only need images from matrix blocks that are enabled.

FYI - body and builder are matrix fields and asset is the corresponding block handle.

{% set imageAssets = craft.assets().relatedTo([
  'or',
  { sourceElement: entry, field: 'body.asset' },
  { sourceElement: entry, field: 'builder.asset' },
]).all() %}

Is there a way I can add conditions onto the fields that I am passing into the relatedTo parameter?

This turned out to be a Craft bug. I’ve posted an issue for it at https://github.com/craftcms/cms/issues/5849, and fixed it for the next release (3.4.12).


Is there any way to set enable by default a permission on the registerUserPermissions hook? When I create a permission using the registerUserPermissions hook I would like everyone, in all user groups have access to that permission. An admin has to take an explicit step to restrict access to that pemission. Something like this:

/**
 * @return array
 */
public function registerUserPermissions()
{
    return array(
        'my-permission' => array(
            'label' => Craft::t('Edit Settings'),
            //****ENABLE BY DEFAULT****
            'enable'=> true
        ),
    );
}

There's not a native way to do this, but you might want to consider adding it as a feature request.

In the meantime, you might be able to work around it a bit with some custom JS in the control panel and using something like the Control Panel JS plugin.


How to set up Craft to use Google Cloud Storage? I've been clattering around the google developers console for a while, and i just can't get it to work with Craft! I figured it'd be simple (and it may well be!) considering in Craft it just asks for two bits of data, "Access Key ID" and "Secret Access Key".

After an age of digging about in the google developes console site and a bit of searching, i  ended up in the Project Dashboard for my Cloud Storage.
Enabling "Interoperable Access" gave me some new tabs on the side, one of which is "Interoperable Access", and in there FINALLY i found two strings that have the names "Access Key" and "Secret".

Putting them into Craft and hitting refresh next to Bucket gives me the error "Credentials rejected by target host".

And so now i'm stumped! Does anyone have experience using Google Cloud Storage with Craft who can point me in the right direction?

Craft 3:

Once you have created your project in GC, navigate to GC Storage.

Create a bucket. You can only create a bucket containing the domain name if you are able to prove ownership. For example, I (personally) could not create files.craftcms.com as my bucket. Otherwise it can be anything you'd like. Or check out the Bucket and Object Naming Guidelines
Navigate to IAM & admin. We'll need to create a Service Account that can be used to give Craft access to the bucket.
Give your Service account a name. For example, "Cloud Storage". Google will create a service account ID that will look something like cloud-storage@<project-name>.iam.gserviceaccount.com. For Project Role, (you can filter) but choose "Storage Admin". You'll also want to select the checkbox labeled, "Furnish a new private key". Choose json as the format and click "Save".
A file will be downloaded to your computer - awesome. Next install the Google Cloud Plugin for Craft: composer require craftcms/google-cloud
Once installed, create a new Asset Resource and instead of "Local" choose "Google Cloud Storage" as a volume type.
Give your resource a name. For example, "Images". If you choose to have public url's use this url: http://storage.googleapis.com/. Unless you have a specific DNS record set up to serve images from that you want to use, you could do that too. Enter the project ID of your project. You can find that by clicking on your project name - very top (blue) nav bar. For example, it could be my-project
Finally, remember that .json file that was downloaded? Open that with your favorite text editor and paste the contents into "Contents of the access key file". Hit the "Refresh" button, and you should now see the name of your primary bucket. In my case files.mysite.com. You might also notice that Craft will update the base url to the files: http://storage.googleapis.com/files.mysite.com/

From there, you could create sub-folders in GCS. In my case, I've created one called images. I will update that in the Subfolder input: images.

Save your newly created resource!


User Registration Form error message customisation Where can I edit the error messages for the user registration form e.g for

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

I want to change this wording:

Email "tom.bowler@mailbox.net" has already been taken.

to something like:

Email "tom.bowler@mailbox.net" has already been taken. Login here instead...

You can do this using Craft's static translation support.

For example, if your site is using en_us for its primary locale, then add a craft/translations/en_us.php file that has this in it:

<?php

return array(
    '{attribute} "{value}" has already been taken.' => '{attribute} "{value}" has already been taken. Login here instead.',
);


Edit FreeForm lite from front end in Craft 3 I currently have a freeform which allows a user to register his/her information. I'm looking to build an edit page for each of these entry's so the user can come back and edit it if they've made a mistake.

I don't know of a native way to edit Freeform submissions on the frontend, at the moment. Apparently Freeform 3 is coming out next week and it includes front end submission editing! Based on this edition comparison page it will only be available for Freeform Pro.

I did think of a way to accomplish this right now.

Setup an Element Connection for the form you wish to allow editing for. Make the connection to a new Craft section (e.g. User Submissions). Then you can use a standard Craft edit entry form to allow your users to make edits. When creating the Element Connection make sure you pass some sort of Craft user identification so the new entry is tied to the correct Craft user. That will make editing much safer and easier. The downside to this method is that Freeform will no longer hold the master version of the submission. That would limit your ability to use some of Freeform's features.


Loop through Matrix Block fields within a Switch Case and retain HTML structure I'm struggling to get my head around the syntax to output information in a correct HTML structure.  At the moment I have this:

{% for block in entry.menuBuilder %}
{% switch block.type %}
{% case 'menuItem' %}

{{ block.dishName }}

{{ block.dishDescription }}

{{ block.dishPrice }}

{% case 'subHeading' %}

{{ block.heading }}

{% endswitch %}
{% endfor %}

This code is working in that it's displaying the information for me but unfortunately it opens and closes the UL for every item so I end up with:

Name

Description

Price

Name

Description

Price

Name

Description

Price

 ... etc

What I need to achieve the UL to open, loop through all instances of the Block using just the LI and then close:

Name

Description

Price

Name

Description

Price

Name

Description

Price

I've tried adding a for-loop around the LI but I just get errors or nothing at all.

Hopefully this will be simple to somebody!? :D

Many thanks

You'll want to implement something like this:

{% for block in entry.menuBuilder %}

  {% set type = block.type.handle %}
  {% set isFirstConsecutiveBlockOfType = (loop.first or type != block.getPrev().type.handle) %}
  {% set isLastConsecutiveBlockOfType = (loop.last or type != block.getNext().type.handle) %}

  {% switch block.type %}
  {% case 'menuItem' %}

    {% if isFirstConsecutiveBlockOfType %}

    {% endif %}

{{ block.dishName }}

{{ block.dishDescription }}

{{ block.dishPrice }}

    {% if isLastConsecutiveBlockOfType %}

    {% endif %}

  {% case 'subHeading' %}

{{ block.heading }}

  {% endswitch %}
{% endfor %}

Basically, for each block we're checking if it is the first or last item in the loop, or if that block's type doesn't match the previous or next block's type. This will let us know if the block we're dealing with is the first or the last in a series of menuItem blocks. Then in the switch/case we can use our new variables to conditionally include any wrapping html.