Find the nth top-level category in a nav tag I want to output some code after the 10th top level category in a category listing. For example...

1.

1.1.
1.2.

2.

2.1.

3.
...
10.
Zoiks!

The problem is, I can't use Twig's loop.index in a conditional because it counts each of the children too (like a flat list). How can I test for the 10th top-level category?

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

    {{ category.title }}
    {% ifchildren %}

        {% children %}

    {% endifchildren %}

  {% if category.level == 1 and loop.index == 10 %}

Zoiks! That‘s a lot of categories!

  {% endif %}
{% endnav %}

Maybe you can add in a little counting magic of your own:

{# before the nav tag #}
{% set topLevelIndex = 1 %}

{# inside nav loop #}
{% if category.level == 1 and topLevelIndex == 10 %}

Zoiks! That‘s a lot of categories!

{% endif %}
{% if category.level == 1 %}
    {% set topLevelIndex = topLevelIndex + 1 %}
{% endif %}

This code hasn't been tested...


How do you create an alternating layout in a template? i.e. an image on right then an image on left I'm a new user so I really don't know how to do this.

I want to create a template that displays the results of a "news" type entry in alternating rows - image on left/text on right - image on right/text on left.

Could someone help in explaining where to put the code and what the code should be?

Personally I'd do this in pure CSS. e.g.,

        ...

        ...

CSS:

.item {
    overflow: hidden; // expand around floated children
}
img {
    float: left; width: 50%;
}
.text {
    float: right; width: 50%;
}

.item:nth-of-type(2n) img {
    float: right;
}
.item:nth-of-type(2n) .text {
    float: left;
}


How to avoid "Double-instantiating a pane on an element" Without going into too much detail, I have a plugin where I'm trying to manage two different sets of tabs with some custom javascript. When the object initializes, I need to add a pane from the page layout to the object. Something like:

this.$pane = new Craft.Pane($(".pane"));

That line of code kinda works. However, when the page loads the console reports:

Double-instantiating a pane on an element

If I remove the above line of code this.$pane = new Craft.Pane($(".pane"));, the console log message goes away. With the line of code some things work. Without the line of code other things work. I need all the things to work at the same time.

I'm struggling to know the right question to ask, so please point me in the right direction if I am off the mark. Is it possible to check if there is an existing Craft.Pane object that exists before I try to create a new Craft.Pane object?

I was able to resolve this by testing to see if the pane existed before re-instantiating the element. Happy to consider another answer if someone can explain what is going on better. For now, the following worked:

// Check to see if an element was already registered as a `Craft.Pane`:
if (!$("#myelement.pane").data('pane'))
{
    // Create a pane object if it is not
    this.$pane = new Craft.Pane($("#myelement.pane"));
}
else
{
    // Use the existing pane object if it exists
    this.$pane = $("#myelement.pane").data('pane');
}


How do I output an entry author's data I have a blog. I want to output an entry author's first and last name. What is a good method to accomplish this?

For each entry, you can get the username of the author by simply using {{ entry.author }} (assuming entry is the variable containing the blog entry).

If you want to display Full name, first name and/or last name for one entry, you'd use:

{{ entry.author.fullName }}
{{ entry.author.firstName }}
{{ entry.author.lastName }}

For a list of entries and their authors, you'd use:

{% for entry in craft.entries.section('your-section').find() %}
    {{ entry.author.fullName }}
{% endfor %}


Private Plugin Repository Using Satis Has anyone been successful using Satis for composer repo(s) with Craft plugins? I have a repo set up with artifacts, that are posted as a public composer repo in the network. It finds the plugins and downloads, but for some reason I keep getting the following error whenever I try to do composer update:

[craft\composer\InvalidPluginException]
  Couldn't install vendor/plugin: Unable to determine the base path

It works if I do a local path and pull it in that way.

Instead of wrestling with artifacts and that whole approach I simply created a private repo on github, then set up a local satis that pulls in from that repo and then serves it to the installs as a composer repository when running composer update. Works like a charm.


Where are all these columns coming from on the Entries in happy-lagger.test project? I just started looking around the example project happy-lager, and I realised that on the Entries there's a bunch of columns displayed that I don't see on my company project (URI, Service Icon and some others in different Entries, such as background colour or image thumbnails). I didn't know this was possible, but it's great. How are those set?

FYI: Our project was updated from Craft 2, I don't know if this might be related.

On every entry type (or even on the "All entries") you can specify the columns visible in the Panel. Click on the cog at the bottom of the light-grey sidebar. You'll have access to all entry' fields!

The magic of Craft ;)


Limit DevMode to admin users? Is there an easy way to enable devMode only to users logged in with specific permissions?

The goal for enabling dev mode so I can troubleshoot things while not showing those ugly errors to anyone else.

If that's all you're looking for, there is a per-user account setting for this under the user account's preferences:


Eager loading fields within categories Is it possible to eagerLoad fields in categories?

I have this code;

{% set markets = craft.categories.group({
  section: 'markets',
  with: ['bannerImage']
}) %}

which for some reason is throwing an error;

  mb_convert_case() expects parameter 1 to be string, array given

Is this a bug or something bad in my code? Removing the with call and it renders fine.

This is basically just a syntax error. What you are doing is: searching for entries in the group section: 'markets', with: ['bannerImage'] but what you want is searching for categories in the group markets with the field bannerImage

{% set markets = craft.categories.group('markets').with(['bannerImage']).all() %}

The group parameter in your CategoryQuery defined which group(s) you want to select. The with parameter your eager-loading elements. Btw: Categories have no section property


Outputting .relatedTo() total entries number I'm trying to get the total number of entires that match a .relatedTo() search.

{% set category = craft.categories.group('products').title(cat).first() %}
{% set entries = craft.entries.section('products').relatedTo(category).find() %}

I have tried ...

{% set entryCount = craft.entries.section('products').relatedTo(category).find().total() %}

But no joy. What Am I missing?

The best way to do it depends on whether you actually want to loop through the related entries or not.

If you only want the total, and aren’t going to be looping through them, use .total():

{% set entryCount = craft.entries.section('products').relatedTo(category).total() %}

(Note that’s just .total(), not .find().total().)

That way you’re not making Craft do any more work than what you actually need - just figuring out the total related entries.

If you do want to loop through them as well, then grab the entries normally and then figure out how many came back using Twig’s |length filter:

{% set entries = craft.entries.section('products').relatedTo(category) %}
{% set entryCount = entries|length %}

{% for entry in entries %}
    ...
{% endfor %}


How to get data from a Global Set in a plugin? I have a Global Set called "Settings" (handle = 'settings'); Within that I have a text field called "Address" (handle = 'address').

I have a function in my Plugin and I'd like to get the Address data.

In the front-end I would write this:

{{ settings.address }}

How can I get the same information in my plugin with PHP?

I've got as far as this:

$address = craft()->elements->getCriteria(ElementType::GlobalSet);

When I var_dump this array, I can see the address string. But I can't figure out how to filter down to the address correctly.

Thanks

You can use the GlobalsService service available with craft()->globals like so:

// Get the settings global set
$settings = craft()->globals->getSetByHandle('settings');

// Access the address field
var_dump($settings->address)

Or you could use ElementCriteria as you suggested:

// Get the GlobalSet element critera
$criteria = craft()->elements->getCriteria(ElementType::GlobalSet);
// Set the handle you want
$criteria->handle = 'settings';
// Find the settings set
$settings = $criteria->first();

// Access the address field
var_dump($settings->address)

You can access all fields on the $settings variable using this synthax.

Mario


How do I access an asset field in the 'onSaveEntry' event? I'm listening on an entries save event with:

craft()->on('entries.saveEntry', function(Event $event) {
  //$event->params['entry']); -> passes to function
});

How can I assess assets that are also part of that saved entry?

$event->params['entry']->getContent()->{fieldname} doesn't give me the array with information I was hoping for.

This gives you an EntryModel:

$entryModel = $event->params['entry'];

This will give you an array of AssetFileModels:

$assetFileModels = $entryModel->myAssetFieldHandle

You can loop through them like so:

foreach ($assetFileModels as $assetFileModel)
{
    $url = $assetFileModel->getUrl();
}


Order PDF in back-end error with Globals I have created a PDF template for orders and this works fine on the front-end. However, when I click to Download  PDF through the admin panel in an order. I get an error that:
Variable "companyInfo" does not exist

companyInfo is a global field - I am using it to populate the company invoice details like so;
{{ companyInfo.companyName }} (there are several of these).

Any ideas why this is an issue on the back-end and not the front-end and how to resolve?

Since the templates are rendered on the server and not in a regular http request (in the front end templates), the globals are not loaded automatically, into the global twig namespace.

You can still access your global set and use it as you usually would by setting it to a variable. You can do so like this:

{% set companyInfo = craft.globals.getSetByHandle('companyInfo') %}

You can then do:

{{ companyInfo.fieldNameHere }}


German locale & English CP language resulting in disappeared entries I have just one locale (German, de). Now, I've changed my CP language to English ('defaultCpLanguage' => 'en' in general.php).

But now, all my entries have disappeared in the CP (Craft Pro 2.4.2670).

What am I doing wrong?

Thank you very much for your help!
MISc

From the docs:

  The default language that the Control Panel should be rendered in, for users that haven’t specified their Preferred Locale.

defaultCpLanguage is only applied for users that don't have a Preferred Locale set in their user profile.

Your entries disappeared because you don't have any entries created in the English locale, yet.  You might need to enable en under the Section's settings before that's an option.


Show matrix fields based on quantity [Sprig] I'm using Commerce to sell tickets to an event and need to get the names of each person. I would like to do this via a Matrix field, showing fields based on the quantity selected.
I followed along with the new Sprigform tutorial, which covers part of it but it has an add button as opposed to a dropdown.
This is what I have so far, but on changing the select value the input field disappears, so maybe I'm just looping over things incorrectly?
{% set qty = qty ?? [['']] %}
<select sprig name="qty">
  {% for i in range(1, 5) %}
    <option value="{{ i }}" s-val:qty="{{ i }}" {{ qty == i ? 'selected' }}>{{ i }}</option>
  {% endfor %}
</select>

{% for guest in qty %}
  <input sprig type="text" name="options[guests[{{ loop.index0 }}][0]]">
{% endfor %}

Would appreciate any pointers!

The problem that you expect your qty variable to be an array of guests and initialize it like that, but once you set a quantity it will be an integer, so the loop won't work correctly. See this line:
{% set qty = qty ?? [['']] %}

This initializes qty to an array containing another array containing an empty string (by the way, why do you need the nested array? Wouldn't a simple array of guest names suffice?). But once you select a quantity, the qty variable will simply be an integer (or numeric string, not sure). A for-loop expects an iterable (array or iterable object), so your for-loop is invalid:
{% set qty = 3 %}

{# this is invalid #}
{% for guest in qty %}
    {# this will never be reached #}
{% endfor %}

Instead of qty, what you want is a guests variable which holds a number of items in your expected format (in this case, arrays of strings) corresponding to the selected quantity. For example:
{% set qty = qty ?? 1 %}
{% set guests = range(0, qty - 1)|map(i => ['']) %}

{% for guest in guests %}
  <input sprig type="text" name="options[guests[{{ loop.index0 }}][0]]">
{% endfor %}

Note this will reset the values in the guest input fields whenever the quantity is changed. You'd need to retrieve the current inputs as well to set the current values of the input fields as well.


Create nested categories with Feed Me plugin I'm trying to import nested categories. My JSON is like:

[{"title":"Title""location":[{"Florida":["Key West"]}]}]

I want to be created "Florida" category and nested child "Key West"
But plugin offers me to import that like this:
https://d.pr/free/i/NvgGOm

Only "Key West" category will be created.

Is it possible to import nested categories? What is the right JSON structure for that?

Additional info:

Plugin version: 4.1.2
Craft version:3.3.18.4

I would approach this by splitting up the work into two tasks:

Import the categories and their parent/child relationships first
Import the entries with a flat listing of categories (just the cities is okay).

The structure of the JSON for importing the categories would be something like this:

[
  {
    "state": "Florida",
    "city": "Key West"
  },
  {
    "state": "Florida",
    "city": "Orlando"
  },
  {
    "state": "Florida",
    "city": "Jackonsville"
  },
  {
    "state": "Florida",
    "city": "Miami"
  },
  {
    "state": "Florida",
    "city": "Tampa"
  },
  {
    "state": "Texas",
    "city": "Austin"
  },
  {
    "state": "Texas",
    "city": "Dallas"
  },
  {
    "state": "Texas",
    "city": "San Antonio"
  }
]

I know this is redundant but it works better with how Feed Me loops over the category elements and creates the category if it doesn't exist and then assigns the parent if (and creates it if it doesn't exist).

You want the mapping to look something like this:

When you go to import your entries you only need to include a flat listing of the category titles (cities) and then they'll be mapped to parent state.


File upload - maximum upload size of 0 B I just upgraded Craft to the latest version, and this error now shows up.

The file “myfile.jpg” could not be uploaded, because it exceeds the maximum upload size of 0 B

Any fix ? Everything worked fine before the update.
Thanks !

I had the same problem, changing post_max_size in php.ini to something other than 0 (I used 8M) did it for me.

I'm not sure why this works: php.ini says a value of 0 should disable the limit altogether, and this was never an issue on my other Craft installs. Perhaps a bug?


How can I use aliases in a module / plugin? I'm writing a module that needs to grab the path of a file.

I know I can use {{ alias('@webroot') }} in the templates to get the root web folder. Is there a way I can do this in module/plugin land?

I've been looking for PHP constants or similar, and landed on $fullpath = CRAFT_BASE_PATH . '/web/' . $filename; which doesn't feel great.

Cheers!

Would it be an option for you to use

Craft::getAlias('@webroot');

Yii2 Aliases


Route token that includes forward slashes I'm setting up a route in control panel. I'd like to use a token that is similar to asterisk but involves forward slashes. Here's an example:

I want to route everything from site.com/blog/* to a single template.
If I route site.com/blog/some-uri-identifier , it works fine and I'm able to get "some-uri-identifier" in my template (using slug option).
I need to route site.com/blog/some/uri/identifier-long-name and still go to the same template + get "/some/uri/identifier-long-name" in it.

Thanks!

The CP route settings don’t have a token for matching multiple URI segments. However you can pull it off from craft/config/routes.php instead:

return array(
    'blog/(.+)' => 'path/to/template',
);

You’ll be able to access whatever was captured by (.*) from your templates via matches[1].


Query Entries based on current Entry's related Entries I'm wanting to show related articles based on the current article's related Markets.

How do I get the current markets and filter relevant posts based on those related markets? This is what I have so far but doesn't seem correct.

{% set allMarkets = entry.relatedMarkets.all() %}
{% set currentID = entry.id %}

{# Get Related Articles Based on Markets #}
{% set expertBlog = craft.entries()
    .section('blog')
    .orderBy('postDate desc')
    .expertOpinion(true)
    .relatedMarkets([allMarkets])
    .id(['not', currentID])
    .limit(3) %}

Enjoyed this article? Keep reading more expert insights...

          {% cache %}
          {% for entry in expertBlog %}
              {% set columns = 'w-100 w-50-m w-33-l w-33-xl' %}
              {% include "_partials/lists/blog/_cards_blog_article_authors_expert.twig" %}
          {% endfor %}
          {% endcache %}

You're close!

In your entry query, change .relatedMarkets([allMarkets]) to .relatedTo(allMarkets) (use relatedTo instead and you don't need array brackets).

Final code looks like:

{% set allMarkets = entry.relatedMarkets.all() %}
{% set currentID = entry.id %}

{% set expertBlog = craft.entries()
    .section('blog')
    .orderBy('postDate desc')
    .expertOpinion(true)
    .relatedTo(allMarkets)
    .id(['not', currentID])
    .limit(3)
%}


Why does MultiAdd think I am not sending any items? I am trying (and failing miserably) to send multipule products to my cart using MultiAdd

I can see the data getting sent - it looks ok? I get a 200 response back, so I know its working, but I'm always getting this error:

{"error":["No items?"]}

Here is what my form data looks like:

action:multiAdd/multiAdd
redirect:commerce/cart
qty:1
CSRF:gQBSJxqkMIQChG3r6TJ4Dz81dgtZuh4yrv_ZUDTp|ecc547c00a45b29a506b9f4c7904e62add62d37a
myProductOne:174
myProductTwo:64
myProductThree:189

My product template looks like this:

<form>
<input type="hidden" name="action" value="multiAdd/multiAdd">
...

<select name="myProductOne">
    <option value="174">Value</option>
</select>
...
<select name="myProductTwo">
    <option value="64">Value</option>
</select>
...
<select name="myProductTwo">
    <option value="189">Value</option>
</select>

I am using jquery validator to validate my form; I'm handling the submit like this:

...
 onFormSubmit(function (response) {
     console.log(response);
 });

var onFormFormSubmit = function (callback) {
    var data = $('#campRegistrationForm').serialize();
    data['CSRF'] = $('input[name="CSRF"]').val();

    $.ajax({
        'type': 'post',
        'contentType': 'application/x-www-form-urlencoded; charset=UTF-8',
        'cache': false,
        'data': data,
        'url': '/actions/' + $('input[name="action"]').val(),
        'dataType': 'json',
        'timeout': 50000
    }).done(function (response) {
        callback(response);
    }).fail(function (error) {
        // Total fail.
    });
};

I see on the plugin's page, I need to have markup like this:

<select name="items[{{ loop.index }}][options][color]">

I believe it all boils down to the fact I'm not doing this correctly:

{% for product in craft.commerce.products.find() %}
...
{% endfor %}

Since I am selling 3-5 different products on any given page, I can't loop through all of my products as I only need specific ones at any given time. I'm not sure how to set that up correctly.

EDIT

Thank you so much!

To help others, here is what each of my select input(s) look like:

<select id="myProductOne" name="items[1][purchasableId]">
<input type="hidden" name="items[1][qty]" value="1">
...
<select id="myProductTwo" name="items[2][purchasableId]">
<input type="hidden" name="items[2][qty]" value="1">

...

Ok you're getting there, but your form syntax is a bit off.  MultiAdd needs you to post a form with an array named items.

Here's an example of precisely the sort of thing you need to post:

action
multiAdd/multiAdd

items[1][purchasableId]
854
items[1][qty]
0

items[4][purchasableId]
857
items[4][qty]
1

items[5][purchasableId]
858
items[5][qty]
0

items[6][purchasableId]
859
items[6][qty]
1

redirect
/cart

So you're posting items, each keyed by an index value to keep the attributes together.  This can be anything really.  You just have to send for each the purchasableId and a qty (if you send 0 the item will just be ignored).

items[whatever][purchasableId]
items[whatever][qty]

Just send as many of those pairs as you need, exactly like that (i.e. it must be called items, and the word whatever you can replace with an arbitrary key).  Each pair must have a value for purchasableId and qty (so for the first example the purchasableId is 854 and the qty is 0, so this one won't be added to the cart).

(You don't need to use the options syntax to add products as such, that's only required if you're using options with those products.  Maybe get your form working without options first, so just adding products) and then we can add them if you need them!)


Entries with different styling Is it possible to build categories with a list of entries that have different styling, like

{% for entry in entries %}
    Row 1 - Entry 1 - full-wide
    Row 2 - 3 entries with (1/3 width of each)
    Row 3 - 2 entries (1/3 and 2/3 width)
    ....
{% endfor %}

Thank you

I'm not sure how dynamic you need this to be. One way would be to set an order of classes to loop through with Tiwg's Cycle function. This would go through each class in the array, in a cycle.

{% set classes = ['full-wide', 'third-wide', 'third-wide', 'third-wide', 'half-wide', 'half-wide'] %}

{% for entry in entries %}
    <div class="{{ cycle(classes, loop.index0) }}">
        {# output entry #}
    </div>
{% endfor %}

If you need a bit more flexibility you could use conditionals querying the loop variable to determine where you are in the output.


Exporting/Importing Fields Is there an easy way for Importing/Exporting Fields?

I'm just working on a selection of Global fields that I'd like to be able to add for each client site. These would be things like Contact Details, Social Links, etc.

EDIT: I created FieldManager for this!

I always write migrations to do this.

Here's and example for changing the label of a field.

You could, of course, do whatever you want - modify fieldlayouts, add/modify/remove fields, etc.

UPDATE

Nowadays I use the Schematic Plugin to transfer all kinds of settings (fields, fieldlayouts, settings etc.) over different setups.


How do I only display list of categories at certain level of parent category that have entries I try to explain you semantically what I want to achieve here. I couldn't make it shorter. Sorry.

Navigation will be constructed from .level(1) categories.
At "site.com/firstLevelCat" I want to display list of populated .level(2) categories like this

site.com/firstLevelCat/secondLevelCat
site.com/firstLevelCat/secondLevelCat2
site.com/firstLevelCat/secondLevelCat3

At "site.com/firstLevelCat/secondLevelCat" I'd like to display list of .level(2) categories along with a list of .level(3) categories like this

site.com/firstLevelCat/secondLevelCat/thirdLevelCat
site.com/firstLevelCat/secondLevelCat2/thirdLevelCat
site.com/firstLevelCat/secondLevelCat3/thirdLevelCat

I intend to build it up to 4th level.

If I understand your issue correctly, try changing

{% set topLevelCats = craft.categories.relatedTo({ sourceElement: entryIds }).group('filter').level(1) %}
{% set secondLevelCats = topLevelCats.slug(secondSeg) %}

to

{% set topLevelCats = craft.categories.relatedTo({ sourceElement: entryIds }).group('filter').level(1) %}
{% set secondLevelCats = craft.categories.slug(secondSeg).level(2) %}


How to get all images from entries including Matrix field I have a photo gallery that pulls in all entries and then finds the images within them and then displays them along with links to the entries that used that image.
Except, it's not pulling in the ones that are in a matrix field named extendedContent with a block type of insertedImage and a asset field named image.
A simplified version of the code I'm using is:

{% set content = craft.entries({
    section: 'news,information,events',
    with: ['imageGallery','extendedContent.insertedImage:image']
}) %}

{% paginate craft.assets.relatedTo(content).order('elements.dateCreated desc').kind('image').limit(25) as pageInfo, usedPhotos %}

{# Loop through the array of assets #}
{% for imageGallery in usedPhotos %}
    <img src="{{ imageGallery.url }}">

    {# find all entries related to this asset #}
    {% set entry = craft.entries.relatedTo(imageGallery).order('title') %}
        {% for entry in entry %}
            {{ entry.title }}
        {% endfor %}

{% endfor %}

Added: I'm guessing the issue is that the relationship of the image in the matrix field isn't to the entry but to the block it's in?
Does that mean that it's not possible to do what I want?

I doubt there is a good solution in twig but you can fetch the entries with php.

First you have to get all used asset Ids. So you'll check in the relations table for all used assets with your 2 fields and for entries with your section ids

public function getAllAssetsRelatedToEntries(){
    // list the ids of the sections, so you need the id of news, information and events
    $sectionIds = [2, 7];
    // id of your insertedImage field
    $fieldIdMatrixContent = 6;
    // id of your imageGallery field
    $fieldIdImageGallery = 7;

    // fetches all assets that have a relation in the matrix field
    $imagesFromMatrixContent =  craft()->db->createCommand()
        ->select('craft_relations.targetId')
        ->from('relations')
        ->join('matrixblocks', 'craft_matrixblocks.id = craft_relations.sourceId')
        ->join('entries', 'craft_entries.id = craft_matrixblocks.ownerId')
        ->where('craft_relations.fieldId = :fieldId', ['fieldId' => $fieldIdMatrixContent])
        ->andWhere(['in', 'craft_entries.sectionId', $sectionIds])
        ->queryColumn();

    // fetches all assets that are related with the ImageGallery Field
    $imagesFromNormalField = craft()->db->createCommand()
        ->select('craft_relations.targetId')
        ->from('relations')
        ->where('craft_relations.fieldId = :fieldId', ['fieldId' => $fieldIdImageGallery])
        ->join('entries', 'craft_entries.id = craft_relations.sourceId')
        ->andWhere(['in', 'craft_entries.sectionId', $sectionIds])
        ->queryColumn();

    return array_unique(array_merge($imagesFromMatrixContent,$imagesFromNormalField));
}

This will return you an array of all ids, thus you can build your paginate or other queries like you want and change the sort order or include other conditions

{% set allAssetIds = craft.pFplugin.getAllAssetsRelatedToEntries() %}
{% paginate craft.assets.id(allAssetIds).kind('image').limit('30') as pageInfo, usedPhotos %}

The next step will be to search the entries for each asset

public function getAllEntriesForAsset($assetId)
{
    // list the ids of the sections, so you need the id of news, information and events
    $sectionIds = [2, 7];
    // id of your insertedImage field
    $fieldIdMatrixContent = 6;
    // id of your imageGallery field
    $fieldIdImageGallery = 7;

    $entryIdsFromMatrix = craft()->db->createCommand()
        ->select('craft_matrixblocks.ownerId')
        ->from('relations')
        ->join('matrixblocks', 'craft_matrixblocks.id = craft_relations.sourceId')
        ->where('craft_relations.targetId = :assetId', ['assetId' => $assetId])
        ->join('entries', 'craft_entries.id = craft_matrixblocks.ownerId')
        ->andWhere('craft_relations.fieldId = :fieldId', ['fieldId' => $fieldIdMatrixContent])
        ->andWhere(['in', 'craft_entries.sectionId', $sectionIds])
        ->queryColumn();

    $entryIdsImageGallery = craft()->db->createCommand()
        ->select('craft_relations.sourceId')
        ->from('relations')
        ->where('craft_relations.targetId = :assetId', ['assetId' => $assetId])
        ->join('entries', 'craft_entries.id = craft_relations.sourceId')
        ->andWhere(['in', 'craft_entries.sectionId', $sectionIds])
        ->andWhere('craft_relations.fieldId = :fieldId', ['fieldId' => $fieldIdImageGallery])
        ->queryColumn();

    return array_unique(array_merge($entryIdsFromMatrix,$entryIdsImageGallery));
}

In your template

{% set entriesForAsset = craft.pFplugin.getAllEntriesForAsset(asset.id) %}
{% for entry in craft.entries().id(entriesForAsset).order('title') %}
    {{ entry.id }} {{ entry.title }}
{% endfor %}

In total it could look like this I just did not use the paginate

{% set allAssetIds = craft.pFplugin.getAllAssetsRelatedToEntries() %}
{% for asset in craft.entries.id(allAssetIds).find() %}
    {{ asset.id }} {{ asset.title }}
    Entries for Image<br>
    {% set entriesForAsset = craft.pFplugin.getAllEntriesForAsset(asset.id) %}
        {% for entry in craft.entries().id(entriesForAsset).order('title') %}
        {{ entry.id }} {{ entry.title }}
    {% endfor %}
{% endfor %}


Form for admins to register users from the front end Is there a way to create a front-end form that would allow a user with appropriate privileges (Register users) to register new users?

What you could try to do, though I don't know if this will work, is use the same form that craft CP uses in the backend. Using Google f12 I managed to find this:

<form id="userform" class="pane" method="post" accept-charset="UTF-8" autocomplete="off" data-saveshortcut="" data-saveshortcut-redirect="users/{id}">
<input type="hidden" name="action" value="users/saveUser">
<input type="hidden" name="redirect" value="users">
{{ getCsrfInput() }}
//Forms you want user to input
<input type="submit" class="btn submit" value="Save">
</form>

The above form is the same form that Craft uses natively to register users so it might work. Obviously, your admins will require the privileges to register users.


Craft CMS - 3.6.11.1 - Why are Assets Backed Up to Temporary Storage? Since updating Craft CMS to the latest version I noticed that our uploaded files get backed-up daily to temporary storage. Uploaded files live on DigitalOcean Spaces so we have no need to back up these files to the same server Craft CMS resides on.

Files are stored on the following path: storage/runtime/temp/tfxrsolmuf/images
This caused us to go over our allotted disk space and cause the server to go down
The backup is happening daily
Using Craft 3.6.10
We use the DigitalOcean spaces volume plugin

We have isolated the issue to a crone job connected with the Remote Backup Plugin for Craft.
Commenting out the following stops the daily backup.
# /home/forge/www.example.com/craft remote-backup/volume/create
# /home/forge/www.example.com/craft remote-backup/volume/prune

I think there is an issue with trying to connect to the remote storage location.


How to create code blocks with syntax highlighting I'm deciding on the best way to have code blocks in my content. I'm doing something similar to Craft Docs. Do you have any best practices?

Currently I'm thinking about having a matrix field for the whole entry content - and then just add a Title block, a Rich text block and a Regular text with line breaks for code. I'd then use Prism.js in the frontend to format the code.

I guess I could use another field to identify language for syntax highlighting for each Regular text block. Has anyone seen a special field type dedicated for syntax highlighting? I'd love to have syntax highlighting already in the admin and also a better way to choose language type.

Thanks for any insights!

There is the Ace Freely plugin, which adds an Ace Editor Field Type that would work well in a Matrix field.


Is it achievable to route a dynamic URI with prefixed character? The goal is to have a variable(link) merged with prefix "any special character", that will not break the URL(this was pointed to my about character in URL lately, but in this question, We use "#"). So the final output would be "site.com/#variable" (in my case it is the author of an entry and a link to author's profile.

Also, I'd have to route it to get the correct template loaded. The whole reason behind is, that the current prefix would avoid of potential conflicts with other templates in case, some username will be 'index'.

So from reading your updated answer and looking at the other question you mentioned I would assume you are trying to create prefixed dynamic links that don't conflict with your routing.

For example site.com/about would link to your about page and site.com/#about would load up your custom template.

Problem

The problem with using a # for your trigger is that really this should be used for linking to internal sections on a page and with the above site.com/#about would actually just link to your index page and if you had a <div> with an id of about you'd find the scroll position at that div, so I think using a # is going to give you a lot of headaches.

Solution

Perhaps use the @ sign? if it's good enough for twitter to use then I don't think you'll have many problems using it.

So, in your config/routes.php you would have:

return array(
 '(?P<username>\@\w+)' => '_someCustomTemplate',
);

This will match anything starting with an @, assign it to username a variable in your template and load it up, I tested on the Happy Lager install and it worked like a charm, /about goes to the about page /@about goes to my custom template

So in your custom template you could have the following:

{# This will get rid of the @ #}
{% set username = username|replace({'@': ''}) %}

{% set user = craft.users.username(username) %}

If you want to change the trigger to something else, just change @ in the route expression and then in the replace filter, but that should do the trick for you and avoid conflicts!

on a side note, I replaced @ with a # and it didn't work, just went to the home page


Dynamically generating a JPG from SVG I'm wondering how I can dynamically generate a JPG fallback image from an SVG. Can image transforms be modified to handle this?

No, Craft will not be able to generate JPGs from SVGs out of the box (I tested it), but it should be relatively easy to write a plugin handling it.

As GD doesn't support SVG, ImageMagick support is a must. Craft actually does use ImageMagick, if its installed on your server – so your first step would be to check for ImageMagick support. An easy way to do that, is to use Craft's ImagesService.

From there, the actual PHP code generating the JPG should be relatively straight-forward – check this Stack Overflow thread for a concise example (not tested the mentioned code myself).

Note: Be advised that Craft actually implements all of its image manipulation through the Imagine library – I'm pretty sure Imagine would handle the generation, but if you need to work with ImageMagick directly you could do

$factory = new \Imagine\Imagick\Imagine();
$svg = $factory->open( $path );
$imagick = $svg->getImagick();

Finally, when it comes to implementing the JPG generation you have a few options – for example you could create a Twig filter:

You could also implement it as a template variable method:

...or you could even hook into AssetsService events if you needed to generate the fallback automatically.

Updated answer: The original question asks if "image transforms can be modified to handle this". The short answer is no – ideally there would be a beforeTransformApplied hook or something like that, but as of 2.3 there isn't (see this thread for reference). My opinion is that your best bet is creating a variable method or Twig filter, as outlined above.


Programmatically create a product using Craft Commerce 2? The docs for v1 mention a method craft()->commerce_purchasables->saveElement().

This is omitted in the docs for v2. Does anyone know how I can create a product programmatically in PHP?

    $product = new Product();
        $product->title = "Test Product 1";
        $product->typeId = 2;
        $product->enabled = true;
        $product->promotable = true;

    $variant = new Variant();
            $variant->isDefault = true;

    $product->setVariants([$variant]);

    Craft::$app->getElements()->saveElement($product);

With the above code I get the following error:

Call to a member function getProductTypes() on null

I know the typeId is correct, because I can output it on a product template with {{ product.typeId }}

You probably have it figured by now, but for anyone wondering, here's a complete working example.

use craft\commerce\elements\Product;
use craft\commerce\elements\Variant;

// Create product
$product = new Product();
$product->title = 'Hello world';
$product->typeId = 2;
$product->enabled = true;

// Create variant
$variant = new Variant();
$variant->title = 'hey';
$variant->sku = 'hey';
$variant->price = 123;
$variant->stock = 5;

// Save product with variant
$product->setVariants([$variant]);
Craft::$app->elements->saveElement($product);


Model validation not run when using EntriesService saveEntry method Currently i have to validate my model before saving because of some custom validation rules setted on the model which won't run when using the EntriesService saveEntry method.

This causes a two step validation when errors arise, first you get the custom validation errors and after that if there is still something wrong you get the "base" validation errors.

Is this a normal behavior?

$model->validate();

After that i am saving the model like so:

$result = craft()->entries->saveEntry($model);

Custom rules on model:

public function rules()
{
    $rules = parent::rules();
    $rules[] = ['state', 'validateState'];
    $rules[] = ['vacancyId', 'validateId'];
    //$rules[] = ['vacancyId', 'numerical', 'unique' => false];
    $rules[] = ['office', 'validateOffice'];
    $rules[] = ['sector', 'validateSector'];

    return $rules;
}

Why are the custom validation rules not evaluated on the saveEntry method?

It's normal behavior... EntriesService->saveEntry() never calls validate() on the model directly, but does call validate() on the EntryRecord and if there are errors, add it back to the model and return.

So if you want to run custom validation rules before calling saveEntry you'll need to do that yourself and respond accordingly.


Using the coupon code from Craft Commerce site I got this code off of Craft Commerce, I had caught an error on the site previously so I'm thinking there might be an error here? I've put it in my file but when I input anything in the form I don't have any response of any kind. I don't get an error message or success message, it just redirects back to the cart and the pricing also remains exactly the same. Thanks!

<form method="POST">
     <input type="hidden" name="action" value="commerce/cart/updateCart">
     <input type="hidden" name="redirect" value="store/cart">
     {{ getCsrfInput() }}
     <span class="{% if cart.getError('couponCode') %}has-error{% endif %}">
     <input type="text" name="couponCode" class="{% if cart.getError('couponCode') %}has-error{% endif %}" value="{{ cart.couponCode }}" placeholder="{{ "Coupon Code"|t }}">
     </span>
     <input type="submit" value="{% if cart.couponCode %}Change{% else %}Apply{% endif %} Coupon"/>
</form>

I had this problem and the cause was that I was doing this in the base template:

{% set cart = craft.commerce.carts.cart %}

When I should be doing the following:

{% if cart is not defined %}
    {% set cart = craft.commerce.carts.cart %}
{% endif %}

The reason behind is that the cart object in cart.getError function was always being initialized instead of getting the cart from the POST response.


Craft 2 to Craft 3 upgrade: User Photos not migrated to User Accounts I followed the instructions in the docs at https://docs.craftcms.com/v3/changes-in-craft-3.html#user-photos.

I can browse the User Photos in the User Photos Asset Volume in the Control Panel. However, the User Photos are not linked to their respective User Accounts. I noticed that in the C3 craft_users table the photoId col is NULL. I can add an asset ID manually and the User Photo displays in the User Account in the CP.

I can upload new User Photos in User Accounts in the Users section of the CP.

How can I link the original Craft 2 User Photos to the User Accounts (ca. 100) in Craft 3?

The migration should have taken care of that. The only scenario where it's not a bug I can imagine is if you ran the migration on a staging server that did not have the actual user photo files and then pushed the DB to live server. If that's not the case, can you get in touch via support@craftcms.com?


Loop through all possible options of a Dropdown-field I'm currently trying to create a for-loop that loops through all options of a dropdown field created in Craft.

I have a field called "Season", with the possible options to choose from being "2015/16" and "2016/17". What I'm trying to do now is to create a loop that would loop as many times as there are options available in that field.

I'm thinking of something like this:

{% for option in fields.season %}
    ...code...
{% endfor %}`

Is there a way to accomplish this within Craft?

{% for option in entry.dropdownFieldHandle.options %}

{{ option }}

{% endfor %}

That should be it :)

{% for entry in craft.entries.section('sectionname') %}
  {% for option in entry.dropdownFieldHandle.options %}

{{ option }}

  {% endfor %}
{% endfor %}

Use the above if it is only one page

{% set myArray = [] %}

{% for entry in craft.entries.section('sectionname') %}
  {% for option in entry.dropdownFieldHandle.options %}
        {% set value = option %}

        {% set myArray = myArray|merge([value]) %}
  {% endfor %}
{% endfor %}

And loop over that variable , better to load 1 variable as array if you need it over multiple pages. Just make sure all pages have access to this variable (or create a macro for it)


How do you display a user's User Group? This seems simple, but I cannot get it to render -- how do display a user's User Group? Assuming I set the user in segment 2:

{% set thePartner = craft.users.username( craft.request.getSegment(2) ) %}
This Is My User Group: {% ???? %}

The UserModel has a getGroups() function which:

  Returns an array of
  UserGroupModel
  objects that the user belongs to.

Since a user can belong to multiple usergroups, you have to loop through the array containing them:

{% set thePartner = craft.users.username( craft.request.getSegment(2) ) %}

# Loop through array of UserGroupModels #
{% for group in thePartner.getGroups() %}
    # Print name of current UserGroupModel #
    {{ group.name }}
{% endfor %}

If you are sure the user only belongs to one group, you can fetch the first UserGroupModel from like this:

{% set thePartner = craft.users.username( craft.request.getSegment(2) ) %}

# Get first UserGroupModel #
{% set group = thePartner.getGroups().first %}

# Print name #
{{ group.name }}


Accessing plugin settings in template How can I access plugin settings in the template?

I have config.php file defined in plugin directory and i want to access these values (or their overwritten values) in Twig templates.

I tried {{craft.pluginHandle.getSettings}} but it didn't work, it throws an error that such a method does not exist.

This should do it:

craft.app.getPlugins().getPlugin('pluginHandle').getSettings()


Building relationships I am currently working on a project in EE that involves food delivery services and have run into a block. The project is about users subscribing to a plan and receiving a different dish every day of the week. During signup, users select their meat preferences and any items they're allergic to.

On the food side, when dishes are added, the type of meat in them is one field and ingredients (ones that users could be allergic to) is another. There will be about a couple of hundred dishes added in total.

What I would like to do is select 2-3 types of dishes daily and have them distributed to users based on their meat preference. With EE, I can't figure out of I can create a relationship based on multiple queries (such as select users that have chosen Vegetarian AND chicken or Select Users that have chosen Chicken but NOT vegetarian.) Would this be something Craft is capable of? And What would be the best way of picking a dish and then figuring out which users it can be assigned to and then picking the second dish and assigning to the remaining users and if need be, pick a third dish to assign any users that are left over?

This is a very difficult problem. And to be honest, I'm not sure if 3 dishes will actually cover the possible combinations in the way that you're asking. Just the common dietPreferences alone could result in 63 combinations (6+15+20+15+6+1). If you add allergens into the mix the numbers get very large very quickly.

dietPreferences = ['beef', 'pork', 'chicken', 'fish', 'vegetarian', 'vegan'];
allergens = ['dairy', 'peanuts', 'gluten', 'shellfish', 'etc', 'etc'];

I think that you will need to reduce the combinations to something like ['redmeat(including chicken)', 'redmeat+fish', 'fish+vegetarian', 'vegetarian', 'all']; And then always have a meat, fish and vegetarian dish that do not include any allergens. Vegans would not be supported; nor would those allergic to dairy, gluten, and other ingredients that are difficult to avoid.

As far as a CMS goes however, craft is as capable as any CMS to tackle the problem, but you would need to establish the parameters carefully first.

For more information on relationships check out the documentation for relatedTo. You might also do a search on this site for 'relatedTo', 'advanced search' and 'elementCriteriaModel'.


Asset transforms saved on S3 storage I've just set up an S3 bucket and have a transform in my template. Should these transformed images be saved on S3? It doesn't look like they are, however my template is pulling out an S3 URL:

When using a base image at http://s3-eu-west-1.amazonaws.com/rallyagency/princess-leia-princess-leia-walking-in-new-york-is-just-plain-awesome.jpeg, my template outputs this:

Note the addition of the directory _200x200_crop_center-center_75 in the path - that doesn't exist on the S3 bucket.

If I recall, they should get created on S3 and also cached locally.

But if I try to load https://s3-eu-west-1.amazonaws.com/rallyagency/_200x200_crop_center-center_75/princess-leia-princess-leia-walking-in-new-york-is-just-plain-awesome.jpeg?mtime=20141217123237 directly, I'm getting an "Access Denied" error, so it looks like you've got some S3 permission issues.


Nginx: index.php URLs still being served alongside pretty URLs For whatever reason https://domain.com/index.php?p=path/to/whatever and https://domain.com/index.php/to/whatever both still work and are not being redirected or rewritten to https://domain.com/path/to/whatever/.

We are enabling these in our CraftCMS configuration:

'omitScriptNameInUrls' => true,
'usePathInfo' => true

But they have not rectified the issue. Does anyone have a solution to this? Here are the important parts of our current Nginx.conf. I appreciate any help I can get on this.

location ~ /.well-known {
    allow all;
}

location / {
    try_files $uri $uri/ @rewrites;
}

location @rewrites {
    rewrite ^(.*) /index.php?p=$1 last;
}

location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt  { access_log off; log_not_found off; }

error_log  /var/log/nginx/error_craft_https.log error;

error_page 404 /index.php;

location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass unix:/var/run/php-fpm.sock;
    fastcgi_index index.php;
    include fastcgi.conf;
    include fastcgi_params;
}

location ~* (?:\.(?:bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist)|~)$ {
    deny all;
}

location ~* \.(?:manifest|appcache|html?|json|xml)$ {
    try_files $uri /index.php?$query_string;
    expires -1;
    access_log /var/log/nginx/access.log;
}

location ~* \.(?:rss|atom)$ {
    try_files $uri /index.php?$query_string;
    expires 1h;
    add_header Cache-Control "public";
}

location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|h$
    try_files $uri /index.php?$query_string;
    expires 1M;
    add_header Cache-Control "public";
}

location ~* \.(?:css|js)$ {
    try_files $uri /index.php?$query_string;
    expires 1y;
    add_header Cache-Control "public";
}

location ~* \.(?:ttf|ttc|otf|eot|woff)$ {
    try_files $uri /index.php?$query_string;
    expires 1M;
    add_header Cache-Control "public";
}

I fixed it by adding rewrite ^/index.php/(.*) /$1 permanent; to my server block. This will redirect all urls containing index.php and something after it to the contents after index.php.

E.g. /index.php/about will be permanently redirected to /about. Google knows that if something is permanently redirected its the same content and will only index the redirect.

There's one drawback though, because index.php is an actual file you can still access that. So you need to keep Disallow: /index.php into your robots.txt as well.


Do slugs absolutely have to be unique? I know Craft appends slugs with -1 if they already exist but I'm working on an app where the addition makes things awkward for us (we have to match the slug to a third-party service). I was under the impression they had to be unique but it seems you can edit an entry and change the slug to be the same as one that already exists.

This could be a good workaround for us, but I want to check whether it's a bug that's likely to get squashed or deliberate behaviour.

Technically it's a combination of the element's slug plus URI that is required to be unique (on a per-locale basis).

You can see the logic used and where it's enforced at the code level in ElementHelper::setUniqueURI()


Filtering/Searching fields with enumerated data (e.g. Smart Map) in an ElementCriteria model I have an ElementCriteriaModel in which I need to find elements that contain a particular value for "state", which is a property of a "Smart Map" field ($element->smartMapField->state).

Filtering after a find would be easy, but I need to do this in the ElementCriteriaModel, as I am passing it to the 'criteria' option for ElementAPI (https://github.com/pixelandtonic/ElementAPI).

UPDATE
As of Smart Map 2.3.0, this is now possible!

https://plugins.doublesecretagency.com/smart-map/filtering-entries-by-subfield-value/

ORIGINAL
Currently, this isn't possible. However, it's a popular feature request which is rising quickly on the priority list.
The current workaround (as you noted) is to simply filter the results afterward.


Creating a smart restaurant menu I'm building a website for a restaurant and I wanted to make the back-end as easy to use as possible. So I thought of a system like this.

Allergens - Contains name and icon
Ingredients - Contains allergens
Recipes - Contains ingredients and text about the dish
Menu - Contains recipes

So the concept is that they can just add as many recipes as they want. And just drag and drop/select the ingredients. And never ever worry about which allergens is present.

Thing is, I'm not sure what's the best way of achieving this. Would allergens, ingredients and recipes need to be separate entries in separate channels? Since I want to be able to attach an icon to an allergen, I guess that needs to be a channel?

Here's how I'd do it...

Create a channel called Allergens with a custom field for the icon. If the icon is an image, make it an assets field.
Create a channel called Ingredients with a custom field for the allergens. It will be of the Entries field-type and only allow the user to select Allergens entries.
Create a channel called Recipes with a custom field for the Ingredients and another custom field for the description of the dish. The Ingredients field will be of the Entries field-type and only allow the user to select Ingredients entries. The description field would probably be a simple Rich Text field.
Create a channel called Menu. If there is only one menu needed, I'd probably make it a Single. If more are needed, make it a standard channel. It'll need a custom field for the Recipes, which would be an Entries field where the user can only select Recipe entries.

There are other ways of doing it, but this would probably give you the most flexibility in the long run, and keep things simple for the users.


if statement in a template not working I am making a condition to use a certain template for a specific article category, but it's not working and giving me an error.

{% extends "_layout" %}

{% set title = category.title %}

{% block head %}
{% endblock %}

{% block content %}

    {% if category.postType=="video" or category.videoLink|length%}
        {% include 'news/hiwar.html' %}
    {% elseif category.postType=="file" %}
        {% include 'news/file.html' %}
    {% else %}
        {% include 'news/articless.html' %}
    {% endif %}

{% endblock %}

5th line: category.videoLink|length%}
Could you try to insert a space between "length" and "%"?


Site with public profile pages I'm looking to try and build a site that allows users to register an account and then add all of their social media profiles in one place, similar to addme.fun. Their profiles would then have public URLs that they could share, and it would also give them the ability to add more content and edit their profiles. Is Craft a good CMS for that?

I've built some really great projects with Craft and overall I love it, but I just want to make sure that it has all the capabilities that I'd need before I put too much time into it. Thanks, all!

Yes craft provides many tools that allows public registration and editing the profiles without a single line of php or even a plugin. Most functions are covered by the cms and even custom functions like social media support is really easy since you can extend the UserController and change the things you need.

You have the ability to create dynamic user groups, give permissions to those and restrict content on the site via twig. Like with entries you can define a field layout for every user so you could create all the fields you can create in a normal entry and give users the ability to change them in a frontend form

You have config variables and settings that allows you to send custom invitation mails and validation mails.

But you need the commercial version for this. It's not provided in the free one.


Craft 3 Module Working but Throwing Errors in web.log I'm seeing a lot of "Invalid argument" errors in the web.log for a "Multiple Option Variant" module I have running. It seems to be working just fine on the site, but curious as to what the issue might be. Do I need to put in some "guards" in the code, and if so, what would that look like?

This is the error;

[error][yii\base\ErrorException:2] yii\base\ErrorException: Invalid argument supplied for foreach() in /httpd.www/craft/modules/multipleoptionvariantmodule/src/variables/MultipleOptionVariantModuleVariable.php:52
#0 /httpd.www/craft/vendor/craftcms/cms/src/web/ErrorHandler.php(76): yii\base\ErrorHandler->handleError(2, 'Invalid argumen...', '/httpd.www/...', 52)
#1 /httpd.www/craft/modules/multipleoptionvariantmodule/src/variables/MultipleOptionVariantModuleVariable.php(52): craft\web\ErrorHandler->handleError(2, 'Invalid argumen...', '/httpd.www/...', 52, Array)

The referenced file at looks like this—and it seems to be the foreach function that's the culprit;

namespace modules\multipleoptionvariantmodule\variables;

use modules\multipleoptionvariantmodule\MultipleOptionVariantModule;

use Craft;

class MultipleOptionVariantModuleVariable
{
     public function getUniqueVariantAttributeValues($fieldName, $variants, $onlyInStock=false) {
         $addedIds = array();
         $sizes = array();

         foreach($variants as $variant) {
             $outOfStock = (($variant->stock <= 0) && ($variant->hasUnlimitedStock == false));

             if (!$onlyInStock || ($onlyInStock && !$outOfStock)) {
                 if (isset($variant->{$fieldName}[0])) {
                     if (array_search($variant->{$fieldName}[0]->slug, $addedIds, true) === false) {
                         $sizes[] = $variant->{$fieldName}[0];
                         $addedIds[] = $variant->{$fieldName}[0]->slug;
                     }
                 }
             }
         }

         return $sizes;
    }
}

This is then how that is used in the template(s);

{% set variants = product.variants %}
{% set variantColors = craft.multipleOptionVariantModule.getUniqueVariantAttributeValues('variantColor', variants, false) %}
{% set variantTypes = craft.multipleOptionVariantModule.getUniqueVariantAttributeValues('variantType', variants, false) %}

I'd take any hints on how to convert that php functionality to pure twig too. :)
That would actually be ideal.

You'll get that error in PHP when you try to iterate over a variable that isn't an array.

My guess is you'd be able to guard against it with something like:

if (is_array($variants)) {
    foreach($variants as $variant) {
    ...
    }
}


Outputting Matrix blocks with grouped values based on Entries field id This is the setup:

I have a Matrix field called Breads. There is 1 block called Bread.

Within, I have two fields:

An Entries field called Selected bread (limited to 1 entry)
A Number field called Quantity.

Lets say I have 3 rows. Row 1 and 3 have the same entry selected, but different quantities. Is there a way to group by the Bread entry id, but get the different quantities?

The goal is to consider all entries with same id as "one", and to make it easy to sum them together.

Try something like:

{% set breadGroups = entry.breads | group('bread.first.id') %}

{% for breadId, blocks in breadGroups %}

    {% set sum = 0 %}

    {% for block in blocks %}

        {% set sum = sum + block.quantity %}

    {% endfor %}

    Total qty for Bread ID {{ breadId }}: {{ sum }}

 {% endfor %}

The group filter consumes a list — in this base, an array of Matrix blocks — and produces an array of arrays where the key is the grouping parameter, and the value is an array of items from the original list for which the group criteria matches the key.

c.f. Craft docs: http://buildwithcraft.com/docs/templating/filters#group


Dynamically load a background image I realize this may not be possible to do at all. But I thought I'd go ahead and ask anyway. I'm trying to set up a "hero" image of sorts for specific entries. Here is how I have it setup currently:

Series > Series Entries

Each series entry has a series artwork entry that belongs to it.  What I'm trying to do, is have Craft dynamically add the image in based on what series comes up. However, I have it styled just right in my css and I'm using it as background-image: url(). Is it possible to have craft dynamically change it? I tried to using a for loop and putting it in hard coded in the html, but I lose the responsiveness framework of Foundation.

Edit: Code:

{{ entry.title }}

    {% endfor %}

    #hero {
        background: url(https://s3-us-west-2.amazonaws.com/bridge-     assets/photos/hero_image_blue.jpg) #074e68;
        background-repeat:no-repeat;
        background-size:cover;
        height: 200px;
        text-align: left;
        position: relative;
        width:100%;
        padding: 100px 20px 0 20px;

        @media #{$medium-only} {
            height:300px;
       }

       @media #{$large-up} {
        height:300px;
       }
    }

Edit 2:

Here is my series page which lists all the series

{% extends "_layouts/_page" %}

{% block content %}

Messages

        {% for series in craft.entries.section('series').level(1).order('postDate desc') %}

            {% for image in series.seriesArtwork %}

                   {{ series.title }}
                  {{ series.seriesDates }}

            {% endfor %}

        {% endfor %}

{% endblock %}

and the css

section.series {
    position: relative;
    top: 20px;
    display: inline;

    li {
        list-style: none;
        text-align: left;
    }

    #overlay img {
        width: 100%;
        vertical-align: top;
    }

    img {
        position: relative;
    }

   @media #{$medium-up}{

   }

    .card {
        padding: 10px;
        margin-top: -10px;

        span.series-dates {
            display: block;
            color: #0A9CC9;
            font-family: 'grota_sansregular';
            font-size: 14px;
            margin-top: -5px;
        }

        span.series-title {
            font-family: 'grota_sansregular';
            font-size: 24px;
            color: #333;
        }
    }
}

And then when you click on a series (still work in progress, just trying to get image working first),

{% extends "_layouts/_page" %}

{% block content %}
  {% for image in entry.seriesArtwork %}

{{ entry.title }}

   {% endfor %}

{{ entry.title }}

    {{ entry.body }}

Written by {{ entry.author }} on {{ entry.postDate|date('M d, Y') }}

{% endblock %}

Adding this from the comments above as a solution:

Try style="background-image:url({{ image.getURL() }})" instead, this means you would only overwrite the image and not any of the other background properties


Using CRSF, AJAX form posts, with a CDN We have a setup where we have a Contact Us page that submits a form using the plugin from P&T.
We will have quite some load on the site, so want to keep all of the GET responses in a CDN cache, CloudFront.

We have an issue where the CSRF token is of course cached in the page and so when the form is submitted by AJAX the token is invalid.

How do we ensure CSRF protection for the form and still have CDN caching enabled for the page?

I don't think you can cache that, since the tag is run server-side and rendered with template output, and will be unique on every page load. If you have content that's unique on every page load, you'd have to either ignore that page from CDN caching, or dynamically load in the unique content after page load via an AJAX call to a page that is ignored from CDN caching.


How to make a mixed field type required From this incredibly helpful validation article(s), I found that:

  AttributeType::Mixed does not apply any validation rules

Ok cool. I am using two fields that are DateTime fields, but due to a known bug, a work-around is to make the field type Mixed.

Everything is working 100% - and I can't thank the community for their help.

However, in my settings page, I would (like) to have my start date (Mixed) and end date (Mixed) fields required.

This isn't a make-or-break deal, just curious if there is a way.

MyPlugin.php

....
'myStartDate' => array(AttributeType::Mixed, 'required' => true),
'myEndDate' => array(AttributeType::Mixed, 'required' => true),
....

EDIT

Hi Brad, they are attribute settings. I've updated to show the file(s) below. Thank you for your time!

_settings.html

....
{{
    forms.dateField({
        'label': "Start Date"|t,
        'instructions': "What week do we start?"|t,
        'required': true,
        'id': 'myStartDate',
        'name': 'myStartDate',
        'placeholder': 'mm/dd/yyyy',
        'value': settings.myStartDate,
        'errors': settings.getErrors('myStartDate')
    })
}}
....

MyPlugin.php

public function defineSettings()
{
    return array('myStartDate' => array(AttributeType::Mixed, 'required' => true),
                 'myEndDate' => array(AttributeType::Mixed, 'required' => true)
        );
}

If I make the field type a DateTime, then the required works. Maybe it's all part of the same bug. If it is, that's cool. It's not a big deal I'm more curious if I'm doing something wrong for the field type since ::Mixed does not apply any validation rules.

100% untested and I haven't had coffee yet, but I think it'd be a combination of a few things.

1) Having your plugin override BaseSavableComponentType's getSettingsModel() so that it returned a MyPluginSettingsModel().

2) Have MyPluginSettingsModel override the rules method to do something like:

public function rules()
{
    $rules = parent::rules();

    $rules[] = array('myStartDate, myEndDate', 'required');

    return $rules;
}


Multiple articles with individual entries I am laying out a site which will have a newspaper style IA. There are multiple Main Sections and each section will have multiple Articles and each article has multiple entries.

The client only knows the names of the Articles and needs to create these and then subsequent start adding the  entries to each article. The articles have their own Landing Page (listing the entries) and there will be a Landing page for all Articles.

Creating the Articles as sections, with structures would have the benefits of the <nav> tag, but the layout for each entry will be the same.

Which is the easiest for the client? Setting the Articles up as Sections or as Main Categories (which they really aren't as the are simply titles for each article), or is there a better way?

PS: the Articles are like mini-books, with multiple chapters......

There are always so many ways to configure a CMS like Craft. Personally I would make:

"Articles" a Channel
"Main Sections" a Structure

Within Articles, you could have a Matrix field, which would in turn contain an Entries custom field, allowing your client to select Main Sections and sort them as content-blocks, using the drag-n-drop features of the Matrix custom field.

From the client's perspective, they would see something like this:

Let us know if that helps, I'm sure others will offer alternatives :)


Hide flagged (inappropriate) comments from comment list Craft CMS V2.
Comment Plugin: verbb comment

{% set comments = craft.comments.all({
    limit: 10,
    status: 'approved'
}) %}

{% for comment in comments %}
    {{ comment.comment }}
{% endfor %}

This query fetches all approved comments including flagged (Comment marked as inappropriate) comments because flagged comment status is 'approved'.

But I want to hide flagged comments from approved comments.

You can use the isFlagged() method to only display non-flagged comments:

{% set comments = craft.comments.all({
    limit: 10,
    status: 'approved'
}) %}

{% for comment in comments if comment.isFlagged() == false %}
    {{ comment.comment }}
{% endfor %}


Sort entries by most popular I'm in charge of creating a website with a 'most popular' section.

I was wondering if there was any native way/plugin that lets me sort craft entries based on most popular?

I know Expression Engine has view tracking, I'm not sure if Craft does anything similar.

Thanks!

Depends on how you want to determine "most popular"...

If you want to calculate based on page views, then check out Ben Croker's Entry Count plugin (as Brad mentioned in his answer).

If you want your users to vote on most popular, then check out my Upvote plugin, designed to emulate Stack Exchange or Facebook "likes".


Get a named parameter value from request Yii's named parameters are available in the template. For example, for the following route configuration:

'post/<post_id:\d+>' => ['template' => 'post-entry'],

The value of post_id in my template for the request post/3 will be 3.

But how can I access it from PHP, for example from the Craft::app -> getRequest() ?

Note: I don't mean queryString parameters. QueryString parameters can be accessed using getParam('paramName').

It is passed as a parameter to your function

public function actionView($post_id){
    Craft::dd($post_id);
}

Note: your parameter must have the same name like defined in your route. You can't access it with public function actionView($postId)


Can setRouteVariables be in Services? It seems that something like

craft()->urlManager->setRouteVariables(array('calupdateResponse' => $out));

works in a Controller so that {{ calupdateResponse }} has a value, but it doesn't work in a function in a plugin's Services (no error, just no values show up in twig).

I'm wishing that a single function in Services can output a number of variables to twig for templating. What is the most straightforward way?   Is it necessary to create a function for each one in PluginVariables.php?  Then I have many functions instead of just one.  This is for a CP page, if that makes a difference.

On a related note, is it possible for twig to instantiate a plugin's model, with access to all it's properties?

Thank you!

Services are not meant for rendering templates, but for business logic, saving data, and retrieving data. The setRouteVariables method should only be used in a controller to send some information to a variable.

You can use a controller to reach out to a service for some data, then use the controller to report that data back to the view for display using the setRouteVariables function. You can skirt around this by using Variables to directly call services, using a separate variable for each service function.

  On a related note, is it possible for twig to instantiate a plugin's
  model, with access to all it's properties?

Not directly, and this shouldn't be done. It is best practice to not have views directly instantiating models, but to have controllers and services act as the middle-men. It will help keep your code testable, reusable, and readable.

From the Craft documentation:

Controllers

  Generally speaking, controllers are the middlemen between the front
  end of the CP/website and your plugin’s services. They contain action
  methods which handle individual tasks.

Services

  All of your plugin’s business logic should go in services, including
  saving data, retrieving data, etc. They provide APIs that your
  controllers, template variables, and other plugins can interact with.


Get username and email on setpassword form I am looking to make use of the users first name as well as their email address on setpassword page.

I am not seeing any way to grab those fields unless I am missing something?

Craft currently doesn't expose that user info to the setpassword template.

You could write a plugin that mimicked that portion of Craft's UsersController except returns the UserModel (or part of it) to the template and/or make a feature request to expose more of info to that template.


SQLSTATE[42S02]: Base table or view not found I am developing my Craft site locally with MAMP. Today when starting my site on localhost, I got this error:

  CDbCommand failed to execute the SQL statement: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'craft_mysite.craft_info' doesn't exist

I have replaced the /app folder with a fresh copy, but it didn't help.

Also, I can no longer log into my site: When navigating to my login page, I get the same error as mentioned above.

I have a recent database backup in /craft/storage/backups. Is there a way to get my site up and running again?

I solved the problem by setting up a new installation and then importing my backup database into that new installation. Now everything is there again and works.

I must admit I haven't found the reason why this problem occurred. But the solution was ultimately quick and easy.


How to set stability version in plugins? I've made a plugin, that I'm now trying to include in a live project, but when I try to install it via the plugin installer, I get a 500 error, and if I try to include it using composer, I get the following error:

$ composer require mustasj/expanded-search
[InvalidArgumentException] Could not find a matching version of
package mustasj/expanded-search. Check the package spelling, your
version constraint and that the package is available in a stability
which matches your minimum-stability (stable).

I've set the version to 1.0.1 in GitHub: https://github.com/mustasj/expanded-search/releases

Looks like you haven't submitted your plugin repo to Packagist yet. You'll need to do that before it's available via Composer (per the docs).

Update and additional info:
Like you mentioned in the comments, and like it's mentioned in the docs (see the Tip box here), Packagist is optional for your Craft plugin. You can totally add your plugin to the plugin store and install it via the plugin store without ever putting it on Packagist. If you use Craft's Update button in the dashboard, everything will work like you'd expect. The reason is because Craft is using its own logic (relying on Craftnet) to resolve packages. However, once you switch to running composer commands in the CLI to do your updating/installing/whatever, those packages won't be found (because they don't exist on Packagist yet) and Composer is obviously not using Craftnet's logic.

So if you want to be able to install/update your plugin via Composer, I'd recommend adding your plugin to Packagist. It honestly doesn't take that long (like 2 min maybe) and it will save you from quite a few support tickets down the road of people using Composer and having issues with your plugin's "absence".


devMode, phpdotenv variable ignored I'm using dotphpenv for environment specific config.

This works perfectly for my db config. I added another 2 environment vars for devMode and allowAutoUpdates

DEV_MODE=false
AUTO_UPDATE=false

and updated general.php

<?php

return array(

  // Default

  '*' => array(
    ...
    'devMode' => getenv('DEV_MODE'),
    'allowAutoUpdates' => getenv('AUTO_UPDATE'),
    ...
  )
);

But with that set, dev mode and auto-update are still available to production.

If I set both to false we have no problem. This is obviously a phpdotenv thing because Craft is doing what it's supposed to but if anyone can shed light I'd appreciate it.

It looks like getenv returns a string (or false if the variable is not set, but it is in this case). So you need to cast the string to a boolean value to make it work. However, (bool)'false' gives true, not false. There are two possible solutions:

Set the variable to 0 instead of false in your .env file:

DEV_MODE=0
AUTO_UPDATE=0

And then in your config:

'devMode' => (bool)getenv('DEV_MODE')

This works because (bool)'0' gives false.
Use this solution:

'devMode' => filter_var(getenv('DEV_MODE'), FILTER_VALIDATE_BOOLEAN);

This works because the FILTER_VALIDATE_BOOLEAN filter returns TRUE for "1", "true", "on" and "yes", and returns FALSE for any other value.


omitScriptNameInUrls is not working I think I've just about hit my wits end here. I'm trying to get set up on a new Rackspace server and I can't seem to get my URL rewriting to work properly. Here's what I got so far:

My Craft install is in /var/www/html.

apache2.conf

<Directory />
        Options FollowSymLinks
        AllowOverride None
        Require all denied
</Directory>

<Directory /usr/share>
        AllowOverride None
        Require all granted
</Directory>

<Directory /var/www/>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
</Directory>

000-default.conf (my vHost configuration)

<VirtualHost *:80>

        ServerAdmin webmaster@localhost
        DocumentRoot /var/www/html/www

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>

... and then within my craft install in /var/www/html

config/general.php

return array(

  '-- omitted --' => array(
    'devMode'              => true,
    'omitScriptNameInUrls' => true,
    'environmentVariables' => array(
      'siteUrl'            => 'http://-- ommitted --/',
      'fileSystemPath'     => '/var/www/html/www'
    ),
  ),
);

www/.htaccess

<IfModule mod_rewrite.c>
    RewriteEngine On

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

</IfModule>

Am I missing any configuration here? I can't access any of my entries or the admin panel without appending index.php before the path.

Any help would be greatly appreciated!

On recent Ubuntu systems (for sure on 14.04), mod_rewrite is installed but not enabled within Apache. You may just need to enable the rewrite module and restart Apache.

$ sudo a2enmod rewrite
$ sudo service apache2 restart


Craft request returns null in test, but works locally I have a search that is working locally, but not when I push it to my test environment.

I imported the database from my local environment into test, so the data should exist.

The URL for each is:

test: https://mytesturl/site/?q=test

local: http://local/site/?q=test

I set the query, which returns null/empty in test, but populates correctly locally:

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

I'm drawing a blank what could be wrong. Seems to be a config issue, but I'm not sure where to look.

Any ideas? Thanks!

This sounds similar to your issue, have a look. People provided a solution there, it apparently might have something to do with your .htaccess file.

getParam not working on live server?


Display field from one section in another section I have two sections:

Games
Publishers

Games has a field called "GamesPublisher" that is a relation (field type "Entries"), the Source is "Publishers".

In my template to show an entry from games, I want to display the default field "title" of a publisher that I assigned to the games entry in the admin CP.

{% extends "_layout" %}
{% set title = "Games" %}
{% set entries = craft.entries.section('games').limit(10).order('title') %}
{% block content %}

    {% for entry in entries %}

            {% for category in entry.GamesGenre %}{{ category.title }}{% endfor %}: {{ entry.title }} (***Put Title of Publisher Here***, {{ entry.GamesReleaseYear.format('Y') }})

    {% endfor %}

{% endblock %}

The place I want to insert the publisher's title is shown as:
Put Title of Publisher Here

Thanks all. I just started using Craft about 3 hours ago for the first time!

This is untested but, give it a try:

{% extends "_layout" %}
{% set title = "Games" %}
{% set entries = craft.entries.section('games').limit(10).order('title') %}
{% block content %}

    {% for entry in entries %}

            {% for category in entry.GamesGenre %}{{ category.title }}{% endfor %}: {{ entry.title }} {% set publishers = entry.GamesPublisher %}{% for publisher in publishers %}({{ publisher.title }}{% endfor %}, {{ entry.GamesReleaseYear.format('Y') }})

    {% endfor %}

{% endblock %}

If need be, have a look at An introduction to relations and reverse relations in Craft CMS, with examples


Search form - Passing only field params that are not empty or selected Is it possible to have a search form pass (into the search query) the field params of only fields that have been populated/selected? For example, if the following form is submitted, both q and color params are passed in the receiving template to which the form submits.
<form action="{{ url('search/results') }}">
    <input type="search" name="q">
    <select name="color">
        <option value="">Select a Color</option>
        <option value="black">Black</option>
        <option value="white">White</option>
    </select>
    <input type="submit" value="Go">
</form>

Output URL: http://mydomain.com/people/results?q=&color=
I have a search form that includes a lot of fields, so I want to only pass the params that are not empty or have been selected. This way, the URL that's passed is cleaner and less monstrous.
So in the example above, if the color dropdown isn't selected, the output URL would be http://mydomain.com/people/results?q=somequerystring

That's just the way forms work in html. If you don't want to use a POST method, (because that would make the results not URL-addressable at all), I'd recommend using an intermediary Twig template to perform a redirect based on what parameters exist - i.e., set your form action to search/process and in that template write a load of conditional statements to build up a query string to pass into a {% redirect %} tag which loads search/results.
If you don't want two templates, you could instead set your form method to POST and then in your search/results template you could conditionally perform a redirect to the same template appended with your custom query string, and use craft.app.request.method to distinguish between the request types to avoid an inifinte redirect loop.


How to fetch all assets that are in use, via a specific field We have a channel of entries which all include the same asset field.
We are trying to fetch all assets that are actively in use, ergo the assets which have been linked to any of the entries in the channel via the specified asset field.
If possible we would also like to also get the title(s) of the entries to which the asset is linked, as part of the query.
This is happening in a module (PHP) not template (Twig).
Context: gallery of photos (assets) uploaded by teams (channel entries).

You can use Relations to find assets which are related to a set of entries (i.e. used in a field of the entries). Specifically, the relatedTo parameter allows you to limit an asset query to assets that are used in a specific entry or set of entries. One caveat is that you have to load the entries which contain the assets field first (at least as far as I can tell from the documentation).
So you need to queries, one to get all entries with assets on them and one to get all assets:
$teams = Entry::find()
    // replace with the name of the section your asset field is used on
    ->section('teams')
    // replace with name of your image field; find only entries with images in your image field
    ->my_image_field(':notempty:')
    ->all();

$assetsUsedInTeams = Asset::find()
    ->relatedTo([
        'element' => $teams,
        'field' => 'my_image_field',
    ])
    ->all();

Now getting the titles of entries where the asset is used is slightly more involved. You can use the same approach, but you will probably need another query for each image to find related entries. For example:
foreach ($assetsUsedInTeams as $asset) {
    $entriesContainingAsset = Entry::find()
        ->relatedTo([
            'targetElement' => $asset,
            'field' => 'my_image_field'
        ])
        ->all();
}

Not sure about that last query, might need some adjustments to work properly. Also, those are a lot of N+1 queries, so once it's working as you want it to make sure to optimize your queries with Eager-loading and maybe add some caching as well.


Frontend Form Search Users based on Tags Context:
I'm trying to build a search form that will filter users based on Name, Skills and School. Users who have any of the search criteria should appear in my results.

Name Is a fuzzy keyword search of user.fullName

Skills Is a multiple select of tags, where any should match (if multiple are selected)

Schools Is a single select of a tag.

Problem 1:
When I search just by tags, leaving the Name field blanks, only the last tag is used to return results. So if two users were tagged with multiple tags, only the one relating to the last search term tag will be returned.

Problem 2:
It seems I can't combine the query so that I am searching not only by 'who has these tags', but also 'who's name partially matches this search' as well.

Thanks for any suggestions!

Code: Form

<form action="{{ url('search') }}">
    <input type="search" name="qName" placeholder="Name" value="{{craft.app.request.getParam('qName')}}">

    Skills
    <select multiple id="qSkills" name="qSkills[]">
        {% for item in craft.tags.group('profileSkills').all() %}
        <option value="{{ item.title }}">{{item.title}}</option>
        {% endfor %}
    </select>

    School
    <select id="qSchool" name="qSchool">
        <option value="">All</option>
        {% for item in craft.tags.group('schoolPrograms').all() %}
        <option value="{{ item.id }}">{{item.title}}</option>
        {% endfor %}
    </select>

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

Code: Results (on same page)

    {% set searchName = craft.app.request.getParam('qName') %}
    {% set searchSkills = craft.app.request.getParam('qSkills') %}
    {% set searchSchool = craft.app.request.getParam('qSchool') %}
    {% set queryParams = {} %}

    {% if searchName is defined and searchName is not empty %}
        {% set queryParams = queryParams|merge({
            search: {
                query:'fullName:*' ~ searchName ~'*',
            },
        }) %}
    {% endif %}

    {% if searchSkills is defined and searchSkills is not empty %}
        {% set skillList = "" %}
        {% for skill in searchSkills %}
            {% set skillList = skillList ~ 'profileSkills:' ~  skill ~ " OR " %}
        {% endfor %}
        {% set queryParams = queryParams|merge({
            search: {
                query:  skillList,
            },
        }) %}

    {% endif %}

    {% if searchSchool is defined and searchSchool is not empty %}
        {% set queryParams = queryParams|merge({
            search: {
                query: 'profileSchoolProgram:' ~ searchSchool,
            },
        }) %}
    {% endif %}

    {% set entries = craft.users(queryParams).group('members')
        .orderBy('score')
        .all()
    %}

    {% if entries|length %}

{{ entries|length }} results:

            {% for entry in entries %}

{{ entry.fullName }}

            {% endfor %}

    {% else %}

Your search didn’t return any results.

    {% endif %}

In order to get at the tag relationships, I think you'll need to use the relatedTo parameter instead of search. You'll still use search for the full-name search. This should solve both your problems.

The tricky part is fetching the appropriate elements to pipe into relatedTo() - you can't just send through the raw title string from the post data - you'll need to fetch the actual element ids.

Here's a very rough example. You'll need to replace 'facetFieldHandle_n` with the field handle names of your tag selector fields held against the users.

{% set facet1 = craft.tags.title(searchSkills).ids() %}
{% set facet2 = craft.tags.title(searchSchool).ids() %}

{% set params = ['and',
    { targetElement: facet1, field: 'facetFieldHandle_1' },
    { targetElement: facet2, field: 'facetFieldHandle_2' }
] %}

{% set users = craft.users.relatedTo(params).search(searchName).orderBy('score').all() %}

    {% for user in users %}

{{ user.fullName }}

    {% endfor %}


Correct way to merge craft.user field arrays and use outside the loop? I'm using preparse field plugin to limit the amount of tags a user can add to his account. I've modified the code slightly so the tags are processed as a comma, separated, list.

The plan is to integrate Selectize with the search form, so that users can choose from all available tags. As I can't use relatedTo, it'll have to involve some manipulation. I understand it isn't considered best practice to do this with Twig, but I'm not versed in PHP to build a plugin (I'm learning Python so Twig will have to do!).

The code below sets a variable to allow access to a merged array, I know there's a similar post (I'd also like to avoid duplicates, but Selectize will ignore them anyway) but I'm struggling to follow that example and use it for my requirements.

Code below:

{% set users = craft.users.group('verified') %}
{% set merged = [] %}

{% for user in users %}
  {% set tags = user.tagsSpecialismSearchable %}
  {% set specialisms = tags|split(', ') %}

  {% for specialism in specialisms %}
    {# Merge the tag arrays #}
    {% set merged = specialisms|merge(specialisms) %}
  {% endfor %}

    {# Test the output #}
    {% for specialism in specialisms %}

{{specialism}}

    {% endfor %}

{% endfor %}

{# Output the merged array #}

{% for mergedSpecialism in merged %}

{{ mergedSpecialism }}

{% endfor %}

I know I'm setting merged in the wrong place, as all it outputs is a duplicate of the last specialisms array. So how would I loop through all users and output the available tags?

I'm probably missing some conditionals to check if the user has actually set tags, so any advice in layman's terms appreciated!

Updated: Working code (Thanks @kcolls)

{% set users = craft.users.group('verified') %}
{% set merged = [] %}

{% for user in users %}
  {% set tags = user.tagsSpecialismSearchable %}
  {% set specialisms = tags|split(', ') %}

  {% for specialism in specialisms %}
    {# Check if specialism already merged #}
    {% if specialism not in merged %}
      {# Merge each specialism #}
      {% set merged = merged|merge([specialism]) %}
    {% endif %}
  {% endfor %}

    {# Test the output #}
    {% for specialism in specialisms %}

{{specialism}}

    {% endfor %}

{% endfor %}

{# Output the merged array #}

{% for mergedSpecialism in merged %}

{{ mergedSpecialism }}

{% endfor %}

For an added bonus, sort the array alphabetically:

  {% for mergedSpecialism in merged|sort %}

{{ mergedSpecialism }}

  {% endfor %}

It looks like you have a typo in your merge, and the structure of the merge is incorrect.

{% set merged = specialisms|merge(specialisms) %}

This is saying set merged to the array specialisms merged with itself.

What I am guessing you want to do is merge each specialism into the merged array, which looks like this:

{% set merged = merged|merge(specialism) %}

Note that we are merging specialism and not specialisms (no s at the end).

I'm not sure what data type specialism is, but if it isn't an array, you may need to wrap it in square brackets. This would become:

{% set merged = merged|merge([specialism]) %}

I hope this helps!


Trying to automatically add a product in Commerce I'm trying to add a product to a cart (and emptying the cart first) if a user just visits a template. My goal is to make a one-page checkout: so I want the address info on the product page itself. This is what I have so far. I thought the first line would make a cart if there is no cart yet, but it seems nothing happens. (cart.id = null)

{% set cart = craft.commerce.carts.cart %}
Cart ID is {{ cart.id }}
{% do cart.setLineItems([]) %}
{% set lineItem = craft.commerce.lineitems.resolveLineItem(cart.id, product.id, [], 1, '') %}
{% do cart.addLineItem(lineItem) %}

I tried this myself and it threw an error when there was no cart attached to the session.

I then found these two lines of code in the Craft Commerce CartController.php:

        // Get the cart from the current users session, or return a new cart attached to the session
        $cart = Plugin::getInstance()->getCarts()->getCart(true);

getCart() can be found in the Carts Service

Which lead me to try:

{% set cart = craft.commerce.carts.cart(true) %}

So if you pass in true, you force it to save the cart and thus you seem to be able to create a new (empty) cart.


Use getCriteria with OR condition on multiple fields I am filtering users in my CP by adding a new user source.
I know how to get users for specific criterias.

But in this case I want to make a OR condition on those two users fields :
$user_criteria->emailLogo = true;
$user_criteria->webLogo = true;

public function modifyUserSources(&$sources, $context)
{
    if ($context == 'index')
    {

        // LISTING USERS
        $sources[] = array('heading' => 'Stats Users');

        $user_criteria = craft()->elements->getCriteria(ElementType::User);
        $user_criteria->group = 'myMembers';

        // THIS WILL MAKE A -AND- CONDITION (I WANT A -OR-)
        $user_criteria->emailLogo = true;
        $user_criteria->webLogo = true;

        $sources['users:memberBranding'] = array(
            'label'    => Craft::t('Logo'),
            'criteria' => $user_criteria,
        );
    }
}

sorry I didn't try to do this and after trying, couldn't get it to work myself... So...

If you have flexibility and can replace your ligthswitches with a group of checkbox, this becomes a lot easier and potentially more flexible as you could add new 'types of logo' without reviewing your plugin whereas at the moment, you would need to manually add new 'types'.

So, if you can, change your ligthswitches for a group of checkbox called 'logos' for example and add 2 checkbox 'Web' & 'Email', then:

public function modifyUserSources(&$sources, $context)
{
    if ($context == 'index')
    {
    $sources[] = array('heading' => 'Stats Users');

    $user_criteria = craft()->elements->getCriteria(ElementType::User);
    $user_criteria->group = 'editors';
    $user_criteria->logos = ':notempty:';

        $sources['users:memberBranding'] = array(
          'label'    => Craft::t('Logo'),
          'criteria' => $user_criteria,
      );
    }
}

As long as a user 'has' a logo AND is an editor, they will show in your source.

If you can't change the lightswitch setup, I'm afraid I don't know how to do it and I would love to find out if you manage to get it working!


Commerce: How can I check order history to see if a product type has been purchased? I am building a plugin that grants access to a "hidden" (for lack of better words) entry. if a user has purchased a specific product type.

For example, I don't care which piece of clothing the user purchases, just as long as it was of type clothing.

How can I check the users order history to see if they have purchased a qualifying product?

Thank you for any suggestions!

First you'll need to grab the user's orders. Then you can check the product type through the purchasable.

Something like this:

{% set orders = craft.commerce.orders.user(currentUser).find() %}

{% if orders|length %}
    {% for order in orders %}
        {% for lineItem in order.lineItems %}
            {{ lineItem.purchasable.product.typeId }} {# 1 #}
        {% endfor %}
    {% endfor %}
{% endif %}

You can take that a step further by doing something like this:

{% set orders = craft.commerce.orders.user(currentUser).find() %}
{% set product = false %} {# set the condition to false by default. #}

{% if orders|length %}
    {% for order in orders %}
        {% for lineItem in order.lineItems if lineItem.purchasable.product.typeId == 1 %}
            {% set product = true %}
        {% endfor %}
    {% endfor %}
{% else %}
    {# No orders found. #}
{% endif %}

...

{% if product %}
    {# User has purchased product type at some point in time. #}
{% else %}
    {# User has never purchased product type. #}
{% endif %}


Craft 3 Element API Authentication/Login First things first: This is quite similar to this, yet different.

I'm trying to get authentication/login for Element-API for Craft 3 to work. Meaning I would like to restrict access to certain endpoints that require the client to be logged in and also (essentially, this is the question) have a way to login via the API (or a different way, but preferably over the API).

This is what I got so far:

<?php
use Craft;
use craft\elements\Entry;
use craft\helpers\UrlHelper;

function requireLogin(){
    header("Access-Control-Allow-Origin: *");
    header("Access-Control-Allow-Headers: X-Requested-With");

    if (!Craft::$app->user->isGuest) {
        // you are authenticated
    } else {
        // check params
        $loginName = Craft::$app->request->getQueryParam('loginName');
        $password = Craft::$app->request->getQueryParam('password');

        if (Craft::$app->user->login($loginName, $password)) {
            // login success
            $user = Craft::$app->userSession->getUser();
        } else {
            // login fails echo message
            $errorCode = Craft::$app->userSession->getLoginErrorCode();
            $errorMessage = Craft::$app->userSession->getLoginErrorMessage($errorCode, $loginName);
            Craft::$app->end(JsonHelper::encode(array('data' => array( ['status' => 'error','message' =>'wrong login']  ))));
        }
    }

}

return [
...

using requireLogin(); inside the transformer of the given endpoint.

Most of this is copied from the before mentioned, related link. But as I'm no PHP developer I kind of struggle getting it to work.
The error I get is the following with this code:

  Argument 1 passed to yii\web\User::login() must be an instance of yii\web\IdentityInterface, null given
  as a result of Craft::$app->user->login($loginName, $password)

I do understand whats happening and am capable of reading the error, but I'm not very familiar with yii, nor PHP. If someone could point out what needs to be done, which problems also might occur of if I'm on the wrong track or even post a working solution, I would be very grateful.

First of all passing the password and username as query strings is one of the most insecure things you can do. It would highly suggest you to not do that unless you want to expose your accounts to everyone with minor knowledge.

Furthermore you are mixing Craft 2 with Craft 3. There is no userSession in Craft 3. I don't want to post a code snipped that would work with the way you are trying since would could eventually copy it without knowing the harm it might cause.

In the end: you should either create some kind of access token, don't pass the params via get request or do something similar. Globally passing sensitive data via url is not clever


Send Password Reset Email to all users at once I have a bunch (about 3000) of imported users from a website, which is currently on a redesign.
When the site is finished, I would like to send an email to all users,
saying that the site is relaunched, has a new structure ect. and therefore they have to set a new password.

I found nothing in the Craft settings, as well in the forum.

Do I have to write a plugin?
Or can I achieve this with the Sprout Email plugin?
I saw, there is a event "When a user logs in".

This could also work for me: a users logs in and gets automatically
to the a page to set a new password.

I'm not sure if the Sprout Email plugin can do anything to help you or not, but I can think of a few options that would involve simple, custom plugins.

Every user has a "Require a password reset on next login" that an administrator can set from the CP under their settings.  You probably don't want to do that manually for 3,000 users, but a simple plugin (or a simple SQL query) could set the passwordResetRequired column in the craft_users table in the database to 1.

If you wanted to send an email and include a password reset link in that email ahead of time, a plugin would change that column to 1 for all users and follow similar logic in the UsersController for getting the password reset link and include that in the email body that you'd send to every user programatically.