Entry not saving when Redactor bold I'm having a weird issue with the Rich Text Editor (Redactor -> simple.json, only "bold" and "italic") on newly added fields and only ONE (that i know of) older field.
Every time i add a "bold" format and then save the entry, it goes back to its previous state and never actually saves it.

If there is a bold word in that block and i try to add / modify other blocks, nothing saves either.

If i don't use "bold" in THAT specific field or newly created ones, it all works perfectly. Even the "italic" option works. If i use "bold" in an other older field, it works perfectly.

It used to work like a charm, no updates has been done since (i did it afterwards to try and solve it: nothing changed).

No trace about that in the craft logs.

Any idea what's the problem? Or how to debug further?

PS: That one is on Craft 2.7.2!

Looks like this was a ModSecurity tripping up the contents of the particular Redactor field in the POST request.

The nuclear option for a fix is to disable ModSecurity.  The more nuanced fix is to find the particular rule that is tripping up the request and either disable it or to modify it so it allows that content through.


Custom status based on chosen payment gateway We're working on our first Craft Commerce site and are in need of your good advice. This might be related to a similar question (Craft Commerce: send notification emails when setting status dynamically?) but I can't comment there.

We have a Craft Commerce setup with two payment gateways for credit card and bank transfer (Manual payment). We'd like to achieve the following scenario:
1) If the customer pays with Credit Card, the order status is "Approved". They receive an email with the invoice and confirmation.
2) If the customer pays via bank transfer, the order status is "Pending" and they receive a different email.

We can't find any clues on the docs on how to pass a specific status on checkout. Is there anything obvious we might be missing? I appreciate any input. Thanks!

Listen for the onBeforeOrderComplete event and do something like this (replacing values to match your setup).

craft()->on('commerce_orders.onBeforeOrderComplete', function($event){
    $order = $event->params['order'];
    if ($order->paymentMethodId == 2)
    {
        $order->orderStatusId = 3;
    }
});


Using variable references to fields in a template I have a situation where Matrix within Matrix would be ideal, but instead we've ended up with a Matrix row that has pairs of fields up to a maximum of 6:

quote1
attribution1
…
quoteN
attributionN
…
quote6
attribution6

Rather than work through each pair…

{% if matrixBlock.quote1|length %} {# quote 1 stuff #} {% endif %}
…
{% if matrixBlock.quote6|length %} {# quote 6 stuff #} {% endif %}

…I thought I might be able to use a variable reference to numbers 1 to 6:

{% set quotes = [1, 2, 3, 4, 5, 6] %}

{% for n in quotes %}
    {% set nText = 'quote' ~ n %}
    {% set nCite = 'attribution' ~ n %}

        {{ matrixBlock.nText|md }}
        {{ matrixBlock.nCite }}

{% endfor %}

…but although {{ dump(nText) }} confirms the reference string is being parsed correctly, the string is clearly invalid as a field reference.

Is there a way to get this done to achieve a nice terse template (not the end of the world if I can't)?

I have a sense that Twig's attribute function might help, but I can't join the dots.

Figured it out:

{% for n in [1, 2, 3, 4, 5, 6] %}
    {% if attribute(matrixBlock, 'quote' ~ n)|length %}

        {{ attribute(matrixBlock, 'quote' ~ n) }}
        {{ attribute(matrixBlock, 'attribution' ~ n) }}

    {% endif %}
{% endfor %}


Sales prices on items Is it possible to have both the standard price and sale price visible on the items tiles on a website?

I would like to have both prices visible and wanted to know if this was doable .

Yes simple use

{{variant.price}}

Or

{{variant.salePrice}}


AttributeType::Number giving validation error "Must be an integer" So I have a model attribute attributeName with an AttributeType::Number

I haven't implemented any personal validation rules yet, however when I run:
model->validate(),
its giving me a "attributeName must be an integer" error.

Is this just the default validation rule of the AttributeType::Number?  and if so, is there anything I can do to make it accept floats?

I am trying to use this attribute for a price, I should note.

CNumberValidator has an integerOnly attribute, so I tried setting 'integerOnly'=>false in the attribute declaration, to no avail. Not sure if its relevant, I think I might be grasping at straws. Any help would be greatly appreciated!

Not really documented anywhere, but AttributeType::Number can accept an array of options, including min, max and decimal.  You're looking for the last one.

AttributeType::Number => array('min' => 0, 'max' => 10, 'decimals' => 2);


Cloudflare CDN integration Is it possible to integrate assets with Clouflare CDN service ? In docs only Amazon, Google and Rackspace are referred.

Cloudflare's CDN isn't a true CDN like Amazon, Rackspace, or Google.

With Cloudflare you host your assets on the server and Cloudflare then automatically keeps a cached copy of that.

In other words, you don't upload to CloudFlare, CloudFlare downloads from you.

So on Craft, simply use the "Local folder" source type.


Can I choose a language for the translate filter? So I've built a language switcher as per this answer.

I want the text for each link to be in the native language, for example I want the link to the English locale to say "Read this page in English" and the link to Spanish locale to say "Leer esta página en Español" etc.

However using the |t filter uses the locale that you're currently on, so if I'm on Spanish it says "Leer esta página en English".

Is there a way to pass in a parameter or something to say, for example, |t(Spanish).

Thanks!

Yes. You can see all of the arguments the |t filter supports by looking at the docs for Craft::t(), the function that |t maps to. Its $language argument defines the target language translation to use. So in your case you could do this:

{{ "Leer esta página en Español"|t(language="es") }}


Creating an archive page with full year and month list Trying to create an archive page for each of my blog types within Craft. The page sorts by year and by month. (year and month are coming from my routes in this code.)

By using the following, I can print out each month with posts and the number of posts the month has. My problem is that I also need to print out the months with no post count and can't seem to figure out how to do that.

{% set entriesInYear = craft.entries.section('pressReleases').limit(null).after(year).before(year+1) %}

{% for month, entries in entriesInYear | group("postDate|date('F')") %}

{{ month }}&nbsp;({{ entries|length }})

{% endfor %}

That will yield me a printout of:

April (7)
March (4)
February (1)

I just need to also print out all the months in between with a (0) indicator.

{% set groupedEntries = entriesInYear | group("postDate|date('F')") %}

Will give you an associative array where the keys are the months, and the values are the entries for that month.

Now you need to loop over all the months, not just the ones in the groupedEntries.

Make an array of all the months.

{% set allTheMonths = ['January', 'February', 'March', ... 'December'] %}

Make an array of all the months that have entries (twig's keys filter)

{% set monthsWithEntries = groupedEntries | keys %}

Loop over the months (all of them), and output either the number of entries (groupedEntries[month]|length) or 0

{% for month in allTheMonths %}
  {% if month in monthsWithEntries %}

{{ month }}&nbsp;({{ groupedEntries[month]|length }})

  {% else %}

{{ month }}&nbsp;(0)

  {% endif %}
{% endfor %}


Is there a way to delete all entries in a section? I've ended up with loads of duplicate entries after a botched import job.

Is there an easy and safe way to delete all entries in a section, so that I can start over again?

If you delete the section, that will delete all the entries in the section as well.


Plugin Development - Template Resources? I'm in the middle of creating a plugin that needs a template to display information stored in some records when the user clicks this in the CMS sidebar.

I've managed to get the template to appear (Yay!) And I've been looking at other plugins with regards to styling / structure of these pages.

A lot of them are extending and using classes that appear within Craft.

Is there a reference to this anywhere? Such as a class / styleguide or any where I can find out a bit easier what blocks etc are used?

Thanks

No such reference currently exists. Your best bet is to backwards-engineer what you see in the control panel.

Since the makers of Craft do such a great job of "eating their own dog food", they've made sure that most of their CSS classes are fairly generic and reusable. So if you see an element that you want to imitate (ie: a button), just inspect the element, and copy its classes.


Create structured object from query results I'm trying to create a list of countries with a sublist of territories per country based on their existence in the same record. The following is shorthand pseudocode to illustrate:

    locations =>
         United States =>
             California
             Massachusettes
             New York
         France =>
             Lille
             Marseille

Here is my code so far:

   {% set allEntries = craft.entries.section('projects').limit(2000) %}
   {% set countries = allEntries|group('country') %}
   {% set country_arr ={} %}

   {% for country, entriesInCountry in countries %}

       {% if not attribute(country_arr, country) is defined %}

         {# Add country to list, if unique #}

         {% set country_arr = country_arr | merge([country]) %}

       {% endif %}

       {% for entry in entriesInCountry %}

          {# Somehow add the entry.state here as a property or sub-object of the country, if unique #}

       {% endfor %}
  {% endfor %}

Definitely not the most efficient way to do this (it'd be cleaner and more efficient with PHP), but assuming you have  "projects" section that has a "country" Plain Text field and it also had a "state" Plain Text field and you wanted to group projects by country and then state, something like this should work:

{% set countryArr = {} %}

{# grab all projects #}
{% set allEntries = craft.entries.section('projects').limit(null) %}

{# group them by country #}
{% set countries = allEntries|group('country') %}

{# Build the nested array structure #}
{% for country, projects in countries %}
    {# if it's a new country, add it to our structure #}
    {% if countryArr[country] is not defined %}
        {% set countryArr = countryArr|merge({(country):[]}) %}
    {% endif %}

    {# loop through all of the projects in that country #}
    {% for project in projects %}
        {# see if we have a record for the state yet #}
        {% if project.state not in countryArr[country] %}
            {# because twig isn't great with multidimensional arrays #}
            {% set tempArr = countryArr[country] %}
            {% set tempArr = tempArr|merge([project.state]) %}

            {# merge back into our main structure indexed by country #}
            {% set countryArr = countryArr|merge({(country):tempArr})  %}
        {% endif %}
    {% endfor %}
{% endfor %}

{# output our structure #}
{% for country, projects in countryArr %}

{{ country }}

                {% for project in projects %}

{{ project }}

                {% endfor %}

{% endfor %}


ContactForm Plugin - Where does the email source come from? Trying to find out where the source email comes from with the ContactForm Plugin. The plugin is perfect and saved me a lot of time, so thank you guys!

Alas, my client is getting emails from the site in my name, yet I can't see where this is being sourced form - except possibly my profile page.

Is there a place I can configure the email for the ContactForm plugin other than changing the email address for the admin account?

Many thanks,

Stephen

The email's "from" field is set to the system email that is under Settings->Email in the control panel.

The email's "reply to" field is set to the "fromEmail" hidden input you set on the form.

This is done because many email servers will see that the "from" domain is different than the domain the email originated from and mark it as SPAM.


Searching for a way to add products to cart and sending the csrf token with ajax Searching for a way to add products to cart and sending the csrf token  with ajax
This is my current code;
$('.add-to-cart-form').on('submit', function(e) {

            e.preventDefault()
            var formData = new FormData($('.add-to-cart-form')[0]);
            formData.append('action', 'commerce/cart/update-cart');

            $.ajax({
                contentType: false,
                processData: false,
                type: 'POST',
                url: '',
                dataType: 'json',
                data: formData,
                success: function(response) {
                    var cartCount = response.cart.totalQty;
                    $('.cart-count').text(cartCount);
                    if (response.success) {
                        console.log('success');
                        console.log(response.success);
                    }
                    else {
                        console.log('error');
                        console.log(response.success);
                    }
                }
            });
        });

So normally in your main layout twig template, you'd have something like this to set some JS variables to hold the current CSRF token:
    {# Super preliminary JS Stuff #}
    <script type="text/javascript">
        window.csrfTokenName = "{{ craft.app.config.general.csrfTokenName|e('js') }}";
        window.csrfTokenValue = "{{ craft.app.request.csrfToken|e('js') }}";
        window.cartId = "{{ cart.id }}";
    </script>

Then, in your add-to-cart JS, you do something along the lines of this to add those variables to the form data:
   formData.push({
     name: window.csrfTokenName,
     value: window.csrfTokenValue
   })

Craft's own documentation for this is here:
https://craftcms.com/knowledge-base/enabling-csrf-protection#updating-your-javascript


Visitor-facing pages work; admin login doesn't--I can't login in to admin The login page has no styling, including no Powered by image. This is what displays beneath the site's title:

When I try to login I receive:

Bad Request
Unable to verify your data submission.

The site is one I moved from dev to production, from a local to remote server. I used checkit.php on the remote server and it passed. I know the paths to asset volumes are incorrect, so while public pages display properly, they do so without images, which is what I was trying to login to fix. CSS, JS, text pulled from the database--all work.

What could be wrong? Thank you in advance for any help.

[Edit]

Thank you for responding. This site is on a Namecheap Stellar Business shared hosting plan. It's an addon domain. The "web" directory is set as document root. The site's folder is above the public_html directory in the hosting account's root directory.

Yes, there are 404 errors in the console. The unfound files exist where they should, in the web/cpresources directory. The 404 paths don't include the "web" directory.

Because the web directory is set to root, won't resources in the web folder will be found even if the "web" directory doesn't show up paths? The web/index.php file is found without "web" being in the url. The site loads for visitors to the site.

The contents of the "web" folder should be inside public_html, not public_html/web. The craft folder (or it's contents) can then go into private_html (or whatever you have as a private folder, if any). Just remember to point index.php to the right folder for it to load.

It should in practice work if you set the right flags in .htaccess or nginx config, but there might be some inherent bug or hardcoded paths/routes in Craft. Not sure what might be causing it other than cpresources not being in /public_html/


"Template not found: dashboard" error on setup When setting up Craft CMS I get a 404 error page that says

HTTP 404 - Not Found - yii\web\NotFoundHttpException
Template not found: dashboard

I am running MAMP (PHP 7.2.8 and MySql 5.7.23) on a Mac and followed the installation instructions (using Composer) found on https://docs.craftcms.com/v3/installation.html.

Everything seems to run smoothly until I hit the "Web Browser Setup" part (https://docs.craftcms.com/v3/installation.html#step-6-run-the-setup-wizard), which is where I get the 404 page instead of the setup wizard.

Any clues to what could have gone wrong?

Thanx!

I misread the installation instructions and thought I had to do BOTH the terminal setup and the web browser setup.


PDF creation with password My client is setting up a digital downloads shop (PDF's) and has a requirement that after one or multiple products are purchased the PDF's are then available for download.
He wants one or more of the following and i am just wondering if any of these are possible with any plugins or otherwise?

Password protect the PDF (the password could be the customers email or other random password)
Add a watermark - perhaps a logo and maybe date
Add header and footer with some dynamic information (e.g. date, email)

Its worth noting that the customer's PDF is wanted ideally to be created from an already existing base PDF but i see a lot of the plugins use HTML to create the PDF so could look into that possibly also
Many thanks
Malcolm

It looks like https://plugins.craftcms.com/super-pdf might do what you're asking for although I've not used this plugin.
Check out the docs here:
https://docs.amiciinfotech.com/craft-cms/super-pdf/backend/config
Search for password on that page to see what it offers.
Good luck.
-John Morton


How can I make the broadest search possible? I have three (3) different channels. One (1) channel have Assets attached to it, and those Assets have a couple of fields attached to them as well.

How can I make the broadest possible search on all these channels (and the channels Assets and fields) using the .search() function?

For clarification; I want to make a search in all channels, and their Assets (and the Assets own fields) with (if possible) one single line of code.

I gave this a quick test, and it seems that Craft only searches the title field of related assets, when searching entries. What you could do, is first search for all entries with your search term, then all assets with the search term AND related to an entry. Combine those to sets of ids, and you're all set (not really one line of code, though):

{# your search term #}
{% set searchTerm = craft.request.param('q') %}

{# first, search all entries with given search term #}
{% set entries = craft.entries.search(searchTerm).ids() %}

{# first, search all assets with given search term and their relations #}
{% set assets = craft.assets.search(searchTerm).ids() %}
{% set entriesRelatedToAssets = craft.entries.relatedTo(assets).ids() %}

{# Combine those ids to one array #}
{% set allIds = entries | merge(entriesRelatedToAssets) %}

{# Then get all the entries with the given IDs #}
{% for entry in craft.entries.id(allIds) %}
    {{ entry.title }}<br />
{% endfor %}


Migrate sprout forms Is there any way to migrate the configuration of a Sprout Form between my local environment and the production environment?

I'm on Craft 3.

Ideally, I'd love to generate a migration using the migration manager https://github.com/Firstborn/Craft-CMS-Migration-Manager but would love any way to move the settings of a form.

Sprout Forms will be adding support for Project Config in Craft 3.1. At the time of this posting the Craft Project Config has not yet been released, the Project Config will likely give us a much better workflow to maintain plugin settings between environments.

While there is an alternative, the export/import path described below would be a bit tedious to maintain and could just be easier to do manually depending on how many Forms you need to migrate (as you will have to define those forms in the export JSON to get them exported).

Sprout Forms has a Sprout Import integration and supports importing Form and Form Entry Elements via the Sprout Import Element Importer API.

With the Sprout Forms/Sprout Import integration you could:

Create a Twig template or script that outputs your Forms (and/or Entries) to a JSON file
Create a Migration that grabs that JSON export and hands it off to Sprout Import to import.

This import can be triggered using the Sprout Import service layer or via a console command.

./craft sprout/import/run --file="@root/import.json"

More on importing forms using this API: https://sprout.barrelstrengthdesign.com/docs/forms/importing-data.html#forms


How to use license in different environments We have a very simple development process, and I believe this process has messed up the license.

app-client.local.mycompany.com.br => developer environment (intranet only)
app-client.qa.mycompany.com.br => quality insurance environment (openshift)  (intranet only)
app-client.hom.mycompany.com.br => client test environment (openshift) (intranet only,client access via vpn)
something.com.br => client website

local/qa/hom I'm using "environment = dev", but somehow local is working but qa and hom is not.

The database is a copy =>

from local to qa/hom when is a website in development
from prod to local/qa/hom when it is an already made website

It means every environment has its own database.

How to proceed to use dev licensing at local/qa/hom ?

A few pre-requisites:

A Craft purchase/edition is tied to the craft/config/license.key file that is in place at the time the purchase is made and wherever that file goes, the purchase/edition will follow.
A craft/config/license.key file can only be tied to one "public" domain at a time.
Craft license validation doesn't run on "non-public" domains and you're able to trial the different editions of Craft for as long as you want on non-public domains.

https://craftcms.com/support/license-enforcement#how-do-we-determine-craft-is-running-on-a-public-domain

Craft will treat app-client.local.mycompany.com.br as a "non-public" domain, because it has one of the keywords we're looking for in its own segment in the subdomain.  You can see a list of those keywords here in number 4 of the previous link.

The rest of those domains Craft treats as "public" because they don't match any of the rules in that link, so license validation will run on them.

You don't say exactly what you're issue is, but if you purchased Craft on the development domain and you're using that same license.key file on the three other public domains, you're probably getting a warning in the Control Panel saying that license is already in use on another domain.

Since they are all for the same "site", you can either tell everyone that has access to the Control Panel to ignore the message and to not transfer the license away from the production domain, or you can change your qa and hom domains so Craft treats them as "non-public" and license validation won't run.

More related reading: https://craftcms.com/support/license-key-info


Multi-Site | Multi-Domain? I have the following problem: I would like to have one craft backend / one installation for different one pager sites on different domains. The reason is, that we have one HTML template we would like to use for our landing pages for different purposes (e.g. landingpage with different testimonials) and we would like to use a different domain for each version of the landingpage.

My initial thought was, to build a channel and to setup it up like www.domain.com/landingpage01, www.domain.com/landingpage02 etc.

So how do I route mycooldomain.com to /landingpage01 and myothercooldomain.com to /landingpage02?

Or are there any other solutions for my problem?

One way to do this, is use different environments for each domain and set a variable (for instance, an entry ID) for each environment. So, your config/general.php would look something like this:

return array(
   '*' => array(
       // Every config setting that's the same for all domains (like devMode, omitScriptNameInUrls, etc.
   ),
   'firstDomain.com' => array(
       'siteUrl' => 'http://www.firstDomain.com/',
       'environmentVariables' => array(
           'baseUrl' => 'http://www.firstDomain.com/', // For use in asset source, for example
           'basePath' => '/path/to/public/folder/', // Same for this
           'entryId' => 5 // Or whatever the ID of your entry is
       ),
   ),
   'secondDomain.com' => array(
       'siteUrl' => 'http://www.secondDomain.com/',
       'environmentVariables' => array(
           'baseUrl' => 'http://www.secondDomain.com/', // For use in asset source, for example
           'basePath' => '/path/to/public/folder/', // Same for this
           'entryId' => 8 // Or whatever the ID of your entry is
       ),
   ),
);

Then, in your template (entry.html or whatever file you use as your section's template), you get the data like this:

{% set entry = craft.entries.id(craft.config.environmentVariables['entryId']).first() %}

<h4>{{ entry.title }}</h4>


cannot update Craft CMS - composer errors I'm upgrading a site to 3.0.41.1 (not ready to go to 3.1) and when I do I get the following error. How do I resolve this?

composer update craftcms/cms
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Can only install one of: twig/twig[v2.6.2, v2.5.0].
    - Can only install one of: twig/twig[v2.6.2, v2.5.0].
    - Can only install one of: twig/twig[v2.6.2, v2.5.0].
    - craftcms/cms 3.0.41.1 requires twig/twig ~2.6.2 -> satisfiable by twig/twig[v2.6.2].
    - Installation request for craftcms/cms 3.0.41.1 -> satisfiable by craftcms/cms[3.0.41.1].
    - Installation request for twig/twig (locked at v2.5.0) -> satisfiable by twig/twig[v2.5.0].

in composer.json I have this

"craftcms/cms": "3.0.41.1",

All other plugins were successfully updated.

composer update vendor/package by design does not update the dependencies of vendor/package. Instead, use

composer require --update-with-dependencies craftcms/cms:3.0.41.1

Per the docs, --update-with-dependencies will

  Also update dependencies of the newly required packages, except those that are root requirements

That will update Craft to 3.0.41.1 and, because 3.0.41.1 has a new Twig requirement (~2.6.2, where 3.0.41 used ^2.5.0), it will update Twig as well.


Categories in a RelatedTo - How do I not list the parent if there is a child? I am going to try this again...

I have a page for a category (country) with all the entries that match that country.

I have buttons that allow you to filter the entries using categories from a second category group ('market').

All, I want to do is list the markets to make the filter buttons.
BUT, I don't want to list the parent if their is a child.  And, there is not always a child.

This is how I have things setup.

{% set entries = craft.entries.relatedTo(category).find() %}
{% set markets = craft.categories.group('markets').relatedTo(entries).find() %}

But, this prints both the parent and child of a market. I don't want to print the parent if there is a child.

Addling level(x) does not work because then it leaves out those markets that might be x+1 or x-1.

And adding last() did not work.

This has to be possible.  It's killing me.

You could just use what you got, loop through the categories and try to grab the descendants for each of them.

{% set entries = craft.entries.relatedTo(category) %}
{% set allMarkets = craft.categories.group('markets').level(1).relatedTo(entries) %}

{% for market in allMarkets %}
    {% set descMarkets = market.getDescendants() %}

    {% if descMarkets %}
        {% for market in descMarkets %}
            {% include '_includes/partial' %}
        {% endfor %}
    {% else %}
        {% include '_includes/partial' %}
    {% endif %}
{% endfor %}

Another good approach is to "collect" element IDs.

You would basically do the same as in the output loop of the above example, but instead of having the conditionals and extra queries in the output loop, you’d work with element IDs that you merge into an array. You can then query for the categories nicely using the id param in a craft.categories criteria model.

{% set entries = craft.entries.relatedTo(category) %}
{% set topMarkets = craft.categories.group('markets').level(1).relatedTo(entries) %}

{% set allMarketIds = [] %}

{% for market in topMarkets %}
    {% set descMarketIds = craft.categories.descendantOf(market).ids() %}

    {% if descMarketIds %}
        {% set allMarketIds = allMarketIds|merge(descMarketIds) %}
    {% else %}
        {% set allMarketIds = allMarketIds|merge([market.id]) %}
    {% endif %}
{% endfor %}

{% set allMarkets = craft.categories.id(allMarketIds) %}

{% for market in allMarkets %}
    {% include '_includes/partial' %}
{% endfor %}

Update:

One more approach! I just noticed, that you can simply test whether a category has descendants or not. This should probably be best from a performance point of view.

{% set entries = craft.entries.relatedTo(category) %}
{% set allMarkets = craft.categories.group('markets').relatedTo(entries) %}

{% for market in allMarkets %}
    {% if market.getDescendants().total() == 0 %}
        {% include '_includes/partial' %}
    {% endif %}
{% endfor %}


Responsive Images Srcset and Sizes based on Image Transform So I have setup a macro based on the excellent article here;
https://straightupcraft.com/articles/responsive-images-with-twig-macros

{% macro responsive(asset, options={}) %}
{% import _self as self %}

{% set options = {
    alt: '',
    class: [],
    style: 'default'
}| merge(options) %}

    {% set transform = {
        mode: 'crop',
    } %}

{% set nativeWidth = asset.getWidth(false) %}

{% set config = {
    default: {
        srcsetWidths: [300, 600, 1000,],
        sizes: [
            '(max-width: 47.5em) 100vw',
            '50vw'
        ],
        defaultWidth: 600
    },

    cards: {
        srcsetWidths:   [345, 600, 700, 905, 1000, 1200, 1400],
        sizes: [
            '(max-width: 47.5em) 100vw',
            '(max-width: 60em) 50vw',
            '33vw'
        ],
        defaultWidth: 600
    }
} %}

{% set params = config[options.style] %}
{% set srcset = [asset.getUrl(false)~' '~nativeWidth~'w'] %}

{% for width in params['srcsetWidths'] %}
    {% if width < nativeWidth %}
    {% set srcset
         = srcset|merge([asset.getUrl(transform|merge({width: width}))~' '~width~'w'])
    %}
    {% endif %}
{% endfor %}

<img
    {# src attr: transformed only if necessary #}
    {% if nativeWidth <= params['defaultWidth'] %}
      src="{{ asset.getUrl(false) }}"
    {% else %}
      src="{{ asset.getUrl(transform|merge({width: params['defaultWidth']})) }}"
    {% endif %}

    srcset="{{ srcset|join(', ') }}"
    sizes="{{ params['sizes']|join(', ') }}"

    alt="{{options.alt}}"
    {{ self._classAttr(options.class) }}
/>
{% endmacro %}

However, I want to be able to generate each individual responsive set based on different transform parameters. The first instance I have is created a series of card images images for a 1x3 row of feature cards. These will be a fixed ratio which I want the system to handle and not the user. These cards have the following sizes for each srcset width;

1400 x 875
1200 x 750
1000 x 625
905 x 566
700 x 438
600 x 375
345 x 216

I have created an image transform in the Control Panel called Card Image that has been set to crop and the width/height set to the largest size (1400x875). I wondered if I could use this handle in the macro, but I run into errors;

  The merge filter only works with arrays or "Traversable", got "string" as first argument.

As I will have different use cases and create different 'responsive images' throughout the site, I want the flexibility of setting up different transforms, I thought it was perhaps sensible to keep these all in the control panel under the Image Transforms section, as these are easily referable and editable. Then pass in the required handle into the Macro.

Does anyone have a better approach or solution, and any ideas how I can overcome the error mentioned?

Thanks.

Merge operates on arrays or array-like things, and you probably handed it the string "card", which is why you got that error.

I think what you want to do here is use the transform in the control panel to define the aspect ratio, but use the img macro to determine which sizes to transform to.

You can calculate the aspect ratio like this:

{% set aspectRatio = asset.getHeight(options.style) / asset.getWidth(options.style) %}

And generate transforms like this:

transform|merge({width: width, height: width * aspectRatio})

You will want to be careful with the native (untransformed) image: only use it if it has the correct aspect ratio.

You will want to be careful with avoiding transforming to a larger image - skip the ones where the width would be greater than the native width and the ones where the height would be greater than the native height.

Using the crop transform instead of the stretch one (that the article uses) is the right thing to do too.

Also, consider the imager plugin, which has some useful srcset supporting features (and postdates that article)


Uploaded image not appearing I'm having an issue where a user is uploading images but they're not showing up correctly. The photo is listed in /admin/assets and shows the correct file size, kind, dimensions, etc but I'm getting a 404 error on the file's url.

I seem to able to upload images without issue myself.

My first step to troubleshooting this is to confirm that the Asset Source URL is correct in the source settings.


Need to build products page with filters (price, category,..etc) I need to build a product page with filters on the side to filter the product by : price ( less than 100, between 100 and 200 , between 200 and 300 , greater than 300 )
and also by category,
Category only now is working :

{% if category is defined %}
   {% paginate craft.commerce.products.relatedTo(category).limit(limit) as products %}
{% endif %}

Not using variants right now.

regards

I am using https://isotope.metafizzy.co/filtering.html for this. Really easy to use


Plugin Stylesheet 404 Hey guys I have created a plugin with an accompanying Stylesheet which I am adding to the page via

class SitemaphtmlPlugin extends BasePlugin
{

function init(){

     craft()->templates->includeCssResource('sitemaphtml/css/sitemaphtml.css');
}

however the link being generated is prefixing the path with cpresources/ making it 404.

/cpresources/sitemaphtml/css/sitemaphtml.css?x=xXhFyszUs

how can i overcome this this?

Cheers

Is your css file located in the /resources/ folder of your plugin? So your path should be something like:

<plugin folder>/resources/css/sitemaphtml.css

I've tried it myself and whilst you do get the /cpresources/ part of the Url in your markup, the CSS file is loaded on the front end.

EDIT: If you take a look in the docs, it says the following:

  By default, Craft will search for the resource file in its own
  craft/app/resources/ folder. If it can’t find the file there, it will
  check if the first segment of the resource path is set to a plugin
  handle. If it is, Craft will look for the resource file within that
  plugin’s resources/ folder.


Craft 3 - Plugin - Override Control Panel column values for field or field types How can I override the column value for a plugin in the Craft CMS control panel?

For example:

Append "Hello " in front of a particular column value, or add hyperlink HTML markup to a value, in each row where the value makes a particular condition.

For the life of me, I can't figure out how to hijack column values!

Depending on how complex your needs, you might do with the following:

Control Panel JS
Preparse Field

I've used this combo to alter field value display in the control panel.

For example, if a myField can contain a value of '1', then in a Preparse Field I do this:

{% if element.myField == 1%}ONE{% endif %}

And then using Control Panel JS, I can check the value of that field in the CP (in this case, checking for '1'), and then add/remove a CSS class, change the value of the HTML, etc. Part of the reason to use Preparse fields is they allow you to shorten the column header.

It's a little fiddly, but it works well.


Query a Supertable using MySQL Stored Function I have a supertable which lists stockists. Each stockist has a lat/lng for map location. On a page of the site i am implementing a map locator which will need to make an ajax request for the 10 closest stockists to a user supplied address. Basically I will need to query the supertable of stockists (in a plugin) to find these 10 closest. I have written a MySQL stored function to calculate distance between two pairs of lat/lngs. If I was doing raw sql on the database, the query would, for example, look like:

SELECT * FROM `craft_supertablecontent_stockistlist`
order by (GeocodeCalcDistance(field_lat, field_lng, -27, 153, "km")) ASC
limit 10

where GeocodeCalcDistance() is my stored function. I have tested this sql and it works.

Now to tranlate that into craft code! My stockists are stored in a supertable, which is defined wholly in the CP (i.e., I don't have custom Model/Record classes in a plugin for the data). How do I express this query in Craft logic? Usually you could do something along the lines of:

$criteria = '....';
$params = array('param1' => value1);
$stockists = RecordClass::model()->findAll($criteria, $params);

but I don't have a "record" class for the table data. I am pretty stumped. any clues greatly appreciated.

ok i found the solution. something about craft that i am (slowly) learning is that when i access elements via something like, e.g., craft()->globals->getSetByHandle('stockists') i'm not getting raw data as such, i am getting an ElementCriteriaModel object! thus my solution is:

$target_lat = ...;
$target_lng = ...;
$limit = ...;

$stockists = craft()
    ->globals
    ->getSetByHandle('stockists')
    ->stockistList
    ->order(sprintf('(GeocodeCalcDistance(lat, lng, %f, %f, "km")) asc', $target_lat, $target_lng))
    ->limit($limit)
    ->find();

where GeocodeCalcDistance is my stored function.

et voila!

ANOTHER SOLUTION

ok so what i did above was fine. but then i wanted to limit my results by the distance from the target location. this meant i needed the distance calc to move into the select clause, then i could reference it in a having clause. sounds a bit daunting to try and include in an element-based query. but then i came across a great answer to another question here, which gave me some inspiration.

so, i need to inject a new column into the select clause (the new column being a call to a stored function). then i need to reference that column in a having clause. this is done by constructing an "initial" element query (based on a typical ElementCriteriaModel query), then turning it into a DbCommand object by using craft()->elements->buildElementsQuery(). then i can tweak that query, execute it, then populate models with the raw data returned.

$target_lat = ...;
$target_lng = ...;
$limit = ...;
$range = ...;  // results have to be within this distance from the target

$query = craft()->elements->buildElementsQuery(
    craft()->globals
        ->getSetByHandle('stockists')
        ->stockistList
        ->order(sprintf('dist asc', $geocode->lat, $geocode->lng))
        ->limit($limit)
    );

$query->select(sprintf('(GeocodeCalcDistance(field_lat, field_lng, %f, %f, "km")) as dist, ', $geocode->lat, $geocode->lng) . $query->select);
$query->having(sprintf('dist <= %d', $range));
if ($results = $query->queryAll()) {
    $stockists = SuperTable_BlockModel::populateModels($results);
}


Prevent queries based on condition I have a set of parameters that need to be checked before outputting an entry in a particular section of a website. The code for that looks somewhat like this:

{% for slide in craft.entries.section('events').featured('1').order('dateTime asc').limit(2) if (slide.dateTime|date_modify("tomorrow 5am")|date("c")) >= now|date("c") %}

The problem is that it obviously is looping through all entries, even those that do not match my conditional based on the date. Is there a way to prevent the loop through entries that don't match that condition to prevent bloat as there will eventually be thousands of entries that it would be looped through that do not end up being output due to the conditional.

I don't think you're going to be able to do what you're looking for purely through Twig.

You can, however, write a plugin that either uses a service and variable or a Template Hook, so you can drop down to the PHP level and use DbCommand's where to apply your extra date conditionals to your SQL query directly.


Localization - "not found" in CP on language selection Folks:

I'm creating a localized site on Craft2 and CraftCommerce. I have followed the instructions for creating a localized site but none of the content shows at the localized URL and the homepage shows the craft default template. The default template has no content.

In the CP, the language is available in the upper right of an entry. The fields that are translatable are labelled. When I click the language, the Craft "not found" page is shown.

My guess is that because no fields exist for the language, no fields can be shown on the front end.

Error from the logs:

2019/02/22 11:28:37 [error] [exception.Craft\HttpException.404] Craft\HttpException in /usr/home/name/temp.domain.com/craft/app/controllers/EntriesController.php:773
Stack trace:
#0 /usr/home/name/temp.domain.com/craft/app/controllers/EntriesController.php(52): Craft\EntriesController->_prepEditEntryVariables(Array)
#1 [internal function]: Craft\EntriesController->actionEditEntry(Array)
#2 /usr/home/name/temp.domain.com/craft/app/framework/web/actions/CAction.php(109): ReflectionMethod->invokeArgs(Object(Craft\EntriesController), Array)
#3 /usr/home/name/temp.domain.com/craft/app/framework/web/actions/CInlineAction.php(47): CAction->runWithParamsInternal(Object(Craft\EntriesController), Object(ReflectionMethod), Array)
#4 /usr/home/name/temp.domain.com/craft/app/framework/web/CController.php(308): CInlineAction->runWithParams(Array)
#5 /usr/home/name/temp.domain.com/craft/app/framework/web/CController.php(286): CController->runAction(Object(CInlineAction))
#6 /usr/home/name/temp.domain.com/craft/app/framework/web/CController.php(265): CController->runActionWithFilters(Object(CInlineAction), Array)
#7 /usr/home/name/temp.domain.com/craft/app/framework/web/CWebApplication.php(282): CController->run('editEntry')
#8 /usr/home/name/temp.domain.com/craft/app/framework/web/CWebApplication.php(141): CWebApplication->runController('entries/editEnt...')
#9 /usr/home/name/temp.domain.com/craft/app/etc/web/WebApp.php(291): CWebApplication->processRequest()
#10 /usr/home/name/temp.domain.com/craft/app/framework/base/CApplication.php(185): Craft\WebApp->processRequest()
#11 /usr/home/name/temp.domain.com/craft/app/index.php(73): CApplication->run()
#12 /usr/home/name/temp.domain.com/public_html/index.php(20): require_once('/usr/home/name/...')
#13 {main}
REQUEST_URI=/admin/entries/contact/5-contact/en_gb
HTTP_REFERER=http://temp.domain.com/admin/entries/contact/5-contact

What I've done:

As mentioned, I've followed the instructions in the Craft docs.

I have updated the asset indexes.

I have used environment variables like so:

'temp.domain.com' => array(
        'environmentVariables' => array(
        'devMode' => true,
        'basePath' => '/usr/home/business/temp.domain.com/public_html/',
        'baseUrl'  => 'http://temp.domain.com/',
        ),
        'siteUrl' => array(
        'en_us' => 'http://temp.domain.com/',
        'en_gb' => 'http://temp.domain.com/en_gb',
        )
    ),

I have verified that asset source settings are:

{basePath}images_product/
{baseUrl}images_product/

I have made appropriate fields translatable.

I enabled the locales for each section.

I created and populated subfolders. Index.php looks like so:

// Path to your craft/ folder
$craftPath = '../../craft';

// Tell Craft to serve the British content
define('CRAFT_LOCALE', 'en_gb');

Additional info:

I am using SEOMatic and that does work as advertised with different meta content showing up for the localized site even if nothing else shows on the page.

This turned out to be an issue with stalled tasks. There were a number of stalled tasks that were blocking the queue, preventing the localized pages from being created ("resave all localizable elements"). Clearing the stalled tasks resolved the issue. Thanks to Brad Bell for resolving this.


Does composer update make changes to the SQL database When creating plugins on my local I need to run composer update to make sure everything is in sync. In order to make sure the client has the same vendor and plugin folders, I then upload them to the server.

I just want make sure that when running composer update that Craft does not make changes to the database. If so, I need to make sure I also send the latest database to prod as well.

We've made a cli tool to easily sync environments, and I would like to add a command that takes care of this edge case as well.

No, running composer update will not – by itself – result in any changes to your database.

When you run composer update, all that happens is that Composer downloads updated versions for all your installed packages (i.e. Craft, plugins and other dependencies), before writing a manifest of your currently installed packages to the composer.lock file. Full stop; Craft isn't actually involved in this process at all.

However, sometimes an updated version of Craft (or a plugin) might need to change something in the database, in order to function. This is called a "migration", and is distributed with the package in question as a "migration file", containing the database queries necessary to perform the update that the new version of the package needs. In terms of updating core code or plugins, running these migrations is the only thing that will end up actually updating your database. You do have to run them at some point, because if there are pending migrations on your site's file system (i.e. migrations that have been downloaded but not run yet) your site will be unavailable until those migrations have been run (important – note that if you're updating Craft or a plugin through the Control Panel and not using the command line/Composer directly, Craft will attempt to auto-run any migrations for you, after Composer finishes downloading the new packages).

There are two ways to run pending migrations:

Visit the control panel in a browser, and click the prompt(s)
Execute the following from your command line (this should be run from the root directory for your project, i.e. where your composer.json file resides):

./craft migrate/up

The above command is safe to run even if there aren't actually any migrations pending, so if you're writing some sort of update/sync script, it could easily be tacked on at the end to make sure that any pending migrations that might be included with the updated code, are run (if you sync up the database instead, this won't be necessary as long as you've run the migrations locally).

In addition to the above – while your strategy for keeping Composer dependencies on the live server updated certainly works, it seems a bit unnecessary and/or convoluted to have to sync the database from local to production. I'd advise to either just run the migrate command in case there are migrations, or even follow what is generally considered the best practice for dealing with Composer dependencies: don't commit the actual dependencies (i.e. your /vendor folder) to version control, only the composer.lock file, and run composer install on the server, after the latest version has been deployed. Here's how a very simple deploy script could look:

cd /path/to/host/root
git pull origin production
composer install --no-interaction --prefer-dist --optimize-autoloader
./craft migrate/up
echo "" | sudo -S service php7.0-fpm reload


Multi-lingual site without subfolders Would it be possible to have a cleaner site setup without all those 'locale' subfolders in the webroot? Somehow it looks like there's something similar already done here (https://github.com/craftcms/cms/tree/master-v2/src/services/HttpRequestService.php#L99) if I'm not wrong, wouldn't it be nicer to also just remove the locale if one is detected?

Bonus question :) :
Where in the hell is the actual Entry Slug -> Template resolving done? I know there's a lot of stuff happening with filters, action and resource requests. The closest I could get is that here the template/render controller gets triggered (https://github.com/craftcms/cms/tree/master-v2/src/framework/web/CWebApplication.php#L274) which in the end resolves to the action render method in the TemplatesController (https://github.com/craftcms/cms/tree/master-v2/src/controllers/TemplatesController.php#L50), already with the correct $template parameter set.

Could someone guide me in a direction here?

I'm not exactly sure what you are trying to achieve, but here is a way to have unlimited locales with only a single subfolder in your public root directory.

Put all of your locale subfolders into a single folder, called locales for example. So your directory structure would be:

public/locales/de/
public/locales/es/
public/locales/fr/

Make sure you update the craft path in each locale's index.php file accordingly:

$craftPath = '../../../craft';

Then you just need the following code in your root .htaccess file to redirect to the appropriate subfolder:

# Redirect locales
RewriteCond %{REQUEST_URI} ^/(de|es|fr)/ [NC]
RewriteRule (.+) /locales/$1 [QSA,L]


Working with Variables How do I display a variable in my template?

I have the following code:

<?php
namespace Craft;

class HelloPlugin extends BasePlugin
{
    function getName()
    {
         return Craft::t('Hello');
    }

    function getVersion()
    {
        return '1.0';
    }

    function getDeveloper()
    {
        return 'Richard G.';
    }

    function getDeveloperUrl()
    {
        return 'http://example.com';
    }

        public function hasCpSection()
    {
        return true;
    }

}

plugins/hello/variables/HelloVariable

<?php
namespace Craft;

class HelloVariable
{
    // property
    $message = 'Hello, World";"
 }

plugins/hello/templates/index.html

{% extends "_layouts/cp" %}

{% set title = "Hello World"|t %}

{% set content %}

MessageVariable  {{ craft.helloPlugin.HelloVariable.message }}

{% endset %}

Within your variables class file you will want to define methods that 'return' values to your template, like so:

class HelloVariable
{
    public function message()
    {
        return "Hello, world!";
    }
}

Which you would call from your template using:

{{ craft.hello.message }}

On a side note, a really good place to start plugin development is to download and install a plugin template such as BusinessLogic, which provides a basic plugin structure, some sample files, and includes inline documentation for basic business logic kind of functionality.


New Install, Permission Errors With /storage I've configured Apache vHosts on a local box and installed a Craft 3 website onto it. This new instance will serve as my "staging" environment for an upcoming website.

I've installed with composer from a Git repo of my work-in-progress site.

Everything installed fine, and I can access the site through my browser. However, the site displays the error message:

  /var/www/vhosts/wine/storage isn't writable by PHP. Please fix that.

Now, I've run into this before, normally I would just chmod 775 and chown the folder to apache. But, this isn't working. I've even chmod 777 on the folder and it still gives me the error message.

An ls -la on the storage folder gives me (currently 774):

drwxrwxr--.  2  apache apache

This should be working.
I've been at it for 4 hours, and I'm at a loss. If anyone has any ideas, please let me know.

CentOS 7
Apache 2.4.6
PHP 7.2.20

Disabling SELinux worked, but only as a workaround. This particular issue was on a Staging server, so disabling SEL was not a huge issue.

However, I would highly recommend not anyone else do this for a Production environment unless they really know what they're doing in terms of permissions.

Good luck.


Validating date fields in a plugin's settings I have a plugin that has some settings, some of which are dates. I want to make these fields required, and ensure they are valid dates.

Because of this bug the date attributes are set as AttributeType::Mixed.

I'm using a structure like this and this to set up the attributes on my settings, but I can't get the date fields to be required, never mind use a custom date-validation method.

<?php
namespace Craft;

class My_SettingsModel extends BaseModel
{
    protected function defineAttributes()
    {
        return array(
            'myText' => array(AttributeType::String, 'column' => ColumnType::Text),
            // There are multiple date fields, but for the example:
            'myDate' => array(AttributeType::Mixed),
        );
    }

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

        $rules[] = array('myText', 'required');
        $rules[] = array('myDate', 'required');
        $rules[] = array('myDate', 'validDateString');

        return $rules;
    }

     public function validDateString($attribute, $params)
     {
         if ( /*  $this->$attribute is not a valid date  */ )
         {
             $this->addError($attribute, 'Please enter a valid date');
         }
     }
 }

myText is required OK - the form re-displays with an error message if you try to leave it empty.

I have two problems:

myDate is not required - if I leave the date field empty, the form is always successfully submitted, and when I go back to it the field has the date that was previously there.
Ignoring that, although validDateString() gets called, and doing var_dump($this->$attribute) looks something like array(1) { ["date"]=> string(0) "18/01/2016" }, I get "Illegal string offset 'date'" if I try to access $this->$attribute['date']. I'm baffled.

It turns out that because I'm now using my own settings model, I don't need to use AttributeType::Mixed for my date fields any more. (Thanks to carlcs for suggesting this.)

So I've removed the stuff I had in my Plugin's getSettingsHtml(), which massaged the fields before sending them to the template. And now, in theory, I only need to do this:

<?php
namespace Craft;

class My_SettingsModel extends BaseModel
{
    protected function defineAttributes()
    {
        return array(
            'myText' => array(AttributeType::String,
                            'column' => ColumnType::Text, 'required' => true),
            'myDate' => array(AttributeType::DateTime,
                            'column' => ColumnType::DateTime),
        );
    }

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

        $rules[] = array('myDate', 'date',
                        'format' => array('dd/MM/yyyy'),
                        'allowEmpty' => false,
                        'message' => 'Please enter a valid date');

        return $rules;
    }
 }

However, although the form requires me to enter dates - it doesn't accept empty fields - it won't accept the dates I'm typing in. e.g., if I enter 31/12/2016 it fails the date validation. Looking at Yii's date validation docs I think this should work...


Whats the best way to place content without using a lot of categories? I have a technologies magazine and recently find out about Craft CMS. It looks like I can make everything that I need to but I need advice.
So basically we are writing about smartphones, cars, computers, games and etc. All of these I can put as categories but different posts also have different sub-categories. We split our content into three sub-categories: news, tips, reviews. That means that all the categories (like smartphones, cars and etc.) have the same sub-categories (news, tips, reviews).
I'm looking for the best option for sorting all our content in Craft CMS. I was thinking to use entry types but we also want to have separate archives where people can find only smartphones news or smartphones tips. At the same time, we want to have the archive with all the tips.
The idea is to have a structure like this:
Home -> device type -> post type -> article
Url structure should be with all these components included and all of them should have the archive. I was thinking to use categories for device type and entries type for post type but it gets a bit messy. Does anyone have better ideas on how I can make this thing working for me? Thanks!

There is no definite answer to your question but I think you can get pretty much what you want using just two types of categories.
Section setup

create 2 category groups:

device types (with the deviceTypes)
post types (with the postTypes)

create an Articles section (with the article handle)
configure you section with the following Entry URI format: {articlesDeviceType.slug}/{articlesPostType.slug}/{slug}
on the entry type of the articles section (you just need one entry type), add the following required custom fields:

Device type (with the articlesDeviceType handle)
Post type (with the articlesPostType handle)

Your entries should now have the URL structure you wanted.
Archive page
Now if you want an archive of all smartphone related tips, you can get the entries with the following entry query in a template:
{% set tipsCategoryId = craft.categories().group('postTypes').slug('tips').ids() %}
{% set smartphoneCategoryId = craft.categories().group('deviceTypes').slug('smartphones').ids() %}

{% set entryQuery = craft.entries().section('articles').relatedTo([
    'and',
    { field: 'articlesPostType', targetElement: tipsCategoryId },
    { field: 'articlesDeviceType', targetElement: smartphoneCategoryId },
])

This should return an EntryQuery matching all entries related to both smartphones device type and tips post type.


How to compare currentUser with entry.author? How can I compare the results of currentUser and entry.author on an entry page?
I've tried the following, but none of these get a positive result:

{% if  currentUser == 'entry.author.id' %}

Or

{% set author %}{{ entry.author.id }}{% endset %}
{{ author }}
{% if currentUser.id == '{{ author }}' %}

(I'm aiming to provide a way for the author of an entry to be presented with a form to edit the entry)

Try this:

{% if currentUser.id == entry.author.id %}

When using quotation marks, it means that it's a string in Twig. What you want to do is compare the value of the actual variable.

Also, currentUser is a UserModel, so you need to get the id property to compare it with entry.author.id.


Phantom routes load index template, no 404 and no errors I have an issue regarding two (that I’ve come across) routes just simply loading the index template when they shouldn’t.

My template structure looked like this:

- search
 - index.twig
- index.twig

When I visited /search the root /index.twig template (front page) loads up.

If I create search.twig next to /index.twig and again go to /search I still get the home template rendered. Removing all search templates and going to /search again, still renders the index.twig template.

There is nothing in config/routes.php and there are also no routes present in craft_routes within the database.

I may have had these routes set up at some point in the past (the project is a bit old), so I created a new database and installed Craft again (kept all other template files, replaced craft/app folder) and the problem went away. Switched database in config (kept new craft/app folder) and now the problem is back again.

Is there anything in the database somewhere that would cause old routes to persist or be funky when the templates and any config/routes.php have been deleted?

I did try and look through the tables but couldn’t really spot anything that stood out, any help would be awesome!

Thanks to P&T via a support ticket, this issue has been resolved.

Basically I just had a structure which, some point, I had used as my navigation and was causing a conflict. Something which I just completely overlooked.

From P&T via a support ticket:

  The issue seems to be in your Navigation structure. You have "Entries in this section have their own URLs" turned on, but you do not set a template for the section. So, when a user requests 'search', which is an entry in your Navigation structure, Craft defaults to show the index.twig template.


How can I expand on a normal Craft query to sort by a column in a custom table? I have a plugin which contains a Record. My record contains a foreign key of the related element ID. The only other column in my custom table is the value I'd like to sort by.

In Twig syntax, how can I expand on a normal Craft query to sort by a column in my custom table?

Ordinary query:

craft.entries.section('colors').find

Ordinary query which sorts by my custom data:

craft.entries.section('colors').myPlugin('asc').find

Disclaimer:

I've done something similar to this once before... But in that case, I used the modifyElementsQuery method in my Field Type. Since this new plugin doesn't require a field type, I'm not exactly sure of the best way to modify a standard query.

You can't do this using the craft.entries tag in twig. You'll need to create a new function in your plugin that returns the entries in your custom order.

Assuming you can create an array of element ids in your custom order then the following code should allow you to then fetch entries in that order:

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

// filter entries by element ids
$criteria->setAttribute('id', $elementIds);

// order entries by element ids
$criteria->setAttribute('order', 'FIELD(elements.id, '.join(', ', $elementIds).')');

// get entries
$entries = craft()->elements->findElements($criteria);


Weird issue with craft/setup command I have been trying to install Craft CMS on Windows.

I tried composer:

composer create-project craftcms/craft d:\temp\craft

After that when I try to craft setup there is a loop on the console which doesn't end.

When I try to run craft install the same thing happens, a loop but different text!

Thanks

My guess is you're running PHP 7.4.0.  I could reproduce it on 7.4.0 on Windows, but when I updated to PHP 7.4.2, the issue went away.

This appears to be a PHP 7.4.0 bug on Windows as evidenced by this Github issue for Yii: https://github.com/yiisoft/yii2/issues/17782


Get entries that aren't related to current user I am trying to get all the entries that don't related to the current user via a user field.

I have used the following code to fetch all the entries that do related to the current user

{% set entries = craft.entries.section('movementCoursesEntries').level(1).relatedTo({
   targetElement: currentUser,
   field: 'permittedUsers'
}).find() %}

When I try to exclude these entries from the rest of the entries in the structure, I get nothing
{% set unrelated = craft.entries.section('movementCoursesEntries').level(1)|without(entries) %}

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

Any idea how to filter those entries properly?
Thank you!

Try this:
{% set entries = craft.entries.section('movementCoursesEntries').level(1).relatedTo({
   targetElement: currentUser,
   field: 'permittedUsers'
}).ids() | join(', not ') %}

{% set unrelated = craft.entries.section('movementCoursesEntries').level(1).id('and, not '~entries).all() %}

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


Determine a layout based on column number Okay, I want to create a Matrix based layout like this:

| x | x | x |
| x |   y   |
|   y   | x |

X is a 1/3 column and Y is a 2/3 column.

I want to activate the size Y with a lightswitch.

The problem is: If I have | x | x |   y   | the layout will blow up because there are too many columns so when the column amount is 3/3 I want to create a new row so all is nice and tidy.

How do I solve this?

My idea was to add a number to each column and when the maximum number is reached, there will be a new row.

That code doesn't work. I just want to show the idea.

{% set x = 33.33 %}
{% set y = 66.66 %}

{% for block in entry.this %}
  {% if x + y = 100 %}
{% endif %}
    {# content #}
  {% if x + y = 100 %}
{% endif %}

{% endfor %}

If I can get all variables and add them up it should be possible. But how do I get the variables from each iteration.

Anybody know what I'm talking about? Other solutions?

How about we have a matrix, with block types x and y. Then you can test for block type in your loop:

{% for block in entry.this %}
  {% switch block.type %}
  {% case 'x' %}
    ...
  {% case 'y' %}
    ...
  {% endswitch %}
{% endfor %}

Another issue is that 33.33 + 66.66 = 99.99, which is never going to be equal to 100. (Also, the test for equality is ==: {% if x + y == 100 %}). So let's use x = 1, and y = 2, for a maximum column width of 3. Here's the code:

{% set thisRowLength = 0 %}
{% set thisBlockLength = 0 %}

  {% for block in entry.this %}

    {# how long is this block? #}
    {% switch block.type %}
    {% case 'x' %}
      {% set thisBlockLength = 1 %}
    {% case 'y' %}
      {% set thisBlockLength = 2 %}
    {% endswitch %}

    {# start a new row if necessary #}
    {% if thisRowLength + thisBlockLength > 3 %}

      {% thisRowLength = 0 %}
    {% endif %}

    {# now we know it fits, output this block #}
    {{ block.content }}
    {% set thisRowLength = thisRowLength + thisBlockLength %}
  {% endfor %}

You will end up with an empty

 if there are no matrix blocks. If that will be a problem, test for it.


I cannot create any more admin user accounts Can it be that I have hit a limit for amount of admin users? I have only 6 now and I would like to add 3 more. But when I try to set a new one up, it cannot send the verification email.

If I try to resend verification, then an internal server error pops up with the message "Could not instantiate mail function."

Does this mean my server is the issue?

Any support is greatly appreciated.

Thanks in advance!

josh

Could not instantiate mail function.

That error means that the PHP mail is not installed and/or configured for use on the server you're currently on.

You can either configure that to properly work, or go under Settings->Email and choose another mail delivery option that does work for you.


Batch assigning a certain category to existing entries I have a few 1000 existing entries and just introduced a new Category type. And I would need to assign all existing entries, to a certain category.

I've been looking in the MySQL databases what exactly is going on, so I could reproduce it with a query directly in there, but can't seem to pinpoint exactly what I would need to update.

Any ideas?

You could build a plugin to grab all the entries and then assign that new category to it that way.

This bit of code is untested but this should do it, since this is a one off thing, you can get away with just doing it in chunks by setting the limit and offset, otherwise I'd recommend creating this as a Task:

// get all the entries
$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = "news"; // just using news as an example, be sure to set the appropriate section handle
$criteria->limit = null;
// $criteria->offset = null; // you could use the limit and offset field to do this 200 at a time, to avoid it timing out on you
$criteria->status = null;
$entries = $criteria->find();

$categoryIds = array(222); // this would be the new category (its ID) that you want to assign to the entry, be sure to set the correct ID here

for($i=0; $i<count($entries); $i++)
{
    $entry = $entries[$i]; // for easier reference

    // lets get the existing categories that are assigned to this entry and add it to the new category ID you set a few lines above, if there are no existing categories for this, then you can remove this for loop entirely
    for($c=0; $c<count($entry->categoryFieldHandle); $c++)
    {
        $categoryIds[] = $entry->categoryFieldHandle[$c]->id; // be sure to replace categoryFieldHandle with the category field handle for the category field
    }

    // setting the categories to this field, be sure to replace categoryFieldHandle here too
    $entry->getContent()->setAttributes(array(
        'categoryFieldHandle' => $categoryIds,
    ));

    craft()->entries->saveEntry($entry); // save the entry
}


Craft.log showing Buggy iconv installed. Will fallback to mbstring I'm curious if others are seeing a similar error in their Craft logs.  It says:

  Buggy iconv installed.  Will fallback to mbstring.

It's repeated over and over seemingly with almost every request.

It's a pretty simple server, setup using the default setting from Laravel Forge on Digital Ocean.

Any ideas on how to fix it?

Iconv is a system C library that converts string encodings, and is generally preferable to PHP’s mb_convert_encoding() because it supports significantly more character encodings. However it’s not guaranteed that it will be available, and if it is, some versions of it have a bug that could put it into an infinite loop in certain circumstances. So Craft’s StringHelper::convertToUTF8() checks for those things before using it, and logs if it’s not available or a buggy version is installed, before falling back on mb_convert_encoding().


Update an order custom field after order complete in Craft 3 I am trying to update an order's custom field after order complete.
I set it like this in my plugin:

Event::on(Order::class, Order::EVENT_AFTER_COMPLETE_ORDER, function(Event $e) {
        $order = $e->sender;
        $order->setFieldValue("customFieldHandle", "My value");
    });

But it is not working. I guess I used the wrong method to do it.

What I wrote is correct. I debugged it, and I had a problem in another place where the order did not get completed in the first place. silly me LOL.
So my answer is:

Event::on(Order::class, Order::EVENT_AFTER_COMPLETE_ORDER, function(Event $e) {
    $order = $e->sender;
    $order->setFieldValue("customFieldHandle", "My value");
});


Display Entries in a calendar I have a section for holding calendar entries stored by postDate in the CMS.
On the front end I want to basically display these in a calendar.

I have code which displays the calendar looping through each day of the month.
For each day it currently queries if there is any entries for this day.

Is there a better way to do it? - my current method had a query for each day?

Current code is:

      Sun
      Mon
      Tue
      Wed
      Thu
      Fri
      Sat

    {% set time = "now"|date("U") %}
    {% set daysInMonth = time|date('t') %}
    {% set startDow = time|date('F 1\\s\\t Y')|date('w') %}
    {% set dow = startDow %}
    {% for day in range(1,daysInMonth) %}
        {% if loop.first and startDow != 0 %}

        {% endif %}

                {{ day }}
                    {% set today=thisyear ~ "/" ~ thismonth ~ "/" ~ day %}

                    {% if (category is defined) and (category is not empty) %}
                    {% set params = { section: 'calendar', status: null, postDate:today|date('Y-m-d'), relatedTo: category } %}
                    {% else %}
                    {% set params = { section: 'calendar', status: null, postDate:today|date('Y-m-d') } %}
                    {% endif %}
                    {% set entries = craft.entries(params)%}
                    {% if entries|length %}

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

                    {% endif %}

        {% if loop.last and dow != 6 %}
            &nbsp;
        {% endif %}
        {% if dow == 6 %}
            {% set dow = 0 %}

        {% else %}
            {% set dow = dow + 1 %}
        {% endif %}
    {% endfor %}

I haven't tested this, but it should be a good starting point, at the very least.

{# Determine the number of days in the month #}
{% set daysInMonth = "now"|date("t") %}

{# Determine the date range spanning the month #}
{% set firstDayOfMonth = "now"|date("Y-m-01") %}
{% set firstDayOfNextMonth = "now"|date_modify("first day of next month")|date("Y-m-01") %}
{% set postDateParam = "and, >= " ~ firstDayOfMonth ~ ", < " ~ firstDayOfNextMonth %}

{# Create our parameters object #}
{% if (category is defined) and (category is not empty) %}
    {% set params = {section: 'calendar', postDate: postDateParam, status: null, order: 'postDate', relatedTo: category} %}
{% else %}
    {% set params = {section: 'calendar', postDate: postDateParam, status: null, order: 'postDate'} %}
{% endif %}

{# Retrieve all of the events for the month, and group them by day #}
{% set groupedEvents = craft.entries(params)|group('postDate|date("Y-m-d")') %}

{# Set a shortcut for the YYYY-MM portion of the current month #}
{% set yearMonth = "now"|date("Y-m") %}

{# Loop through all of the days in the month #}
{% for day in range(1, daysInMonth) %}
    {% set formattedDay = "%02d"|format(day) %}
    {% set dayOfMonth = yearMonth ~ "-" ~ formattedDay) %}

    {# If the current day is a key in our groupedEvents array, we have events #}
    {% if dayOfMonth in groupedEvents|keys %}
        {{ dayOfMonth }}

            {% for event in groupedEvents[dayOfMonth] %}
                {{ event.title }}
            {% endfor %}

    {% endif %}
{% endfor %}

As I said, I haven't tested the above code, but the basic principle works (I've used it for grouping people by surname, and so forth).

Let me know if anything is unclear, I realise it's quite the chunk of Twig.

Stephen


Check if submitted email address belongs to a user account How could I go about allowing a (not logged in) guest user to submit their email address, check behind the scenes if it belongs to a user account, and then return:

A login form if it does
A registration form if it doesn't

I assume you have basic knowledge about plugins and routing, if not I'll update my post in a few hours.. otherwise Your form could be

{% if userExists is defined %}
    {% if userExists == true %}

        hello {{ user.name }}

        <form method="post" accept-charset="UTF-8">
            {{ getCsrfInput() }}
            <input type="hidden" name="action" value="users/login">

Username or email

            <input id="loginName" type="text" name="loginName"
                   value="{{ craft.session.rememberedUsername }}">

Password

            <input id="password" type="password" name="password">

                <input type="checkbox" name="rememberMe" value="1">
                Remember me

            <input type="submit" value="Login">

            {% if errorMessage is defined %}

{{ errorMessage }}

            {% endif %}
        </form>

Forget your password?

    {% else %}

    {% endif %}

{% else %}

    <form method="post">
        <input type="hidden" name="action" value="test/checkEmail">
        <input type="text" name="email">
        <input type="submit">
    </form>
{% endif %}

And your controller

public function actionCheckEmail(){
    $email = craft()->request->getParam('email');
    if($user = craft()->users->getUserByEmail($email)){
        // user registered
        $userExists = true;
    }else{
        $userExists = false;
    }
    craft()->urlManager->setRouteVariables([
        'userExists'    => $userExists,
        'user'          => $user
    ]);
}


How to show if a user is logged in to control panel Is there a way to show if a user is currently logged in to the control panel? As I need a way to see if the client is working in the CMS.

Check out the MN Snitch plugin. It probably comes the closest to what you're looking for.


craft/app: gitignore, or no? Just looking for pros and cons here, I guess. My gut says to let updates flow through version control, but the part of me that wants to give up web design and become a mountain man says it might be beneficial if the client was at least able to patch in critical updates if necessary.

Thought I remember glancing at a conversation about this in the Slack channel, but couldn't find it.

No. Keep craft/app in your repo.

  Disclaimer: This is my own personal opinion. The topic comes up with some frequency on Craft Slack, and you will find advocates of both approaches. I fully expect to see an opposing position posted by someone else.

Benefits to keeping app in your repo...

You can properly vet an update, and make sure it does not create any problems in your site before pushing that update to production.
You have a guarantee that every environment (dev, staging, production) all contain the exact same version of Craft. This means that you can take advantage of specific features with confidence, and similarly, rule out bugs which may have been fixed between Craft versions.
You can prevent your client from "accidentally" upgrading, and potentially making a mess. Though it is rare, some breaking changes (or new bugs) are occasionally introduced when updating.


What is "Temp Uploads Location" in Craft 3.2.10 In Craft (Solo) 3.2.10, In Settings > Assets > Asset Settings, there's a field called "Temp Uploads Location". I do see images in mine that I intended to go into the system, but not into there.

What is that feature for?

That setting is basically saying, "where do you want your Assets to be stored while the related Entry is still being processed?"

Take a practical example... You are editing an Entry, and want to upload an Asset to a specific field in your entry. Click-click-click, you've added the Asset. But until you've saved the Entry, this will be considered a temporary Asset. After all, if you abandon your changes to the Entry, is it still worth saving the newly uploaded Asset?

"In the local temp folder" will drop those temporary assets into the Temporary Assets folder. That folder is exactly what it says... a temporary location for uploaded assets. Once you've properly saved your Entry, the new Asset will be moved to the appropriate location.

It's worth noting, Assets stored in the Temporary Assets folder are real assets. You may not have a front-end path to reach them, but by all other measures they are real Assets as far as Craft is concerned.


How can I check if a plugin is installed and enabled, in Craft 3? In a question I asked a few years ago, it was very simple to perform a check on wether a plugin was installed or not.

As of Craft 3, the same methods don't seem to work. The likes of this always returns true:

{{ craft.myPlugin is defined ? 'Installed' : 'Not Installed' }}

Is there another way to determine if a specific plugin is installed and enabled?

PHP

\Craft::$app->plugins->isPluginInstalled('plugin-handle')

Twig

{% set installed = craft.app.plugins.isPluginInstalled('plugin-handle') %}

There is also a isPluginDisabled and a isPluginEnabled function.
Here is a class reference craft\services\Plugins


Custom shipping cost One of the shipping companies that my client will use works by distance.
This company offers an api where you tell the pickup address and the shipping address. You also specify what type of package to carry (small or medium).
When I have a complete address, I make the call to the API of this company and it returns the shipping cost to me.
Given the particularity of this shipping company, I would like to be able to specify the price of the shipping cost without depending on any shipping method of the system itself. Is this possible?
thanks in advanced

Yes this is definitely possible.
We don't use any of Commerce's in-built shipping stuff - fields or calculation, as it's too limited for our needs (not Commerce's fault - we have very complicated shipping requirements!).
You will want to write yourself a custom module with either a full custom shipping calculator, or an adjuster for shipping.
You'd use an adjuster if you don't need to present any options to the user, and a full shipping calculator if you do.  If the latter, as long as you implement the interfaces for Rules and Methods, you can do just about anything you wants and present it to the user any way you want.  Can be a little tough to get going, but is very flexible once you've got it working.
Docs for this are here:
https://craftcms.com/docs/commerce/3.x/shipping-methods.html


How to translate a structure url I'm working on a multilingual website where I have one structure called Products. Currently, this structure's URI format is configured like this:
{parent.uri ?? section.handle}/{slug}

Which returns URLs like this:
/products/topLevelProduct1
/products/topLevelProduct1/nestedProduct1
/products/topLevelProduct1/nestedProduct2

/products/topLevelProduct2
/products/topLevelProduct2/nestedProduct1
/products/topLevelProduct2/nestedProduct2

etc

The main thing I'm struggling with now is: how do I translate the top-level part of the URI (i.e. /products)? I guess I could use the built-in t() function on section.handle (is that even a good idea?) but that would still be overwritten by parent.uri.

Since the URL is specific for each multisite, simply do not use section.handle in the structure's URI definition, but go for the term you want as a string instead, e.g.

English: {parent.uri ?? 'products'}/{slug}
German: {parent.uri ?? 'produkte'}/{slug}
French: {parent.uri ?? 'produits'}/{slug}

and so on...


Paginate Entries With The Same Tag On a single entries page I have the following code:

    {% set params = {section: 'databytes', order: 'title'} %}
    {% set prevDatabyte = entry.getPrev(params) %}
    {% set nextDatabyte = entry.getNext(params) %}

    {% if prevDatabyte %}

    {% endif %}

    {% if nextDatabyte %}

    {% endif %}

I am wanting to somehow only paginate through entries that are tagged with the same tag maybe by passing that into the params object is that possible?

You can limit the prev/next links to only show entries with the same tags using the relatedTo param:

{% set params = {
    section: 'databytes',
    order: 'title',
    relatedTo: { targetElement: entry.tagsFieldHandle, field: 'tagsFieldHandle' }
} %}

That might do the trick, but it may lead to inconsistent prev/next page links, because you can have more that one tag associated with each entry.

Take this entry/tag setup, for example:

Pizza

Lunch
Dinner

Ice Cream

Desert

Crepe

Breakfast
Lunch
Desert

If you land on Pizza, its Next Page link would take you to Crepe, since they share the Lunch tag. But when you click on Crepe, its Prev Page link should take you to Ice Cream, rather than Pizza, because Crepe also shares the Desert tag with Ice Cream.

You can see why that might get a little confusing.

One way to keep the navigation more consistent would be to choose one single tag that all entries should have in common, and pass that tag in the Prev/Next URLs.

{#
  Figure out which tag ID we should use to limit the previous/next entries.
  It will either be set in the query string already,
  or we can just use the first tag that the current entry has.
#}

    {% set tagId = craft.request.getQuery('tag') %}

    {% if not tagId %}
        {% set tagId = entry.tagsFieldHandle.ids()|first %}
    {% endif %}

{# Find the previous/next entries that have that tag #}

    {% set params = {
        section: 'databytes',
        order: 'title',
        relatedTo: { targetElement: tagId, field: 'tagsFieldHandle' }
    } %}

    {% set prevDatabyte = entry.getPrev(params) %}
    {% set nextDatabyte = entry.getNext(params) %}

{# Output their links, and pass the tag ID in the query string #}

    {% if prevDatabyte %}

    {% endif %}

    {% if nextDatabyte %}

    {% endif %}


Craft 3 Plugin Development: Add CSS and JS File to Frontend Templates How do I add js and css files to frontend page loads via a plugin? I did reference this issue:
Can a plugin add JS or CSS to the control panel?

but that is for Craft 2.

Reading the docs here:
https://docs.craftcms.com/v3/changes-in-craft-3.html#template-tags
and here
https://docs.craftcms.com/v3/extend/asset-bundles.html

show that Craft 3 is much different. I've looked through several Craft 3 plugins that do load scripts and styles on the frontend but each seems to handle this in very different ways. Is there a straight-forward standard that should be used if a plugin is loaded and needs to add resources to frontend page loads?

On the Asset Bundles doc page, it seems you can link directly to the asset in the plugin init but a comment further down the page suggests that you need to load the assets into the template:

"With that in place, all that is left is to register the asset bundle wherever its JS/CSS files are needed."

or I may be understanding this incorrectly.
Can I accomplish what I'm trying just by placing:

$this->sourcePath = '@ns/prefix/resources';
    $this->depends = [
        CpAsset::class,
    ];

    $this->js = [
        'custom-scripts.js',
    ];

    $this->css = [
        'custom-styles.css',
    ];

within the init function? Is this enough to get those files onto the frontend loads or do I need something else and something to tell them not to load onto backend pages?

Thank you for any help. Most of my plugin knowledge is based on reverse engineering plugins and in this area I'm still confused.

Did you place the init function within your asset bundle class as stated in the docs?

e.g.:

<?php
namespace ns\prefix;

use craft\web\AssetBundle;
use craft\web\assets\cp\CpAsset;

class MyPluginAsset extends AssetBundle
{
    public function init()
    {
        // define the path that your publishable resources live
        $this->sourcePath = '@ns/prefix/resources';

        // define the dependencies
        $this->depends = [
            CpAsset::class,
        ];

        // define the relative path to CSS/JS files that should be registered with the page
        // when this asset bundle is registered
        $this->js = [
            'script.js',
        ];

        $this->css = [
            'styles.css',
        ];

        parent::init();
    }
}

If so, there is only one step left to register the asset in your template (e.g. yourplugin/src/templates/index.twig), you simply have to register it in your template with:

{% do view.registerAssetBundle("ns\\prefix\\FooBundle") %}

If it still does't work, you could generate a minimalistic plugin scaffolding with https://pluginfactory.io/ , its all set up for you and commented out.

Update:
To register the plugins assetbundle in your frontend layout, add

<body>
  {{ beginBody() }
    .
    .
    .
    content
    .
    .
    .
    {% do view.registerAssetBundle("ns\\prefix\\FooBundle") %}
  {{ endBody() }}
</body>

to your frontend templates, e.g. in your main layout.twig at the start and the end of the body tag.


Control panel switches to HTTPS protocol on its own On one Craft CMS site I have, all control panel URLs I call over HTTP are rewritten to HTTPS. E.g. the login page, as well as all its assets, are being served via https://www.mywebsite.com/admin/….

The rest of the site is available via https://www.mywebsite.com/

I've already tried to enforce HTTP via mod.rewrite in .htaccess, as well as explicitly setting baseCpUrl and an new cpTrigger in config/general – with no success at all.

Is this a feature that I can deactivate? A bug in Craft CMS 2.4.2670?
Or is this a server-side issue?

It turned out not to be Craft's fault, indeed:

On the server, the HTTP_X_FORWARDED_PROTO environment variable was erroneously set to https in the reverse proxy – an issue that my hosting provider had to resolve.

(As a quick fix, the following line in index.php did the trick, too:)

 apache_setenv('HTTP_X_FORWARDED_PROTO', 'http');

Thanks to @brad-bell and @ritterknight for pointing in the right direction!


In an Asset field, how to use a dynamic subfolder field value that is dependent on the element type? I have a field named image that is assigned to an entry as well as a category.

When a user edits an entry, I would like the subfolder to be named after the section.handle property.

When a user edits a category, I would like the subfolder to be named after the group.handle property.

Is there a way to achieve this? I've tried something like this:

{{ section.handle ?? group.handle }}

...but unfortunately it does not seem to work.

It seems that the ?? operator or the is defined operator do not work at that level, for a reason unkown to me.

I found a workaround: testing against a property which I know will always be there. In our case, we know that the field will only be assigned to a category or an entry. Thus, we can check if the element type is a category and use the group handle as subfolder or the entry's section handle if it is an entry:

{% if object.elementType == 'Category' %}{group.handle}{% else %}{section.handle}{% endif %}

I don't know if it is the best solution, but it works.


How do I display the Image of an Author in a post? This might be a stupid question... but I can't seem to figure it out.

I'd like to show the photo of an author beside their entry. I thought the proper variable was...

{{user.photoUrl}}

...until I logged out and my photo disappeared.

That will get you the url of the current user's photo. To get an author's photo do this:

{{ author.photoUrl }}

If the author is not defined in your context but the entry is, then get the entry's author's photo as follows:

{{ entry.author.photoUrl }}


Can I apply an image transformation to an arbitrary image (non-Assets field)? Curious if I'm able to use the resizer on a random, sourced image, not coming from a field anywhere.

So I would just be passing a string to the path of the image.

While transforms are an asset-only feature, you can get at all of the underlying image manipulation features pretty easily using the ImagesService.

$image = craft()->images->loadImage($imageSource);
$image->setQuality($quality);
$image->resize($transform->width, $transform->height);
$image->saveAs($targetFile);


User Order History Not showing Up in CP I have a user I am running some Commerce order tests with. I have 6 orders they have placed. If I add a Commerce Customer Info field to their profile, I can see all their past orders on their Profile in the Users area (left side of screen below). However, if I view one of their orders in the Commerce Orders section, the Order History section only ever shows the current order (right side of screen below). Shouldn't it show all their orders like on their profile?

The Order History is the history of that particular order and not designed to pull in other prior orders from that customer.

You might want to make a feature request if you want to be able to see customer histories in the order view:
https://github.com/craftcms/commerce/issues

....if they're a registered Craft user you can use the email at the top to get to their profile (and thus to that field) of course, but that doesn't not help for guest users.


Save and login user in a Plugin? How can I register and login a user in my Controller? I have tried something like this:

$newUser = new User($userName, $userPassword, $userEmail);
Craft::$app->elements->saveUser($newUser);

Put this at the top of the file:

use craft\elements\User;

Within your function use the following code:

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

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

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

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

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


Loop through entries with custom ordering, showing one from each category then start loop again I have a channel with entries that may or may not have a custom date field populated.

I'd like the display a list of entries, looping through each category, showing one entry from each category. Then just start the loop again.

Then, show the rest of the entries which don't have the date field populated. I guess they would just have to be just ordered by postDate, but still only showing one per category each loop.

So (assuming there are 3 categories in total)...

Entry - 4th April - Category 1
Entry - 6th April - Category 2
Entry - 8th April - Category 3
Entry - 5th April - Category 1 - start the loop through categories again
Entry - 7th April - Category 2
Entry - 9th April - Category 3
Entry - Category 1
Entry - Category 2
Entry - Category 3

Note that the dates appear jumbled, as the categories are the thing dictating the order. Date order is a factor, but secondary to the looping of the categories.

This is the code I have so far, all it does is output the entries but with the ones without date fields populated appearing first.

{% for entry in craft.entries.section('heroes').order('date') %}

    {% if entry.date|length %}

{{ entry.title }} - {{ entry.date|date("j") }}{{ entry.date|date("S") }} {{ entry.date|date("F") }} {{ entry.date|date("Y")}} - {% for category in entry.genre %}{{ category.title }}{% endfor %}

    {% else %}

{{ entry.title }}

    {% endif %}

{% endfor %}

Hope that makes sense! Any help will be appreciated.

I'd suggest breaking your problem down into code which gathers the IDs of each of the types of entries first, then outputs them....roughly like this (very much untested!! - but should be enough to understand the approach):

{# Arrays to store the IDs of the entries as we find them #}
{% set noDateIDs = [] %}
{% set dateIDs = [] %}

{% for entry in craft.entries.section('heroes').order('date') %}

    {% if entry.date|length %}
        {% set dateIDs = dateIDs|merge([entry.id])} %}
        {# Or of course you could output the data you want here directly but I like to keep my building and output separate for clarity #}
    {% else %}
        {% set noDateIDs = noDateIDs|merge([entry.id])}  %}
    {% endif %}

{% endfor %}

{% set noDateIDsString = noDateIDs|join(', ') %}
{% set dateIDsString = dateIDs|join(', ')  %}

{# Now actually output the dated entries #}
{% for entry in craft.entries.section('heroes').id(noDateIDsString).find() %}

{{ entry.title }} - {{ entry.date|date("j") }}{{ entry.date|date("S") }} {{ entry.date|date("F") }} {{ entry.date|date("Y")}} - {% for category in entry.genre %}{{ category.title }}{% endfor %}

{% endfor %}

{# Output the undated ones ordered by postDate #}
{% for entry in craft.entries.section('heroes').id(dateIDsString).order('postDate') %}

{{ entry.title }}

{% endfor %}

This approach is very useful generally in Craft, and is documented really well here in 'Manipulating Craft's ElementCriteriaModel objects with Twig' by Jérôme Coupé of Webstoemp


Is it possible to skip entries with children? Hi I m using elementapi plugin to create an json object from my elements. I would like to get all entries, but not those ones who have a children.

My criteria it looks like this now

'elementType' => 'Entry',
'criteria' => ['section' => ['pages', 'home']],
'transformer' => function (EntryModel $entry) {

this returns all entries. For example I have one single home and some other pages the result looks like this:

Home
About us <- this one has children
---------
test1
test2
test3
---------
Contact us

I would like to have result like this

Home
About us
Contact us

Is it possible to achieve this whit some criteria attribute. I've already tried to add level, like this

'criteria' => ['section'=>['pages','home'], 'level'=>'!=2' ]

not working

'criteria' => ['section'=>['pages','home'], 'level'=>1 ]

it's working but returns only pages not giving me the home section

I've tried hasChildren, hasDescendants none of this is working.

If someone can help, thank you in advance.

So after some rest, I did find the solution as follow:

'criteria' => ['section' => ['pages', 'home'], 'level'=>array(null,1)]

This gives me the desire result.


Query for enabled categories In a template, I want to show only enabled categories. I can't figure out how to filter the returned categories by only enabled ones, without doing it in the for loop.

This works:

{% for category in craft.categories.level(1) if category.enabled %}
  # only enabled categories
{% endfor %}

but instantiates the disabled categories, even though they won't be used.

Something like this should work:

% for category in craft.categories.level(1).enabled(true) %}
    # only enabled categories
{% endfor %}


Use email address as username Is there a specific or preferred way to set the username for new user registrations to be their email address?

At the moment my user signup form contains both fields:

  Username
    <input type="text" id="username" name="username" placeholder="joesmith" {%- if account is defined %} value="{{ account.username }}"{% endif -%}/>
    {% if account is defined %}
        {{ _self.errorList(account.getErrors('username')) }}
    {% endif %}

  Email
    <input type="text" id="email" name="email" {%- if account is defined %} value="{{ account.email }}"{% endif -%}/ autocapitalize=off autocorrect=off>
    {% if account is defined %}
        {{ _self.errorList(account.getErrors('email')) }}
    {% endif %}

I believe you're looking for the conveniently named useEmailAsUsername config setting.

When that is set to true, any new user that is saved with a valid email address will have that copied over to the username field as well.


How do I create a page with a dynamic id? Here’s an example: I have a job listing at www.example.com/designer and the user hits "apply" on that page. The user is then taken to a form. How can I know that the user came from www.example.com/designer and not www.example.com/developer?

Depending on how your redirect works, you can redirect and get the param in the template where the form is via:

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

You can then set this param in your form template and post it to your action controller.

<input type='hidden' name='param_name' value='{{ param_name }}' />

In your action controller you can retrieve it by getting it from the post.

$param_name = craft()->request->getPost('param_name');

Is this anything you can use? Or need? Good luck!