Sprout Email PHP Warning Trying out Sprout Email on a fresh local (MAMP/PHP 7.1) install, and whenever I try and create a new Notification I get

PHP Warning – yii\base\ErrorException
get_class() expects parameter 1 to be object, string given

in /vendor/barrelstrength/sprout-base-email/src/controllers/NotificationsController.php

Tried a few different PHP versions in case that helps, but same. Anyone experienced this before and got any suggestions? Much appreciated.

Thanks Ben. Thought I had very latest version of the plugin, but just updated both Craft and plugin, and problem solved!


How to list all existing values for a field across site I have a huge set of entries which have a lot of fields. Say, the entry type is a 'book' and fields are 'keywords', 'year', 'authors', etc.

Now I'm building a filter form which would allow user to output entries by field values. On frontend side this form contains generally inputs with datalist tags which should contain all of a specific field's values. For example, the datalist for the 'Year' search input should contain all years ever set for all the books on the site.

How do I do this efficiently, how do we list all existing values for a field? This answer proposes to loop through each entry every time and collect the field values used in entries in an array - but when I tried to do it I hit the memory exhausted problem.

An example code of the approach which leads to memory being exhausted:

{% set years = [] %}
{% for book in craft.entries.section('books').year.order('year desc').limit(0) %}
    {% if book.year not in years %}
        {% set years = years|merge([book.year]) %}
    {% endif %}
{% endfor %}

{% for year in years %}
    <li>{{ year }}</li>
{% endfor %}

To get better performance you need to switch to using PHP. All you need is a MyPluginVariable class
to do some logic in PHP and make the result available to your Twig templates. It's really not very complicated.

From your variable class you'd use Yii Query Builder to create your SQL statements. There's now two ways to approach this.

Start from fresh using craft()->db->createCommand() and add all the necessary parameters manually (section, locale, limit,...).
Pass a Craft criteria model with all parameters already set to the buildElementsQuery method to convert it.

I'll show you exampe code for the second approach. From your template prepare a criteria model as usual, set the section and other parameters. Then call the new template function we are going to create soon, which will take two parameters, a criteria model and a field handle.

{% set criteria = craft.entries.section('books').order('myYearsField desc').limit(null) %}
{% set years = craft.businessLogic.getDistinctValues(criteria, 'myYearsField') %}

Now we need to create this getDistinctValues method in our variable class.

public function getDistinctValues($criteria, $column)
{
    $query = craft()->elements->buildElementsQuery($criteria);

    // Modify query to select just our `$column` column, only distinct values
    $query->selectDistinct("field_{$column}");

    // Query for one column only and return the result
    return $query->queryColumn();
}

That selectDistinct parameter overrides the select set by Craft in the initial criteria model. Performance should be way better, you're querying for a single column only, only for distinct values and you don't populate entry models which you do not need anyways.


Looking for tips on cleaning up craft_content and craft_entryversions tables after spam attack Long story short, a client had 300,000+ entries come in through a form, which caused the database size to swell, exceeding the storage capacity of the VPS and causing the site to crash.

I was able to manually delete all the entries from that channel from the craft_entries table, which got them back within storage limits and got the site back online. Rebuilding the search index got that table back down to a normal size. However, both the craft_content and craft_entryversions tables are still measured in GB.

I don't know much about the database architecture in Craft, and raw MySQL is not my strong suit. Is there anyway to cleanup those tables based on a channel? As in, I need to remove any stored content that's related to a specific channel and leave the rest of it in tact.

Any help would be greatly appreciated. Thanks.

Assuming the SPAM posts came through in a contiguous block, one semi-easy way would be to restore the 300k entry database locally on a Craft install.

Then you could do a SQL query like:

DELETE FROM `craft_elements` WHERE `id` IN (
    SELECT `id` FROM `craft_entries` WHERE`dateCreated` BETWEEN '2017-02-01 00:00:00' AND '2017-02-02 00:00:00'
)

Adjusting the dateCreated values for the beginning and ending of the SPAM posts.

The cascading deletes on the foreign keys that Craft use will kick in and clean up all of the content in the related tables like craft_content and craft_entryrevisions (as well as others).

Then you could restore that cleaned-up database back to production.


Does CSRF protection for controller actions require POST? I've got a controller action which will work as the callback URL for OAUTH authentication with an external, third-party API. After authenticating, the external API will issue a GET request to my callback URL, which means I need to allow anonymous access for the action method. However, I'd like to use CSRF protection for it.

I've set enableCsrfProtection to true in my config/general.php file, and the tokenParam setting is token. I've also added protected $allowAnonymous = array('actionAuthCallback'); to my Controller.

Here's how I create the callback URL:

$callbackUrl = UrlHelper::getUrlWithToken(UrlHelper::getSiteUrl('actions/myplugin/mycontroller/authCallback'), craft()->request->getCsrfToken());

The resulting URL looks like this:

https://mysite.com/actions/myplugin/mycontroller/authCallback?token=2423552353djfsjfdsfjsdfsdfrandomrandomawesome

I've validated that the correct action method fires, so all good so far.

Here's the important bits for the action:

public function actionAuthCallback()
{
    $this->requireToken();
    ...
    $this->returnJson(array(
        'success' => true,
    ));
}

If I call the action URL without the token query parameter, stuff works as expected – Craft throws a 400, as it should.

However, if I do include the token parameter in the URL, Craft throws a 404. What's even more confusing, this happens even if I leave out the $this->requireToken(); call in the actionAuthCallBack() method – as soon as Craft sees the token query parameter in the URL, the 404 exception is thrown.

What am I doing wrong? Does CSRF protection require POST requests?

According to https://craftcms.com/support/csrf-protection CSRF does require POST requests

  With CSRF protection enabled, all of your site’s visitors will get a “CRAFT_CSRF_TOKEN” cookie set on their browser, and all POST requests must be accompanied by a POST parameter with a matching name and value (the CSRF Token).

On top of that, you'll need to (manually) enable it in your config:

  You will need to enable it to take advantage of it. You can do that by setting the enableCsrfProtection config setting in your craft/config/general.php file.


P&T Contact Form Plugin: HTML Email Templates Can you create HTML templates using Twig/Craft tags to style the body of the email message sent by the P&T contact form plugin?

If you mean to build a template for all the e-mail messages, including the ones sent by P&T Contact Form Plugin, then you should at least have Craft Client edition, which supports Custom HTML email templates.

If you have Client or Pro, you can set an e-mail template in your Email Settings (in the field called HTML Email template).

If, on the other hand, you want to change the text sent by the plugin (so the body of your e-mail), I don't think there's a way to do that without altering the plugins code.


Search entries by matrix field I have a matrix inside of which I have 2 fields, 1. dropdown list containing download types and another asset field. I would like to search first by a category and then I would like to further filter them and see if they have downloads of a certain type.

I would like to avoid a 2 step searching if possible and search articles that belong to certain category that have a certain download type associated with it.

Any idea on how to achieve this?

You could loop through the Matrix field on every entry save using the awesome Preparse plugin, to store the categories an entry contains in a new field.

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

Here’s example code for your Preparse field, it would store strings like firstCategory,thirdCategory,secondCategory.

{%- set categories = [] %}

{%- for block in entry.myMatrixField.type('myRelevantBlockType') %}
    {%- if block.myDropdownField %}
        {%- set categories = categories|merge([ block.myDropdownField.value ]) %}
    {%- endif %}
{%- endfor %}

{{- categories|join(',') -}}

Once you have populated that field for all your entries, you can filter them by a category using this criteria model.

{% set categoryToSearch = 'secondCategory' %}

{% set entries = craft.entries({
    section: 'myEntriesSection',
    search: 'myPreparseFieldHandle:*' ~ categoryToSearch ~ '*',
}) %}

I have to say that I’m not very proud of this solution as it uses search which I usually try to avoid. But I wasn’t able to come up with a better idea.


Assets Content/Fields not available until entry is saved? I've got Asset location setup with a Photo Caption field. And a Photo Gallery field which references said Asset.

When creating a new entry, I'm uploading images to the Photo Gallery field. When the images are uploaded, double-clicking brings up the modal but the Photo Caption field is not available. Only after saving the entry and then re-opening it to edit is the Photo Caption field available in the Assets modal.

Is the normal behavior? Did I miss something?

It would be ideal for my clients to be able to edit the photo meta information while they're creating a new entry.

This is an issue with Assets fields if you have a dynamic Subfolder path set on in the field’s settings. It’s been fixed for 2.3 though ;)


Plugins with element criteria selection does not work for empty or zero values I made a plugin which count the number of users per groups defined by the field accent which is a text field and can be empty or contain numbers from 0 to 12.

public function actionCountUsers() {

    // Delete all the entry caches
    craft()->templateCache->deleteCachesByElementType('User');

    // Now find the entry IDs
    $criteria = craft()->elements->getCriteria('User', array('group' => 'unepMembers', 'limit' => null, 'status' => null, 'localeEnabled' => null));
    $criteria->group = 'unepMembers';
    $criteria->limit = null;
    $criteria->status = null;
    $criteria->localeEnabled = null;

    //
    $totalEntries = $criteria->total();
    UnepPlugin::log($totalEntries.' USERS (no criteria)', LogLevel::Warning);

    //
    $criteria->accent = '';
    $totalEntries = $criteria->total();
    UnepPlugin::log($totalEntries.' USERS with empty accent', LogLevel::Warning);

    //
    $totalUsers = 0;
    for ($i = 0; $i <= 15; $i++) {
        $criteria->accent = $i;
        $totalEntries = $criteria->total();
        MigPlugin::log($totalEntries.' USERS with accent :'.$criteria->accent, LogLevel::Warning);

        $totalUsers = $totalUsers + $totalEntries;
    }
    MigPlugin::log($totalUsers.' USERS with accents', LogLevel::Warning);

}

As you can see the result here below there is a problem with a criteria values empty or 0 on the accent field: they just do not work and count the total number of users.

***********************
2015/10/11 07:09:48 [warning] [plugin] 3109 USERS (no criteria)
2015/10/11 07:09:48 [warning] [plugin] 3109 USERS with empty accent
2015/10/11 07:14:01 [warning] [plugin] 3109 USERS with accent :0
2015/10/11 07:09:48 [warning] [plugin] 1849 USERS with accent :1
2015/10/11 07:09:48 [warning] [plugin] 501 USERS with accent :2
2015/10/11 07:09:48 [warning] [plugin] 0 USERS with accent :3
2015/10/11 07:09:48 [warning] [plugin] 72 USERS with accent :4
2015/10/11 07:09:49 [warning] [plugin] 8 USERS with accent :5
2015/10/11 07:09:49 [warning] [plugin] 1 USERS with accent :6
2015/10/11 07:09:49 [warning] [plugin] 0 USERS with accent :7
2015/10/11 07:09:49 [warning] [plugin] 4 USERS with accent :8
2015/10/11 07:09:49 [warning] [plugin] 81 USERS with accent :9
2015/10/11 07:09:49 [warning] [plugin] 232 USERS with accent :10
2015/10/11 07:09:49 [warning] [plugin] 246 USERS with accent :11
2015/10/11 07:09:49 [warning] [plugin] 115 USERS with accent :12
2015/10/11 07:09:49 [warning] [plugin] 0 USERS with accent :13
2015/10/11 07:09:49 [warning] [plugin] 0 USERS with accent :14
2015/10/11 07:09:49 [warning] [plugin] 0 USERS with accent :15
2015/10/11 07:09:49 [warning] [plugin] 3109 USERS with accents

Craft bug or did I miss something in my code?

When you do this:

$criteria->accent = '';

Craft is going to look for users where the accent field’s DB cell is an empty string.

Those values are probably null though, if they aren’t getting returned.

Try setting your accent param to :empty: instead of ''. When you do that, Craft will search for both empty strings and null values, so you should get the results you’re expecting.


Migrating from WordPress to Craft CMS I am trying to migrate blog posts from WordPress to Craft CMS through the Feed Me plugin.

First, I export posts in .xml file from Wordpress. Then, I import in Craft CMS.

All things are good except the category and tags. It imports the category and tags from .xml file but it is not able to separate the category and tags.

Here the few code of category and tags means how it look in .xml

<category domain="post_tag" nicename="computer"><![CDATA[computer]]></category>
<category domain="post_tag" nicename="corporate"><![CDATA[corporate]]></category>
<category domain="post_tag" nicename="employee"><![CDATA[employee]]></category>
<category domain="post_tag" nicename="expert"><![CDATA[expert]]></category>
<category domain="post_tag" nicename="forensics"><![CDATA[Forensics]]></category>
category domain="category" nicename="forensics"><![CDATA[Forensics]]></category>
<category domain="category" nicename="infosec-training"><![CDATA[InfoSec Training]]></category>
<category domain="post_tag" nicename="warlock"><![CDATA[warlock]]></category>
<category domain="post_tag" nicename="witness"><![CDATA[witness]]></category>

And also the screen shot of mapping and and how it looks in section.

Mapping

Section View

How can I separate these?

Feed Me currently doesn't support this, as sometimes your data is contained in attributes, so it needs to be able to access that. Crucially, the tags are the same value, which is what trips things up.

Have you looked at the Wordpress to Craft guide? https://sgroup.com.au/plugins/feedme/guides/migrating-from-wordpress


Database Request with entry variable as argument I am new to Craft CMS and although it is quite simple to use I am stuck on this one. I have 3 sections ('books', 'games', 'movies') and want to do the following:

{% for sub_entry in craft.entries('{{ entry.sectionName }}').find() %}

The problem is that it gives me all sub_entries not just the ones within a specific section i.e. entry.sectionName? If I print out {{ entry.sectionName }} on my website it gives me the correct sectionNames but somehow I can not pass it on to the for loop?

How do I solve this?
Kind regards,
Pete

hmm, wat do you mean with sub_entries? As a general pointer I would do it like this:

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

and then loop over the books.

To get back to your question, I would suggest moving all the different sections into 1 channel with multiple types in it. For example:

Channel: Media

Types:

Books
Games
Movies

Then you can query them like this:

{% set books = craft.entries.section('media').type(['books']) %}

{% for entry in books %}
    <h2>{{entry.title}}</h2>
{% endfor %}

More info on types here


Using craft.entries to return entries with empty entries field I'm new to all this. Is it possible to use craft.entries to return all entries with an empty entries field? Something like:

{% set drinksWithNoIngredients = craft.entries.section("drinks").ingredients(":empty:") %}
{% for drink in drinksWithNoIngredients %}

Do something with {{ drink.title }}...

where ingredients is an entries field handle. This doesn't seem to work on entries fields, though. Or maybe I could do some kind of relatedTo magic, where the targetElement is some kind of special null value?

An alternative seems to be this:

{% set drinksWithNoIngredients = craft.entries.section("drinks") %}
{% for drink in drinksWithNoIngredients %}
    {% if not drink.ingredients.total() %}

Do something with {{ drink.title }}...

But doing it that way calls .total() on every drink. Is that going to cause performance problems if I have a lot of drinks?

You were on the right track using relatedTo. But as there's no notRelatedTo parameter, you'd first have to get all drinks that are related to any ingredient and those entries can then be removed from a new ElementCriteriaModel, that returns all your drinks, using Craft's without filter. Instead of passing whole element models, you should better use this filter with element IDs (→ Why is the Craft without filter not working correctly and how to debug?). To get them just make use of the ids() method.

{% set ingredients = craft.entries.section('ingredients').limit(null) %}
{% set drinksWithIngredientsIds = craft.entries.section('drinks').relatedTo({targetElement: ingredients}).limit(null).ids() %}

{% set drinksWithNoIngredients = craft.entries.section('drinks')|without(drinksWithIngredientsIds) %}


How can I translate checkboxes on a frontend user registration form to lightswitch custom fields? I've got a frontend user registration form working that's populating a whole set of custom fields I've set up on my user profiles in Craft.

But I've got a set of lightswitch fields on my user profiles that I'm trying to set via checkboxes in the registration form but the values are not transferring over when submitting the form.

Here's an example of my checkbox code in the frontend form (the corresponding lightswitch field handle is memberShowEmailLink):

<div class="checkbox">
  <label>
    <input type="checkbox" id="memberShowEmailLink" name="fields[memberShowEmailLink]" {% if account is defined %}value="{{ account.memberShowEmailLink }}" checked="checked"{% else %}value="0"{% endif %}>
    Show a link to contact me via email in the member directory?
  </label>
</div>

Is there a way to change it to make this work?

When the checkbox get submitted, it get's transferred with whatever value is set with the value attribute.

Thus, your need to set the value to 1. Your code should be more like this:

<div class="checkbox">
  <label>
    <input type="checkbox" id="memberShowEmailLink" name="fields[memberShowEmailLink]" value="1" {% if account is defined and account.memberShowEmailLink %} checked="checked"{% endif %}>
    Show a link to contact me via email in the member directory?
  </label>
</div>


Email Notification When Post Submitted Is it possible for a user group to be notified by email when a post is submitted using either the backend or a form on the front end?

Currently there isn't a native way to do this, but you could write a plugin which would work like this:

Wait for an event like: content.onSaveContent or entries.onSaveEntry
Get all users from a specific usergroup using the ElementCriteriaModel.
Use the EmailService to send a mail to each of them.

.

Quick-and-Dirty:

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

    //Event: onSaveEntry
    craft()->on('entries.saveEntry', function(Event $event) {

        //Get all users from UserGroup
        $user_criteria = craft()->elements->getCriteria(ElementType::User);
        $user_criteria->groupId = '1';
        $users = $user_criteria->find();

        //Send to each User
        foreach ($users as $user) {
            //Send Mail
            $email = new EmailModel();
            $email->toEmail = $user->email;
            $email->subject = 'Heyyyyy';
            $email->body    = 'How you doin?';

            craft()->email->sendEmail($email);
        }
    });
}


Is it possible to bulk-edit a field across multiple entries at once? I would like to know if it's possible to select multiple entries and update a field for them all at once – for example, give all the selected entries the same category.

This plugin does it for Craft 3: https://github.com/kffein/craft-bulk-edit


Why do I get 'Could not resolve the subpath “{slug}” after trying to add a category select to a Neo field? I tried to add a Category Select field into a Neoblock but when i first saved the entry I received the following error:

  Internal Server Error

  Could not resolve the subpath “{slug}”.

I removed the Neo Block with the Category Select but the error persists.

Any ideas?

i removed {slug} altogether from an Asset field definition.


Can you set the redirect path for system forgot password form? At the moment when a user clicks on the forgot password link in an email the following happens:

User is redirected to the forgot password page.
User enters their new password.
User is redirected to the Craft admin login page.

Is there a way to set where they are sent to? For example, if they do not have admin access I don't want to be showing them the admin login page.

Thanks,

Gareth

You can. You have to build some front end forms:

Forgot Password Form (http://buildwithcraft.com/docs/templating/forgot-password-form)
Set Password Form (http://buildwithcraft.com/docs/templating/set-password-form)

Be aware of the config setting, setPasswordPath.

It's also worth noting that a user account with control panel privileges will be redirected to the control panel set password and login no matter what.

Edit:
Also, check out setPasswordSuccessPath for redirecting the user after they've successfully set their new password. Again, this only applies to non admin users that have completed this process using the front end forms you have setup.


Looping on the User Field added to Entry I am fetching the fields of an entry in a block but can not draw through a user field named as eventHost.
I get error 'Variable "name" does not exist.' What is wrong with my loop?
{% set webinar = block.webinar.all() %}
{% if webinar is not empty %}

{% for entry in webinar %}

        {% set url = entry.url %}
        {% set title = entry.title %}
        {% set desc = entry.previewDescription %}
        {% set img = entry.previewImage.one() %}

        {% for expert in entry.eventHost %}
            {% set name = expert.name %}
            {% set avatar = expert.avatar %}
            {% set job = expert.personJobTitle %}
            {% if expert.linkedInProfile %}
                {% set linkedin = expert.linkedInProfile.url %}
            {% endif %}
        {% endfor %}

{{ title }}

{{ name }}
{{ job }}

{% endfor %}

{% endif %}

You are setting variables within the scope of the for loop – they only exist there. You can fix this by setting up empty variables before the loop, like:
{% set webinar = block.webinar.all() %}
{% if webinar is not empty %}
    {% for entry in webinar %}

        {# Setup empty variables #}

        {% set name = null %}
        {% set avatar = null %}
        {% set job = null %}
        {% set linkedin = null %}

        {% set url = entry.url %}
        {% set title = entry.title %}
        {% set desc = entry.previewDescription %}
        {% set img = entry.previewImage.one() %}

        {% for expert in entry.eventHost %}
            {% set name = expert.name %}
            {% set avatar = expert.avatar %}
            {% set job = expert.personJobTitle %}
            {% if expert.linkedInProfile %}
                {% set linkedin = expert.linkedInProfile.url %}
            {% endif %}
        {% endfor %}

        {{ title }}
        {{ name }}
        {{ job }}

    {% endfor %}
{% endif %}

Or in one line, for neatness:
{% set name, avatar, job, linkedin = null, null, null, null %}

This one has got me many times ;)


Redactor plugin for Bootstrap Responsive Image Doing a quick redactor plugin to added a class to images after upload. Based on the docs, imageUpload should be the callback used.

The plugin loads, but am I doing this wrong:

if (!RedactorPlugins) var RedactorPlugins = {};

RedactorPlugins.responsiveimage = function () {
  return {
    init: function()
    {
      var that = this;
      console.log("loaded");
    },
    imageUpload: function(image, json){
      console.log(image);
      image.addClass("img-responsive");
    }
  };
};

For those who find this, After some more digging into Redactor, looks like Craft overrides the original button to accommodate for sources and transforms in RichTextInput.js at  onImageButtonClick - line 261.

onImageButtonClick: function()
{
    this.redactor.selection.save();

    if (typeof this.assetSelectionModal == 'undefined')
    {
        this.assetSelectionModal = Craft.createElementSelectorModal('Asset', {
            storageKey: 'RichTextFieldType.ChooseImage',
            multiSelect: true,
            sources: this.assetSources,
            criteria: { locale: this.elementLocale, kind: 'image' },
            onSelect: $.proxy(function(assets, transform)
            {
                if (assets.length)
                {
                    this.redactor.selection.restore();
                    for (var i = 0; i < assets.length; i++)
                    {
                        var asset = assets[i],
                            url   = asset.url+'#asset:'+asset.id;

                        if (transform)
                        {
                            url += ':'+transform;
                        }

                        this.redactor.insert.node($('<img src="'+url+'" />')[0]);
                        this.redactor.code.sync();
                    }
                    this.redactor.observe.images();
                }
            }, this),
            closeOtherModals: false,
            transforms: this.transforms
        });
    }
    else
    {
        this.assetSelectionModal.show();
    }
}

Ended up using Retcon Twig filters plugin to add the class:

{{ entry.body|retconAttr('img', {class: 'img-responsive'}) }}


Will craft attempt to reconnect to MySQL if the connection drops? We have a customer using a cheap managed hosting provider, and their MySQL server very aggressively times out and drops the connection.

I wonder if this could be causing us troubles as outlined here: Massive template cache cleaning tasks always get stuck

Does Craft attempt to reconnect to MySQL if the connection drops halway through a request?

If a MySQL connection drops in the middle of a request, then that will either cause a PHP fatal error (that will end the request entirely) or cause an exception to be thrown.

If the exception isn't handled, then the request will end as well.  If it is caught, it can be gracefully handled and the request can continue. The remaining part of the request might attempt a new database connection, but it will not attempt to re-execute the SQL on the previously dropped MySQL connection. It has moved on.


Transforms not working Having issues getting Craft to use a transform I set in the CP: squarePhoto. I keep getting a template error, even though that transform exist.

  Variable "squarePhoto" does not exist

The template code in question is:

{% for asset in block.photoImages %}
    <img src="{{ asset.getUrl(squarePhoto) }}" alt="{{ asset.title }}">
{% endfor %}

After digging through other threads, I saw that Craft adds a subfolder to the directory with the transform name–this has not been generated. What am I missing?

I've also added the config var 'generateTransformsBeforePageLoad' => true, to my general.php to see if that made a difference.

It's a very subtle difference, but what you have added there is a variable, when what you are looking for is a string.

<img src="{{ asset.getUrl('squarePhoto') }}" alt="{{ asset.title }}">

Notice the difference?

Your current way would be correct if you had set a variable somewhere with the name of squarePhoto, like so:

{% set squarePhoto = 'transformName' %}

Check out the Twig Primer in the Craft docs.


Commerce: How can I check that a user has bought a product? I have a digital product, with a landing page, and I want to know if the connected user has already bought the product so I can give him access to the content.

There is a direct way to find this out.
Here's an example.  Note the id you supply must be the specific purchasableId, not the product id (so the defaultVariant.id or variant.id).
{# Has the customer explicitly bought the XXX product? Returns 0 (==false) or >= 1 (==true) #}

{% set purchasedXXX = craft.orders()
    .user(currentUser)
    .hasPurchasables(10637)
    .isCompleted()
    .count()
%}

You can then use that as just
{% if purchasedXXX %}
 ...
{% endif %}


Can't duplicate a product in Craft Commerce? I can't seem to find a way to duplicate a product in Craft Commerce.

I've duplicated articles before, with the "save as new" feature... But can't find anything similar for products.

Does such a thing exist?

Update:

Added in Craft Commerce 1.1.1196.

There currently isn't a native way, but it sounds like a great feature request!


$this->renderTemplate() breaks the CP navigation I'm locally working on a Craft Plugin with a Page in the Control Panel where I have a form that posts to a controller.
<form action="/actions/import-products/product/create" method="POST" enctype="multipart/form-data">
...
</form>

The controller returns the following at the of it's action
// Render and return the plugin's 'index.twig' template
return $this->renderTemplate('import-products/index.twig', $variables, View::TEMPLATE_MODE_CP);

However, after the renderTemplate, the CP navigation is broken.
It seems that Craft is using the base URL to build the navigation items. Where it should be localhost/admin/dashboard, it's localhost/dashboard? How do I fix this?
Changing the Base URL of the site to localhost/admin breaks everything because the default routes are changed to localhost/admin/admin/dashboard.

Alright! I've been able to fix my problem. I did a couple of things wrong so I'm writing this for whoever makes the same mistakes I made and is now trapped in an endless loop of despair and impending doom.
First mistake!
You should leave the action attribute of your form element empty.
Call you action by using a hidden input, like this
<input type="hidden" name="action" value="/import-products/product/create">

This will automatically keep the user on your page, so there's no need to redirect in the controller and break the CP while doing it.
Second mistake!
I shouldn't have used $this->renderTemplate() at the end of my controller. It's not the preferred flow of doing it. After your controller did everything it needed to do, you should either stay on the page and display feedback or redirect to another page.
Staying on the page to display feedback can be done by sending variables back to the template. That's done like so:
Craft::$app->getUrlManager()->setRouteParams([
        'variable' => $myVariable
]);

return null;

If you want to redirect to a confirm-page. You should use the redirectToPostedUrl.
To be able to use this, you need a hidden input field with a url as value. Luckily Craft has a Twig function to do so.
{{ redirectInput(url|hash) }}

The URL needs to be hashed otherwise craft will throw an Invalid Body Parameter error. In your controller you can end your action with:
//You should wrap this in an if that checks if there are no errors
return $this->redirectToPostedUrl($variable);


Is it possible to route a subdomain to specific template group? We are looking for a way to route a subdomain to a specific template to use as a landing page.

Is there a way to do this without routing through index.html and redirecting to the specified template folder and file?

I can confirm that using the redirect does lose some of the user information, tracking codes etc. However it does retain the referral url from the 3rd party site.

For this example we have two domains:

http://www.example.com
http://subdomain.example.com

To use different templates for the subdomain, we can accomplished this with these steps:

1) Setup subdomain to point to a different directory on your server:

Domain: /home/wherever/public_html
Sub-domain: /home/wherever/public_html_subdomain

2) Copy your index.php file over to your new subdomain directory and update the CRAFT_TEMPLATES_PATH variable to point to the location you want to have your templates.  In this example, both template folders are above web root.

// index.php for domain
define('CRAFT_TEMPLATES_PATH', realpath(dirname(__FILE__) . "/../templates").'/');

// index.php for subdomain
define('CRAFT_TEMPLATES_PATH', realpath(dirname(__FILE__) . "/../templates_subdomain").'/');

Your template folders now look like:

/home/wherever/public_html
/home/wherever/public_html_subdomain
/home/wherever/templates
/home/wherever/templates_subdomain


Pass last segment to solspace freeform field Using freeform on another CMS, I was able to pass the last segment of the previous page url (when navigating to the form page) to a form field in the freeform composer, is this feature possible in the Craft version? Or alternatively, would this be possible passing an entry title? Thanks

You can use the overrideValues parameter to set field values automatically and dynamically. E.g.

{{ craft.freeform.form("composerForm", {
    labelClass: "form-label",
    inputClass: "form-control",
    overrideValues: {
        myFieldHandle: entry.title,
        myOtherField: craft.app.request.getSegment(3),
    }
}).render() }}


Separate User Groups / forms I have two forms on my site, one that you can use to sign up as a registered user that allows you to view content through out the site and participate in steps (tests) etc.

The second form is a form that allows you to just download CERTAIN content on the site rather than view the whole site's content.

I need to figure out how to separate users when signing up, the forms are pretty identical other than 2 options. However if the user wants to come back and register for the site after downloading the content, i need to figure out a way where they can use the same email they used in the past.

I have 2 forms one for registered users and one for kit users
registered users form gets FULL access to the site and kit users get access to one page with some downloads.
if user signs up for kit i need to separate the kit users from registered users.
if the user comes back, need to figure out how to let them use the same email they originally used.

Why do you want to let them register twice? Maybe re-think the way you go about this:

Possible solutions:

Add them to a certain user group (via a plugin) on registration with the appropriate permissions and/or...
...if you don't want to write a plugin, you can add a certain category to the user element on registration. You can than check throughout your site if the user has the correct category ('permission') to do something. If they come back and want to become a full member, just let them fill out a new form which UPDATES their already existing user account with a new category/permission.

That's the way I used it on a large site and it works rather fine.


How can I add images to field instructions? I'd like to have images in my field instructions, but adding the Markdown code doesn't work, nor does HTML. Is there a way to include images and other HTML within?

This works with standard markdown code...

![Alt text](/path/to/image.png)

You can use either a full URL, or a local path to the image.


Matrix field not saving 200th entry We have a matrix field for weekly winners names in a company promotion. We've entered 199 so far, the 200th is not saving, it blanks out the fields and logs a validation error - cannot save because name is blank.

If we delete item 199 then we can add a new item, it then fails on item 200 again

Is this a known limit in craft matrix fields??

Take a look here, it sounds like you are hitting the max_input_vars limit. Strange things happen when you do.

Matrix field input error from within the control panel


Check Structure for Entry or Child of Entry I have setup a few different navigation lists through the Menus 0.9 plugin by Familiar. Within my website, I have setup several different site sections all through the same structure called, "General". They all share the same page template.

I would like to run a check to see if the page is "About" or is a child of "About" (all within the "General Structure"). If it is "About" or a child of "About", I would like to server it a specific sub-nav.

Here's the code to run that subnav:

{% nav node in craft.menus.getNodes('aboutSubnav') %}

{{ node.title }}

{% endnav %}

How do I do the lookup to see what page it is? I tried the following code, but it did not work:

{% if entry in craft.entries.section('general').descendantOf(42) %}
 {% nav node in craft.menus.getNodes('aboutSubnav') %}

{{ node.title }}

 {% endnav %}
{% endif %}

The containment operator in does have problems working with whole element models. I'd try and modify your conditional to compare entry IDs instead:

{% if entry.id in craft.entries.section('general').descendantOf(42).ids() %}
    ...
{% endif %}

To include that parent page ID to that array you would do that with the merge filter:

{% set aboutPagesIds = craft.entries.section('general').descendantOf(42).ids() %}
{% set aboutPagesIds = aboutPagesIds|merge([42]) %}


How to create a Matrix Relation field / relate Matrix Blocks to other Elements I would like to create a field / a way to relate a certain Matrix Block to another Element. Is this possible?

For example:

Entry A contains a Matrix Field matrix and has several blocks. I want to relate one of those blocks to Entry B

The BaseRelationField is able to relate all elements - even Matrix Blocks but it's a little bit tricky because in order to display everything properly you need to define sources but Matrix Blocks have no sources.

At first we need to make sure our Matrix Blocks have a valid source, otherwise this Javascript check messes all up

var $sources = this._getSourcesInList(this.getSourceContainer());

// No source, no party.
if ($sources.length === 0) {
    return false;
}

And nothing works So we need the following

Event::on(
    MatrixBlock::class,
    MatrixBlock::EVENT_REGISTER_SOURCES,
    function(RegisterElementSourcesEvent $event) {
        if (empty($event->sources)) {
            $event->sources[] = [
                'key'         => 'MySource',
                'label'       => 'All Matrixes',
                'defaultSort' => 'elements.id',
                'data'        => [
                    'handle' => 'matrix'
                ],
                'criteria'    => [
                    'typeId' => 21,
                    'fieldId' => 70 // <-- this is the matrix field of Entry A otherwise the values won't be populated
                ]
            ];
        }
    }
);

In order to display an identifier we need to set the title attribute to the block, otherwise all we see is an id.

Event::on(
    MatrixBlockQuery::class,
    MatrixBlockQuery::EVENT_AFTER_POPULATE_ELEMENT,
    function(PopulateElementEvent $event){
        $element = $event->element;
        if($element->getType()->handle === 'person'){ //<-- make it is the correct matrix block
            try{
                $element->title = $element->getFieldValue('firstName') . ' ' . $element->getFieldValue('lastName');
            }catch(Exception $exception){
                // whatever you need
            }
        }
    }
);

Since Matrix Blocks usually have no table attributes we need to define them as well

Event::on(
    MatrixBlock::class,
    MatrixBlock::EVENT_REGISTER_TABLE_ATTRIBUTES,
    function($event) {
        $event->tableAttributes['id'] = ['label' => 'ID'];
        $event->tableAttributes['email'] = ['label' => 'Email'];
    }
);

After that you can use the normal BaseRelationField and extend it like you are used to for custom element types


Charge plugin thanks page 404 I keep getting the 404 after successful payment.

I am pretty sure I have everything set up correctly, the thanks template is there, but it seems like Craft won't respond to the request, so the routing is not trigged, Apache is still trying to serve that file directly, it won’t recognize the {hash} part in the URL, so keep return the 404 page.

The only way I find to make this work is manually add another redirect in the Route section (last screenshot), but it's not a nature way.

Any insight would be great.

Instead of slug try using * in your route definition


IOHelper::fileExists always false I use the following code:

$sourcePath = $assetRecord->source->sourceType->getBasePath();
$folderPath = $assetRecord->getFolder()->path;
$path = $sourcePath.$folderPath.$assetRecord->filename;

if (IOHelper::fileExists($path)) {
    $content = IOHelper::getFileContents($assetRecord->url);
    craft()->request->sendFile($test, $content, array('forceDownload' => true));
}

The fileExists always return false. I use the image all over the site without any problems. Also the $path variable return normal path from inside the public folder.

This code lives inside a custom plugin.

IOHelper::fileExists() will return false for a few reasons:

Either PHP's realpath or is_file returns false. i.e. the given path doesn't exist or PHP doesn't have executable permissions on the folders leading up to that path or read permissions on the file itself.
You're using a case-sensitive file system and you're passing in a different cased path/filename than what's on the file system.


Paginating Merged Element Queries I really want something like this to work but the merge function turns Elements into Arrays. I've managed to work around it other times but what's the best practice to combine two entry sets and then paginate?

{% set cat1 = craft.categories.group("catAttributes").slug('diabetic').one %}

{% set firstEntries = craft.entries.section("cats").relatedTo([cat1]) %}

{% set secondEntries = craft.entries.section("cats").showInOtherOnCatsWithNeeds('1') %}

{% set allEntries = firstEntries | merge(secondEntries) %}

{% paginate allEntries.limit(12) as pageInfo, pet %}

I think you're correct in how you currently do it. You can't merge Element Queries, you can merge IDs (or any array of anything, really).
The only thing you should remove, is the all when settings posts, because paginate expects an element query, not an array of elements.


Default field values? This seems so simple, but after reading over the docs, I couldn't find an answer:

Is there a way to have a field have a default value in Craft?

In my case, I have a Lightswitch field that I want to be on by default, so my client doesn't have to turn it on every time they publish an asset.  But they still do need the ability to turn it off in exceptional cases.

I realize I could just reverse the logic of the field, but it raises a broader question of default field values (which would be useful to me).

As far as I know, the only fields that allow defaults are those that extend the BaseOptionsFieldType, namely Dropdown, Multiselect, Checkboxes, and RadioButtons. You could change your lightswitch to one of these other fieldtypes and have a default value available.


Why are gif transform file sizes very large? Our site makes use of gifs to enable the client to upload basic animating images. Any asset field on the site can be jpg, png or gif, and the site makes significant use of transforms for responsive imagery.

Transforms for jpgs and pngs are working fine, but the gif transforms are coming out huge (significantly bigger than the original file size), and at the point of transform generation, the server is grinding almost to a halt, with most of the Generating pending image transforms tasks eventually stalling.

Image 1

Natural: 2.4MB
400px Constrain: 4.3MB
800px Constrain: 19.2MB
1200px / 1600px / 2400px Constrain: Failed

Image 2

Natural: 5.4MB
None of the transforms for this seem to be being created now (I previously had to remove it because of the detrimental effect of the transform process on the server but have just tried re-uploading and visiting the page), but one of these was something like 37MB!

Technical Details:

Craft 2.6.2967
imageDriver is set to imagick (which is reported to be available under Utilities / Server Info)
defaultImageQuality is set to 70
PHP Memory Limit is set to 256MB (had previously been 512MB, which may explain why none of the transforms for Image 2 are being created any more)
PHP Max Execution Time is set to 90 seconds

No Current Good Solution

Having liaised directly with Craft Support on this issue, the outcome after a bit of research was that there is not currently any good solution.

Apparently, Imagick is really, really bad at animated GIFs, but there's no other option.

My workaround was to edit the templating for gif images, so a super-simplified version would look something like the following:

{% set src = image.getUrl('someTransform') %}

{# No transform used for gifs #}
{% if image.getMimeType() == 'image/gif' %}
    {% set src = image.getUrl() %}
{% endif %}

<img src="{{ src }}">

Whilst this did result in larger than ideal file sizes for gifs (because the original file was being used rather than smaller transforms), it prevents the issues detailed above. Not great, but better than the enormous file sizes we were seeing and the tasks getting stuck!

Possibilities in Craft 3

Apparently, Craft 3 allows for further image optimisation after transforms, and there's a plugin that capitalises on this already, so hopefully, we'll see some improvement in Craft 3.


Routes to fake a Structure I'm building a site with loads of complex itineraries. Entries are in a channel for various reasons, but I want to split the data across subpages, with a URL structure like:

/itinerary/name-of-itinerary
/itinerary/name-of-itinerary/dates-prices
/itinerary/name-of-itinerary/gallery
/itinerary/name-of-itinerary/etc...

I want to route everything through my _views/itinerary/index template, and then just have a bunch of includes (dates-prices, gallery, etc...) in my index, something like:

{% include ( '_views/itinerary/' ~ craft.request.lastSegment ) %}

In my routes.php I've got:

'itinerary\/(?P<slug>[^\/]+)\/([^\/]+)'                 => '_views/itinerary',
'itinerary\/(?P<slug>[^\/]+)'                           => '_views/itinerary',

So everything is routing fine to _views/itinerary/index. Trouble is, I get a 404 for anything other than /itinerary/name-of-itinerary because Craft uses the last segment to resolve the entry, which is exactly what you'd want normally. But if the last segment is 'dates-prices' or 'gallery' I'm screwed.

Have I set this up right? Is there a more efficient and complete way? Any help much appreciated.

The route/template for '/itinerary/name-of-itinerary' will be defined in the section's settings, so it's the others you need to deal with.

I'd add this route to your routes.php file:

'itinerary/(?P<entrySlug>[-\w]+)/(?P<subpageSlug>(dates-prices|gallery|etc))' => '_views/itinerary/index',

And then in '_views/itinerary/index' I'd include these conditionals:

{% if entry is not defined %}
    {% set entry = craft.entries.section('itineraries').slug(entrySlug).first() %}
{% endif %}

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

On your subpages, the entry model object won't be available by default so you need to check whether it's defined, and if not define it.


Receive all used slugs I want to create a Excel file with all used slugs in my Craft website.
I've searched for a plugin but without succes. I also tried to find a useful table in the Craft database, also without succes.

Is there a simple way to achieve this?

I already found a solution. I just created a simple query:

SELECT content.elementId entryId, title, uri
FROM `craft_content` content
JOIN craft_elements elements ON elements.id = content.elementId
JOIN `craft_entries` entries ON entries.`id` = content.`elementId`
JOIN `craft_elements_i18n` `elements_i18n` ON elements_i18n.elementId =
elements.id


Get value of variant field in plugin I'm trying to access a custom variant dropdown field in a plugin inside the commerce_lineItems.onPopulateLineItem event. How would I access the value of the dropdown, in order to do a comparison on it?

Thanks!

Something like this should work:

public function init()
{
    craft()->on('commerce_lineItems.onPopulateLineItem', function(Event $event) {
        $purchasable = $event->params['purchasable'];

        $myDropdownFieldValue = $purchasable->getProduct()->getContent()->myDropdownField;
    });
}

Relevant event docs: https://craftcommerce.com/docs/events-reference#commerce_lineitems.onpopulatelineitem


Image transformation of tif image does not work I use craft transformations for resizing images. The transformation of jpg files works as exepted, but the transformation of a tif image does not work. Imagick is installed and in the backend it creats and shows thumbnails of the images. When i rename the image from .tif to .jpg it performs the transformation also.

The Twig code looks like this:

The output HTML Code of a tif image looks like this:

The output HTML Code of a jpg image looks like this:

Is this a bug or have i missed a config setting?

Here are some images for explanation:

I found the way to create thumbnails of tif files. You have to change the function isImageManipulatable in the file /craft/app/helpers/ImageHelper.php:

public static function isImageManipulatable($extension)
{
    $extensions = array('jpg', 'jpeg', 'gif', 'png', 'wbmp', 'xbm');

   if (craft()->images->isImagick())
    {
        $extensions[] = 'svg';
    }

    return in_array(mb_strtolower($extension), $extensions);

}

To this:

public static function isImageManipulatable($extension)
{
    $extensions = array('jpg', 'jpeg', 'gif', 'png', 'wbmp', 'xbm');

   if (craft()->images->isImagick())
    {
        $extensions[] = 'svg';
        $extensions[] = 'tif';
    }

    return in_array(mb_strtolower($extension), $extensions);

}

I know, changing core code is not a real solution: i posted this change as a Craft feature request -> http://feedback.buildwithcraft.com/forums/285221-feature-requests/suggestions/8794456-better-support-of-image-types-in-image-transformat


Does Craft parse requests inside a conditional if it is false? Does Craft parse the contents of a false/negative/empty conditional statement? So would you take a performance hit if you had a big chunk of code inside a conditonal that was false?

{% set foo = "foo" %}
{% if foo == foo %}Small code {% else %} MASSIVE CODE{% endif %}

Yes, Twig will parse it all down to PHP before running it. It stores the rendered PHP in a /storage/runtime/compiled_templates/ file.

No, Craft will not run anything inside the conditional if it's false. At that point, it's simply processing exactly as normal PHP would.

So no, you shouldn't be notably penalized for anything inside a falsey if statement.


Modifying entry with 'onBeforeSaveEntry' event I'm trying to modify a field on an entry before it is saved.

What I'm trying to do is use a field from a linked entry to populate the same field on the entry being saved.

From logging I know the event is triggered, and that I can access the seo variable on the linked element.

Edit: The field I'm trying to copy the content from is the SEO field supplied by the sprout SEO plugin.

However when I try to set the field on the main entry with the content from the linked one, I get the following message

  Property "Craft\EntryModel.seo" is not defined.

So my question is, how can I correctly set the seo field on the entry being saved?

Below you can see the code currently in my plugins init function.

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

    if($entry->type['handle'] === 'service'){
        $serviceContent = $entry->linkToService->first();
        $event->params['entry']->seo = $serviceContent->seo;

        // Tried this aswell, gives second error mentioned below
        $entry->getContent()->seo = $serviceContent->seo;
    }
 );

After trying the answer provided by @justussimon91, the error message changed to:

  Property "Craft\SproutSeo_MetadataModel.metadata" is not defined.

Now this might be related to something specific with the Sprout SEO plugin so I'll raise the issue there as well.

Sprout SEO is a conjunction of different fields when you save an entry it will send the values from the Sprout SEO field (title, description, ogImage, etc..) in the 'metadata' namespace. So, in order to override this value, you can follow the next example:

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

       if($entry->type['handle'] === 'service'){
          $serviceContent = $entry->linkToService->first();

          $seo = $entry->getContent()->seo;
          $seo['metadata']['optimizedDescription'] = "Override description value";
          // Update it in the post request
         $entry->setContentFromPost(array('seo' => $seo));
      }
});

In this example I override the 'optimizedDescription' you can see all the properties in the 'sproutseo/models/SproutSeo_MetadataModel.php' File.

Remember that you can also override any value on the front-end using Template Overrides or add a Custom Format to specific values like the title or description using twig logic on your Sprout SEO field settings


Listen for checkbox check event for assets table and modify action trigger menu item I am able to listen to an event when the user checks the checkbox in the assets table. This is within my js file init file that extends garnish: Garnish.Base.extend

When the checkbox is selected, I see "checkbox clicked" in the console. The commented out in the function below is just to explain what I need to do when the checkbox is checked.

$('.elements:first').on('click', '.checkbox', function(event) {

    if ($(event.target).is('#main .elements:first .checkbox')) {
        console.log('checkbox clicked');

        // if file kind == "Image"
            // hide "View asset" from actions menu in the toolbar
        // else
            // do nothing

    }
});

What I need to do is, when the user checks the box, I need to determine the file kind, using the data-attr kind, the html for that td cell is below.

Image

If it is an image, then hide the "View asset" from the menu dropdown that displays in the toolbar. (image attached)

The view asset has an id of: View-actiontrigger

I am having trouble accessing it as it does not exist when my code is firing on the checkbox click.

Here is one approach: Whenever an asset is checked on or off, it triggers a manipulation of the hidden ul.menu. You could listen for that update to be complete, then you’ll be able to access and hide the link.

$('#main .elements:first').on('click', '.checkbox', function(evt) {

    // "View Asset" action is visible by default
    var isViewActionVisible = true;

    // If only one asset is selected and it is an image, set up to hide "View Asset"
    // Otherwise, stick with default behavior
    if ( $('#main .elements:first tr.sel').length == 1 &&
         $('#main .elements:first tr.sel td[data-attr="kind"]').html() == "Image" ) {
        isViewActionVisible = false;
    }

    // Wait for menu ul to finish updating, then show/hide "View Asset" action
    $(document).one('DOMNodeInserted', 'ul.menu', function() {
        $('a#View-actiontrigger').parent().toggle( isViewActionVisible );
    });

});


Cache table filling too quickly Have been using nystudio107 scripts to manage database workflow. Just launched first Craft 3 site and noticed that when i went to sync the database locally from server the /tmp partition on the server maxed out in seconds and brought the whole server down when trying to copy the database.

The culprit turned out to be 5G of cache content in craft_templatecachequeries which maxed out the partition tmp size (4GB)

I had added cache tags around main for loops, but i spotted that i had lazily tried to cache the whole news index page with the news index template being cached from top to bottom. I have removed these.THe cache table size has improved to a more stable 1GB but that seems incredibly high still.

Is this normal for Craft3?
(I guess there is a possible separate issue with scripts for db sync/pulling)

I'm not sure if it's the same thing, but if the queries you are caching are complex (nested queries, etc), it may be caused by the queries being serialized in Craft 3. Have a look at Brad's answer to a question I had a while go, to see if it covers your case as well:
Caching in Craft 3 causes out of memory when including grouped for loop

I ended up using the Cache Flag plugin to work around this.


Eager-load and pagination I'm currently working on a relation-heavy website with a colleague of mine and, for that reason, eager-loading stuff looks very appealing to us.
We've succeeded in eager-loading pretty much everything that we needed but there is just one kind of template that we couldn't make it work with: paginated archives

The context:
We have this archive page that loads every entry of a 'projects' section and, next to each entry, we have a list of all images that the entry contains which is between 8-20 images (remember, I said it was relation-heavy ;) ). We care a lot about performance so we decided to paginate this big entry listing.

The issue:
All this works very well except that when we tried to eager-load those images, we transformed our original query which was:

{% set allProjects = craft.entries(queryParams).limit(itemsPerPage) %}

to

{% set allProjects = craft.entries(queryParams).limit(itemsPerPage).find({
    with: [
        'gridMatrixBlock1:rowItem1',
        ['gridMatrixBlock1:rowItem1.gridimageFile', {
            kind: 'image',
            withTransforms: projectThumb
        }],
        ...
    ]
}) %}

The question:
Since .find() returns an array, we have no way to paginate this (pagination need an ElementCriteriaModel). Is there any workaround I don't know about?

with is just another query param, like limit or whatever parameters you’re defining in entryParams.

The {% paginate %} tag requires that you pass in an ElementCriteriaModel, but as soon as you call find() you’re actually dealing with an array of the matched entries.

So the key to getting eager-loading working with pagination is to assign the with param like any other param, rather than passing it into the find() function.

{% set queryParams = {
    // ...
    with: [
        'gridMatrixBlock1:rowItem1',
        ['gridMatrixBlock1:rowItem1.gridimageFile', {
            kind: 'image',
            withTransforms: projectThumb
        }],
        ...
    ]
} %}

and then you can create your ElementCriteriaModel just like you were doing before:

{% set allProjects = craft.entries(queryParams).limit(itemsPerPage) %}


Database driver & version after server upgrade The server I'm running Craft installations on just got an upgrade to Ubuntu 20 with MariaDB 10.5 Before MySql 5.7 was used.
When I look at the System Report in the Craft CP, it says: Database driver & version    MySQL 5.5.5
When I look at phpMyAdmin it says: "Server-Version: 10.5.6-MariaDB-1:10.5.6+maria~focal-log - mariadb.org binary distribution"
Why is it showing MySQL 5.5.5 in the System Report?

MariaDB is a "drop-in" replacement for MySQL and Craft/PHP/PDO treats them as identical 99.99% of the time.
Craft gets the information about which database/version is being used directly from PDO and since there isn't a specific MariaDB PDO driver, the MySQL is used and that is what is reported back.


How to shorten 'craft.request.getUrl()' with the shortener plugin? How can I use the shortener plugin to get and shorten the current URL?

I've tried both twig and plugin methods shown in the docs, but the twig method outputs the FULL url, and the plugin method doesn't work at all (no output).

Here is what I have in my template:

 {% set longUrl = craft.request.getUrl() %}

share link: {{ longUrl|shorten }}

The result with this is the full URL.

My configs in the plugin settings:

I cleared my system cache after I updated the settings as well.

Any ideas what I'm missing here?

The issue was that the custom short name I was using (in this case the development domain) was not associated with the bitly account.  Total oversight! I've removed that and it works perfectly.


Update Craft CMS, now I get HTTP ERROR 500 I have a site that's been running Craft 3 and has been running smoothly for several months now.

I was going to update a post today, and noticed that there were updates to Craft 3 that needed to happen (there were several craft updates, along with two plugins). I selected the Craft CMS first to update, and after hitting the update button, it did its thing for about a minute, then gave me a message that the update failed. When I tried to go back to my admin panel, I got the HTTP ERROR 500. Same when going straight to the website.

I tried change my php mode from FastCGI to just CGI as suggested in another post, but that hasn't helped. I also tried setting the devMode to true in my general.php config file, but nothing has changed there.

At this point, I'm dead in the water.

Any suggestions?

If the error 500 is displayed by craft, look in craft/storage/logs (i.e. phperrors.log)

Otherwise have a look at the server logfiles, if you have access to them. The Apache (or whatever http server you use) error log might be useful.


Is there anyway to use manual payments? I'm trying to create manual payments within Craft Commerce so the customer doesn't have to enter their credit card but every time I use the checkout button it says that the payment information is invalid. Is there anyway to have customers checkout without credit card info?

You need to create a 'Manual' payment gateway in Commerce > Setting > Payment Methods This will allow the customer to choose the manual payment method on checkout.

The 'Manual' payment method is the only way a customer can submit an order without payment information. This gateway does not place any validation on the payment form action, so you should not see any errors. If you are seeing errors, make sure you are sending the ID of the manual payment method with the paymentMethodId param to the payment form action.

The 'Mark as Complete' is a separate action that allows those that have the 'Manage Orders' permission, to turn a Cart that is in progress into an Order:


Saving causes server not to respond We're currently in the process of migrating web server to a new Ubuntu 14.04 box, and we are running into the same problem across our multiple Craft installations which is majorly affecting our workflow across all projects at the moment.

When we're updating content in Craft, we're frequently clicking 'Save' on categories, entries etc then having the server response timeout on us. The browser says 'Waiting for reply...', but it can take up to 5 minutes for the page to refresh with the saved data, which does appear to eventually being saved correctly.

I've spoken to our hosting company, and they told me that they couldn't see anything unusual in the logs, and advised that I install New Relic to be able investigate the problem further.

I installed the monitoring software along with the PHP service, and added a line at the top of index.php in Craft to identify the individual applications in New Relic.

I've just experienced the problem again on this site, when I was saving a new nested Category.

Going into New Relic transactions, I see in the transaction breakdown for the saveCategory transaction that 300,000 ms was spent in CInlineAction::runWithParams.

I've included the summary trace from NewRelic in the attached image.

Could this is a bug inside Craft, or if there is anything specific to our server which maybe causing this?

The first thing I would try is to "Disable" every single one of your plugins. If that solves the problem, go through and re-"Enable" each one of them until you have pinpointed which plugin is causing the problem.

If that doesn't help at all, the next thing I'd do is to open up the Craft logs, and see if anything suspicious is in there...

/craft/storage/runtime/logs/

And if you're still not seeing anything noteworthy, then it might be worth submitting a ticket from the "Get Help" widget on your dashboard. Be sure to include your logs, database export, and files.


Retrieve entries on custom field date using ElementCriteriaModel I am trying to retrieve an array of entries on a particular section where inspectionDate is greater than today's date. Here is the code.

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = 'inspections';
$criteria->inspectionDate > '("now")';
$criteria->order = 'dateCreated asc';
$inspections = $criteria->find();

I am getting a Property "Craft\ElementCriteriaModel.inspectionDate" is not defined. error when trying to run this code.I have made sure that inspectionDate is the field handle and is also a date type.

The Error was because

  $criteria->inspectionDate > '("now")';

This way you can't get today's date.

You could try this:

$date = new DateTime();
$formattedDate = $date->format(DateTime::MYSQL_DATETIME);
$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = 'inspections';
$criteria->inspectionDate = '> '.$formattedDate;
$criteria->order = 'dateCreated asc';
$inspections = $criteria->find();


Check if a value exists in a Matrix field http://sanderson.brycekirk.com/floor-plans/1-bedroom-1-bathroom/f123-f148-f248

This page displays a floor plan, of which there are many. Currently, within each floorplan entry, you add the floors it is on, along with the image of each floor:

I'm using a for loop to display a big button for each available floor, as you can see on the linked page.

My problem: I want to add disabled buttons for each floor the floorplan isn't on, but I can't figure out how to do it.

The logic should be something like this ("floors" is the name of the matrix field, "floor" is the block type handle):

IF '1' exists in entry.floors.floor.floorNumber
    Show the big selectable '1' button
ELSE
    Show the disabled '1' button

IF '2' exists in entry.floors.floor.floorNumber
    Show the big selectable '2' button
ELSE
    Show the disabled '2' button

etc for 3 and 4

It seems like their should be some straightforward solution, but I've had no luck.

Current code for displaying the floor number buttons:

{% for floor in entry.floors.all() %}
{% if floor.type.handle == 'floor' %}

{% endif %}
{% endfor %}

Floor matrix:

You can check if certain elements match for your Query via exists()

entry.floors.type('floor').floorNumber(1).exists()

returns true or false. However keep in mind entry.floors returns an element of type Query and you'll append the parameters type and floorNumber to the Query. These properties won't reset magically since you call the object by reference and not by value thus you'll either need to reset them

{% do entry.floors.type(null).floorNumber(null) %}

or you don't use the object directly and clone/copy it instead

{% set exists = clone(entry.floors).type('floor').floorNumber(1).exists() %}


Can fields be reused with a different name per section? I've got a redactor field used on several sections, and category groups. Is there a way to change the displayed name per section in the edit form?

On a category group the field is, 'Category Description', and on products, 'Product Description', but under the hood they're both 'richText'.

One of these might help (I use the first one):

https://plugins.craftcms.com/fieldlabels
https://plugins.craftcms.com/relabel


Get field Matrix field label inside template I have Matrix field containing block with various fields. How can I output into template label of single field?

Can I get type of that field? (for example - textfield, dropdown field, etc.)

Something like this should do what you're looking for:

{% for block in entry.body %}

    {% set fields = block.getFieldLayout().getFields() %}

{{ block.getType().name }}

            {% for field in fields %}

{{ field.getField().name }}
            {% endfor %}

{% endfor %}


Loading a plugin template via ajax I'm trying to load a plugin template via ajax inside another plugin template like so:

 $("#modal").load("/mypluginname/myplugintemplatefolder/myplugintemplate.html?queryvar="+var);

but it keeps looking for myplugintemplate.html on the frontend templates folder instead of in my plugin template folder - I don't understand how to tell it that I'm trying to load a file from my plugintemplate folder

Basically I'm trying to refresh a section of my template by reloading an include

Plugin files are located outside your web root, thats why you can't access them directly. You should create a controller action and render the template from there.

class DefaultController extends Controller{
  protected $allowAnonymous = ['getTemplate'];

  public function actionGetTemplate(){
    $request = Craft::$app->getRequest();
    $templatevar = $request->getParam('templatevar');

    use craft\web\View;
    $oldMode = \Craft::$app->view->getTemplateMode();
    \Craft::$app->view->setTemplateMode(View::TEMPLATE_MODE_CP);
    $html = \Craft::$app->view->renderTemplate('plugin-handle/path/to/template');
    \Craft::$app->view->setTemplateMode($oldMode);
  }
}

(see https://docs.craftcms.com/v3/extend/updating-plugins.html#rendering-templates)

You can define the route to your controller action in your plugin file

public function init(){
  Event::on(UrlManager::class, UrlManager::EVENT_REGISTER_SITE_URL_RULES,
  function(RegisterUrlRulesEvent $event) {
      $event->rules['gettemplate/<templatevar:\w+>''] = 'myPlugin/getTemplate';
  });
}

and call it via
 $("#modal").load("/gettemplate/"+templatevar);


Evaluating the if statement in entryType I have this simple the loop, and want to assign a unique code, if condition is met.

{% paginate craft.entries.section().type().limit(20) as entriesOnPage %}

{% for entry in entriesOnPage %}

{{ entry.type.name }}

     {% if entry.type('entryTypeHandleA')|length > 0 %}
          a
     {% elseif entry.type('entryTypeHandleB')|length > 0 %}
          b
     {% endif %}
{% endfor %}

This code snippet is the last try, I've tried. I always get printed the first condition, even if it's false. Without filter length, I got printed both conditions.
I'm assuming, that it's ECM that will always exists, so that's why I never get falsey return?

When you do:

entry.type('entryTypeHandleA')

What you're given is an instance of an EntryTypeModel.

So when you do:

entry.type('entryTypeHandleA')|length

EntryTypeModel's __toString() method will be called, which returns the handle of the entry type ('entryTypeHandleA') and |length tells you how long that handle is (16 characters).

So essentially what you're saying is:

{% if 16 > 0 %}

Which is always true.

However, I'm still not clear exactly what you're trying to compare against.

If you're just looking to see if the handle of an entry type is equal to something, then you'd use this:

{% if entry.type.handle == 'entryTypeHandleA' %}
    a
{% elseif entry.type.handle == 'entryTypeHandleB' %}
    b
{% endif %}


Send payment requests Is there a plugin/solution or something else in Craft so that I can basically:

1) Create a payment request in the CP and send it to a specified email?

2) The email contains a link to a payment form which the user can fill in and pay (amount would have been passed via email)

3) When paid the status would be updated in Craft CP

I have seen the 'Charge' plugin (https://transition.topshelfcraft.com/software/craft/charge) which looks great but it doesn't look like its up to date.

Many thanks
Malcolm

This is possible with Craft Commerce 3 Pro.

Create an email that would trigger on an 'Invoice' order status that you configure. (or any other name you want)

You would make the order in the Control Panel, then mark it as complete (which will set the the default status), then change the status to 'invoice' to trigger the email.

In the email template, link to a front-end payment form with the order number appended as a param like this ?number=78nc4y83fn4830f4nu304 Then in the payment form, pass in the orderNumber param based on the url number param.

This will make payment on the order and mark it as paid.

You can then see all orders with the status of 'invoice' in the CP, and see the ones that are paid or unpaid. You could move the order to a 'completed' status once you verify payment and ship the order.

Hope that helps.


Craft 3: When querying for Matrix blocks in a plugin, how do you sort by a custom field? My goal is to order an element query of Matrix blocks by a custom field. Any thoughts?

namespace modules\mymodule\services;

use Craft;
use yii\base\Component;
use craft\elements\MatrixBlock;

class MyService extends Component
{
    public function myFunction()
    {
        $blocks = MatrixBlock::find()
            ->type('myBlockType')
            ->orderBy(???)
            ->all();
    }
}

Edit to show working Example

(This is showing how I used this to sort by a custom date field)

$blocks = MatrixBlock::find()
    ->type('blockType')
    ->fieldId($fieldId)
    ->where(['>', 'content.field_blockType_fieldHandle', new \yii\db\Expression('NOW()')])
    ->orderBy(['content.field_blockType_fieldHandle' => SORT_ASC])
    ->all();

->orderBy('fieldHandle')

or

->orderBy(['fieldHandle' => SORT_DESC])

But you have to make sure the field is sortable, otherwise it won't work


How to prevent inconsistent comments in generated project config YAML files We're using Project Config to enable a decentralised, git-based workflow. One issue we have is that sometimes the generated YAML files will include a specific comment, and sometimes it won't. In particular, in the /config/project/sections/ files, the YAML files for each section have a siteSettings key, with a list of settings per site (currently we're working only with a single site). Now the line with the UUID of the site will sometimes include a comment with the site name, and sometimes it won't. Here's a diff showing the difference:
--- a/config/project/sections/home--12b67b1c-1077-4a7a-8312-c1cba1234567.yaml
+++ b/config/project/sections/home--12b67b1c-1077-4a7a-8312-c1cba1234567.yaml
@@ -3,7 +3,7 @@ handle: home
 name: Home
 propagationMethod: all
 siteSettings:
-  649a64c1-52f1-4463-8a03-bc84c1234567:
+  649a64c1-52f1-4463-8a03-bc84c1234567: # NameOfTheSite
     enabledByDefault: true
     hasUrls: true
     template: entries/home

We want to prevent this from cluttering up our commits. Of course, we can just not commit those files and/or reset them manually, but keeping track of that manually is a bit tedious. I haven't been able to find out why the comment is sometimes there and sometimes it isn't. Sometimes after creating some new fields, sections or similar all YAML files in config/project/sections will show up as changed in git status, and I don't know when they got overwritten. Maybe it's got to do with whether the site name is defined or not? Though that hasn't changed at least on my machine.
Anyway, is there a way to either prevent Craft from including those comments when generating YAML files, OR have them be consistent? Of course, if the comment depends on the local name of the site, that would result in a lot of unnecessary changes if multiple people use a different site name in their local development environment.
I'm open to other solutions. The main problem is that it's cluttering up our commits and it's annoying to manage manually when commiting. Any insight would be appreciated. Thanks!

Comments were added to Project Config files after Craft 3.6.8 referencing GitHub issue 7584.
They shouldn't be appearing and disappearing unless you're committing config files without them over the ones that already do have them in the repo. That being said, from my experience the comments are only applies to NEW fields added after 3.6.8, or at least are not all done at once as soon as you update to 3.6.8. To get around this, I'd do ./craft project-config/rebuild which will regenerate your config files and add comments to EVERYTHING, commit that, then get your developers to pull them.


Interacting with table fields via plugin When you set up a table field column through the admin cp, you assign a name and a handle. When I var_dump the table field, all row data is referenced by column number. (e.g. col1, col5, col2, col3, col4)

    $partnerProducts = $currentPartner['0']->getContent()->productInfo;
    foreach ($partnerProducts as $pp){ echo ($pp['col2']); }

These columns may not be in order depending on how they were drag and dropped in the admin control panel, which is super confusing from the PHP plugin side. Is there any way to reference the table items by their cp handle?

You CAN do this from the twig side.

    {% for partnerProduct in partner.productInfo %}
        {{ partnerProduct.sku  }}
    {% endfor %}

I'm still not sure what the difference between $currentPartner['0']->getContent()->productInfo; and $currentPartner['0']->productInfo is but the latter works.

If you use:

$partnerProducts = $currentPartner['0']->productInfo;

Then you should be able to do:

foreach ($partnerProducts as $pp)
{
    echo ($pp['sku']);
}


Display xml feed - xml parser Is there anything in craft that can take an xml feed and display it on my site.
It doesn't need to be saved as entries or anything. Simply just display the data.
It's a sports xml feed and there will be fixtures/results and league tables.

I have seen this: https://craftcms.com/docs/templating/craft.feeds
But you only seem to be able to access a few fixed fields.

You can use the Feed Me plugin if you like! While it can save feed items as entries, you can use the template tag which allows you to simply fetch feed data without actually saving it. Then you can loop through your feed items in your templates.

Let me know if you have any issues - I created the plugin, so happy to assist :)


Deploying CraftCMS to Digital Ocean Currently I'm having an issue deploying to Digital Ocean and would love some advice, i've followed numerous tutorials but they seem to just drop off half way through the process so just need some clarity on this. I've broke down what I've done below:

Developed my CraftCMS site in localhost using MAMP.
Committed everything to Github apart from db.php
Created a droplet with LAMP
Setup my database names so it corresponds with my localhost
Setup my database user
Created a deploybot setup which contains my     db.php file
Deployed the application using deploy bot which deploys my latest
push in the git repo.

Am I supposed to be reinstalling CraftCMS on the droplet and upload my localhost database after these steps?

I would suggest to read through the following articles:

https://nystudio107.com/blog/multi-environment-config-for-craft-cms

https://nystudio107.com/blog/database-asset-syncing-between-environments-in-craft-cms

About reinstalling craft on your droplet and uploading the local database:

the craft install i used in my local dev environment will be pushed onto the droplet, like this i can assure that it doesn't differ in any of the enviornments. About syncing the database read through the articles it will clear things up. In general all of the articles in nystudios blog are more than helpful. i hope it helped at least a bit.


Ordering entries based on an eager-loaded element's custom field I have a query that loads a set of movies, and eager-loads corresponding shows, which are related elements. For now, the movies are sorted by startingDate, which is a custom field in the movie entry:

{% set currentMovies = craft.entries({
        section: 'movies',
        type:    'movie',
        order:   'startingDate asc',
        limit:   null,
        with: [
            'shows',
            'poster',
            'stills'
        ]
    })
%}

What I actually want is to sort the movies by whichever film has the first upcoming screening. That basically means I would like to order the set by something to the effect of order: shows.showTime or order: shows[0].showTime, but that doesn't seem to work.

Is there a way to order by a field on a related entry, or is that variable simply not yet accessible at the point of ordering?

I tried to eager-load the shows.showtime field, but realised that doesn't work either, as eager-loading only makes sense for relations, not fields themselves.

This requires a bit of extra work on the ElementQuery, but it can be done in the same query.

We need to perform an inner join on the relation between the movie and the show and then another inner join on the show's content table. Finally we can order on the custom field of the show's content table.

{% set currentMovies = craft.entries()
    .section('movies')
    .type('movie')
    .limit(null)
    .with([
        'shows',
        'poster',
        'stills'
    ])
    .innerJoin('{{%relations}} shows_relation', '[[shows_relation.sourceId]] = [[elements.id]]')
    .innerJoin('{{%content}} shows_content', '[[shows_content.elementId]] = [[shows_relation.targetId]]')
    .orderBy('shows_content.field_startingDate asc')
%}


How to develop plugin/module to build landingpage upon fetched JSON-data I've developed an app which fetches data from an API based on Laravel 5.5. The marketing landingpage of the app is based on Craft CMS Version 3. The marketing website and the API and the databases of both systems are running on the same server.

I want to generate landingpages for each row of table X of the Laravel database.

www.website.com/awesome-landingpage-about-{slug}

What is the best approach to realize this?

I don't want to fetch the data directly from Laravel's database
I don't want to synchronize the Craft CMS database with the Laravel (add/remove the rows from the laravel's database as entries to Craft)
It would be awesome to be able to have an entry-type "Landingpage" where we can optionally create a landingpage, referencing to an ID of the laravel table and add additional content for the landingpages.

Would be a JSON-API from Laravel to Craft CMS Plugin a good performant idea?

One option would be to use a Dynamic Route and just fetch the data from 127.0.0.1 (because same server) from the template file? Or is there a smarter way in Craft CMS?

I'd make a template called landing that would have various entries/entry types in it where I can add whatever CMS content I want.

https://www.example.com/landing/landing-page-slug

For a nice content authoring experience, I'd make a custom Element that knows to go out over the wire and fetch the data from the Laravel database via whatever JSON endpoint you've set up in your Laravel app, and a custom Field that is just a simple ElementSelect for my custom Element.

That way in your Craft CMS entry, you could just click a button to browse the various rows in your remote Laravel db (presenting the information in a nice UI that'd look exactly like you're selecting another Craft entry).

Then on the templating side of things, it'd work like anything else does in Craft. Through the custom Element, you'd have access to all of the data from your remote Laravel db table, e.g.:

{{ entry.laravelData.someField }}

Bonus points would be awarded for a nice caching layer to keep things performant.


Craft Cache Config - Remote Support? Is there a way to configure Craft further beyond just settings like 'cacheMethod' => 'redis',? I'm exploring the possibility of using Redis outside of the server Craft CMS is running on, and am curious if there is a way I can set this up while still using the built-in craft()->cache service.

I'd love to be able to utilize a remote cache option and configure it in the same way that cache has a db.phpconfig file where you can set your database as local or remote.

Is there any information about doing this out there and/or plans to support this eventually? Just curious.. thank you!

You can configure the Redis cache driver to use an external host, see the config page for the documentation and here for details on copying the default Redis config file and configuring it.

Long story short... Copy craft/app/etc/config/defaults/rediscache.php to your craft/config/ folder and configure the settings as you wish.


Is there a 2-factor auth plugin? Is there a 2-factor authentication plugin for Craft? Or is there a way to secure the login for Craft CMS beyond the common installation instructions? I want to build a system that someone on a dynamic IP could access, so static IP's are a bit harder.

I was also thinking if there was a way to add another field to the login page, which was a decryption key, then use one the twig decryption method. If you don't have it, you'd see the data, but it would be all garbled up.

Is there a 2-factor authentication plugin for Craft?

I've heard of one in private testing, but I'm not aware if they plan to release it publicly or not.

Until the official Craft plugin store becomes a thing, the most comprehensive list of Craft plugins available I know of is over on the awesome Straight Up Craft.

  I want to build a system that someone on a dynamic IP could access, so static IP's are a bit harder.

O.K. What's the reasoning there, if you don't mind me asking?

  I was also thinking if there was a way to add another field to the login page, which was a decryption key, then use one the twig decryption method. If you don't have it, you'd see the data, but it would be all garbled up.

Not currently, but we've discussed giving plugins the ability to control the HTML of the login page.  Probably worth making an official feature request for that.

It is worth mentioning that there is an onBeforeLogin event a plugin can already listen to and apply their own custom password business logic (i.e. must be 200 characters long, have 40 emojis, 20 Egyptian hieroglyphs, be purple and only work on Tuesday).


Issues with picture and image transforms I'm having some issues with  when applying image transforms. Hopefully it's something obvious I'm over looking. The code is as follows:

<picture>
    <source media="(min-width: 401px)" srcset="{{ imageUrl.getUrl('homeBanner') }}">
    <source media="(max-width: 400px)" srcset="{{ imageUrl.getUrl('iphone400x710') }}">
    <source srcset="{{ imageUrl.getUrl('iphone400x710') }}">
    <img src="{{ imageUrl.getUrl('iphone400x710') }}" alt="Image Desc">
</picture>

Images uploaded are all 2000px x 1330px and the transform should crop from center to the specified size in the handle.

My problem is it works on my local server but once uploaded to my (shared) dev server I am getting php out of memory errors on this script

craft/app/vendor/imagine/imagine/lib/Imagine/Gd/Image.php on line 617

Am I doing something incorrectly that is causing the script to run for too long?

Cheers

You might try putting putting something like:

<IfModule mod_php5.c>
  php_value max_execution_time "30"
  php_value memory_limit "256M"
</IfModule>

inside your .htaccess. file.

You can tell what your PHP values are right inside Craft... unless you changed your admin trigger, just visit http://server/admin/utils/phpinfo and search for memory_limit and max_execution_time. That'll give you some clues as to what's going on.

Some hosts set these values really low but the default execution time is 30 and memory limit is 128M.

If you run PHP as a cgi, some hosts allow you to use ini files in lieu of .htaccess. Typically these are at the root of your home folder but they could be stored elsewhere. Put memory_limit = 256M in one and throw it up in your home folder. Running php_info() would tell you the location of the current in use one.


Get current entry category I haven't used categories before so maybe I'm looking at this the wrong way.

I currently have a category group named products with the following structure:

Featured
Fruit
----Apple
----Banana
Veg
----Turnip

I know I can do the following to show just the subcategories of fruit:

for cat in craft.categories.group('productCategories').descendantOf("fruit ID")

But how do I get the "fruit ID" when I'm on the on the fruit page?

 craft.categories.relatedTo(entry)

returns all the categories in products but I want just the current category.

Any help greatly appreciated!

I take it you are on the category template as defined in admin/settings/categories/:id.

You should have a model representation of the category assigned to category in the template, so you should be able to get the current category id by simply doing {{ category.id }} in the template.

Your code could look like:

for cat in craft.categories.group('productCategories').descendantOf(category.id)


Receiving 'template loader exception' when trying to view asset (image) after upload Anyone ever encounter this error when trying to view an asset (image) after upload? I'm working in homestead and everything appears to be compiling correctly, however the images don't render in the browser. The path shows up in dev tools and looks correct...any thoughts?

Craft\TemplateLoaderException
Unable to find the template “_layout”. (/home/vagrant/sites/my-craft-sites/wcs/craft/app/etc/templating/twigextensions/TemplateLoader.php:123)
#0 /home/vagrant/sites/my-craft-sites/wcs/craft/app/etc/templating/twigextensions/TemplateLoader.php(71): Craft\TemplateLoader->_findTemplate('_layout')
#1 /home/vagrant/sites/my-craft-sites/wcs/craft/app/vendor/twig/twig/lib/Twig/Environment.php(265): Craft\TemplateLoader->getCacheKey('_layout')
#2 /home/vagrant/sites/my-craft-sites/wcs/craft/app/vendor/twig/twig/lib/Twig/Environment.php(323): Twig_Environment->getTemplateClass('_layout', NULL)
#3 /home/vagrant/sites/my-craft-sites/wcs/craft/storage/runtime/compiled_templates/fc/9e/d83ba99cc7bfbe696da10fbdcf65536dc4ae270165035f00e6cfb3c5b953.php(10): Twig_Environment->loadTemplate('_layout')
#4 /home/vagrant/sites/my-craft-sites/wcs/craft/app/vendor/twig/twig/lib/Twig/Environment.php(345): __TwigTemplate_fc9ed83ba99cc7bfbe696da10fbdcf65536dc4ae270165035f00e6cfb3c5b953->__construct(Object(Twig_Environment))
#5 /home/vagrant/sites/my-craft-sites/wcs/craft/app/vendor/twig/twig/lib/Twig/Environment.php(292): Twig_Environment->loadTemplate('404')
#6 /home/vagrant/sites/my-craft-sites/wcs/craft/app/services/TemplatesService.php(220): Twig_Environment->render('404', Array)
#7 /home/vagrant/sites/my-craft-sites/wcs/craft/app/controllers/BaseController.php(74): Craft\TemplatesService->render('404', Array)
#8 /home/vagrant/sites/my-craft-sites/wcs/craft/app/controllers/TemplatesController.php(203): Craft\BaseController->renderTemplate('404', Array)
#9 /home/vagrant/sites/my-craft-sites/wcs/craft/app/framework/web/actions/CInlineAction.php(49): Craft\TemplatesController->actionRenderError()
#10 /home/vagrant/sites/my-craft-sites/wcs/craft/app/framework/web/CController.php(308): CInlineAction->runWithParams(Array)
#11 /home/vagrant/sites/my-craft-sites/wcs/craft/app/framework/web/CController.php(286): CController->runAction(Object(CInlineAction))
#12 /home/vagrant/sites/my-craft-sites/wcs/craft/app/framework/web/CController.php(265): CController->runActionWithFilters(Object(CInlineAction), Array)
#13 /home/vagrant/sites/my-craft-sites/wcs/craft/app/framework/web/CWebApplication.php(282): CController->run('renderError')
#14 /home/vagrant/sites/my-craft-sites/wcs/craft/app/framework/base/CErrorHandler.php(331): CWebApplication->runController('templates/rende...')
#15 /home/vagrant/sites/my-craft-sites/wcs/craft/app/framework/base/CErrorHandler.php(204): CErrorHandler->render('error', Array)
#16 /home/vagrant/sites/my-craft-sites/wcs/craft/app/etc/errors/ErrorHandler.php(128): CErrorHandler->handleException(Object(Craft\HttpException))
#17 /home/vagrant/sites/my-craft-sites/wcs/craft/app/framework/base/CErrorHandler.php(129): Craft\ErrorHandler->handleException(Object(Craft\HttpException))
#18 /home/vagrant/sites/my-craft-sites/wcs/craft/app/framework/base/CApplication.php(732): CErrorHandler->handle(Object(CExceptionEvent))
#19 [internal function]: CApplication->handleException(Object(Craft\HttpException))
#20 {main}

I assume this is all in context of the control panel and not the front-end, correct?

If so and I had to guess, it looks like you're missing some Craft files on your box.  Try downloading a fresh copy of Craft from http://buildwithcraft.com and replace your existing craft/app folder with the freshly downloaded one.


Updating plugin to Craft 3: craft()->urlManager->setRouteVariables? What would be the Craft 3 / Yii 2.0 version of
craft()->urlManager->setRouteVariables(array('calupdateResponse' => $out));

This doesn't work (it doesn't complain, either):

$urlManager = new UrlManager;
$urlManager->setRouteParams(['calupdateResponse' => $out]);

Craft::$app->getUrlManager()->setRouteParams(['calupdateResponse' => $out]);

All Components should be treated as singletons, don't create a new instance of them

Note: you can also do

Craft::$app->urlManager->setRouteParams(['calupdateResponse' => $out]);

But it is considered as bad practice

Edit: most parts of Craft 3 are working with Craft 2 as well... craft() is just a mapper for Craft::$app


How Do You Add A Form on a Page to Gate the Content? I am new to Craft, but one of my clients has a website built in Craft. They would like to "gate" the content on a page of their website.

A. Is it possible to gate content in the Craft CMS? Client wants to add the capability of requiring an email address before viewing the content on a certain page.

B. If it is possible, what are the steps to adding/implementing?

Thank you in advance.

Depending on your Craft License you could make use of a login form as described inside the docs here.

If you got the loginform working, simply use {% requireLogin %} on the site template (i.e. inside the twig template file) that should have restricted access.

If your goal is to just provide an E-Mail without a password you would need to tinker around a bit and maybe just write up a small plugin. To get startet I suggest reading this and this. Out of the box this is not possible as far as I know.
I would advise not just using an E-Mail for validation as ab@c.de for example is a valid E-Mail, though unlikely that it is real. Some sort of login/auth would provide a more solid experience and enforces that the user is real and has validated their E-Mail with the CMS (as craft can send a validation link to given E-Mail after registering with the site).


How can I change variant price in Craft Commerce 2 form I want to add range field that will change price based on its value.
How can I send updated price to the cart? Is there something easy like:

{% set product = craft.products.one() %}
{% set variant = product.defaultVariant %}

<form method="POST">
    <input type="hidden" name="action" value="commerce/cart/update-cart">
    {{ redirectInput('shop/cart') }}
    {{ csrfInput() }}
    <input type="hidden" name="price" value="HERE NEW PRICE">
    <input type="hidden" name="purchasableId" value="{{ variant.id }}">
    <input type="submit" value="Add to cart">
</form>

It's not possible to send the price to the cart in this way.

You will need to send that price as a custom option on the item and then use a custom module or plugin to update the line item's price.

You can just alter the line item price directly if desired but it may be more appropriate to create an adjuster to do it.

So your add to cart form might look like...

<form method="POST">
    <input type="hidden" name="action" value="commerce/cart/update-cart">
    {{ redirectInput('shop/cart') }}
    {{ csrfInput() }}
    <input type="hidden" name="options[customPrice]" value="HERE NEW PRICE">
    <input type="hidden" name="purchasableId" value="{{ variant.id }}">
    <input type="submit" value="Add to cart">
</form>

Then your custom module would listen for a Commerce event, probably populateLineItem (see events here https://docs.craftcms.com/commerce/v2/events.html#order-related-events)  and update the item's price.

use craft\commerce\events\LineItemEvent;
use craft\commerce\services\LineItems;
use yii\base\Event;

Event::on(LineItems::class, LineItems::EVENT_POPULATE_LINE_ITEM, function(LineItemEvent $e) {
   // update the line item's price with the customPrice option from this line item
   // save the line item
});


Match to Existing Category on FeedMe Entry Import JSON I've successfully exported product entries out of an ancient version of ExpressionEngine (1.7.1) into a JSON file and for the most part I've successfully imported that JSON using FeedMe—except for two things: Categories and a field that is a Dropdown menu in Craft.
The most important thing is the Categories (I can live without the dropdown field if I have to), but I thought I'd mention it because I thought the solutions might be related.
In Craft I have a Category Group with Existing Categories. What I want to do is have the entries I import match into those existing categories; the Craft Categories are an exact copy of the old ExpressionEngine categories so they are exactly the same.
I can't figure out what FeedMe/Craft is looking for to "match" the JSON category field to the corresponding existing category. I've tried the cat name and the cat slug. I've also tried Cat Id but I'm not sure I had the right Id value (I couldn't find an obvious place where the Cat Id is listed in Craft so I did an export on the Categories page and tried what I found in there).
Here is a simplified version of the JSON I'm importing:
[
  {
    "title": "Product: A type of Chair",
    "dropdown": "Chair",
    "category": "Wing Chair",
    "description": "Text here"
  }
]

I actully have many more fields, which all import fine, but the category and dropdown won't no matter what I try.
In the FeedMe Content Fields when I choose the Feed Element for the Category field (which I'm able to select) but under it there is a drop down with instructions that say:
Data provided for this category is:
And the drop down is a listing of all the possible Craft fields, EXCEPT for the Craft Category field; so I'm completely confused by this.
I'm sure this is something basic that I'm just missing, but I'm new to Craft/FeedMe and none of the other quesions on here that I could find were matching existing categories.

For the category, you need to pass an array of objects and choose to match on title (or ID if you have them).
For the dropdown, pass in the value, not the label and it will work. Try this:
[
  {
    "title": "Product: A type of Chair",
    "dropdown": "valueNotLabel",
    "category": [
      {
        "id":"1234"
        "title":"Wing Chair"
      },
      {
        "id":"5678"
        "title":"Another category"
      }
    ],
    "description": "Text here"
  }
]

To find your category ID, you can click the small cog (customize) on your Categories page in your control panel and add the ID column to your table.