Plugin's action URL not working and showing 404 error

There's a 99% chance you're running into a case-sensitivity issue on your file system.

Check your plugin's name, the handle and the action URL for the controller you're trying to hit.

Most likely locally, you've got a case insensitive file system, so it doesn't matter that pluGiNHanDlE is not equal to pluginHandle, but on staging it's case sensitive so it does.


Why can't I set the 'type' of my Asset source?

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.


Can plugins in the Plugin Store require development versions of libraries via Composer?

Currently the Plugin Store requires non-development dependencies in your composer.json file.


As far as I know, there are no plans for an automatic update from Craft 2 to Craft 3. I'd suggest following the instructions from the docs to perform the update manually: https://docs.craftcms.com/v3/upgrade.html


Without knowing how your templates look, I can only give you a basic example:

{% set team    = craft.users.username(craft.request.lastSegment) %}
{% set entries = craft.entries.section('schedules').relatedTo(team) %}

This should give you all entries in the schedules channel which have a relation to the team username.


It must be /admin/module-id/leads. So in your case maybe /admin/leadsmodule/leads or /admin/leads-module/leads depending on your ID if you want to access it directly via template route.

Otherwhise you need to create custom URL rules


How to set a response 200 from a plugin?

See here for various methods of setting the response code depending on what version of PHP and which PHP module you're running.


It looks like the database schema (at Craft version 2.6.2773) is ahead of the craft/app files on your file system (at Craft version 2.5.2763).

Since (I assume) you're not seeing any update info being logged in production around 2016-03-09 22:07:49 (from the dateUpdated column in the craft_info table), my guess is that someone updated the site/database locally, then restored the updated database to production with the older files still in place.


Put this at the top of the file:

use craft\elements\User;

Within your function use the following code:

$user = new User();
$user->pending = true;
$user->username = $contact["login_email"];
$user->firstName = $contact["first_name"];
$user->lastName = $contact["last_name"];
$user->email = $contact["login_email"];
$user->passwordResetRequired = false;
$user->validate(null, false);
Craft::$app->getElements()->saveElement($user, false);
Craft::$app->users->assignUserToGroups($user->id, [1]);
Craft::$app->getUsers()->sendActivationEmail($user);

The sendActivationEmail is not a required step and can be removed but this code is working on a Craft 3 site I've been building and it creates user accounts.

This assumes that a $contacts array has been set with all of the correct values, just swap these out for your own values or omit them if you don't have any. From here you should be able to customise it though for what you need once the user account is created.

The final step for you to log in as that user would be to use something like this, this is untested however and may need some tweaking but has come from the docs:

$userLogin = new \Craft\web\User();
$userLogin->loginByUserId($user->id);


How can I set a landing page for a structure with no slug?

You can create change the uri pattern for your structured section to something like { parent.uri }/{ slug } and create an additional entry type landing-page. Your landing page will have the slug liver and all entries below that will have the URI liver/{slug}

You can load different templates based on the entry type and if the type is your landing page, you'll display all children

Another Approach is to use a template path directly and insert the template liver.twig in your templates folder


Using Craft::import() to include external resource into the Craft Namespace

and import that class into the Craft namespace

Nope... it'll import that file, but will use whatever namespace the file is using (including global).

My guess is that the ChargeBee.php file has a ChargeBee class in it that lives in the global namespace, which is why you have to reference it there.


Display/edit Sprout Form entry in front end

Sprout Forms improved support of this scenario in v3.0.0-beta.27. You can now use the setEntry variable to populate the Form Entry Model that you want to use in the Form Templates that you output using the displayForm tag. See the docs on Editing Entries for more info.

Populate a Front-End form with existing data

{# Get an instance of the your Form #}
{% set form = craft.sproutForms.getForm('application') %}

{# Get an instance of the Entry you'll be allowing a user to edit #}
{% set entry = craft.sproutForms.getEntryById(123) %}

{# Set the `entry` variable so your Form Templates know how to populate the fields with existing values #}
{% do craft.sproutForms.setEntry(form, entry) %}

{# Output your form as usual #}
{{ craft.sproutForms.displayForm('application') }}

Original Answer

I've looked into this and am considering this a bug. I've opened an issue on Github and will update my answer here when we have a fix in place.


Element query: find entries where a field's value is greater than, or less than another field's value?

I agree that any solution where you run a query and then conditionally render the result isn't very efficient.
You can do this in SQL by using the where() condition.
craft.entries
    .section('mySection')
    .where('content.field_field1 > content.field_field2')
    .all()

Documentation on the where() condition can be found here.


How to directly access translated variables by language

Take a look at the Craft docs page for "Globals" under Querying Globals.
You can pass a site ID number to an element query to get globals from another site/language. For example, if your French site id number is 2, you could do this:
{% set siteOwnerInfoFrench = craft.globalSets()
  .handle('siteOwnerInfo')
  .siteId(2).one() %}

{{ siteOwnerInfoFrench.siteOwner }}


Possible to share assets, templates and plugins across two domains but not all content?

As long as your sites are hosted on the same server, you can easily share templates and plugins between them by defining the appropriate path constants in the index.php files for your sites:

define('CRAFT_PLUGINS_PATH', '/absolute/path/to/your/plugins/folder');
define('CRAFT_TEMPLATES_PATH', '/absolute/path/to/your/templates/folder');

As for your resources (i.e. CSS and JavaScript files), symbolic linking is an option. However, I would recommend following Tom Bauer's suggestion in his answer – pick one domain and serve all assets from that domain's public folder, or even better: host the resources on a CDN.


Sounds like something may be corrupt in your /app folder... I'd recommend performing a manual update to try to fix the problem.

If you are still experiencing this issue after performing the manual update, I'd recommend contacting Pixel & Tonic directly, to report this as a bug.

You can email them at support@buildwithcraft.com, or use the "Send a message to Craft Support" widget on your dashboard.


Ok, I figured it out. First, to solve the birthday input problem, I used javascript to gather the values of each individual date dropdown and assemble them into a hidden text input that would be what passes in the datetime value to Craft.  No problem.

However, the datetime formatting tripped me up because there are two posts here that had the formatting differently.

The formatting needs to exactly match the example shown here on StraightUpCraft under the date row.  So a date value like 2014-06-24 does not work; it needs to be 06/24/2014. Likewise, the time value of 23:30:00 does not work either; it needs to be 11:30 PM.

My final code looks like this after the javascript fills in the date value. Since it's a birthday, the 6pm time is just hardcoded in.

<input type="text" size="10" name="fields[birthday][date]" value="02/24/1985">
<input type="text" size="10" name="fields[birthday][time]" value="6:00 PM">

Extra note for those using localized sites: you need to submit the date and time exactly how Craft formats them for each localization. For example, "6/24/2016" would be the acceptable date format for the U.S., but it will need to be "24.6.2016" when submitted on the German version of that page. You can output the formats dynamically in Craft using the translations filter:

<input type="text" size="10" name="fields[fieldHandle][date]" value="{{ now|date('Date Input Format'|t) }}">
<input type="text" size="10" name="fields[fieldHandle][time]" value="{{ now|date('Time Input Format'|t) }}">

And then in your translations files put something like:

"Date Input Format" => "d.m.Y",
"Time Input Format" => "G:i",

etc


The cause of this is most likely an overloaded (very common if this is a shared hosting account) or misconfigured MySQL server.

The installer itself should only take 10-20 seconds on 99% of hosts.  However on this one, it sits for about 120 seconds, before Apache redirects the AJAX request to:

'p' => 'internal_error.html',

As seen from your log files.  The underlying error is probably being logged in your Apache error logs, but it is most likely something related to a timeout from the long request.

If I try to manually execute the SQL from a database dump that is working, removing Craft from the equation entirely, it does finish in time, but still takes about 45 seconds when it should be done in less than 10.

I'd contact your host and ask them to check on the performance/configuration of your MySQL box.


Title Format - Auto Generation via linked entry

Lindsey's answer is correct when outputting to a template, however, from within the title field of an Entry Type you would use the following:

{songTitle} - {performedWith.first.title}

entry is not needed, and only need single brackets.


Create entry with newly-uploaded asset programatically

Assets fields are capable of storing newly uploaded files into assets folders, and then automatically relating them to the entry (making this feature possible).

When you’re saving the entry yourself rather than using the entries/saveEntry controller action, there are two things you need to do in order to take advantage of this feature:

Make sure your form is set up correctly.

The form should be submitting with a POST request, and encoding with multipart/form-data:

<form method="post" enctype="multipart/form-data">

And the file input needs to have an input name based on the Assets field’s handle:

<input type="file" name="fields[myAssetsFieldHandle]">

Your controller needs to tell the entry where to find the uploaded file.

You can do this with setContentFromPost() if you want all custom field values in the POST data to be assigned to the entry automatically, or setContentPostLocation() if you want to assign the custom field values to the entry manually.

setContentFromPost() example:

$entry = new EntryModel();
$entry->getContent()->title = 'My New Entry';

// Look through $_POST['fields'] for any custom field values
// and assign them to the entry's content automatically
$entry->setContentFromPost('fields');

craft()->entries->saveEntry($entry);

setContentPostLocation() example:

$entry = new EntryModel();
$entry->getContent()->title = 'My New Entry';

// Assign the custom field values manually
$entry->getContent()->summary = craft()->request->getPost('fields.summary');
$entry->getContent()->body = craft()->request->getPost('fields.body');

// Tell the entry where these custom fields are coming from in the POST data
// so that the Assets field will know where to look for an uploaded file
$entry->setContentPostLocation('fields');

craft()->entries->saveEntry($entry);

Alternatively, you can manually store the uploaded file into an asset folder using AssetsService::insertFileByLocalPath(), get the resulting file ID, and assign that file ID directly onto the Assets field.

$fileIds = array();

$uploadedFile = UploadedFile::getInstanceByName('fields.myAssetsFieldHandle');

if ($uploadedFile)
{
    $response = craft()->assets->insertFileByLocalPath(
        $uploadedFile->tempName,
        $uploadedFile->name,
        $folderId,
        AssetConflictResolution::KeepBoth
    );

    if ($response->isSuccess())
    {
        $fileIds[] = $response->getDataItem('fileId');
    }
}

$entry = new EntryModel();
$entry->getContent()->title = 'My New Entry';

// Assign the custom field values manually
$entry->getContent()->summary = craft()->request->getPost('fields.summary');
$entry->getContent()->body = craft()->request->getPost('fields.body');
$entry->getContent()->myAssetsFieldHandle = $fileIds;

craft()->entries->saveEntry($entry);

Note that in this approach, the name of the file input doesn’t matter, since you’re the one that’s telling UploadedFile where to look for it in $_FILES.


Off the top of my head and in no way tested or thought through, you could put some logic in your plugin's init() method:

public function init()
{
    $username = craft()->request->getQuery('username');

    if ($username)
    {
        craft()->urlManager->setRouteVariables(array(
            'username' => $username
        ));

        craft()->runController('myPluginHandle/myPluginActionMethod');
    }
}

Then in your plugins's controller:

class MyPluginController extends BaseController
{
    protected $allowAnonymous = true;

    public function actionDoIt($username)
    {
        // Do your thing.

        $this->redirect('homepage');
    }
}


How to upload a template in Craft CMS 3 on an Ubuntu web server

The answer will depend on the extent of your web development skills.

Do you have access to the web server via FTP?
If so, upload the template files to the templates folder where you installed craft. The templates will have to be edited to bring in your sections, entries, and content that you add in the Craft dashboard.

Check out these docs to learning templating and converting templates to twig/Craft templates.

https://docs.craftcms.com/v3/dev/


Normalize then validate unique entry in a custom module field

If your model somehow extends Yii's Model (which I think it does because you use Yii validators), you can use the beforeValidate() method to change attribute values before validation:

public function beforeValidate()
{
    // Before validation, normalize the attribute's value with whatever method you create for it
    $this->attribute = $this->yourNormalizationMethod($this->attribute);
}

After that, you can use Yii's UniqueValidator to make sure the attribute's value is unique. The docs show you some of it's possible configs, I'm sure you can make it work!


postCpLoginRedirect wrong redirect when used with autoLoginAfterAccountActivation

Ideally I'd like to keep it separate as eventually the CP will be swapped out for a front-end solution, so any clues as to why this is happening?

I think you're close.  Just so we're on the same plane, you're using the CP for users to edit their profiles but everything else is on the front end? Do you have a front end login form already setup? If not, get one setup at counsellors/login.

Don't set your cpTrigger and loginPath to the same values if you intend to keep the front and back end logins separate to begin with. That's issue number 1.

On the front end, you probably want to set loginPath to something like counsellors/login and you'll want to obviously uncomment your postLoginRedirect to counsellors/dashboard so after they login, they'll get shuttled off to that page.

Set  activateAccountSuccessPath to something like something like members/activation-success and then in that template,  you can do whatever you want there, either link back to the CP with a hyperlink so users can "finish" their profiles or use Craft's {% redirect %} code to send them to the CP.


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.


Google Maps plugin - How to trigger an info window

As of Google Maps 4.0.1, there is a new getInfoWindow method in JavaScript. This makes it easy to retrieve and manipulate existing info windows.
Additionally, I've written a guide for Opening Info Windows...
Hope that helps! :)


How to handle top-level/index pages in structure sections?

I recently setup a structure which contains (almost) every page of my site. When I set it up, I specified only {slug} as the URL.

So far, it's working fantastically! And that's with about 30-40 pages created in the structure (some nested within others).


Recommended hosting company for a Craft site?

TL;DR

DigitalOcean (droplet running Ubuntu 14.04)
ServerPilot
Email hosted elsewhere

Personally, I've had great experience with DigitalOcean.
It is a VPS solution with virtually nothing pre-installed. I've found it to be amazingly fast and stable, even for sites with a high volume of traffic. Spinning up a new VPS "droplet" is incredibly simple and painless.
Since it's basically an "empty" server when you create a new droplet, I've found that DigitalOcean pairs well with ServerPilot. Keep in mind that ServerPilot requires your droplet to be created with Ubuntu 14.04, and must run its setup before you do anything else with your droplet.
ServerPilot gives you an easy interface to setup the common software you'll need to run your site... namely PHP & MySQL. Using both services combined, we're able to easily spin up a new droplet, set it up with ServerPilot, and be up and running quickly!
Only downside... email hosting is not included in either service. So you'd need to find a separate service to handle email hosting. (We use Zoho, which I find to be adequate. I'm still on the lookout for the "perfect" email solution, but that's a topic for another day.)


How to list/filter by the entry type column in the entries listing

Currently it's not possible to sort by custom fields on element index pages.

Feel free to add a thumbs-up/comment on this feature request, though: https://github.com/craftcms/cms/issues/987


How can I set a persistent template variable to use across multiple pages in one site visit?

Sounds like you need a good cookie solution to keep track of which background has been chosen for each visitor.

I'd recommend using the LJ Cookies plugin to easily set & retrieve the filename of the background image.

(I don't believe the cache tag will be useful to you in this case.)


Can Craft handle social-esque frontend user interactions?

What kind of social interactions are you asking for?

You can probably make most of this work in Craft but a lot of what you're asking for isn't really "built in." It's going to take a fair amount of effort on your part via some business logic to assign users to groups (or categories), etc.

  Frontend ability for users to create and join "groups".

How much security do you want? Just as a high level overview, users in Craft have various permissions depending on where (which section) they can "post" entries into.

Basically the system allows users to submit content on a section-by-section basis. It's up to the permissions you have set if other users are allowed to "see" such entries or not.

Without any additional checks, an enterprising user could theoretically mess with some of the front end forms and post to other "groups" if they have permission to do so. It'd be up to your code to make sure the user is part of such "group" (or category) first.

If it were me, depending on what you're trying to achieve, I might programmatically create new sections when a user creates a new "group" and only members of that group when invited are allowed to see / post in it. Craft would help you take care of the heavy lifting too; you would basically assign the permission of viewing/writing of that section to that user.

Plugins can also create their own permissions depending on what you need to do.

  Frontend ability for users to invite others to specific "groups"—basically an email-a-friend a link with a signup/login token that will add them to the specified group.

This wouldn't be native to Craft. You'd have to build the token generation and e-mailing process here, along with doing the business logic of figuring out who was invited by whom, if said token is valid, etc.

  The ability for users to have their own blog on the site, where other users can comment.

Yes, as you mentioned, this is relatively straightforward, as Craft is basically a CMS.

A hybrid approach might be to use a bulletin board/forum style software (xenforo, vbulletin, buddypress, etc.) to handle the discussions / social groups functionality then let Craft handle the blogging part. There is various authentication bridges you could use to handle user login between the two systems.

I'm sure there's a few other ways to pull this off as well.


Change base URL for email activation link?

You can use a Twig replace filter in the email template to replace the URL with whatever you like. (I'm using this method myself because we have a similar problem on multi-site installs). To do this you'll need to be using custom templates for all system emails: Settings > Email > HTML Email Template

I'd set that to something like emails/index, which could then be like this, routing out to separate template files depending on the emailKey:

{# Craft has four predefined email keys:

    account_activation
    verify_new_email
    forgot_password
    test_email

... route to them here, or fallback to default
#}

{% include [
    'emails/' ~ emailKey ?? null,
    'emails/default'
] %}

Then emails/account_activation.twig could be something like this using the replace filter on the link variable:

{% extends 'emails/_emailLayout' %}

{% set lockscreenText = 'Activate your account' %}

{%- set heading -%}
    Hi {{ user.friendlyName ?? 'there' }},
{%- endset -%}

{% block content %}

Your account is now set up and ready to use, with your email address as your username.

To activate your account, click the following link:

{% endblock %}

{% if link is not defined %}
    {% set link = 'http://local.test' %}
{% endif %}
{% set buttonLink = link|replace('https://old.com/actions','https://new.com/actions') %}
{% set buttonText = 'Activate your account' %}

...while emails/_emailLayout would have all the complicated mess of HTML that cross-client email requires.


I'm not familiar with this plugin, but could probably do this in your template where the plugin is called:

// Get the environment
{% set env = getenv('ENVIRONMENT') %}

// If anything but dev, then load the plugin
{% if env != 'dev' %}
    {% include ['_recaptcha/frontend'] %}
{% endif %}

You can also get the environment from the config:

{% set env = craft.app.config.env %}


Entries by non-contiguous postDate years

You may be able to piggyback off of this answer on combining arrays of EntryModels, by providing the template with an array of dateQuery conditions.

For each date condition, you could retrieve the entries as you're doing above, and then combine them with the previous results using the method in that answer. You can then call {% paginate %} using the final combined array, which should contain results matching all of your conditions.

As a side note, this does dump a lot of logic into the template for twig to handle - it may be worth building a small Plugin with a Template Variable that takes in an array of dateQuery instructions, handles this processing for you, and then returns the final combined set to be used in your {% paginate %}.


Get data of user after login (but not with craft()->userSession->getUser())

If you have the any identifying information about the user (user ID, email, username, UID), you can use one of the UsersService's methods:

craft()->users->getUserById()

craft()->users->getUserByUsernameOrEmail()

craft()->users->getUserByUid()

craft()->users->getUserByEmail()

They will each return a UserModel object to interact with.


Use a text field (not rich text).  Then in the output, add "raw" to avoid it stripping any HTML tags.

{{ entry.field | raw }}


For those of you reading through this post, I thought it might be useful to provide a bit of background on my question. The Craft Docs list "multisort" under Filters and it sounded like something that would work nicely for me. However, the Craft Docs do not give an example, instead directing the reader to Yii docs. Those docs confirmed it was exactly what I needed - sorting an array by a given key, descending, numeric. However, the syntax does not make sense in term of using it within a template.

Here is the answer from Brad and Andrew, which works great:

{% for rides in allRides|multisort(['eventDate'],['SORT_DESC'],['SORT_REGULAR']) %}

Here is what you will find on the Yii docs page :

public static void multisort ( &$array, $key, $direction = SORT_ASC, $sortFlag = SORT_REGULAR )

I suppose if you are a php wizard, which, as you might have guessed, I am not, you might figure this out on your own. Having said that, it would save many of us lots of time if the Craft docs simply included the example that Brad was kind enough to provide.


What is the correct way to format a module controller action URL?

It depends on the module handle you chose in config/app.php (the module handle is the key affected to your module in the modules array).
If you want the URL to be /business-logic/example/example-route, the module key must be business-logic:
use modules\businesslogic\BusinessLogic;

return [
    'modules' => [
        'business-logic' => BusinessLogic::class,
    ],
    'bootstrap' => [
        'business-logic',
    ]
];


Freeform unsubscribe and redirect non admin users away from admin area

Sorry for the trouble. This is a known issue and we will have a fix for this available in Freeform 3.10.8 in a few days (February 15-16, 2021). :)


View all discounts applied to a cart and remove discounts from cart

You've sort of answered your own question - Commerce only allows one coupon on a cart at any time (currently).

To determine if a coupon is set, and print the code, it's basically:

{% if cart.couponCode %}
     {{ cart.couponCode }}
{% endif %}

You CAN have discounts applied as well as coupons, though.
With those, you can look through with something like this (removing the coupons if you've previously printed that)

{% for adjustment in cart.adjustments if adjustment.type == "Discount" %}
    {% set isCoupon = adjustment.optionsJson.code ? true : false %}
        {{ adjustment.description }}
        ...etc


Recommended High Availablity Architecture

There's nothing particularly necessary for Craft here, other than what would be needed for a standard PHP application.

https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/php-ha-tutorial.html

And some potentially useful Craft related information around this topic here:

Load balancing nodes configuration (3 Craft nodes behind F5 Big-IP)

Craft admin login infinite redirect in cluster


descendantOf() parameter, entryModel or ID?

These are two different things.

{% set entries = myEntryModel.myEntriesField.descendantOf(var) %}

In this case the Entries field returns an ElementCriteriaModel object and you are setting the descendantOf parameter, which does in fact accept EntryModel objects or an Entry ID as an integer value. The Craft documentation is incomplete in this regard.

{% set bool = myEntryModel.isDescendantOf(var) %}

Here you are using the method isDescendantOf that is available for an EntryModel and returns whether the entry is a descendant of another entry. This method apparently only accepts an EntryModel.


Is there a way to create a new image transform 'onAfterInstall()' of a plugin?

Have a look at the method actionSaveTransform in the AssetTransformsController.

The code you actually need for your onAfterInstall would be like this:

// Only create if it doesn't exist (by handle)
if (is_null(craft()->assetTransforms->getTransformByHandle($handle))) {
    $transform = new AssetTransformModel();
    $transform->id = $transformId;
    $transform->name = $name;
    $transform->handle = $handle;
    $transform->width = $width;
    $transform->height = $height;
    $transform->mode = $mode;
    $transform->position = $position;
    $transform->quality = $quality;
    $transform->format = $format;

    if(craft()->assetTransforms->saveTransform($transform)) {
        // Success
    }
    else {
        // Error
    }
}


Are there any plans to get Craft Docs in Dash App

We've discussed it off and on because so many people have requested it and have got some ideas on how we'd tackle it.  No ETA, but it's on “The List” ™.


How to pass dynamic arguments into Wordsmith chop parameters

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

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

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

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


How can I return all user custom profile fields in an array?

Custom field data is accessible via currentUser.getContent().

Using dump:

{{ dump(currentUser.getContent()) }}

Or to output as string:

{{ currentUser.getContent()|join(', ') }}


How to configure Craft From for a form roulet/carousel?

It's not natively possible, but it's doable.

The plugin does support dynamic recipients.  I'm assuming that the rotating list of people is going to be stored in a database table or some other data source, though.  So in order to pull in the next correct group of people to send to, you'd need to write a plugin so you could run your own business logic.

  I also would like to store the number of form submits every person in the list has received.

When grabbing the next group of people to send to, your plugin would increment a tally for each of the people in the list and save it back out to a database table or other data store.


I got the answer to this thanks to @BrandonKelly from a comment in this question: How can you return elements between two values?

Turning it into a subarray does the trick: expirationDate: [ 'and', '>=' ~ now, '<=' ~ now|date_modify('+2 weeks') ]

Thanks, @BrandonKelly!


Prescribed way to set cookies (from plugin or Twig)

Cookies cannot be set via templates. However, in a plugin you have access to Craft's services. The UserSessionService has the saveCookie function.

craft()->userSession->saveCookie($cookieName, $data, $duration);


How to automatically remove entries after a certain time?

To only disable an entry, use this:
If entries need to be deleted, you can create a custom plugin, where entries will be deleted when expired or when the postdate is older than 2 weeks..


Sprout Forms supports multiple Notification Emails (as of Craft 3) and multiple Email Template. Sprout Forms also now supports CC and BCC functionality.

Create a new Notification Email on the Sprout Forms->Notifications tab. Each Notification Email has a setting for the Event that you would like to use to trigger it. You can select the "When a form entry is saved" event to trigger an email when a form submission is saved.

While there are numerous ways to trigger an email to both an admin and the user submitting a form, two common methods are:

Setup a single Notification Email and set the To field to the handle of a custom field that has the users email, such as: {email} and set the BCC field to your email address of the admin who you wish to receive it as well. You can separate multiple recipients using a comma-delimited list.
Setup two Notifications Emails and adjust the messages of each to each respective audience. You can create custom, company-branded Email Templates for the user-facing email. Impress them and set expectations for any follow-up communications. Send a workflow-oriented email to the admin, showing all data submitted in the form and linking to any next steps the admin may have to take after the email is received. The default Basic Notification (Sprout Forms) Email Template will loop through and display all values of the Form submission.

Legacy Answer:

In Craft 2, you are correct that Sprout Forms can send multiple notification emails to both admins and users, however the default Sprout Forms notification currently only supports a single template.

It's on our list to consider updating this default behavior. For now, your best options are:

Send the same email to both users and admins.
Add Sprout Email to the mix which integrates with Sprout Forms and allows you to customize as many emails and templates as you'd like and trigger them on the Event: When a Sprout Form Entry is submitted


Researching Craft CMS but we are a .NET Shop

Craft can definitely work as a "headless" CMS that you can put whatever want in front of. The go-to solution for such setups is the first-party Element API plugin.

For more info, Mijingo just released a free lesson on Element API and using Craft as a headless CMS.

It's also worth mentioning that Craft 3 (currently in dev preview; public beta ETA early 2017) is expected to add a RESTful API implementation to Craft core (either on release or after).


What are the different scenarios to plan for when using $allowAnonymous in a controller?

Here are the new constants that Craft 3.2 introduced:

const ALLOW_ANONYMOUS_NEVER = 0;
const ALLOW_ANONYMOUS_LIVE = 1;
const ALLOW_ANONYMOUS_OFFLINE = 2;

By default every controller will have the following property:

protected $allowAnonymous = self::ALLOW_ANONYMOUS_NEVER;

And you can override it in your controller in various ways:

// Allow anonymous access to all actions only when the site is live
public $allowAnonymous = true;

// Allow anonymous access to the `preview` action only when the site is live
public $allowAnonymous = ['preview'];

// Allow anonymous access to the `preview` action only when the site is live
public $allowAnonymous = ['preview' => self::ALLOW_ANONYMOUS_LIVE];

// Allow anonymous access to the `preview` action only when the site is offline
public $allowAnonymous = ['preview' => self::ALLOW_ANONYMOUS_OFFLINE];

// Allow anonymous access to the `preview` action when the site is live or offline
public $allowAnonymous = ['preview' => self::ALLOW_ANONYMOUS_LIVE | self::ALLOW_ANONYMOUS_OFFLINE];

The single pipeline | is a bitwise OR operator. It compares each bit (a binary digit of 0 or 1) in the integers and returns a new integer with a 1 wherever either numbers had a 1, and a 0 anywhere else (similar to how the || operator campares booleans). So the expression self::ALLOW_ANONYMOUS_LIVE | self::ALLOW_ANONYMOUS_OFFLINE is the same as 1 | 2 and will evaluate to 3. Here are some examples of how the | bitwise operator works:

( 0 = 0000) | ( 0 = 0000) => ( 0 = 0000)
( 0 = 0000) | ( 1 = 0001) => ( 1 = 0001)
( 0 = 0000) | ( 2 = 0010) => ( 2 = 0010)
( 1 = 0001) | ( 1 = 0001) => ( 1 = 0001)
( 1 = 0001) | ( 2 = 0010) => ( 3 = 0011)
( 2 = 0010) | ( 2 = 0010) => ( 2 = 0010)

The init() method of the Craft base controller now normalizes the value as follows:

// Normalize $allowAnonymous
if (is_bool($this->allowAnonymous)) {
    $this->allowAnonymous = (int)$this->allowAnonymous;
} else if (is_array($this->allowAnonymous)) {
    $normalized = [];
    foreach ($this->allowAnonymous as $k => $v) {
        if (
            (is_int($k) && !is_string($v)) ||
            (is_string($k) && !is_int($v))
        ) {
            throw new InvalidArgumentException("Invalid \$allowAnonymous value for key \"{$k}\"");
        }
        if (is_int($k)) {
            $normalized[$v] = self::ALLOW_ANONYMOUS_LIVE;
        } else {
            $normalized[$k] = $v;
        }
    }
    $this->allowAnonymous = $normalized;
} else if (!is_int($this->allowAnonymous)) {
    throw new InvalidConfigException('Invalid $allowAnonymous value');
}

Source: https://github.com/craftcms/cms/blob/3.2.2/src/web/Controller.php#L75-L96

So if the value is a boolean then false will be normalized to 0, whereas true will be normalized to 1.

If the value is an array then each key-value pair in the array will be inspected. If the key is an integer then the value is set to 1, for example:

public $allowAnonymous = ['preview'];

equates to

public $allowAnonymous = [0 => 'preview'];

and is interpreted as

public $allowAnonymous = ['preview' => self::ALLOW_ANONYMOUS_LIVE];

If the key is a not an integer then the key-value pair is left as is.

Here is how $allowAnonymous is enforced:

// Enforce $allowAnonymous
$isLive = Craft::$app->getIsLive();
$test = $isLive ? self::ALLOW_ANONYMOUS_LIVE : self::ALLOW_ANONYMOUS_OFFLINE;

if (is_int($this->allowAnonymous)) {
    $allowAnonymous = $this->allowAnonymous;
} else {
    $allowAnonymous = $this->allowAnonymous[$action->id] ?? self::ALLOW_ANONYMOUS_NEVER;
}

if (!($test & $allowAnonymous)) {
    // Prevent access unless the user is logged in and has the required permissions to view the site
}

Source: https://github.com/craftcms/cms/blob/3.2.2/src/web/Controller.php#L147-L176

The single ampersand & is a bitwise AND operator. It compares each bit in the integers and returns a new integer with a 1 wherever both numbers have a 1, and a 0 anywhere else (similar to how the && operator campares booleans). Here are some examples of how the & bitwise operator works:

( 0 = 0000) & ( 0 = 0000) => ( 0 = 0000) => false
( 0 = 0000) & ( 1 = 0001) => ( 0 = 0000) => false
( 0 = 0000) & ( 2 = 0010) => ( 0 = 0000) => false
( 1 = 0001) & ( 1 = 0001) => ( 1 = 0001) => true
( 1 = 0001) & ( 2 = 0010) => ( 0 = 0000) => false
( 2 = 0010) & ( 2 = 0010) => ( 2 = 0010) => true
( 3 = 0011) & ( 1 = 0001) => ( 1 = 0001) => true
( 3 = 0011) & ( 2 = 0010) => ( 2 = 0010) => true
( 3 = 0011) & ( 3 = 0011) => ( 3 = 0011) => true

By enforcing the condition $test & $allowAnonymous, we can check that $test (whether the site is live or offline) and $allowAnonymous (the permissions granted to the specific controller action) overlap.

More on bitwise operators here.

I'm not sure what the specific issue with your plugin is , but as far as I can tell the only thing that changed in Craft 3.2 was that the ALLOW_ANONYMOUS_OFFLINE constant was added, allowing for (but not requiring) more specific permissions on controller actions.


Something on the $entryToSave EntryModel is failing validation.  If you
echo out implode(', ', $entryToSave()->getAllErrors());, then you'll see what those errors are and you can correct them.


Craft Commerce: Sage Pay - Redirect Required after payment?

Looks like your redirect does not contain the full url back to your site.

The error shows:

195.170.169.29 - - [20/Jul/2016:09:05:17 +0100] "POST /index.php/actions/commerce/payments/...

But I would expect to see a url starting with http://sitename.com/ since your gateway needs the full url to redirect you back to your site.

Make sure you have a siteUrl set up in your craft settings: https://craftcms.com/support/site-url


The next step is that you would need to chain .relatedTo(restaurant) to your existing craft.entries() call


What is the type of field of family ?
You don't have to enter the domain and language. Just start from family and forward. If family is the title field, write it like this:

{title}/offers/{slug}

if the family field is an element type, do it like this:

{familyField.last().uri}/offers/{slug}

or

{familyField.last().slug}/offers/{slug}

or if it is a title

{title}/offers/{slug}


Apply inline styles to selected text in Redactor

All of Redactor's default Formatting Styles are block elements. But you can add your own styles to it by making use of the newish formattingAdd setting. There's an example editor on the Imperavi website where they added multiple custom styles to it. Some of them are inline styles (try the style "Big Red" for example).

One thing to note here is that it adds the format to the existing ones. To prevent your style from doing so you have to add clear: true to your style settings.

formattingAdd: [
  {
    tag: 'span',
    title: 'Normal inline text',
    clear: true
  },
  {
    tag: 'span',
    title: 'Big Red',
    style: 'font-size: 20px; color: red;',
    class: 'span-big-red',
    clear: true
  },
]

Update: I just tried to remove inline styles by applying my "Normal inline text" style to it and it first seemed not to work. But then I did a new text selection that spanned a greater portion of text and it worked. That's a good sign, but still no real solution.

As Imperavi didn't respond to previous Email I wrote them (not sure if it's because we, Craft users, are not direct customers of them?), I am going to ask P&T to make them aware of this bug.


Issue on new craft (craftcms3) setups: vendor Twig can't read system variable

I've looked all over for a solution to this but couldn't find anything. I don't know if you've already fixed your problem now, but in case you haven't or someone else has found this error and arrived here, a simple fix for it is to add the missing information into the project.yaml in config/project/.
For my local development build, I used the following:
system:
  edition: solo
  live: true
  name: '{YOUR PROJECT NAME HERE}'
  retryDuration: null
  schemaVersion: 3.5.13
  timeZone: UTC

For the schemaVersion, it will need to match the one specified in the installed version of Craft in your vendor folder. This can also be found in the repo.
I'm not sure what the cause of the missing info is, but I am also on a Mac running Big Sur so it may be related. Once you have added in this information, you should be able to edit it normally from Settings -> General.


Is it possible to add an attachment to a Craft Commerce order status email?

According to How to attach an order PDF in an order confirmation email?, it is currently not natively possible as of Craft Commerce 1.1.


I think this plugin does what you want. It allows editing the translations for any static text passed trough Crafts translate functions & filters.


Have a custom plugin do something on every page load?

Add a init() method to your plugin and as long as it's installed and enabled, it'll be called on every request.

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

    /* Do your stuff */
}

If you want it to only happen on front-end requests, you can use:

if (craft()->request->isSiteRequest()) { ... }


How do I target the first item in a Twig for loop?

Twig has loop-variables which can be accessed inside for-loops. loop.first will return true on the first iteration.

{% for image in entry.images %}
    <img src="{{ image.url }}" alt="{{ image.title }}">

    {% if loop.first %}
        Do stuff..
    {% endif %}
{% endfor %}


Get the Category name into the URL for an entry

A Categories field can be related to several categories. So you'll either need to limit your Category field to a single Category relationship or you'll need to make some assumption in how you build your URL as to which category will appear in the URL. The simplest assumption to make will be that you will always return the first category for your URL.

Entry URL Format in the Section Settings:

gallery/{categories.one().slug}/{slug}

Entry Page URL:

http://mysite.com/gallery/category-slug/entry-slug

In the Entry URL Format setting above, you are telling your slug to return the slug of the first item in your array of categories using this line: {categories.first().slug} where categories is the handle of your Categories Relations field.

You may also want to ensure your Categories Relations field is required.


As I thought, I was just being silly. I initially didn't realise that custom controllers need to be encapsulated within a custom plugin

I guess my mistake was going directly to the controllers documentation and missing the line that says:

  To create a controller, first create a new controllers/ subfolder within your plugin’s folder

Hopefully anyone who runs into this (doubtful as I can imagine most, unlike me, will probably read the documentation properly) will find it somewhat useful


To prevent Rich Text fields from stripping your ID attributes, you'll need to disable the "Purify HTML?" setting for your field.

Note that disabling the HTML purifier does represent a potential security risk, but as long as you trust your content editor(s), you should be fine.


I'm getting unexpected output within media queries

Try it this way. Why are your outputting multiple images for the same background image for the same class.  The last item will override the previous.

{% set news = craft.entries.section('news').limit(3) %}
<style type="text/css">
  {% for item in news %}
    @media (min-width: 1200px){
        .hero{
            background-image:url(
               {% set cover = item.promotionImage %}
               {% if cover|length %}
                   {{ cover[0].getUrl('gtLg') }}
               {% endif %}
             );
         }
    }
  {% endfor %}
</style>


during this process :
{% set image = block.image.one() %}
please make sure the name of handle of image is image.
For example in this matrix the type is 'image' but to get image url you should call it. item.imageAssets.one().url


Is there a way to credit a customer's account in Craft Commerce?

Commerce does not, currently (= Dec 16) have any concept of a customer balance or a gift certificate.

You could do it as a plugin, I would think.  Basically you'd keep a list of emails and credits in a record (i.e. table) and then write a controller that you/the customer could call to apply those credits - the actual application of which you'd probably implement as a Commerce adjuster perhaps (https://craftcommerce.com/docs/adjusters).

It would be a relatively involved plugin at this point.

In our case we chickened out on this, hoping it will come later to Commerce core - we just ask that the gift certificate customers call through their order.  Definitely not ideal but for the relatively few GC customers it didn't seem worth the development effort.   Gift certificates are an often requested feature for Commerce, though, so you'd expect it to happen at some point.

Vote here for the feature - https://github.com/craftcms/commerce/issues/253


Craft internal error exposing sensitive data

Your guess is correct... as the docs say, you should never have devMode enabled in production environments specifically for reasons like this (as well as many others).

If you find errors that are leaking sensitive server info with devMode disabled, then that is a bug and should be reported to support@buildwithcraft.com.


Upload file from plugin's Controller to a non-Assets folder

Ahh, a bit of fiddling and poking around later...

$file = UploadedFile::getInstanceByName('myFieldName');
$fileName = AssetsHelper::cleanAssetName($file->getName());

// Make fileName uniqueish by adding a timestamp to it.
$fileParts = explode(".", $fileName);
$extension = array_pop($fileParts);
$fileName = join(".", $fileParts) .'_'. time() .'.'. $extension;

$filePath = '/path/to/my/folder/' . $fileName;

$response = $file->saveAs($filePath);

Seems to work OK!

The unique filename stuff seems not entirely great. Might be better to see if the file exists first, and if so, make a new name.

Just need to work out how to validate my Model now...

UPDATE: Oh, that was quick. So now I do:

$post = craft()->request->getPost();
$myModel = MyForm_FilesModel::populateModel($post);

// All the file-handling stuff as above.

$myModel->myAttribute = $file;

if ($myModel->validate()) {
    ...

Where my model is something like:

<?php
namespace Craft;

class MyForm_FilesModel extends BaseModel
{
    protected function defineAttributes()
    {
        return array(
            'myAttribute' => array(AttributeType::Name),
        );
    }

    public function rules()
    {
        return array(
            array('UploadPassport', 'file',
            'allowEmpty' => false,
            'maxFiles' => 1,
            'maxSize' => 5 * 1000000, // 5MB
            'tooLarge' => 'Sorry, the maximum file size is 5MB',
            'types' => array('jpg', 'png', 'pdf'),
            'wrongType' => 'Files must be one of jpg, png or pdf',
            'message' => 'Please upload a file'),
        );
    }
}

(The defineAttributes() stuff feels very wrong, as this isn't a proper Craft model - I'm not saving any of this as an Entry etc defined in the Craft Admin. But I can't see how else to make this stuff work.)


You can write a plugin that does this.

Use https://pluginfactory.io/ and check the "Console Command" checkbox and it will generate the boilerplate for you.

Your "Find and Replace" command would follow similar logic to what the FindAndReplaceTask's runStep() method does.


Routing generic urls to sections or structures urls

What I would do is create a structure siteUrls which is responsible for page urls. Top-level entries have url of {slug}, nested entries have url of {parent.uri}/{slug}. The top-level entry with slug blog will be the entry with url /blog. Then you can have an entry type of blogLandingPage and use that entry type for this entry.

The other piece of the puzzle is getting the right template for the blogLandingPage. The trick for this is to use a feature of the twig include tag:

  New in version 1.2: The possibility to pass an array of templates has been added in Twig 1.2.

  You can also provide a list of templates that are checked for existence before inclusion. The first template that exists will be included:

So your template for  siteUrls will look like:

{% include ['_siteUrls/'~entry.type, '_siteUrls/default'] %}

And the template for entries (like this one) with type blogLandingPage is _siteUrls/blogLandingPage. Using a list for the {% include %} means some entry types can share templates, and thing fail more gracefully if you have an entry type without a matching template.


Could not find your craft/ folder. Please ensure that $craftPath is set correctly in

This is usually one of 3 things:

The path to the craft folder defined in your public index.php file in $craftPath is incorrect.
The path defined in $craftPath is correct, but PHP doesn't have permissions to go into that folder and open index.php.
Your php.ini file has open_basedir restrictions in place that prevent PHP from opening that folder.


{% redirect "{{ entry.url }}" %} doesn't work

You do not use the {{ }} inside other brackets you also should not use ' ' unless it is a specific string you want interpreted. Try instead:

{% for entry in craft.entries.section('services').limit(1) %}
     {% redirect entry.url %}
{% endfor %}

And you should be good to go


Where does Craft store the field definitions?

Basically look for the tables "craft_fields", "craft_content" and "craft_sections".
For Fields you can use the "Field Manager" Plugin.


It just sounds like your nginx conf file isn't setup properly.  See here for some working examples.


Have you got your htaccess file working ok? By default the htaccess file is named incorrectly, it should be .htaccess nothtaccess`. You can read about renaming that file in the installation docs.

As a quick test you could try:
"/index.php/new-url"

If that works it's your htaccess file.


Include entries to a entries section object, without 'merge'

A colleague of mine shed some light on a very simple solution

{% set myPages = craft.entries.section(['structureName', 'singleName']).order('sectionId desc') %}

<nav>
{% nav entry in myPages.level([1, null]) %}
  {{ entry.title }}
{% endnav %}
<nav>

<aside>
{% for entry in myPages.level(2) %}
  {{ entry.title }}
{% endfor %}
<aside>

Passing an array of handles/slugs instead of just a string works perfectly. Since singles don't have levels; defining null in the level pulls them out too.


A few things to keep in mind.

LogLevel::Infois only going to be logged when devMode is enabled, so any overhead from excessive logging won't be an issue in production.
Excessive logging will consume extra memory because all logging information on a given request is stored in memory and flushed to disk at the end of the request, but overall I imaging that the performance hit will be negligible.
Excessive logging will cause your log files to rotate out quicker.  By default Craft will cap each log file at 1MB worth of data and will start to rotate out the older files after 6MB worth of data has been hit.


This is something that is best done via server-side config. The reason is that when an image is requested, for instance, your Twig code that sets the header never gets run for that request.

You can see how it is done via Nginx here: Nginx-Craft

For Apache (don't use .htaccess pls) go here: html5 boilerplate apache


Getting logged out of admin area when refreshing site

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.


DB Queries in Craft Commerce 2 with large data

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

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

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

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

      return $rows;

    }

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

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

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

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

I hope this helps someone with a similar issue!


Fixed. I downloaded fresh copies of OAuth and Video plug-ins. Re-uploaded to server and it's all working.

I guess something got missed or corrupted in the initial upload.


Disabling unused PHP functions and Craft

I'm not aware of a definitive list, but Craft have problems running with some of the methods in your list disabled.

phpinfo, move_uploaded_file, chdir, mkdir, rmdir, chmod, rename

Any plugins you have installed might have additional function requirements as well.


Can't import a complete url into an url field with feed-me

Have you tried to make external_link an array?

"external_link": [{
    "cta": "Banner import link text (fr)",
    "url": "https://example.com"
}],


This might be a silly question, but is your .pic-banner class for this template styled correctly, ie. given a height etc?

Since you're setting it is a background-image it won't "expand" the element to the aspects of the image as it normally would using a img-element.


Prevent foreign characters in filenames?

Cant you just use preg_replace("/[^A-Za-z0-9 ]/", '', $stuff) for this? Seems that will strip away anything that isnt a number or a letter from the english alphabet?

EDIT ---------
Challenge accepted ;)

public function modifyAssetFilename($filename){
    return preg_replace("/[^A-Za-z0-9-]/", '', $filename);
}

Something according to the above strips out all unwanted characters using the hook if you place it in a plugins main class file. The above preg_replace should also keep dashes e.t.c.

Another way you might be able to approach the sanitation of filenames is listening to the onBeforeSaveAsset method and then using craft()->assets->renameFile() once you have sanitized it. Not sure which one is better. Both should work.


You could try using the date_modify filter with a relative DateTime format:

{% if slide.dateTime|date_modify('tomorrow 5am')|date('U') < now|date('U') %}

And if you want to limit the entries to be displayed, you should not use the limit parameter for that. Your
ElementCriteriaModel doesn't take your DateTime conditional into account, so it requires a custom solution:

{% set slides = craft.entries.section('events').featured('1').order('dateTime asc').limit(null) %}

{% set count = 0 %}
{% for slide in slides %}
    {% if count < 5 and slide.dateTime|date_modify('tomorrow 5am')|date('U') < now|date('U') %}
        {{ slide.dateTime }}
        {% set count = count + 1 %}
    {% endif %}
{% endfor %}


Email notification on field value change?

Sprout Email allows you to create Custom Events where you could add a new rule that allows a user to set the options needed to meet your use case.

Additionally, the entire EntryModel will be handed off to the Notification when your Custom Event fires, so you could have logic in your notification template that sends customized messages depending on the different conditions that were met, just like in any other Twig template.


Got an "Oops" Screen While in Installer, Exited to Try Again, and Now I Can't Get Back to Installer

I feel silly posting an answer to my own question, but I wanted to post the solution in case anyone else ran across this, instead of just deleting the question.

I was using the URL http: //localhost/public/index.php/admin/install to get to the installer, and I think it wouldn't let me go back because the installation-- somehow-- was actually successful. I started playing around with the URL and found that http: //localhost/public/index.php/admin brought me to the admin dashboard. Trying to put in the address I gave the site is still throwing a Page Not Found at me, but I'm hoping that's because everything is there but not quite wired-up correctly yet; I'll try to come back and edit this if I find that there is more that should be included here to remedy this.


Using {% cache globally %} inside {% cache %}

So in short, can I safely use cache tags inside other cache tags?

You can nest {% cache %} tags and in the majority of cases it's probably safe.

Some additional reading:

What effect does nesting cache tags have?

Prevent craftcms caching CMS page with dynamic template


Failed to load Twig template "_includes/field", index "764771142": cache is corrupted

Additional info: This error occurs only when devMode=true

Restricting image upload to a single folder {owner.filmtitle|kebab} possibly caused the error, replacing the folder template helped:

{% if owner.filmtitle %}{owner.filmtitle|kebab}{%else%}default{%endif%}

Nevertheless i don't understand why the former version caused the error, and the error message is very misleading.


How do you use the Element API plugin to output Assets from Matrix block for an entry?

You need a transformer

'transformer' => function(MatrixBlock $element){
    return [
       'image' => $element->getFieldValue('assetFieldHandle')->one()->getUrl()
    ];
}


The question is, is there a multiple license discount?

We currently don't have an official policy, but to-date we've handled bulk discount requests on a case-by-case basis.

As the FAQ suggests, contact support@craftcms.com :).


It depends how you're fetching the category. But if you've defined the template when setting up the categories it would be called be within a var called 'category', which would be a category object. You should then be able to access it using:

{{ category.title }}

If, on the other hand, you were getting the category via a slug in the URL, you would do something like:

{% set category = craft.categories.group('productType').slug(craft.request.lastSegment).first %}
{{ category.title }}

UPDATE: Following on from your updated question, you've already got the category as an object so there is no need to get it again. Try replacing:

// THIS IS YOUR LOOP, BTW
{% for category in craft.categories.group('productType').find() %}

{{ category.title }}

{% endfor %}

with:

{{ category.title }}

But you might need to add a conditional in case the page is loaded without a category. Something like:

{% if category | length %}
    {{ category.title }}
{% endif %}


Pro licence error - Craft is unable to purchase an edition upgrade at this time

According to their Tweet it seems there was an error on P&T's end:
https://twitter.com/CraftCMS/status/1085975322443448321


How do I control order of output using Seomatic plugin

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

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

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

Disable automatic rendering:

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

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

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

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


Importing assets with Feed Me using Element Exporter data

I don't know if you're still facing this issue but it's something I'm working on right now! Basically my solution was to create a short program to parse through the Element Exporter json and to change anything that was an Asset ID to that asset's url (which Feed Me accepts).
    public function modifyExport(array $element): array {
        $result = [];
        //Parse through JSON export
        foreach ($element as $key => $value) {
            //Recursive function to keep traversing down levels
            if (is_array($value)) {
                $result[$key] = $this->modifyExport($value);
            //You've reached a root level, check the content
            } else {
                //If the value is a number, it is representing an ID
                if (is_numeric($value)) {
                    //Find the Element corresponding to this id
                    $assetCheck = Craft::$app->getElements()->getElementTypeById(intval($value));
                    //Check if the element is an asset
                    if ($assetCheck == 'craft\\elements\\Asset') {
                        //Get the actual asset data
                        $asset = Craft::$app->getElements()->getElementById(intval($value));
                        //Create the asset path *this may differ based on where your assets are*
                        $path = getEnv('DEFAULT_SITE_URL') . '/assets/images/' . $asset->folderPath . $asset->filename;
                        //Rewrite the content with the path, instead of the id
                        $result[$key] = $path;
                    //If the element is not an asset, keep it the same
                    } else {
                        $result[$key] = $value;
                    }

                }
            }
        }
        return $result;
    }

Once I got the result, I used file_put_contents('end/path/goes/here.json', json_encode('result here')); to place it in a different file OR you can simply overwrite the same export file. Hope this helps!


Getting relation through entry field by author

This is untested code.

{% set coachingTeam = craft.entries({
  section: "divisions",
  type: "team",
  relatedTo:[
    'and',
    { targetElement: currentUser.id },
    { targetElement: headCoach[0].id }
  ]
}) %}


Cannot select subcategory field in entity

Unlike structured entries, when you relate a category to another element, its ancestors are also included in the relation. Due to the way Craft looks up these ancestors when relating the selected categories, to enforce this behaviour, the ancestors are added to the relation before the one you selected, and it looks like you're limiting that Categories field to 1, so only the parent is being added.

Try setting the limit on that Categories field to 2.


Twig url() function returns CP path when called from plugin

Right, url() (and UrlHelper::getUrl(), which url() maps to) will create a URL to either a front-end page or a CP page, depending on where it is being called from.

If you want to get a front-end URL from a CP request, you can use siteUrl() instead. (You can also get a CP URL from a front-end request via cpUrl().)


Category query returning one fewer items than requested

If it works hard-coded, try trimming your variable:

set searchQuery = searchQuery|trim

OR, even better, build an array:

{% set categories = [] %}

{% for category in currentUser.kb__category %}
   {% set categories = categories|merge(category.id) %}
{% endfor %}

{% for category in craft.categories
  .group('knowledgeBase')
  .id(categories)
  .level(1)
  .all()
%}


Getting unique values from Smart Map addresses

You'd actually need to retrieve all of the entries to count them in this way. Once you've got the complete collection, it would simply be a matter of looping through them and adding everything up.
1. Get all entries in California.
{% set params = {
    filter: {
        state: 'CA'
    }
} %}

{% set meetings = craft.entries.address(params).all() %}

2. Loop through those entries. Build a new array based on the results.
{% set stateMeetings = {} %}

{% for meeting in meetings %}

    {% set city = meeting.address.city %}

    {% if stateMeetings[city] is defined %}
        {% set cityTotal = stateMeetings[city] + 1 %}
    {% else %}
        {% set cityTotal = 1 %}
    {% endif %}

    {% set stateMeetings = stateMeetings|merge{(city):cityTotal} %}

{% endfor %}

3. By the time that's all done, you'll have a neat associative array, where each key is a different city, and the value of each represents how many times it was found.
{
    "Los Angeles": 3,
    "San Diego": 6,
    "Modesto": 1,
}

You'll definitely want to cache all of that... it'll be a pretty expensive process.
To be honest, I'd actually recommend doing all of this work in a plugin (or module). It's a fairly easy thing to achieve with a template hook. This kind of heavy merging is ill-fitted for Twig, but much simpler in PHP.


Eager load a list of entries, then only the first asset, from the first block type

Additionally, it appears I cannot use the loop to save a variable to use outside of it

This is really a separate question. Answering it anyway: you need to give the variable some value before the loop, and then it works:

{% set img = null %} {# initial value #}

{% for block in entry.pageContent %}
  {% if block.type == 'images' %}
    {% if not img %}
      {% set img = block.images[0] ?? null %}
    {% endif %}
  {% endif %}
{% endfor %}

{# img will be the first image of first 'images' block, or null #}


bootstrap.php returns a value of 1 in Craft CMS

In my particular case, I downgraded the Bitnami LAMP stack using instructions found here: https://community.bitnami.com/t/how-can-i-downgrade-to-php-5-6-from-php-7-0/51792

The downgrade fixed the issue although, had I seen Brad's answer before that, no doubt I could have fixed it using those posts....


Template not found error when template file does exist

_category can only be viewed if it's included in another file, because of the underscore. A twig file with an underscore cannot be loaded directly via the URL.

You may also read What is with the underscore in twig template filenames? or hidden templates from the Craft Docu.


Does Craft require any specific configuration for PHP Mail to work?

No.  Craft assumes that PHP's mail function is already working if that's what you've selected under Settings->Email in the control panel.

You don't mention what the actual problem you're having is (i.e. getting an error message or email not being delivered, etc.), but there is a support article here that can help you debug both of those issues: https://craftcms.com/support/troubleshooting-email-errors


I think you solved your own problem — by linking channel entries to structure entries using relationships (via the "Entries" field) you can display the same project in multiple locations. Seems like a perfect solution.


{% set products = craft.commerce.products.relatedTo(category) %}

...is the correct code for finding products related to a category IF category is actually a Category Model at this point - e.g. it is the auto populated category variable in a template set to the template for that category group.  I would check, in the catgeory group settings, what you're using for the Category URL formats and the Category Template settings.

It would be also very helpful to know what's the actual error you are getting?


Not sure how you're outputting the url to the variant itself, but you can always create your own link and change the variant paramater to whatever you want.
Something link this: {{product.url}}?keywordyouwanttouse={{variant.purchasableId}}
On your product page you can then check if the url has the parameter and get the data of that variant.
I use the following code at the top of my product template and then use the selectedVariantto display sku, images, prices, ...
Here I use the variant querystring but you can change that to whatever querystring paramater you want to use.
{% set variantId = craft.app.request.getQueryParam('variant') ?? false %}
{%  if variantId %}
    {% set selectedVariant = craft.variants.id(variantId).one() %}
{% else %}
    {% set selectedVariant = product.defaultVariant %}
{% endif %}


Have you tried

.renewalDate('and', ">= #{dateStart}", "< #{dateEnd}")

The difference is the double quotes. I don't think that single quotes support interpolation.

However, I'm not sure in that case why the version without the 'and' works.

OK, have just tried it myself...
I created a section called test and added a single date field called renewalDate and the code below works on a simple listing page.

{% set dateStart = now|date('Y-m-d H:i')  %}
{% set dateEnd = date('next month') | date('Y-m-d H:i')  %}

{% set params = {
  section : 'test',
  orderBy : 'renewalDate asc',
  renewalDate : ['and', ">= #{dateStart}", "< #{dateEnd}"]
} %}

Entries

{% for entry in craft.entries(params).all() %}

{{ entry.title }}

{% endfor %}


Recoverable error Object of class Craft\ElementCriteriaModel could not be converted to string after Update

Try something like this:

{% set author = entry.metaAuthor|length ? entry.metaAuthor[0] : homepage_entry.metaAuthor[0] }}

<meta name="author" content="{{ author }}" />


Global nav with dynamic links across multiple sites

At the moment, that's not possible with Craft itself. That might be possible in Craft 3, as cloning sites will be an option -- though all of your sites would also have to be in Craft. Not sure if sharing information between sites will exist in C3 or not though.

You COULD use Craft to create the navigation fairly easily. Then you could create a blank template (not extending your base layout) that only contains the navigation, and then loading that via AJAX on the other sites into a nav container div.


How do I output the siblings position number?

Building upon the answer I posted to this question How to get the order number of the current entry in a structure, you should be able to get the order number in your for-loop like so:

{% set parent = entry.getParent() %}
{% set childrenIds = parent.getChildren().ids() %}

{% for sibling in entry.getSiblings() %}
    {% set orderNumber = craft.entries({
        id: siblingsIds,
        order: 'lft desc',
        positionedBefore: sibling,
    }).total() + 1 %}

    {{ sibling.title }} ({{ orderNumber }})
{% endfor %}


The solution provided here actually required some adjustments. Here is what ended up working:

In craft/plugins/sample/SamplePlugin.php:

<?php namespace Craft;

class SamplePlugin extends BasePlugin {

    function getName() { ... }
    function getVersion() { ... }
    function getDeveloper() { ... }
    function getDeveloperUrl() { ... }

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

    protected function getSettingsModel()
    {
        return new Sample_SettingsModel();
    }

}

In craft/plugins/sample/models/Sample_SettingsModel.php:

<?php namespace Craft;

class Sample_SettingsModel extends BaseModel {

    protected function defineAttributes()
    {
        return [
            'mySetting' => [
                AttributeType::String,
                'required' => true
            ]
        ];
    }

    public function rules()
    {
        $rules = parent::rules();
        $rules[] = ['mySetting', 'validateMySetting'];

        return $rules;
    }

    public function validateMySetting($attribute)
    {
        $value = $this->$attribute;

        if ( /* validation condition */) {
            $message = Craft::t("Error message");
            $this->addError($attribute, $message);
        }
    }

}


Nevermind.  Must have been caching or something.  I'm up and running.  Computer voodoo.


You could try something like:

{% for entry in entries %}
  {% for image in entry.portfolio.orderBy('RAND()').limit(8)
    <img src="{{ image.getUrl() }}">
  {% endfor %}
{% endfor %}


Hard to say for sure, but here's what I suspect... You may have multiple instances of firstImage being called from your main template.

For some of those instances, entry.sliderMatrix.total is greater than zero. For other instances, entry.sliderMatrix.total is equal to zero. And of course, when entry.sliderMatrix.total is equal to zero, your if statement will be bypassed.

Realistically, you shouldn't have the image.url call outside of your if statement. Because any time the if statement evaluates to false, then the image variable won't be what you want it to be. In fact, you'll get that exact error, since image will still be set to a string.


Changing asset of entry's assetfield via entries.onBeforeSaveEntry

After taking a look again, it turned out to simply be an issue with the scope of the array and a therefore empty array as a result. Works as expected now.


Error 404 When trying to POST to plugin Controller action

Ok so thanks to @BradBell's suggestion, I regenerated the skeleton of my plugin and it's controller using pluginfactory.io and it now magically works! Still not sure exactly what the difference was, but it does its job now!


How do you download multiple plugins vis Command Line?

You can use the plugin/install command for the ./craft cli utility, I'm not sure if you're aware of this:
https://craftcms.com/docs/3.x/console-commands.html#plugin-install
You'll need to know the plugin's handle, but that's all you need. I've never tried specifying multiple plugins in the one command, but that's an easy one to test.
Now, as to why you're needing this is the real question. If you've got your workflow correct, you shouldn't need to be manually downloading/installing plugins with the cli anywhere other than local dev. Project config (if you're using it) and composer should handle all of this. Typically, a basic deployment is as follows:
composer install
./craft migrate/all
./craft project-config/apply

I guess it would help to know why you're downloading and not installing, and in which kind of environment this is happening.


What you could do is to create a new asset source and a new asset field for the backupimage and a plain text field for the HTML (you can later convert this to an Incognito field). Add those new fields to the ZIP files' field layout.

After unzipping the bundle to a temp directory with you plugin, you can now check if the files meet your requirements. If everything's fine, create an asset file model from the backupimage using the insertFileByLocalPath method and relate that asset to the ZIP asset by storing its ID to the ZIP's backupimage asset field. Now read the HTML file and store it into the ZIP's html plain text field.

You might also want to have a look at the source code of my Asset Metadata plugin, as I'm doing some quite similar things with the field type it provides.


According to "How License Enforcement Works" a subdomain with 'sandbox' should work fine without Craft complaining about your license.

Does it have a dev-sounding subdomain (e.g. ‘craftdemo’, ‘dev’, ‘local’, ‘loc’, ‘qa’, ‘test’, ‘testing’, ‘sandbox’, ‘stage’, ‘staging’, ‘uat’, ‘acc’ or ‘acceptance’)?

Try contacting support thru the Craft control panel about this. If it's not working properly, I think they can at least add your domain to an allowlist.


Still not able to manage tags in Craft 3?

Short answer is "no, this still isn't possible".

Longer answer is:

The Tag Manager plugin from Craft 2 will not be ported.
Pixel & Tonic have mentioned the possibility of rolling that functionality into Craft's core.

  https://github.com/craftcms/cms/issues/820

So what can you do about it? Vote up this feature request!


Have auto selected categories with new section entry

That functionality doesn't currently exist out-of-the-box (as of 2.5.2752), but it would be possible as a custom development: You'd essentially need to create a clone of the Categories fieldtype, add your own config/setting to select the default categories, and then use the prepValue() method of the fieldtype to pre-select those default categories for new entries.


Display a Matrix field block entry when the block's entry exists

Try replacing

{% for asset in block.imageField %}

{% endfor %}

with

{% set asset = block.imageField.first() %}

If you're using Craft 3, replace .first() with .one()


Okay, I found the issue.

It was the caching. I cleared the cache in the cp and emptied the craft_assettransformindex table

I deploied the site to my live server but had the image folder on svnIgnore, so craft tought the images would still be there and didn't try to recreate them.

This answer helps.


On the P&T form add-on you have to use a message field is there a way round this?

Why not just add a hidden input called "messages" set to "" (or if that doesn't work ".")?

What's the use case for wanted to send a contact email with a message body?


What is the best way to append CSRF token without using a form?

You need to pass the token and name into javascript. Easiest is to just have a script tag somewhere.

<script type="text/javascript">
    window.csrfTokenName = "{{ craft.config.csrfTokenName }}";
    window.csrfTokenValue = "{{ craft.request.csrfTokenValue }}";
</script>

Now they will be available to your ajax call.


Importing Entries from Craft 2 to Craft 3 with Feed Me - find/replace twig filter issues

Also run the content through the |raw filter to get rid of the html entities. I believe that it works without the replace filter because once that is run, twig is parsing the provided text.


Holy moly! I've solved it already, Batman. Check the array before adding the event to it, like so:

{% if event not in categoryEvents %}
        {% set categoryEvents = categoryEvents | merge([event]) %}
{% endif %}


Is it possible to download an asset from an entries tab

I'm pretty sure there isn't currently a plugin which makes that possible (complete list is here), but I'd imagine it's possible to build one.

The trick would be to set it up as a Field Type. Then your field type would have to dynamically figure out what file is supposed to be downloaded, and provide a button for your user to download it.


Craft 2 use different template for the same structure

I finally managed to answer my own question. I changed my routing to

/projects/slug/slug/gallery to projects/gallery/_entry

So was able to use a proper absolute link with /gallery added to the end

.com/projects/category/project/gallery

In the gallery _entry I used the following code to get the entry

{% set projectSlug = craft.request.getSegment(-2) %}
{% set categorySlug = craft.request.getSegment(-3) %}
{% set category = craft.categories.slug(categorySlug).first() %}
{% set entry = craft.entries.section('projects').slug(projectSlug).relatedTo(category).first() %}

This then worked fine, even if the same named project was used in two different categories

I would still prefer to do this without routing if anyone has any suggestions please?


Cache invalidation to automatically update all cached template content?

I built the Cache Warmer plugin recently, which takes a blanket approach to refreshing your pages cache, by getting entries url with the .getUrl() method, and then send of batch requests to those url's.

I'm currently using it together with the Cache Clear plugin, when deploying changes to our site, and it's working well. This is a very simplistic approach to a potentially complex problem, so I would say a more granular cache invalidation/refresh strategy might be needed, depending on your use case.

However, I think there is something to be said for this approach on small to medium sites.

I want to at least add some hooks, so that you can warm up single entries/elements as well. My plugin doesn't know which pages your cached elements are living on, but there is a big chance those pages will be hit and warmed up - as long as they're located in a section, and that section is toggled in the plugin settings.


Does deleting an original asset but keeping the transform folder asset make Craft replace the original file with the biggest transform?

No - Craft will always use the originally uploaded asset as the "source of truth" for generating new transforms.
You can, however, replace the originally uploaded 8mb+ file with a smaller one, and it'll be used as the source of truth for generating new transforms.


How can I get a field's value from a global based on a url segment?

You will need to access a few things.

The url segment you need (for example the last segment)
The global set name
The field handle name

You can use getLastSegment to access the last url segment.

Using the global set names above let's say I have a url like this:

mysite.com/first

{% set segment = craft.request.getLastSegment() %}  // first

I know I've got a global set called firstGlobalSet, and now I've got first. We just need to put them together. You can use Craft's
getSetByHandle method to access the global set via its handle.

{% set global = craft.globals.getSetByHandle(segment ~ 'GlobalSet') %}
{{ global }} // firstGlobalSet

Now that we've got the correct global set, we can get to the field we need. In this case it's myTextField.

{{ global.myTextField }}


Is it possible to use `guestEntries.beforeSave` to validate custom fields?

The only model passed into the guestEntries.beforeSave event and returns from it is Craft's EntryModel, so even if you create your own MyEntryModel inside the event with it's own attributes and validation rules, there's not a clean way to return that model back to the controller to return to the template to display.

The easiest thing to do would be to fork the plugin and change GuestEntriesController so that's its using a custom MyEntryModel that extends Craft's EntryModel and adds it's additional attributes/validation rules as required.


It's not doing it due to order of operations. Your browser hits the site, checks htaccess (in the webroot /html/), and then asks craft for whatever page. Craft goes hunting around, and returns your page from templates. And it's Craft (not you the user) accessing the templates, so it's always 'approved.'

Here's a potential solution. Take a look at this page - https://noahread.net/blog/create-password-protected-pages-in-craft

It's how to create a single password-protected page. Uses a for a password. And that password is hidden in a craft variable, so no one can see it. If it returns successfully, you get content.

All that said, craft pro might be cheaper than the time spent building said form.


How to filter entries in multiple category groups by selecting multiple categories

After a lot of back and forth and reading various posts on this I thought I would submit my answer. There maybe better ways of doing what I ended up doing but hopefully this will provide a start for someone wanting to do the same.

First here are a few posts and questions that helped:

Find entries with multiple categories with an and/or twist
How can I create an ElementCriteriaModel with 'and' and 'or'
Combined searches and filters using Craft

My Solution

First I created a search form that had the checkboxes for the search, each checkbox name when posted would form the get variable for the filter. A check is done to see if there are categories, if there are then I loop through and add them. There is also a check done to see if you are on the filter results page, if you are then set the relevant checkboxes to checked on the form.

The Search Form Code

<form action="{{ url('homes-for-sale/filter') }}" method="get">

  {# check if there are any park categories if there are then show them as checkboxes #}

  {% if parkCategories|length %}

    {% for category in parkCategories %}
      {% set loopIndex = 'park' ~ loop.index %}

        {# if you are on the filter results page then set the results to checked #}

        {% if template is defined and template == 'filter' %}
          <input type="checkbox" name="{{ loopIndex }}" value="{{ category.slug }}"{% if category.slug == park1 or category.slug == park2 or category.slug == park3 or category.slug == park4 or category.slug == park5 %} checked{% endif %}>
        {% else %}
          <input type="checkbox" name="{{ loopIndex }}" value="{{ category.slug }}">
        {% endif %}
        {{ category.navTitle }}

    {% endfor %}
  {% endif %}

  {# check if there are any price categories if there are then show them as checkboxes #}

  {% if priceCategories|length %}
    {% for category in priceCategories %}
      {% set loopIndex = 'price' ~ loop.index %}

        {# if you are on the filter results page then set the results to checked #}

        {% if template is defined and template == 'filter' %}
          <input type="checkbox" name="{{ loopIndex }}" value="{{ category.slug }}"{% if category.slug == price1 or category.slug == price2 or category.slug == price3 or category.slug == price4 or category.slug == price5 or category.slug == price6 %} checked{% endif %}>
        {% else %}
          <input type="checkbox" name="{{ loopIndex }}" value="{{ category.slug }}">
        {% endif %}
        {{ category.title }}

    {% endfor %}
  {% endif %}

  <button type="submit">Submit</button>

</form>

The Filter Results Page

On the results page you need to check which filter variables have been set via the get request and then display the appropriate related entries.

{# set park search parameters #}
{% set park1 = craft.request.getParam('park1') %}
{% set park2 = craft.request.getParam('park2') %}
{% set park3 = craft.request.getParam('park3') %}
{% set park4 = craft.request.getParam('park4') %}
{% set park5 = craft.request.getParam('park5') %}

{# set price search parameters #}
{% set price1 = craft.request.getParam('price1') %}
{% set price2 = craft.request.getParam('price2') %}
{% set price3 = craft.request.getParam('price3') %}
{% set price4 = craft.request.getParam('price4') %}
{% set price5 = craft.request.getParam('price5') %}
{% set price6 = craft.request.getParam('price6') %}

{# set park category model if it is in the search query #}
{% set parkCategory1 = park1|length ? craft.categories.slug(park1).first().id %}
{% set parkCategory2 = park2|length ? craft.categories.slug(park2).first().id %}
{% set parkCategory3 = park3|length ? craft.categories.slug(park3).first().id %}
{% set parkCategory4 = park4|length ? craft.categories.slug(park4).first().id %}
{% set parkCategory5 = park5|length ? craft.categories.slug(park5).first().id %}

{# create an array of park categories #}
{% set parks = [
  parkCategory1,
  parkCategory2,
  parkCategory3,
  parkCategory4,
  parkCategory5,
] %}

{# create a park array and trim blank strings #}
{% set trimParks = [] %}

{% for park in parks %}
  {% if park|length %}
    {% set trimParks = trimParks|merge({ (loop.index0): park}) %}
  {% endif %}
{% endfor %}

{# set price category model if it is in the search query #}
{% set priceCategory1 = price1|length ? craft.categories.slug(price1).first().id %}
{% set priceCategory2 = price2|length ? craft.categories.slug(price2).first().id %}
{% set priceCategory3 = price3|length ? craft.categories.slug(price3).first().id %}
{% set priceCategory4 = price4|length ? craft.categories.slug(price4).first().id %}
{% set priceCategory5 = price5|length ? craft.categories.slug(price5).first().id %}
{% set priceCategory6 = price6|length ? craft.categories.slug(price6).first().id %}

{# create an array of price categories #}
{% set prices = [
  priceCategory1,
  priceCategory2,
  priceCategory3,
  priceCategory4,
  priceCategory5,
  priceCategory6,
] %}

{# create a price array and trim blank strings #}
{% set trimPrices = [] %}

{% for price in prices %}
  {% if price|length %}
    {% set trimPrices = trimPrices|merge({ (loop.index0): price}) %}
  {% endif %}
{% endfor %}

{% if trimParks|length and trimPrices|length %}
  {% set entries = craft.entries.section('homesForSale').relatedTo('and',
    {targetElement:parks},
    {targetElement:prices}
  ) %}
{% endif %}

{% if trimParks|length and not trimPrices|length %}
  {% set entries = craft.entries.section('homesForSale').relatedTo('or',
    {targetElement:parks}
  ) %}
{% endif %}

{% if trimPrices|length and not trimParks|length %}
  {% set entries = craft.entries.section('homesForSale').relatedTo('or',
    {targetElement:prices}
  ) %}
{% endif %}

Filter Results

{% if entries|length %}

{{ entries|length }} results:

        {% for entry in entries %}
          {% set park = entry.park.first() %}
          {% set price = entry.parkPriceCategory.first() %}

{{ entry.title }} :: {{ park }} :: {{ price }}

        {% endfor %}

{% else %}

Your search didn't return any results.

{% endif %}


Trouble parsing JSON with getBodyParams()

Got in touch with P&T support and got the following response back:

  We don't currently support parsing JSON via getBodyParams(), however I'm looking into it and looks like Yii can be configured to support that, when the request's Content-Type header is set to application/json. We would need to enable that feature ourselves though.

  In the meantime you could do:

$body = Craft::$app->request->getRawBody();
$data = craft\helpers\Json::decode($body);


After upgrading to 2.5: Table 'alpineductless-craft.craft_elementindexsettings' doesn't exist

As Lindsey D pointed out in the comment, the answer was to restore the database backup from the automatic backup located in /craft/storage/backups that is generated when the update was initiated.

When this backup is put into place it will re-run the database migration when you visit the Admin area.

So my full solution was 2 steps:

Replace /craft/app with a fresh copy
Restore the automatically backed up database in /craft/storage/backups


How to check an entry is in a section within a for loop

Check against entry.section.handle:
{% for entry in craft.entries.authorId(authorIds).orderBy('dateCreated desc').all() %}

      {% if entry.section.handle == 'projects' %}

         Do something

      {% elseif entry.section.handle == 'events' %}

         Do something different

      {% endif %}

{% endfor %}


How to Access the Twig Attribute Name from the Fieldtype Class

Robin's answer is technically correct but I wanted to add a little more detail on how I got it working.

TL;DR

public function normalizeValue($value, ElementInterface $element = null)
{
    if ( $value instanceof SingleOptionFieldData )
    {
        return $value;
    }

    $nakedOpts = array
    (
        "AL" => "Alabama",
        "AK" => "Alaska",
        "AS" => "American Samoa",
        "AZ" => "Arizona",
        "AR" => "Arkansas"
    );

    foreach( $nakedOpts as $optval => $label )
    {
        $isSelected = ($value == $optval) ? true : false;
        $this->options[] = new OptionData($label, $optval, $isSelected);
    }

    if( !empty($value) )
    {
        $value = new SingleOptionFieldData($nakedOpts[$value], $value, true);
        $value->setOptions($this->options);
    }

    return $value;
}

Full Explanation

I ended up using Craft's native OptionData and SingleOptionFieldData classes to convert my values and options into objects that Craft knows how to work with.

So to start with I added these declarations at the top of my fieldtype file:

use craft\fields\data\OptionData;
use craft\fields\data\SingleOptionFieldData;

Now in your fieldtype file you need to do two things:

Convert your options to an array of OptionData objects
Convert the $value to a SingleOptionFieldData object

So we need to take our "naked" option array (our array of US states) and convert it to an array of objects, and we also need to mark which of the options is our selected value. The OptionData object accepts 3 parameters: $label, $value, and $selected:

$nakedOpts = array
(
    "AL" => "Alabama",
    "AK" => "Alaska",
    "AS" => "American Samoa",
    "AZ" => "Arizona",
    "AR" => "Arkansas"
);

foreach( $nakedOpts as $optval => $label )
{
    // is this array item the selected value?
    $isSelected = ($value == $optval) ? true : false;
    // create a new object for each item
    $this->options[] = new OptionData($label, $optval, $isSelected);
}

So now we need to convert our field $value to an object so Craft can compare it to the objects in the options list. Again, SingleOptionFieldData accepts the parameters of $label, $value, and $selected:

$value = new SingleOptionFieldData($nakedOpts[$value], $value, true);

The normalizeValue() method gets called once when the field is loaded on the publish page, and again when the entry is saved. So you have to check if you've already converted the $value to an object and bypass the rest of the code if so:

if ( $value instanceof SingleOptionFieldData )
{
    return $value;
}

The advantage of using a Craft object for this instead of a regular array is that Craft already knows how to use this type of data in the template. So the tag {{ entry.region }} will output AK without having to add the .value attribute. And just like a native Craft dropdown field, you can get the label with {{ entry.region.label }}.

To loop through all of your options in the template, just add this to normalizeValue() after you've converted the $value to an object and created your list of option objects:

$value->setOptions($this->options);

Now you can output a list of your options in your template:

{% for option in entry.region.options %}
    <option value="{{ option }}"{% if option.selected %} selected{% endif %}>{{ option.label }}</option>
{% endfor %}


Conditionally Display Content if Section

You're close!

SectionModel has 'name' and 'handle' attributes and one of those is probably what you're looking for.

{% if entry.section.handle == 'lettings' %}
    {{ entry.rentFrequency.label }}
{% endif %}


How can we use TaxJar with CraftCommerce?

The onBeforeSaveOrder event runs before all of the adjustments are calculated (including taxes), so it seems like that's what you're looking for.


If I figured out correctly what you want to do - this should do the trick:

{% if entry.children | length  %}

Available {{ entry.title }}

                {% for child in entry.children %}

{{ child.title }}

                {% endfor %}

{% endif %}

entry.children is an alias for entry.getDescendants(1) which returns ElementCriteriaModel


Find entries with multiple start and end dates from the same date field

What an idiot.
I almost never use Advanced element queries which is why it never popped into my head I guess.
So you can add where() and orWhere() into your standard craft.entries calls.
So my code becomes
{% if craft.app.request.getParam('departure') | length %}
    {% for dept in craft.app.request.getParam('departure') %}
        {% set lastDay = dept [0:7] %}
        {% set lastDay = lastDay ~ '-31' %}
        {% set firstDay = dept %}
        {% set entries = entries.orWhere(
            ['between', 'field_startsOn', "#{firstDay}", "#{lastDay}" ]
        ) %}
    {% endfor %}
{% endif %}


Pulling in matrix fields from a Single onto a different page

You just need to define entry, which can be done with craft.entries the same way you’d fetch any other entry(s).

{% set entry = craft.entries.section('homepage').first() %}

{% for block in entry.aloneImages %}
    {# ... #}
{% endfor %}


{% for sale in variant.sales %}
  {{sale.name}}<br>
{% endfor %}