How do I get all categories with at least one entry

You could do it like this:

{% set categories = craft.categories.relatedTo({
    sourceElement: craft.entries.limit(null)
}) %}

reference: https://craftcms.slack.com/archives/help/p1429030702000608


It looks like you are trying to access a news variable that probably doesn't exist.

{% for entry in craft.entries.section('news').relatedTo(category) %}

    {# Your image field will be found on your `entry` variable (not a `news` variable) #}
    {% for image in entry.newsimage %}

        {# One you are looping through your image field,
           you can access the image properties via the `image`
           variable you defined in your loop #}

    {% endfor %}

{% endfor %}

If you only have a single news image, you can grab that image directly using the first() method, instead of looping through your image field:

{% for entry in craft.entries.section('news').relatedTo(category) %}

    {% set image = entry.newsimage.first() %}

    {% if image %}

    {% endif %}

{% endfor %}


Create default password for new user registration in CP

If you have "Verify Email Addresses" checked in Settings->Users->Settings and you uncheck "Send activation email now?" users will start in a "pending" state, so the onActivateUser event won't get fired.

If you uncheck "Verify Email Addresses" in Settings->Users->Settings, the "Send activation email now?" checkbox will disappear when registering a new user, users will start in an "active" state and the onActivateUser event will fire.

As you've found, user group information isn't available to the user on the same request they get created in because user group permissions don't get processed until after the onSaveUser event has fired.  You could use onSaveUser, but you'd run into the same limitation.

What you can do, however, is directly check against $_POST (craft()->request->getPost()) to see if the user group you're interested in is there in the onActivateUser event.


Using auto-generated titles against entry field type values

You can access the Software entry’s title exactly the same way you would in your front-end templates: software.first.title. The only difference is the single-brace tags syntax, which you don’t even have to use if you don’t want to. Both of these are identical:

{software.first.title}
{{ object.software.first.title }}


Foreign Key column pointing to `craft_relations` table

I might be wrong, but I don't believe you'll be able to do that within the defineRelations() method – Craft needs a record class for the table you want to create a relation with.

A workaround is to override the createTable() method in your record class and add the foreign key constraint manually using DbCommand:

public function createTable()
{
    parent::createTable();
    craft()->db->createCommand()->addForeignKey($this->getTableName(), 'id', 'relations', 'id', 'CASCADE', 'CASCADE');
}

To be perfectly honest the above feels quite hacky and there might be a better way – but it seems to work :)


List subfolders of a specific asset folder

Not a complete answer, but in your example image if going to be an instance of AssetFileModel.

AssetFileModel has a getFolder method that returns an instance of AssetFolderModel.

AssetFolderModel has a getChildren method you could loop through to get all of the subfolders for the given folder.

Depending on how numerous your file/folder structure is, though, it might be more efficient to do this from PHP in a custom plugin rather than to do it from Twig.


When you are going to apply an and in your relatedTo in Craft 3 it expects the following arguments to be arrays with the structure like here

{% set entries = craft
    .entries
    .section('institutions')
    .relatedTo(['and',
        {element: state}, // <- or targetElement / sourceElement
        {element: solution}
    ])
    .limit(4)
    .all()
%}


How can I output a timeframe in fully written notation nicely?

Add the following macro to your template or import it with a separate twig file. The script allows the start and end date to be the same and outputs a single date instead of a timeframe.

Example:

2014-06-13 to 2014-06-13 yields 13 June 2014

The macro:

{% macro timeframe(dateStart, dateEnd) %}

    {# Output day of the start date if necessary #}
    {{ dateStart != dateEnd ? dateStart|date('j') }}

    {# Output month of the start date if necessary #}
    {{ dateStart|date('FY') != dateEnd|date('FY') ? dateStart|date('F') }}

    {# Output year of the start date if necessary #}
    {{ dateStart|date('Y') != dateEnd|date('Y') ? dateStart|date('Y') }}

    {# Output a hyphen if necessary #}
    {{ dateStart != dateEnd ? ' - ' }}

    {# Output end date #}
    {{ dateEnd|date('j F Y') }}

{% endmacro %}

Example usage:

{# Import external `macros.html` #}
{% import "macros.html" as macros %}

{# Call the macro #}
{% macros.timeframe(entry.exhibitionDateStart, entry.exhibitionDateEnd) %}

.

Edit:

Updated the macro to additionally support "month day, year" notation. The returned notation depends on the localeId attribute passed to the macro (eg. "en_us"). But you probably want to use the current locale's id, craft.locale for that ;)

Examples:

2014-06-13 to 2014-06-13 yields June 13, 2014
2014-06-13 to 2014-06-20 yields June 13 – 20, 2014
2014-06-13 to 2014-07-13 yields June 13 – July 13, 2014
2014-06-13 to 2015-06-13 yields June 13, 2014 – June 13, 2015

The updated macro:

{% macro timeframe(dateStart, dateEnd, localeId) %}

    {# Define locales where 'j. F - j. F Y' format is desired #}
    {% set locales_jFY = ['de', 'it', none] %}

    {# Define locales where 'F j. - F j., Y' format is desired #}
    {% set locales_FjY  = ['en'] %}

    {# Return timeframe for `locales_jFY` locales #}
    {% if localeId in locales_jFY %}

        {# Output day of the start date if necessary #}
        {{- dateStart != dateEnd ? dateStart|date('j. ') -}}

        {# Output month of the start date if necessary #}
        {{- dateStart|date('FY') != dateEnd|date('FY') ? dateStart|date('F ') -}}

        {# Output year of the start date if necessary #}
        {{- dateStart|date('Y') != dateEnd|date('Y') ? dateStart|date('Y') -}}

        {# Output a hyphen if necessary #}
        {{- dateStart != dateEnd ? ' - ' -}}

        {# Output end date #}
        {{- dateEnd|date('j. F Y') -}}

    {# Return timeframe for `locales_FjY` locales #}
    {% elseif localeId in locales_FjY %}

        {# Check if dates are on the same day but in different years #}
        {% if (dateStart|date('Fj') == dateEnd|date('Fj')) and (dateStart|date('Y') != dateEnd|date('Y')) %}
            {% set sameDaydiffYear = true %}
        {% endif %}

        {# Output month and day of the start date #}
        {{- dateStart|date('F j') -}}

        {# Output year of the start date if necessary #}
        {{- dateStart|date('Y') != dateEnd|date('Y') ? dateStart|date(', Y') -}}

        {# Output a hyphen if necessary #}
        {{- dateStart != dateEnd ? ' - ' -}}

        {# Output month of the end date if necessary #}
        {{- dateStart|date('F') != dateEnd|date('F') or sameDaydiffYear ? dateEnd|date('F ') -}}

        {# Output day of the end date if necessary #}
        {{- dateStart|date('Fj') != dateEnd|date('Fj') or sameDaydiffYear ? dateEnd|date('j') -}}

        {# Output year of the end date #}
        {{- dateEnd|date(', Y') -}}

    {% endif %}

{% endmacro %}


To access related entries stored in a matrix field, you need to specify the targetElement (actor/entry) and the matrix field (using dot syntax 'matrixFieldHandle.entriesFieldHandle') from 'plays'.

In your actor biography template:

Actor: {{ entry.title }}

{% set plays = craft.entries.section('plays').relatedTo({
    targetElement: entry,
    field: 'actorsMatrixFieldHandle.actor'
}) %}

Plays:

    {% for play in plays %}

            {{ play.title }}

            {% if play.onStage %}
                ON STAGE
            {% endif %}

    {% endfor %}

To get the role is little more difficult — you first need to find the actor's matrix block in the related 'play' record. We can do this by testing each block to see if it matches the current entry (actor), or use an if clause in the loop.

    {% for play in plays %}

        {% set role = '' %}
        {% for block in play.actorsMatrixFieldHandle if block.actor.first.title == entry.title %}
            {% set role = block.role %}
        {% endfor %}

            {{ play.title }}

            {{ role }}

            {% if play.onStage %}
                ON STAGE
            {% endif %}

    {% endfor %}

You could also try to set the title field as a parameter to the Matrix block query:

{% set actorBlocks = play.actorsMatrixFieldHandle.title(entry.title) %}
{% set role = actorBlocks|length ? actorBlocks.first().role : '' %}


How do I delete an asset with module or plugin

I'm not sure how well it'd go with 50,000 Assets, but you should just be able to call Craft::$app->elements->deleteElement($asset) for each one, or Craft::$app->elements->deleteElementById($asset->id), as seen in the Elements Class Reference.


Solved. There is a bug. When the setting:

omitScriptNameInUrls' => false,

is set to "false" in

/config/general.php

The Plugin Store doesn't load. Switching that setting to true will fix it.


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

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

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

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

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

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

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


I would just leave the URL field blank for parent categories.

In the template you could check if the the category is level two before outputting the URL field.

{% if category.level == 2 and category.categoryUrl %}
    {{ category.categoryUrl }}
{% endif %}


Can I move a local Asset to S3 and keep relations?

Yes you can. Just remember to add your new Assets folder as an assets source to your old Asset fields (fields that are "Asset" types) so users still can add/edit/change their assets.


How can I merge entry values to create a select dropdown

You are using a dropdown field, so you can't query for the counties in use directly from the database. (This would be possible if you had chosen to use categories or tags for them.)

But what you can do is to loop all your jobs entries to collect their respective counties.

{% set entries = craft.entries.section('jobs').limit(null) %}

{% set counties = [] %}
{% for entry in entries %}
    {% set counties = counties|merge({
        (entry.county.value): entry.county.value
    }) %}
{% endfor %}

{% set counties = counties|sort %}

Saving the county name also to the key of each array element makes sure you won't end up getting duplicates. When done use the sort filter to sort the list alphabetically.

Update: there seems to be a problem with getting the dropdown value with entry.county (the shortcut to get the value / calls the field models __toString method) when setting an array key, changing it to entry.county.value works.


What configuration does Craft need to enable Live View on hoster CloudFlare with SSL/https CP?

I'm not completely sure, but would setting site_url to always be whatever the server host is work in this case? In my general.php I use the following before the config array:

$protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://';
$base_url = $protocol . $_SERVER['HTTP_HOST'] . '/';
define('CRAFT_SITE_URL', $base_url);

Then when you run the cp from secure.example.com the livepreview should load urls based on the same url.

I am running a couple of sites on cloudflare and it doesn't matter what domain I call them from they still all work with livepreview so I was wondering if this might be the difference...


Creating a related content subpage to a channel entry?

Two ways that this can be done is A) use a structure, or B) use custom routes.

Using a Structure with different entry types defined for the various sub-page types would probably be the most straightforward and flexible. The base of the structure would be projects (but could just as easily start above projects, if you also wanted to use it to generate your site nav). Your structure might look something like this:

/project1 (entry type: project)
   /news (entry type: projectNews)
   /gallery (entry type: projectGallery)
/project 2
   /...

In your projectNews template, you can access the 'project' entry through entry.parent and can retrieve the news related to the project using relatedTo():

{% set project = entry.parent %}
{% set projectNews = craft.entries.section('news').relatedTo(project) %}
{% for entry in projectNews %}

        {{ entry.title }}
        ...

{% endfor %}

The advantage of the structure is that: you can selectively add these pages to projects on a case by case basis; you can add additional content to the news or gallery pages as needed, in addition to the related content; and that it automatically generates the uri that your looking for.

The other option would be to create custom routes, using the project slug as one of the uri segments (i.e. projects/{slug}/news). The variable slug will be accessible in the templates and can be used to fetch the project using an Element Criteria Model, and the related content via relatedTo():

{% set project = craft.entries.section('projects').slug(slug) %}
{% set projectNews = craft.entries.section('news').relatedTo(entry) %}
{% for entry in projectNews %}

        {{ entry.title }}
        ...

{% endfor %}

The advantage here is that you don't need to generate those additional entries, if 'news' and 'gallery' will always be defined. And if you did need some customizable content for those pages, you could easily place that in the projects main entry.

For another example see this question regarding site structure.


Expanding from Pascal Mollet's answer, this was the solution I came up with.

First setting the address variable with the |nl2br filter:

{% set address = contact.address|nl2br %}

Then, outputting that variable with the |raw filter:

{{address|raw}}

Using them both together at once like this (as Pascal suggested):

{% set address = contact.address|nl2br|raw %}

didn't work.


How to set up CloudFront for a Craft site

I'm running Amazon S3+CloudFront on several of my sites. There's not really much to it, Craft makes it really easy:

Create a new Amazon S3 assets source in Craft.
Set up CloudFront in AWS (see this link).
In the settings for your assets source, add your cloudfront url (something like http://xxxxxxxxx.cloudfront.net/, or your custom CNAME if you set one up) to the "URL Prefix" field.

That should be it!


What is the proper way to fetch items from a custom db table and output them in twig?

I was able to figure almost all of this stuff out by diving through the code. The only exception is triggering the find() method automatically.

The key here was to follow the code in the ElementCriteriaModel. First thing I did was create a method in the MyPluginService class to fetch the data.

public function foo($criteria = false)
{
    return new MyPlugin_MyCriteriaModel($criteria ?: array());
}

I added a wrapper to my MyPluginVariable class.

public function parcels($criteria = array())
{
    return craft()->myPlugin->foo($criteria);
}

This will allow for the following syntax:

{% set data = craft.myPlugin.foo().limit(5).offset(1).find() %}

You must define a find() method in your MyPlugin_MyCriteriaModel class that will perform the SQL query to actually fetch your data. You also have to loop through the results set and instantiate MyPlugin_FooModel for each db row if you want to return a Model to the template instead of a stdObject or array.

For example, my find method looks like this:

public function find($attributes = null)
{
    $this->setAttributes($attributes);

    if (!isset($this->_matchedObjects))
    {
        $objects = craft()->myplugin_foo->find($this);

        $this->setMatchedObjects($objects);
    }

    return $this->_matchedObjects;
}

Then in MyPlugin_FooService I have this:

public function query(MyPlugin_MyCriteriaModel $criteria)
{
    $record = new MyPlugin_FooRecord();

    $query = craft()->db->createCommand()
        ->select('*')
        ->from($record->getTableName())
        ->limit($criteria->limit)
        ->offset($criteria->offset)
        ->order($criteria->order);

    if($criteria->id)
    {
        $query->where('id = :id', array(':id' => $criteria->id));
    }

    if($criteria->uid)
    {
        $query->where('uid = :uid', array(':uid' => $criteria->uid));
    }

    // More conditionals may go here

    return $query;
}

public function find(MyPlugin_MyCriteriaModel $criteria)
{
    $query = $this->query($criteria);

    return $this->_populateModelsFromArray($query->queryAll());
}

protected function _populateModelsFromArray(Array $array)
{
    $models = array();

    foreach($array as $row)
    {
        $models[] = MyPlugin_FooModel::populateModel($row);
    }

    return $models;
}


There are many ways to paginate:

To show next / prev links

#1
getPrevSibling getNextSibling

{% if entry.getPrevSibling %}
    {{entry.getPrevSibling.title}}
{% endif %}

{% if entry.getNextSibling %}
    {{entry.getNextSibling.title}}
{% endif %}

#2 getPrev getNext

{% set params = {section: entry.section.handle} %}
{% set prev = entry.getPrev(params) %}
{% set next = entry.getNext(params) %}

{% if prev %}
    {{prev.title}}
{% endif %}

{% if next %}
    {{next.title}}
{% endif %}

To show list of children (single type page)

{% paginate %}

{% paginate craft.entries.section('sectionHandle').limit(10) as pageEntries %}

{% for entry in pageEntries %}

{{ entry.title }}

        {{ entry.body }}

{% endfor %}

{% if pageInfo.prevUrl %}Previous Page{% endif %}
{% if pageInfo.nextUrl %}Next Page{% endif %}


Have you already made up an html template for this section?

If so you should check if you assigned it right.
Go to: Settings>Sections>(your new section you want to assign) and check the entry template. It should be something like (folder you made the html template in if there is any)/(name of file)

Without any written HTML its not possible to have a live preview as it doesn't output anything.

If thats alright could you post some pictures of your Folders and your back office?


I'm having the same problem for assets and globals.

When craft thinks there are no globals, the entire tab isn't showed.
For the globals i created a new temporary global, so i could access the existing (hidden) ones (they were still connected to one locale).
After that i could open and save them.
After saving they worked for other locales again.

I later found out that setting the admin account to the locale that is working also allows access. Opening and saving each entry works.

Still did not find a solution when content is disconnected from all locales.


JS tag is adding semicolons to my content

I am not sure if the code does what you want it to do - but nevertheless you have three {% endif %} but only two {% if %}. Assuming the line
dynamicEl: [{% endif %}{%- if not loop.last -%}{ "src": "{{ image.getUrl('wsHigh') }}", "width":"{{ img.getWidth('wsHigh') }}", "height":"{{ img.getHeight('wsHigh') }}" },{% endif %}

has one surplus endif tag just at the beginning of the array which prematurely ends the if clause, your code correctly would be:
{% js %}
   {% if image %}
       {%- if loop.first -%}
           window.addEventListener('DOMContentLoaded', function() {
               (function($) {
       $('.slider-pop').on('click', function() {
                $(this).lightGallery({
                    dynamic: true,
                    download: false,
                    zoom: false,
                    hash: false,
                    dynamicEl: [
                       {%- if not loop.last -%}{ "src": "{{ image.getUrl('wsHigh') }}", "width":"{{ img.getWidth('wsHigh') }}", "height":"{{ img.getHeight('wsHigh') }}" },{% endif %}
                           {%- if loop.last -%}{ "src": "{{ image.getUrl('wsHigh') }}", "width":"{{ img.getWidth('wsHigh') }}", "height":"{{ img.getHeight('wsHigh') }}" }]
                })
            });
            })(jQuery);
            });
        {% endif %}
    {% endif %}
{% endjs %}


This would be really tricky without a plugin but you could (and this is a stretch) manipulate the entry channel to accept "reservations" where as the reservations date and time use the date and time field types.

You could then output all the reservation entries to show if/when times are still available. There's no getting around this though, you'd need to work extensively with the saveEntry form, jQuery and a date/time picker to get everything to line up correctly.

The best way to do would be to create a reservation plugin that does specifically this instead of wrangling entires to do the same thing. Either-way I'd say you're looking at some in-depth development time.


How to Show the Total Word Count of an Entry?

You'll need to add a plugin like this one from Lindsey DiLoreto that allows you to insert your own javascript into the CP.  Then you'll need to write some javascript that counts up each word in a textarea input for each block.  I'm sure stackoverflow has several answers on how to do that.  Keep in mind Craft already has jQuery installed if you choose to use it.


Trouble loading custom element action (menu option)

I think your issue may be that the ElementsService getAction method expects the full classname for your custom ElementAction (sans the "ElementAction" suffix), i.e.

$customAction = craft()->elements->getAction('PluginName_Custom');


Special characters in `template->renderObjectTemplate` method

The has been solved (kinda) - turns out CSS was being passed into the renderObjectTemplate method for an email template. This meant that Twig was (understandably) trying to process the { and } characters as objects which was causing the service to throw a wobble.

Have stripped out the CSS for now and will see if there is another way we can pass these characters into the service without breaking it.

Many thanks @robin on the CraftCMS Slack for help identifying and debugging the problem.


Is it possible to group entries by checkbox?

What Brad says, plus an example of grouping by selected checkbox:

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

{# get all checkbox options #}
{% set options = entries.first().checkbox.options %}

{% for option in options %}

{{ option }}

    {% for entry in entries if entry.checkbox.contains(option) %}

{{ entry.title }}

    {% endfor %}

{% endfor %}


Conditionally Applying CSS to Element on Active Page Without Using URL or ID Logic

The craft_structureelements table contains the data you need to determine the exact position & level of each entry in your structure. But you'd need some fancy plugin logic to attack that data and use it to your advantage.

In all honesty, I really feel like you're going the wrong way on this, and you're better served trying to find a way to make the slug or id work for you. The sole purpose of a slug is to identify a specific page.

How about this...

When you dynamically generate your nav, add a CSS class with slug of that nav item. Then, you can verify that against the slug of the page which is being loaded. Even if the slug changes, it'll change in both places simultaneously.


Access environment information in template

In Craft 3 you can get the env using the getenv() function:
{% set env = getenv('ENVIRONMENT') %}

{% if env == 'dev' %}
    hello dev
{% else %}
    hello world
{% endif %}

Or via the app’s config service:
{% set env = craft.app.config.env %}

There's a bit more information about the .env file in the docs for Environmental Configuration.


Create several subcategories without using the GUI in craft

If you have the JSON of the chapters or want to create it, you could import them using FeedMe Pro (required to import the Category element type). It'll import the categories and create child categories if they're not already created.


Control panel switches to HTTPS protocol on its own

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!


Sprout Forms + Email - internal server error

Although the Sprout Email docs state it is preferable to use shorthand syntax for variables in notifications, I found this to not be the case for the Notification subject line.

So using {companyName} in the subject would cause the issue shown above.

{{object.companyName}} fixes this.


How to add custom fields for products in Craft Commerce and output them in the cart

Ok, I think your thinking on this stuff is a little wrong at the moment.

The way Commerce works is that when you add to a cart, it creates a lineItem.  That data model holds basic stuff like qty and a description and so on, enough to just manage and print out the basics of the cart.  However, it also  (for each lineItem) maintains a reference to the purchasable itself - with this purchasable being a purchasable variant (either a products defaultVariant if it is a non-variant product, or the actual variant chosen if it is a variant product).

From this purchasable, you can get back to the full product and/or variant model.

So, you don't actually need any custom fields to get the product's url.  You can print it simply  by working back from the lineitem to the product or variant as you need, using:

lineItem.purchasable.product.url - for the product url
lineItem.purchasable.url - for a specific variant url

In more general terms, in Commerce settings, you can add as many fields to products as you like, and indeed you can also add custom fields to variants.  It's hugely powerful.  And from then on you can get to those fields using the same approach:

lineItem.purchasable.product.fieldHandle - for product fields
lineItem.purchasable.fieldHandle - for variant fields.

The Commerce example templates are very handy for figuring this stuff out, and it's well worth spending a couple hours with the default Commerce install and those templates to see how it all hangs together.


How to insert a Sprout Form into a new page in Craft CMS

If you don't have a local development environment setup, you will need FTP access to the server where Craft is installed to edit templates. The one line of code cannot be copied and pasted into a field in the control panel like one might do with WP.

First of all you will need to make or edit a template to show this form. The "one line of code" needs to be placed in the template where you want to show the form.

For Example

If you are adding a “Contact Us” form that you want to appear at https://[YOUR-DOMAIN-HERE]/contact-us then you would do the following steps:

Login to your company’s server via FTP with and FTP client like Filezilla, Transmit, or Cyberduck. You’ll need to get the FTP login credentials from your company.
Find the location where Craft is installed. If it has not be placed above the webroot then you could probably find it under public_html/craft or www/craft.
Find the templates folder inside the craft folder.
You have a few options at this point:

Make a new file and name it contact-us.html or contact-us.twig depending on your preference. You can probably just make a new file with the .html extension if you don’t have a local development environment set up. I don’t know if there is any performance gains using .twig over .html. You can make a new file usually by right-clicking in the folder where you want it created and there is a context menu to make a new file.
OR you can make a new folder under templates and name it contact-us. Then under that folder you can make a new template named index.html. Your folder structure will then look like craft/templates/contact-us/index.html.

Open the new file that you created in the previous step.
Add the "one line of code" referring to your form.
Save the template.
Go to your browser and type in httpS://[YOUR-DOMAIN-HERE]/contact-us and you should see the form there.

This is probably the simplest way to get your form to show up on your site. There are more advanced and client-friendly ways to do this but this should hopefully get you started.

You’ll need to check the other templates to see how they are created if you want to include the same style as the rest of your site. There is usually a line of code at the top of the template that says something like {% extends '_layout.html'%} or similar.


Can I apply adjustments (discounts) through a controller?

Generally speaking, no. Adjusters should always be computed from the current state of the order—the information required to match an Adjuster should be attached directly to an order.
Your custom Adjuster is registered globally, then applied to Orders that match criteria you've defined in its adjust() method. That method returns an array of Adjustment models, which are then attached to the order.
In this case, what I'd recommend doing is something like this, in your controller:

Looks up the Entry based on a URL param (?code=abc);
Load the current user's Cart;
Set that Entry on the Order via a custom Entry field: $order->setFieldValue('myDiscountEntryField', [$discountEntry]); (noting that the value is an array, due to the way Relational data is saved!)
Save the Cart/Order: Craft::$app->getElements()->saveElement($order);

At this point, Commerce automatically offers each registered Adjuster an opportunity to apply adjustments to the Order.
In your Adjuster, use the attached Discount Entry data to return an Adjustment:
class MyAdjuster implements AdjusterInterface
{
  public function adjust(craft\commerce\elements\Order $order): array
  {
    $discountEntry = $order->myDiscountEntryField->one();

    // We don't want to assume every order contains valid data, and if we can bail early, let's take the opportunity:
    if (!$discountEntry) {
      // The method signature still requires an array returned, but in this case and empty array is basically saying "no adjustments applied."
      return [];
    }

    // Then here, you'll create and return your Adjustment models (like you have in the original question)!
    $adjustments = [];

    // ... Loop over your items...
    foreach ($order->getLineItems() as $lineItem) {
      // ...and use `$adjustments[] = $adjustment` to push new ones into the array, or just `continue;` if you want to skip one.
    }

    // Return anything that was added:
    return $adjustments;
  }
}

If you apply Adjustments outside of this process (the automatic recalculation step, which happens when saving a Cart), you are not likely to have a consistent experience, because they won't be injected the next time a Cart is saved!


How to create ordered list of categories from multiple category groups

You can query on multiple category groups like so:

craft.categories.group('suitability, finish, shape, material, edge, surface').all()

It can also be done with an array:

craft.categories.group([
  'suitability',
  'finish',
  'shape',
  'material',
  'edge',
  'surface'
]).all()

Whenever you invoke .all() it returns an array. As those arrays were merged, they created a larger array. In that last bit of code, categories.orderBy() failed because categories was an array and arrays do not have a method named orderBy.

Hope that helps!


What happened to commerce_discounts->saveDiscounts or How to relate vouchers to product types in Commerce 2?

You now need to set the groups, product types, and purchasables on the discount model directly, then just pass the discount model to the saveDiscount method:

Plugin::getInstance()->getDiscounts()->saveDiscount($discount)

An example of setting these things on the discount before saving can be found in the discount controller:

https://github.com/craftcms/commerce/blob/develop/src/controllers/DiscountsController.php#L128-L166


Activation Email for Pending User Doesn't Work

After following the stack trace for activating a user (with the link), I discovered that activation fails at /craft/app/services/UsersService.php:822:

820:   public function verifyEmailForUser(UserModel $user)
821:   {
822:      if ($user->unverifiedEmail)
823:      {

Apparently I needed to set the unverifiedEmail property when creating "Pending" users via a plugin as opposed to only setting the 'pending' property to false.

$user = new UserModel();
$user->email = 'pendinguser@email.com;
// ... set other properties
$user->pending = false;
$user->unverifiedEmail = '';


Good practice to "Clear Caches" before you "Backup Database"?

Is this helpful, or am I just being OCD?

Completely OCD. :)

The database backup class already excludes unnecessary tables like asset indexing data, sessions, template caches, etc. during a backup.

https://github.com/craftcms/cms/tree/master-v2/src/etc/db/DbBackup.php#L46


Craft 3.1.2 added an index-assets console command that you can use instead of the web-based utility. (#3595)

Sounds like that will work better for you :)

Run this to learn more about it:

./craft index-assets --help


I'm getting a 'couldnt save entry' error for a single but all required fields etc are filled

Under your single's section settings, you had an invalid URI format for the cy_gb (Welsh) locale: ein heiddo.

URI's can't have spaces in them.  It'd be nice if Craft could warn you that the URI format is invalid (no spaces, all URL safe characters, etc), but it's difficult because Twig code is allowed in those fields and all sorts of characters that aren't URL safe are allowed in Twig markup.


The current password it is asking for when you change it is not the password of the user who is having their pasword changed, but the password of the admin (you) who is doing the changing.


Apply different classes and styles when in 'live preview' pane

Craft's Request service has a built-in method for this, isLivePreview.

Here's how to only display content in the live preview view:

{% if craft.request.isLivePreview %}

Only appears in live preview.

{% endif %}


How do I prevent Twig from encoding HTML?

Whenever you output anything with Twig’s {{ output tags }}, the contents will get encoded by default. You have to pass the content through the |raw filter in order for it to be output verbatim.

{{ entry.myFieldHandle|raw }}


Admin panel not working without language code

Solved, I left an .htaccess file in root. It wasn't in local server neither, but It seems it was some config in virtual host or something like that to solve it. Once I find this .htaccess in other craft project, was solved ;)
Don't forget your .htaccess in root!


This is a change in behaviour from Craft 2 to Craft 3 and here is the explanation.
In short, you need to clone your query (docs) - see this post for more info.


Is caching the layout wrapper template a viable option?

In my opinion it's a good, easy and fast way to caching content. We use similar solutions on different Websites and it works perfect for us. Maybe you should do a more specific flagging to avoid deleting all cached entries at once. And you should take care about possible dynamic code parts like forms.


Trying to achieve a row column layout with batch

I think you're getting your variable names mixed up. Something like this should work:

{% for row in entry.content1|batch(2) %}

   {% for block in row %}

Content

   {% endfor %}

{% endfor %}

I've changed the name of the first block to row.


Two things, the variable you send in is called calendarId, not id. Also, inside twig code (like the set function), you don't use twig tags, just the variables directly. Try to change the params object to:

{% set params = {
    calendarId: calendarId,
    dateRangeStart: 'today',
    dateRangeEnd: '+36 months'
} %}


How to handle client expectations regarding page building and layout within Craft

This question comes up in support tickets every so often from client users.

We like to say that Craft fills the space between where WordPress ends and Enterprise begins. It's meant for designers and developers to build bespoke websites for clients. That would include Squarespace-like website building services as well.

If your design, technical, and business requirements exceed what Squarespace can offer then they naturally exceed what a drag/drop website builder can provide. If there's anything a client wishes for in the control panel then they can ask their agency or developers about feasibility. Craft is extensible enough to make most thing possible; it's just a matter of effort and cost.


In order to install under MAMP with PHP7 we added the MAMP PHP7 path with the following command:

  export PATH="/Applications/MAMP/bin/php/php7.0.15/bin:$PATH"

After achieving a successful Craft 3 install we ran the setup in the CLI and we also created a fresh DB and a new MAMP host following the sequence recommended in the installation docs.


Altering Structure order doesn't update cache

After Greg Stewart's help I found that the reason that the Cache wasn't updating when altering the hierarchy of the Structure is:

There were Stuck background tasks.

Here is the official documentation on the matter.


How to add addition attribute and fields in public registration form in Craft CMS

Before you can allow any type of user groups you will need at a minimum of the Client version of Craft. To allow public registration, you will need the Professional version. Only the Professional version will allow you to have public registration on our site. Here is more information about users and user groups.

To add additional fields to your registration form, I would start here. That will get you started with a basic form.

You will need to create a new field within the CP. For example - let's say I want to capture your pets name.

I will create a text input, called petName. Then in the layout builder, I will assign that field to the user profile tab.

Next, I need to update my registration form with my new input.

Note: any new field you want to add to the user's profile must be prefixed with fields[]. For example:

<label for="petName">Pet Name</label>
<input type="text" id="petName" name="fields[petName]" {%- if account is defined %} value="{{ account.petName }}"{% endif %}" placeholder="">
{{ account is defined and account ? errorList(account.getErrors('petName')) }}

Hope this helps!


Commerce 2 Sales Not Present In Cart lineItems

After further testing and debugging, it turns out these issues are related to this bug in Commerce:

https://github.com/craftcms/commerce/issues/1206

As per that github issue, it was a Discount with Ignore sales when this discount is applied enabled that was the culprit, but shouldn't be once that bug is fixed.


Why am I getting ?p=oldpage in a 301 redirect?

Craft works by taking requests that normally would 404—because they don't actually exist on the server but in the database. The piece that makes this happen is the rewrite rules.

It's helpful to look at Craft's .htaccess file line-by-line:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

The request must not already exist and the file is not already an existing directory on the server.

RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]

The URL must not be favicon.ico, apple-touch-icon.whatever.png. The NC at the end means no-case (meaning case-insenstive).

RewriteRule (.+) index.php?p=$1 [QSA,L]

This is the rule that actually fires. Take those would-be 404s, redirect to /index.php (the controller). $1 means the match found in (.+).

The QSA flag means query string append. This is the part that's actually causing you issues. (You could remove it but get URLs with parameters called from controllers might not work in certain situations.)

L means last; if this rule is applied, it won't process anything else. Doesn't matter here unless you have other rules.

What you need to do is tell Apache to exclude this particular request from Craft's processing (put it after the favicon rule):

RewriteCond %{REQUEST_URI} !^/(work/project-name)$ [NC]

Now what will happen is your Redirect 301 rule will fire by itself. Since /case-studies doesn't actually exist on the server,  Apache is going to send that rule back to Craft and fire like any normal "page" which is what you want.

If you have other redirected 301s from the old /work section, you might do something like:

RewriteCond %{REQUEST_URI} !^/(work/.+)$ [NC]

That will let Craft know not to touch any of your 301s in the old work section. You still need your old Redirect 301 rules.  (You could make a RewriteRule for those if you wanted to simply things but this will get you going.)

Your completed file would look like:

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

Redirect 301 /work/project-name http://www.mysite.com/case-studies
...

I find some browsers will "cache"  an old page/redirect for awhile. To confirm it's actually working you might want to use curl -I http://site/work/project-name. If you see "moved permanently" message, you're all set.


Craft entries related on a category page

I should note that the relatedTo method accepts a CategoryModel, not the title of a category. What you ended up doing works, but here's the way to do with the relatedTo method, which is what I'd suggest for anyone finding this in the future:

{% for entry in craft.entries.relatedTo(craft.categories.slug('your-cat-slug')) %}

You now have all entries that are associated with the given category, and can loop through them with the usual {% for entry in entries %} technique.

TL;DR: You can't pass the category name. You have to give relatedTo an actual CategoryModel.


Copy uploaded image in event assets.onSaveAsset

I'm thinking you should use the onBeforeUploadAsset event for this instead.  You can get the path to the temporary location on disk via the path parameter like so:

$path = $event->params['path'];

From there, you can make a copy of the file and save to whatever location you want.  You can also watermark the original and save it back to the same temporary location and let the request continue.


Query entries with latest video field containing a URL

No need to use search in this case.

{% set results = craft.entries.videoField(':notempty:').orderBy('postDate desc').one() %}


Try this:

{{ entry.getChildren().total() }}


How do I add meta data and a page title through ajax?

You almost certainly don't have to update the meta tags when you use AJAX to load pages like this.

Meta tags are not exposed to the end user; they're there for search engine crawlers and social media embedding (e.g. Facebook) etc. Crawlers will read the meta tag values from the original HTML at the URL being crawled or shared, not whatever values you update to using JavaScript in an AJAX callback.

On the other hand, updating the page/document title can be a good idea, as users will see this value in their browser.

You can update the document title simply by setting

document.title = "Who let the dogs out?"

somewhere in your JavaScript. A good place to do this in regards to the tutorial script you're using would be inside the ajaxLoad() method, i.e.

ajaxLoad = function(html) {
    init();

    /* ----- Here you could maybe add logic to set the HTML title to the new page title ----- */
    document.title = "Who let the dogs out?";

    ...
},

Of course, you'll want to set the document title to something relevant – preferably the "real" page title for that URL. You certainly could use the ElementAPI plugin to pull your entry's title, but that would mean a ton of work and an additional AJAX request. A much simpler way to do it is to set a data-attribute somewhere in the markup returned by the original AJAX call, e.g.:

<div class="js-ajax-wrapper" data-title="{{ siteName }}: {{ entry.title }}">
    {{ entry.body }}
    ...
</div>

And then do something like this in your ajaxLoad() method:

ajaxLoad = function(html) {
    ...
    document.title = $('<div />').append(html).children('.js-ajax-wrapper').data('title');
    ...
},

Note that the designbycosmic.com script has a small bug – in order for the above to work you'll have to change the call to ajaxLoad() inside the success callback for the loadPage() method to ajaxLoad(result); – alternatively, you can ignore the ajaxLoad() method and just change the document title inside the success callback:

success: function(result){
    ...
    document.title = $('.js-main .js-ajax-wrapper').data('title');
    /* ----- Bring In New Content ----- */
    ...
},

Finally, as an aside your issue with the ElementAPI plugin is that you're returning a JSON payload (containing only the title, url and jsonUrl for the entry), yet you're attempting to inject that data into the DOM as HTML (i.e. $main.html(result);.


Importing Unix timestamp into date time field

According to the documentation for the Date field, Feed Me uses date_parse to parse a provided date string into a proper date object. date_parse uses strtotime underneath, which seems to have issues with timestamps.

I just wanted to confirm your timestamp though, as it seems to not produce the correct date for me using:

echo date('Y-m-d H:i:s', 1457685095000);

// Results in
48162-03-15 06:23:20


Commerce doesn't support multiple stock sources out of the box but you might be able to work around it, depending on your requirements.
To expand on your thoughts...
Variants
How are your products set up? Commerce doesn't add a product directly to a user's cart, it's actually Purchasable—with Variants being one of the purchasables in Commerce.
If your products don't have a lot of variations that you'd use a Variants for, one way to pull off what you're trying to do is just filter variants based on the user that's logged in—creating multiple groups could be one way.
That way, you could take advantage of Craft's native stock-handling features directly.
Depending on how many products are in the store, you might also choose to use something like a CSV import/export and not touch the Commerce backend directly.
Multiple stock level fields
Another slightly cleaner way to pull this off would be turn off Commerce's native stock handling (set it to unlimited) and roll your own validation with your own inventory fields.
From a code standpoint, that's a more intensive way to go but it does put you more in charge of how you handle inventory. Commerce provides multiple events to let you handle the stock validation and it might be a good way to go depending on your rules (eg you might want to reallocate inventory from a trade customer to handle a regular customer in some cases or vice versa).


How to prevent select user groups from reordering structures

You should be able to ensure that the elements aren't moved by using the structures.onBeforeMoveElement hook in a plugin:

public function init()
{
    craft()->on('structures.beforeMoveElement', function(Event $event)
    {
        $user = craft()->userSession->getUser();

        if (!$user->isInGroup('allowedGroup'))
        {
            $event->performAction = false;
        }
    });
}

I've had a quick look through the source but I'm not 100% sure if this is also run when an element's parent is changed. I would think it is.

You could also create your own custom user permission that can be assigned to individual users or multiple groups for more flexibility:

public function init()
{
    craft()->on('structures.beforeMoveElement', function(Event $event)
    {
        $user = craft()->userSession->getUser();

        if (!$user->can('pluginName-moveElements'))
        {
            $event->performAction = false;
        }
    });
}

public function registerUserPermissions()
{
    return array(
        'pluginName-moveElements' => array('label' => Craft::t('Move Elements in Structures')),
    );
 }


How to create custom field type in Craft 3

In order to include a custom field type you first need to register your own module or plugin you can create the basic structure for both from pluginfactory.io and register them as you like. There is also a default module that comes with every Craft 3 installation. You only need to bootstrap it in your app.php

Then in your module you need the following code

public function init()
{
    Event::on(Fields::class, Fields::EVENT_REGISTER_FIELD_TYPES, function(RegisterComponentTypesEvent $event) {
        $event->types[] = MyField::class;
    });
}

And your class could look like the Incognito Field for example.
Basically every field has several methods implemented in the FieldInterface such as getInputHtml to render the HTML or normalizeValue to create a field value based on user or DB input and serializeValue to prepare the value for your DB. The interface has everything you need.

A good example to get started is to extend the PlainText field and customize it's functions. You can overwrite the inputHtml function and render a custom template

public function getInputHtml($value, ElementInterface $element = null): string
{
    // Get our id and namespace
    $id = Craft::$app->getView()->formatInputId($this->handle);
    $namespacedId = Craft::$app->getView()->namespaceInputId($id);

    // Render the input template
    return Craft::$app->getView()->renderTemplate(
        'module-id/fields/hidden/_input',
        [
            'name' => $this->handle,
            'value' => $value,
            'field' => $this,
            'id' => $id,
            'namespacedId' => $namespacedId,
        ]
    );
}


Is there a way to read IPTC, EXIF or TIFF Metadata in an Image uploaded to Assets?

You can create a plugin that does something like this:

$image = new Image();
$image->load('/path/to/image.jpg');
$exif = $image->getExifMetadata();

See here for other methods on the Image class.


How can I access variables only declared in a template?

I don't think you can. I think the best way to access 'unattached' variables is to create a global field set and attach fields to it. That way you'll be able to access them anywhere.

{{ globalSet1.title }}
{{ globalSet1.description }}
{{ globalSet1.variable3 }}


Test for specific or multiple product variants

product.variants|length will in fact give you the exact number of variants the product has. If it is giving you an unexpected response, you’re probably just not looking at the right product in the first place. Try outputting the following to create a URL to the product’s edit page in the Control Panel:

{{ product.title }}

Then click on that link from your browser to see the actual product you’re dealing with.


Matrix field freezes on localhost when I try to make a new entry

I resolved this by upgrading my wampserver from ver 2.5 to 3.03.


Disabling individual sites on a Craft 3 multisite

Seems like this is something you'd do from your .htaccess file or public index.php files for each of the non-primary sites you define.

For example if you have a public_html/index.php for your English primary site and a public_html/de/index.php for your German site, your German one would just header("Location: http://mysite.com/503"); to redirect.


Safe number of related entries – before performance hindered?

The real answer, as with most performance related questions is, "it depends".

That's based on environmental factors like how much resources does your site and database have, what else the templates are doing, how are the servers configured, etc.

Craft 2 limits the amount of elements returned in a query to 100 by default, so that would probably be a good place to start.


You can create a unique ID function in PHP and pass it to Twig

{% set uniqueId = uniqueId() %}

And your PHP part

class Extension extends \Twig_Extension implements \Twig_Extension_GlobalsInterface
{
    public $uniqueIds;

    public function getFunctions(): array
    {
        return [
             new Twig_SimpleFunction('uniqueId', [$this, 'getUniqueId'])
        ];
    }

    /**
     * getUniqueId
     *
     * @return string
     */
    public function getUniqueId(): string
    {
        // generate a random string
        $id = StringHelper::randomString('12');

        // check if it's already set
        while (\in_array($id, $this->uniqueIds, true)){
            // if so, use another one
            $id = StringHelper::randomString('12');
        }
        // set it as "used"
        $this->uniqueIds[] = $id;

        return $id;
    }
}


How to search on multiple (custom) fields using Element API

In your last example:
$criteria = [
    'section' => $section_handle,
    'excerpt' => "*{$q}*"
];

You are making a fuzzy search by surrounding your keyword(s) with * (see docs for syntaxes) and I wonder if that's why you are seeing results (I'd need to see the keywords/entry).
However, if that works, then this should work for you:
'criteria' => [
    'section' => $section_handle,
    'search' => ($q ? 'title:' . $q . ' OR '.'excerpt:*'. $q . '*' : null),
],

Alternatively, make everything fuzzy (not as precise):
'criteria' => [
    'section' => $section_handle,
    'search' => ($q ? 'title:*' . $q . '* OR '.'excerpt:*'. $q . '*' : null),
],

One final thought, if your section has three fields, if you only check Use this field’s values as search keywords on your Settings → Fields → excerpt field then you can search on both title + excerpt simply by doing:
'criteria' => [
    'section' => $section_handle,
    'search' => ($q ?? null),
],


craft()->cache can point to any one of several different caching drivers as defined by the   cacheMethod config setting.

The available methods are all pretty much stock Yii provided caching drivers, with the exception of FileCache, which we've extended a bit.

Note that FileCache is used by default and its values are saved under the craft/storage/runtime/cache folder.


in a for loop, how do i only display entries of a certain category?

{% for entry in craft.entries.section('News').relatedTo(57).limit(1).all() %}

does work! 57 being the Category ID in this case. Thanks for the help.


How do I delete or remove temporary assets?

From my comment above:

I was able to find the files uploaded to the root of my assets path and deleted them there.

Then on the control panel settings page:

Updated Asset Indexes and Cleared Cache and it seems to be all working.


What media type are SVGs treated as in assets?

Image. Use the kind parameter to filter them out.


Craft Setup 3.6.5.1 with MYSQL with SSL version 5.7.29

Looks like you got this sorted using Craft's database attributes config setting.
https://github.com/craftcms/cms/issues/7583#issuecomment-781168257


I built a website very similar to what you're describing using ExpressionEngine years ago. It's definitely doable in Craft, and it'd be much easier than most other platforms I can think of.

However, as Brad noted in his reply, it will take some development effort.


Issue with twig loop.first loop.last contained in nested for statement

You should be able to access the outer loop.index etc using the loop.parent context. The Twig docs here should give you what you need.

EDIT: You might be getting strange results because the inner loop contains an if so depending on your conditions you might loop over the first item thus making your inner loop.first not work as expected. You can combine for with an if which might get you a bit closer, like this:

{% for thing in things if thing.isAvailable == true %}
{{-- Your inner stuff --}}
{% endfor %}

More info here.


How to add class to ul ol tag in redactor by using formattingAdd

The unfortunate answer here is you can't add classes to ul or ol elements using formattingAdd, at least that's the way I interpret the documentation. See: https://imperavi.com/redactor/docs/settings/formatting/#s-formattingadd
It states:

formattingAdd can only be applied to block tags (p, pre, blockquote, div, heading, etc).

I suspect the etc there also encompasses ul and ol elements, even though they are block elements.
The best workaround I can come up with for this is to have a wrapper around the list and apply the class to that wrapper. As this would be fiddly in Redactor alone, I use a matrix field type to add blocks of content, with the option to add a class to the wrapper for that particular block.
This page describes this method of building out content https://nystudio107.com/blog/creating-a-content-builder-in-craft-cms


Craft 3 to webserver (with only access to public_html )

I figured out, I wasnt keeping my web folder in the root, that was the problem.


Yes, after uploading via FTP, you will need to tell Craft to go and index the new assets: Settings > Tools > Update Asset Indexes


How can I create a status message of X of TOTAL pages under a parent?

I assuming the pages are one level down from the parent?

Parent
  | Child (1)
  | Child (2)
  | ... etc

You can do this:

{% set topLevel =  entry.parent %}
{% set totalPages = topLevel.getDescendants().count() %}
{% set entryIds = topLevel.getDescendants()|group('id')  %}
{% set currentPageNumber = (entryIds|keys)|indexOf(entry.id) + 1 %}

{{currentPageNumber }} of {{totalPages}}

Basically we're making an array (list) out of just the entry IDs by grabbing the descendants from the parent. Then we use Craft's group function to give us an array, grouped by key (in this case the ID). Since we know the current page's ID, we can find it in the array and return its position. Since arrays are indexed starting with 0, we just add 1 to it.


You can move them like this

$asset = Asset::find()->volume('resourceImages')->filename($filename)->one()
$folder = Craft::$app->getAssets()->findFolder(['volumeId' => X]);
Craft::$app->getAssets()->moveAsset($asset, $folder, $filename);

It won't change your relations or anything else in fact all the function does is:

/**
 * Move or rename an Asset.
 *
 * @param Asset $asset The asset whose file should be renamed
 * @param VolumeFolder $folder The Volume Folder to move the Asset to.
 * @param string $filename The new filename
 * @return bool Whether the asset was renamed successfully
 * @throws AssetLogicException if the asset’s volume is missing
 */
public function moveAsset(Asset $asset, VolumeFolder $folder, string $filename = ''): bool
{
    // Set the new combined target location, and save it
    $asset->newFilename = $filename;
    $asset->newFolderId = $folder->id;
    $asset->setScenario(Asset::SCENARIO_FILEOPS);

    return Craft::$app->getElements()->saveElement($asset);
}


trying to use loop.length with some dynamic css

Turns out I was trying to add this to my :hover state and not the initial state. Problem solved by adding a new rule and putting the width in there.


How to calculate the number of hours left?

You can use the date filter to format the DateInterval to your needs, I guess you
are looking for the total hours until the event, so you have to do some math.

Because there's still some strange things going on with Craft DateTime objects, do what I
recommended in the question you mentioned, convert it to a string in a common format that includes time and timezone information
and then use Twig's date function to convert it to a Twig DateTime object.

To get a "DateTime string" in ISO8601 or UNIX format use the iso8601 or getTimestamp method or the date filter with the corresponding parameter.

{% set dateTimeEvent = date(inschrijven.datumEvenement|date('c')) %}
{% set dateTimeNow = date(now.iso8601) %}

{% set dateInterval = dateTimeNow.diff(dateTimeEvent) %}

{% set days = dateInterval|date('%a') %}
{% set hours = dateInterval|date('%h') %}
{% set totalHours = days * 24 + hours %}

{% set upcoming = dateInterval|date('%R') == '+' ? true %}

{% if upcoming %}
    Event start in {{ totalHours }} hours.
{% endif %}


What are useful guidelines for Craft CMS security on VPS (virtual private servers)?

This morning a couple of postings on Craft Slack #devops area linked good descriptions of basic server security, led by @merlingore there.

Their instructions are tilted towards Ubuntu as far as specifics, but should fit for any Linux VPS.

Recording the links here so we don't lose the patterns. I agree with them because they're actually the same as what I came up with personally in arranging VPS security, and they say what's needed clearly and concisely.

https://plusbryan.com/my-first-5-minutes-on-a-server-or-essential-security-for-linux-servers

and to complete on automatic security updates,

https://blog.mafr.de/2015/02/26/ubuntu-unattended-upgrades/

IT's quite worth reading the comments also on each of these, particularly the second. I like the so-often Germanic completeness there, if would suggest that auto-reboot is not just for personal servers.

You can control time-of-day via the auto-cron setting, and if you need 100% uptime, this is very likely better managed (and likely only actually possible for many scenarios) by providing more than one load-balanced server, updating them in a sequence, which again the cron portion could be one way of handling.


Can't get Craft running on a remote server

If you upload Craft, your folder structure should look like this (default):

  /craft/..
  /public/index.php

If this is not the case, you have to set $craftPath (in the index.php) depending on your folder structure. Check out the Installing section in the docs.

.

Example:

If your structure looks like this..

  /craft/..
  /index.php

..the path should be: $craftPath = './craft';


Commerce: are Shipping prices always assumed to include tax?

We fixed this by doing three things...

On our tax rate, setting "Taxable Subject" to "Order total taxable price (Line item subtotal + Total discounts + Total shipping)"
Also on our tax rate, turning on the "Is this tax is already
included in the taxable subject?" switch.
In our templates, wherever tax is displayed, changing from {{getTotalTax}} to {{getTotalTaxIncluded}} — eg to display the total tax (included) on a basket for both line items and shipping you'd want something like {{ cart.getTotalTaxIncluded('tax')|commerceCurrency(cart.currency) }}


For anyone with the same issue- I was able to fix the issue by setting the execution time as infinite and then waiting for an hour.


Tagging and Associating Photos with Entry Type

Assets can have custom fields just like entries. You can create an entry field for the person section, and add it to the asset source field layout from your asset settings.

You can then use relations to query for the right assets or entries as you see fit!


Try adding find() to your ElementCriteriaModel, I think without that function you're not actually saving your entries as an array in your variable todaysOneOffEvents yet.

Here's what I found in the Docs:

  You don’t actually need to call find() yourself though: It will be called automatically as soon as the ElementCriteriaModel is treated like an array (that is, as soon as you check how many elements there are using the |length filter, or start looping through the elements with a {% for %} loop).

We learn that merging doesn't "treat it like an array", good to know.

Edit: You can't use the length filter to "convert" the content of the variable to an actual array. Removed that part from the answer.


Controlling where user is sent if clicking old or expired email activation link

It looks like the config setting activateAccountFailurePath is what you are looking for.


How can I list previously viewed entries?

Craft doesn't have anything like an onViewEntry event, which you could listen for.

One way to do it would be to have a plugin that listens for onEndRequest. That plugin would determine if the current URI matches an entry and if so saves it to the database along with the userId.

Then you could build a management page off of that info where you could remove from the history or delete it all-together.


Automatically create users from http header

You would most likely want to add a controller to your custom plugin, with an 'action' method designed to handle the url request and generate a user; using 'post' or 'get' to pass parameters to the controller action.

In the controller action, you can access your parameters using:

$username = craft()->request->getParam('username');

You can then populate a new User Model using the passed params and save the model.

$user = new UserModel();

$user->username   = $username;
$user->email      = $email;
$user->firstName  = $firstName;
$user->lastName   = $lastName;
$user->getContent()->setAttributes([
    'customField' => $customFieldValue
]);

craft()->users->saveUser($user);

// We now have a user Id, so assign user to a group
craft()->userGroups->assignUserToGroups($user->id, $groupId);

// or to multiple groups
//craft()->userGroups->assignUserToGroups($user->id, [$groupId, $otherGroupId]);

However, by default, controller actions are only accessible to logged-in users. If you want to allow anonymous access you would need to specifically allow it using the $allowAnonymous property. This definitely introduces some security issues however, so proceed with caution. For example: definitely do not just assign user group(s) blindly from passed parameters or someone might be able to give themselves admin access!


I do believe you're missing the handle to the top-level Matrix field when you're passing into setContentFromPost. You should be doing:

$couponCodeMatrix->setContentFromPost(array('couponCodes', $newMatrixData));

Otherwise, you're just passing:

'45623':
    'type': 'blockTypeHandle'
    'enabled': true,
    'fields': []

to the global set, instead of:

'couponCodes':
    '45623':
        'type': 'blockTypeHandle'
        'enabled': true,
        'fields': []

To deal with fetching even disabled blocks, you'll need to actually query the Matrix field's block directly, rather than looking just at the Global Sets content.

$criteria = craft()->elements->getCriteria(ElementType::MatrixBlock);
$criteria->fieldId = craft()->fields->getFieldByHandle('couponCodes')->id;
$criteria->ownerId = $couponCodeMatrix->id; // This is your Global Set id
$criteria->status = null;
$blocks = $criteria->find();

foreach($blocks as $block) { }

More complete code for anyone interested. We loop through the matrix and recreate it only if we updated the disabled status on the matching item.

Thanks again!

    $couponCodeMatrix = craft()->globals->getSetByHandle('couponCodes');

    $criteria = craft()->elements->getCriteria(ElementType::MatrixBlock);
    $criteria->fieldId = craft()->fields->getFieldByHandle('couponCodes')->id;
    $criteria->ownerId = $couponCodeMatrix->id; // This is your Global Set id
    $criteria->status = null;
    $matrixBlocks = $criteria->find();

    $b_updateMatrix = false;
    $o_foundCoupon = false;
    $newMatrixData = array('couponCodes'=>array());
    foreach($matrixBlocks as $block){

        $b_enabled = $block->enabled;
        if ($this->couponCheckMatch($s_code, $block)) {
            $o_foundCoupon = $block;
            if($block->singleUse==1){
                $b_updateMatrix=true;
                $b_enabled = false;
            }
        }

        $blockData = array(
            'type' => $block->getType()->handle,
            'enabled' => $b_enabled,
            'fields' => array(
                'couponCode' => $block->couponCode,
                'couponType' => $block->couponType,
                'couponValue' => $block->couponValue,
                'expiryDate' => $block->expiryDate,
                'singleUse' => $block->singleUse,
            )
        );
        $newMatrixData['couponCodes'][$block->id] = $blockData;
    }
    if($b_updateMatrix) {
        $couponCodeMatrix->setContentFromPost($newMatrixData);
        craft()->globals->saveContent($couponCodeMatrix);
    }


Multi-environment configs and running sites on different ports

You can define CRAFT_ENVIRONMENT in your index.php like so:

switch ($_SERVER['SERVER_PORT']) {
  case "8081":
    define('CRAFT_ENVIRONMENT', 'TRUNK');
    break;
  case "8082":
    define('CRAFT_ENVIRONMENT', 'BRANCH');
    break;
}

And then in general.php and db.php you can:

return array(
  '*' => array(
    ...
  ),
  'TRUNK' => array(
    ...
  ),
  'BRANCH' => array(
    ...
  )
);


Just found the solution:

npm install qs

and

import qs from 'qs'

...
const actions = {
    auth({ commit }, { email, password }) {

        axios.post('url', qs.stringify({
            your token data here
        })).then((res) => {
            console.log(res.data)
        }).catch((err) => {
            console.log(err)
        })
    }
}


modifyEntrySources hook, comparing two field values

A workaround solution was to essentially do an criteria on the section, return all the records, use a conditional to find out which records have the same "parent ID" and ID", stores those in an array and then use the id criteria for the entry source.

Something like:

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = 'theSection';
$criteria->limit = null;
$articles = $criteria->find();

// For storing matching entries on the conditional below
$ids = [];

foreach ($entries as $entry)
{
     if($entry->fieldParentId == $entry->fieldId)
     {
         array_push($ids, $entry->id);
     }
}

This will then provide a list of ids that match the required criteria, which can then be used for a specific entry source.

This has performance issues though, because you have to get the entire list of entries first each time.


In your Control Panel, go to Settings > General.

Then set your Site URL to {siteUrl}.

This will parse out the siteUrl environment variable. For more information, see this thread...


How do I reset a user’s password or email them when I create an account?

If you are an administrator or your account has “administrate users” privileges, then there is a checkbox on the user’s edit page in the control panel that says “Require Password Reset on Next Login” which, if checked, will force the users to reset their password the next time they attempt to login.

When creating a new account, if you leave the “Require Email Verification” checkbox checked, the user will get an email asking them to confirm their email address and set a new password on their account when the click the link in the email.

Note that the password reset and account verification process requires email to be configured and working properly under Settings->Email in the control panel.


Access add and remove events with the Craft Element Selector?

As of Craft 2.4.2688:

  It is now possible to access Craft.BaseElementSelectInput objects
  from their container elements, via .data('elementSelect').

On select element:

$('#theElementSelectField').data('elementSelect').on('selectElements', function(e) {
    console.log(e); // Take a look
    // Do stuff here when elements are selected...
});

On remove element:

$('#theElementSelectField').data('elementSelect').on('removeElements', function(e) {
    console.log(e);
    // Do stuff here when elements are removed...
});

NB. If you are using the Craft macros to build the select element inputs, make sure your javascript is run after craft has done its magic with the input field.

Thanks to Brandon Kelly & Lindsey D


Freeform includes mail list integration for MailChimp, Constant Contact (pro only) and Campaign Monitor (pro only).

As per their documentation, form fields can be mapped to your mail list. You can include a checkbox so visitors can choose to subscribe when submitting a form. If they do tick the checkbox, they will be sent a double opt in email (if this is enabled).

Do bear in mind though that MailChimp is rolling out single opt-in from 31st October 2017 unless you're within the EU.


You have a space between the { and % in your twig tags. That needs to be removed. :)


Show the best sellers and the most visited products - Craft Commerce

This functionality does not currently exist natively in Commerce (June 2016).

You could probably use a plugin like entry count (https://www.putyourlightson.net/craft-entry-count) to achieve the most viewed (you might need to add commerce products support to that?).

For the best sellers, your best bet at the moment is probably to make a plugin that uses a query on the craft_commerce_lineitems table (along the lines of https://stackoverflow.com/questions/12235595/find-most-frequent-value-in-sql-column)...to return a twig variable of the n most popular product objects.


Why is Craft loading jQuery via cpresources? And can I stop it?

If any of your image transforms have not previously been processed they will make a call to /cpresources/... To prevent this, generate all your transforms before page load with the generateTransformsBeforePageLoad config setting:
'generateTransformsBeforePageLoad' => true


Craft CMS plugin with AJAX gives 404 error

If you aren't currently logged in, you're apt to be running up against the "anonymous access" limitation.

This section of the Controller documentation should help:

  By default, controller actions are only accessible to logged-in users. You can override that by changing the protected $allowAnonymous property on your controller class. To allow anonymous access to all of your controller’s actions, set it to true:

<?php
namespace Craft;

class CocktailRecipes_IngredientsController extends BaseController
{
  protected $allowAnonymous = true;

  // Your action methods
}


You can use Craft::getLogger()->log($message, $level, $category = 'application')

It uses the Yii2 logger, you can change the $category to your plugin handle

Edit: You can use the "short" syntax as well class reference

Craft::warning($message, $category);

or

Craft::info($message, $category);


BaseController::returnJson & devMode interference

I had the same problem. See Brad's response here to so this without messing with devMode: Console script tags garbling up non-html output (e.g. json) when in devMode

It would be nice if this happened automatically when specifically outputting non-html, though.


Plugin Store install buttons are not visible

Most likely you have the allowUpdates config setting in your config/general.php file set to false.


Undefined index: siteSettings when updating entry types

Even with 'useProjectConfigFile' => false, it is still active under the hood.

Could you run ./craft project-config/rebuild and see if that fixes the issue?


Different template for an entry in section

Zuccs, have a look at this plugin: https://straightupcraft.com/craft-plugins/template-select


It looks like you're asking how to add a letter 's' to the day.
So how about using

{{ now|date("l") }}s


Ok, so I'm tenatively answering my own question — although I'd like someone to shed light on the duplicate tag problem — it seems like a combination of #1 and #2 works quite nicely, although I haven't extensively tested it yet.

{% if tag is defined %}
  {% set tag = craft.tags.slug(tag).first() %}
  {% set entries = craft.entries.section('articles').relatedTo(tag) %}
{% else %}
  {% set entries = craft.entries.section('articles') %}
{% endif %}

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

This is working with the route articles/tag/[tag token] set up. The only issue is when a tag that has a duplicate slug, whether that be within the same tag group or a different one, it returns no results (I'm not great at reading logs, but it doesn't seem to throw any errors either).

Any additions to this answer would be appreciated!


How to setup custom site routes created by user in plugin settings

You can use the registerSiteRoutes() hook in your plugin's primary class.

Assuming your custom URL formats are stored in an array in a plugin setting called customRoutes (use AttributeType::Mixed for arrays), and that the array consists of key/value paired routes and template paths:

public function registerSiteRoutes()
{
    return $this->getSettings()['customRoutes'] ?: array();
}

Here's how the customRoutes array should look:

array(
    'some-custom-route' => '_some-custom-template',
    'another-custom-route' => '_another-custom-template',
),


Just by the way, Neo is currently not supported with Feed Me. You're welcome to upvote this feature request - https://github.com/verbb/feed-me/issues/335


If you have infoPage with category A and B lets say.

Then, you have a Product 1 with category A and B also.

If in your template you do (with entry being the current infoPage entry):

{% set relatedProducts = craft.entries.section('products').relatedTo(entry.relatedCat).all() %}

{% for relatedProduct in relatedProducts %}
    {{ relatedProduct.title }} <br>
{% endfor %}

You should not get Product 1 returned to you twice..? Have you actually tried?


Is it possible to change the default search result order (CP)?

Maybe?  Pretty hacky I think, but there is an EVENT_AFTER_SEARCH you can listen to that has the results already scored.

You could probably take those results, then resort by whatever other attributes you want and pass them along back to the CP.


Maintaining and deploying many multi-site from a single codebase

Craft's Project config is really made for updating changes from staging to production.
When it comes to making changes across a fleet of (different) sites, you're somewhat on your own there. You might think of all of your sites as the same but Craft is thinking of each site independently because that's how it's designed.
It sounds to me that one way to handle this might be to try to automate migrations between installs? You change one site, test it, and then move the migration to the next client site/grouping.
After all, if you're changing or adding fields, for example,  you're most likely going to be changing the (GraphQL) code that also queries those fields as well or everything is going to fall down pretty quick.
Something like Migration Assistant could useful here?
Also, I'm not sure how your devops is setup but theoretically you could share code between installs (same templates, plugins, etc.) The vendor, migrations,  templates, and other code  directories could be symlinked in from a central spot so when they get updated, the rest of the sites get updated as well. Once the build process is complete you could fire off a craft migrate/up command line that propagates across each install to make sure everything updates.


When I flip the "Featured Entry" switch, disable it on other entries

It depends on your sort order. If your goal is to only display the most recent 'featured' entry, then you could add the .first parameter to your template code.

Craft would simply grab the first entry it finds

OR, you could limit your query by using the Limit parameter. See: https://craftcms.com/docs/templating/craft.entries#limit

Edit (addition):
Here's an example of how you could display the single, most recent entry which has been marked as Featured, using a lightswitch field.

{% set featuredNews = craft.entries.section('news').featured('not 0').order('dateUpdated desc').limit(1) %}
{% for entry in featuredNews %}
    {{ entry.title }}
{% endfor %}

(Some valuable insight here: craft.entries and lightswitch and here: https://craftcms.com/docs/lightswitch-fields)

Hope it helps


JS login form on different domain and handling the CSRF token

I don't have a good answer for this, but my response is too long to to put into a comment so here goes. I've been experiencing the same thing — I can successfully retrieve the CSRF token, but when I try to log in I get the dreaded 400 Bad Request error.
I found this tidbit on a page about Yii CSRF protection:

When you ebable CSRF validation and use form builder to generate a
form(only post), Yii will auto generate a hidden field and put it in
the form, at the same time, Yii will create a cookie with CSRF token.
When you submit the form, Yii will compare two CSRF tokens from post
and cookie.

I know for a fact that I don't have a cross-domain cookie so there's nothing to compare to. I think the missing cookie is the problem.
In any case, searching for Yii CSRF has given me more to work with than sticking to the Craft documentation. Surely someone has figured this out. In the meantime I'm disabling CSRF from whitelisted domains in my Craft config like this: (for development only):
'enableCsrfProtection' => (
  $_SERVER['HTTP_ORIGIN']  != 'http://localhost:3000' &&
  $_SERVER['HTTP_ORIGIN']  != 'https://staging.example.com' &&
  $_SERVER['HTTP_ORIGIN']  != 'https://example.com'
),

Quick update: maybe this thread can be of help.


Get custom field value on entries.onBeforeSaveEntry event

Please take a look at the docs it's the same in PHP as in Twig

foreach($entry->getFieldValue('publishOnMobileApp')->options as $option){
    if($option->selected){
         // $option->label is selected
    }
}


"Template not found: dashboard" error on setup

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


How to create a secondary menu to filter entries?

Ok so if you are showing all of the entries by default, lets say you have 10 entires in your "work" section.

I am assuming that you have a category group(s) that each entry belongs to.
From there I would assign the category in a data attribute. This would give you a hook that you could talk to for filtering.

twig

{# Get all entries within the work section #}
{% set entries = craft.entries.section('work').find() %}

{% if entries|length %}

    {% for entry in entries %}

{{ entry.title }}

    {% endfor %}

{% endif %}

{# data-category="{{ entry.category }}" could be data-category="my-category" #}

Then I would have a drop-down, or a set of links that represented each of my categories.

twig

{# Get all categories within the work category group #}
{% set category = craft.categories.group('work') %}

<select id="workFilter" name="workFilter">
    <option value="">Select Location</option>
    {% for cat in category %}
        <option value="{{ cat.slug }}">{{ cat.title }}</option>
    {% endfor %}
</select>

On the javascript side, you could either listen for a click - and hide whatever nav items did not have the same data-category value.

For example:

html

Use a click event to check the data value, and hide whatever nav elements did not have "my-category" as the data-category attribute.

Or, a drop-down like above.

jquery

$('#workFilter').change(function (event) {
    // get the value of the drop-down. Hide all list items that do not have the same data-category value.
});

You shouldn't need any ajax or anything like that since all of your entries are already on the page. You just need a hook to show/hide them.

Hope this helps!

EDIT

Sure - give fadeOut a look.

If you are using a button/link you can listen for the click event. Then fadeOut the element. That will fade it out, then set the display to none which should remove the empty gaps for you.

Something like this...

jquery

$('nav-element').click(function(event){
    $('all-things-not-matching).fadeOut('fast', function() {
        // Animation complete.
    });

    event.preventDefault();
});

Each element that is now hidden has the css values of:

opacity: 0;
display: none;


Audio file won't play using resourceUrl inside plugin

I think the cleanest way to solve your issue is to create a new Asset for each of your audio files and relate it to your entries.

<audio autoplay loop>
    {% set audioFiles = entry.assetFieldHandle.all() %}
    {% for asset in audioFiles %}
        <source src="{{ asset.getUrl() }}" type="{{ asset.getMimeType() }}">
    {% endif %}
</audio>


Custom-created or personalized products with Craft Commerce?

I don't think there is a plugin for this, so the only way to solve this would be to build the plugin for this yourself, if you have the skills or resources for this. It could be solved by creating a purchasable with (optional) relations to all the products needed, checking the stock of those products on adding it to the basket, and/or on checkout.

What I would start with, though, is creating an issue on Commerce's Github, to see if others have a need for this and hope that Pixel & Tonic's crew will do it for you ;)


Building an accordion with a Matrix field

The error has to do with the line {% for block in entry.sectionaccordion %} because it's looking for a field in your entry called sectionaccordion but sectionaccordion is not a field; it's a block inside a field (your matrix field).  So the error is basically saying "there is no field called 'sectionaccordion' for this entry".

You also don't want to use a for loop here because there's nothing to loop through.  You're already looping through matrix blocks created in this matrix field, and your code is saying "if the block is of type sectionaccordion, print the contents of it."  The contents of that block won't be another loop; it'll only be 1 Accordion Title and 1 Accordion Text field.

Lastly, by saying {% elseif block.type == "sectionaccordion" %}, you are eliminating the chance to display a slideshow since that is a different block type, one not called sectionaccordion.  If you want a slideshow inside your accordion block type, then you need to create a 3rd field for it inside sectionaccordion and just recreate whatever you did in the sectionslideshow block type.


Video embed displays HTML code instead of video

You probably need to add the twig raw filter to your field variable. This will allow twig to interpret the data as safe HTML rather than just plain text.

{{ myFieldVariable|raw }}

Lear more about the raw filter here: http://twig.sensiolabs.org/doc/filters/raw.html


In general, Craft doesn't normally come into the equation when we're talking about general frontend assets.

Things like minification, preprocessing of SASS/LESS/Coffescript/WHATEVER, image compression (asset images, not content images) etc. should preferably be handled by a tool like Grunt or Gulp (my favorite).

Even when it comes to CSS/JS for your plugins, you might want to do the actual build process with Gulp.

I usually have all source files in the project root, under a folder named src. In there, you have subfolders named js, scss, img, fonts etc.

If you're unfamiliar with for example Gulp, I might recommend you Mark Goodyear's article Getting started with Gulp.

On the Craft side, you could take a look at John D. Wells' awesome Minimee and Inlin.


Get the variables of a loop from an include file

Can't you fetch all the blocks with block.topicTeaserItems.all()

{% include 'modules/module-squareteaser/_module-squareteaser' with {
  squareTeasers: block.topicTeaserItems.all()
} %}

And then you display the headlines with item.entryTopicHeadline

  {% for item in squareTeasers %}
    {% include 'modules/module-squareteaser/_module-squareteaser-item' with {
      headline: item.entryTopicHeadline
    } %}
  {% endfor %}

A simplified version would look like

    {% for item in block.topicTeaserItems.all() %}
        {{ item.entryTopicHeadline }}
    {% endfor %}


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...


How to only show translated fields in an additional locale?

The fields that are not marked for translation are duplicated and synced between the different locales. So if you make a change in one locale, it will change it in all. This is different from saying that they are only available in one locale, which isn't possible in Craft.

Removing/disabling them in "secondary languages" isn't possible, and doesn't make sense since there is no "primary" or "secondary" languages in Craft. You can choose to publish an entry in only your "secondary language" if you want, and when doing so you'd probably want all fields to be editable.

But, I see your point, and I've had this dilemma myself. What I did was put the fields that weren't translatable in a separate tab (you could of course do it the opposite way, put the fields that are translatable in a separate tab). That made sense for my client, at least, but I guess it really depends on your project. :)


Updating Craft removed a channel from the CMS?

This was resolved with the above comments from @mmikkel

  Craft Personal is limited to a single channel. Your license.key file must've been overwritten/deleted somehow when you updated – which is weird unless this was a manual update? In any case, if you have purchased a license and don't have a copy of the license.key file you'll need to contact support@buildwithcraft.com to restore it. If this is a dev build and you haven't purchased a license, just click the upgrade link in the CP footer and then the "Test" button under Craft Pro in the modal that appears.


How can I have more than one product on the same page?

Currently only one purchasableId can be added to the cart in a single form action. To get around this limitation you would need to use ajax to send multiple http requests (to add both items) OR use a plugin like MultiAdd: https://github.com/engram-design/MultiAdd


How to modify element's data during import?

The EVENT_STEP_BEFORE_ELEMENT_SAVE is actually fired after the content has been applied to element attributes and field content.

Instead, you'll want to modify the element's content directly. You can do this via:

$event->element->productDescription = " - blah - ";

As the plugin author, I may change this so it acts as you've suggested. Currently, modifying $contentData essentially does nothing. However, this will require a change to the event where it passes in attributeData and fieldData separately, as they need to be applied separately back on the element. I'll look at adding this in the next version.

Let me know if that doesn't work!


While I’m not sure exactly what caused the issue after my client purchased the Craft Commerce Pro license, it was eventually fixed by restoring the database, upgrading Craft and Craft Pro to the current versions on my local machine, pushing those changes to the dev server, and allowing the upgrade scripts to run in full on the dev server. Thanks to @Brad for pointing me in the right direction.


Unless I'm misunderstanding the question, surely you'll need to use an IMG tag?

{% for asset in assets %}
    <img src="{{ asset.getUrl }}" />
{% endfor %}


Craft 3 - Can't access the craft() in plugin controller

craft() is gone in Craft 3; instead you will be accessing Craft::$app-> for most things. I'd suggest generating your Craft 3 plugin scaffolding at pluginfactory.io, and if you leave code comments on, it'll give you some hints on how to do stuff like this.

This article might also be helpful to you: So You Wanna Make a Craft 3 Plugin?


Complex Conditionals with ElementCriteriaModel / Element API

After doing a bit more digging, I think the only real option here is run a preliminary query to pull out the ids of the elements I want and then pass that into the ElementCriteriaModel. It's not ideal, but it'll do.


Assets and S3 - Reduced Redundacy Storage

I was under impression that it was a bucket setting, but after doing some reading, it seems that this is a per-object setting and should be performed while uploading to a bucket. I'll add this to the list and you can expect to see this in Craft 2.2!


Assuming the years are currently rendered in the correct (descending) order, an easy way to make sure the entries are rendered in ascending order would be to simply reverse the entriesInYear array, i.e.:

...

{% for entry in entriesInYear|reverse %}
    ...
{% endfor %}


After some research I found out that this problem has no simple solution (unfortunately). Check https://github.com/smcyr/Craft-FocusPoint/issues/10.

A solution would be not to use eager loading (obvious). Another solution could be using Craft3 (no plugin needed).

The solution I used was Focal Point (https://github.com/aelvan/FocalPointField-Craft). Focal Point is a tool that can be used with Eager Loading. Focal Point creates a focus point on every asset, that means not on every asset field.


When is the find() method actually necessary?

The ElementCriteraModel description in the docs explains what the find() method does.

Essentially, when you use craft.entries you are building an ElementCriteriaModel object that represents the query that you want to make. That query doesn't actually happen until you call the find() method.

As the docs state, as soon as you treat craft.entries (or a variable that you have assigned it to) as an array, by using it in a {% for %} loop, or by calling the | length filter on it, find() is automatically called.

So in the example in your question, you can safely leave out the find() and it will be called automatically anyway when the {% for %} loop is executed.


Integrate Google reCAPTCHA into Contact Form plugin

There are several anti-SPAM form plugins available for Craft that should work for you (including a Google reCAPTCHA one).


How do i put google analytics code into a Global field?

You should just be able to put it in a text field and then output it in an includeJs statement. So, add a new global set (called 'googleAnalytics' or whatever); create a text field (called 'text' or whatever); and add the new field to your global set field layout.

In your template you should be able to access it by the globalSet handle.

{% includeJs googleAnalytics.text %}

Not tested, but I don't see any reason it shouldn't work. If the includeJs statement doesn't like that for some reason you can try the following instead.

{% set GACode %}
    {{ googleAnalytics.text }}
{% endset %}
{% includeJs GACode %}


Is there a logarithm function in Craft or Twig?

The short answer is no... because Twig is a templating language, and Craft doesn't otherwise have a general need for a log type of function.

The longer answer is you can very easily build this yourself!

Grab the Business Logic Template.
Delete the services and controllers folders... you won't need them.
In the BusinessLogicVariable.php file, change exampleVariable to payoffTime. Whatever parameters you assign to this function will correspond to the parameters you'll use when calling this variable from Twig.
Set whatever logic you want within the function, and return the resulting value.
Enable the plugin from your Control Panel.
Call that variable from your Twig template!

{% set payoffTime = craft.businessLogic.payoffTime(foo, bar) %}

UPDATE

Here's an example based on the use case you outlined in the comments below...

Twig:

{% set payoffTime = craft.businessLogic.payoffTime(entry.loanAmount, entry.loanPayment) %}

PHP:

public function payoffTime($loanAmount, $loanPayment)

Alternatively, if you wanted to, you could even pass the whole entry object in as a single parameter, and just use its field values once you're on the PHP side of things...

Twig:

{% set payoffTime = craft.businessLogic.payoffTime(entry) %}

PHP:

public function payoffTime($entry)
{
    // $entry->loanAmount
    // $entry->loanPayment
}


How do I create a Human readable sitemap in Craft CMS

You could do this manually within a template.

This code should get you started – it will output all of the sections and their entries:

{# Loop through all the sections #}
{% for section in craft.sections.getAllSections() %}
  {# We only care about sections that have URLs #}
  {% if section.hasUrls %}

{{ section.name }}

      {# Loop through each of its entries #}
      {% for entry in craft.entries.sectionId(section.id).limit(null) %}

{{ entry.title }}

      {% endfor %}

  {% endif %}
{% endfor %}

Note that this won’t include any links to pages that only exist as a template. For example if you have a contact.twig template, and you don’t have a Single section in the Control Panel for it, then that will need to manually be added at the beginning or end of this list.


You're going to have to remove them directly from the database's craft_locales table.

You're using "locales" in a way we originally didn't design them for, which is why they're getting truncated at 12 characters.

If you're going to do this, you'll need to keep them at 12 characters or less for them to work.


Is it possible to achieve lead scoring, personalisation / marketing automation using Craft?

There are several ways to do this. The best way will likely depend on your situation. This type of functionality will also require some amount of custom development and implementation time.

A few examples:

Services like Intercom can be integrated into Craft. You would manage marketing automation via Intercom and the custom development necessary would be to tie in the actions of your users on your Craft site with Intercom so you had the data you need to communicate how you wish. Intercom can be integrated into login processes, track user actions, and capture data when users submit Forms (plugins like Sprout Forms and Solspace Freeform are both capable of being customized to integrate with third-party services).
For more generic data capture, Mixpanel can capture a lot of data about your customers. Mixpanel is more of a data analytics platform, so using a service like this will require that you have a larger budget to build out your own marketing automation processes around the data you gather.
For additional control over your transactional email in Craft, Sprout Email can help with dynamic personalization of your email notifications, integration with custom events, and targeting specific lists of users.

In all of these cases, you will want to develop a clear plan around your requirements and budget time for customization to integrate the plugins and services into your sites workflows.


Error when updating 2 to 3: Bad Request Unable to verify your data submission

I was able to fix it replacing the content of config/license.key by the word temp


Your second example is easy enough... just make sure the assets folder exists under both of the site1 and site2 folders, the under your Asset Volume settings in the Control Panel, set the "File System Path" to the relative assets.


How to get latest entries, after X number?

In the way you have described that you want to use all the results on the page but just moved and used in chunks you should save a query on the database and use slice over offset.

{% set entriesList = craft.entries.section('news').limit(15) %}

{# Featured #}
{% for entries in entriesList | slice(0, 5) %}
{% endfor %}

{# Other List#}
{% for entries in entriesList | slice(4, 10) %}
{% endfor %}