Check for whole cart adjustment and apply line item discount I'm writing a custom plugin for a customer that does 2 things.

Uses prices from Pricing Categories. There are 10,000 digital products, so adjusting prices for large quantities is cumbersome on a per-product basis.
Uses a Stock Photo model system of PrePay. Purchase a set amount of credits like $100, and get 10% off the products.

I have successfully completed the first step by using the EVENT_POPULATE_LINE_ITEM listener. The following works perfectly.

Upon consultation with the wonderful Michael Rog, I am taking a different apporoach to this project.

Create a function on the backend that upon an product entry save, assign the price from the category. This will assign the price in the CP, rather than doing any line item editing and cart manipulation on the front end.
I will be creating my own adjuster that will fire after a Gift Voucher has been added to the cart that will then apply the sale percentage to the line item in addition to the whole voucher process.

I'll post my update when successful.

Success!

1) I have an Event that does a EVENT_BEFORE_SAVE_ELEMENT check.

Event::on(Elements::class, Elements::EVENT_BEFORE_SAVE_ELEMENT, function(Event $event){

    /**
     *  Runs so an admin doesn't have to set SKU or Slug when creating a NEW SONG
     *  This Event will also set the Price based on the Price Group Category Selected
     */

    // Only perform action if we are working with a Digital Product and Song Type
    if ( ($event->element instanceof \craft\digitalproducts\elements\Product) && ($event->element->typeId == 1) ) {

        // Only adjust the SKU and Slug if this is a NEW Digital Product
        if ($event->isNew) {

            // Get the last row from the Content Table
            $lastId = (new \craft\db\Query())
                ->select([
                    'elements.id'
                ])
                ->from('elements')
                ->orderBy('id DESC')
                ->limit(1)
                ->one();

            // Increment the Last ID number by One. This will work fine unless the last item was deleted.
            // But the point of this is to assign a new, unused number to the Slug and SKU anyway
            $songId = $lastId['id'] + 1;

            // Assign the SKU and Slug
            $event->element->sku = 'song-' . $songId;
            $event->element->slug = $songId;
        }

        // Get the price from the Price Category
        $categories = $event->element->getfieldValue('priceCategory')->one();
        $productPrice = $categories['productPrice'];

        $event->element->price = $productPrice;
    }
});

I also have a method that checks the Categories. If the price changes there, then it goes back and updates the prices on all the products, too.

2) Then, to connect the Verbb Gift Voucher plugin and to adjust the Line Items by a percent discount, I run this EVENT_REGISTER_ORDER_ADJUSTERS

Event::on(OrderAdjustments::class, OrderAdjustments::EVENT_REGISTER_ORDER_ADJUSTERS, function(RegisterComponentTypesEvent $event) {
    $event->types[] = CartAdjustmentsAdjuster::class;
});

which is this:
    class CartAdjustmentsAdjuster implements AdjusterInterface
    {

    // Properties
    // =========================================================================

    private $_orderLineItems;

    // Public Methods
    // =========================================================================

    public function adjust(Order $order): array
    {
        $adjustments = [];

        $this->_orderLineItems = $order->getLineItems();

        // Get the Voucher code by session
        $giftVoucherCodes = Craft::$app->getSession()->get('giftVoucher.giftVoucherCodes');

        if (!$giftVoucherCodes || count($giftVoucherCodes) == 0) {
            return [];
        }

        foreach ($giftVoucherCodes as $giftVoucherCode) {
            $voucherCode = Code::find()
                ->where(['=', 'codeKey', $giftVoucherCode])
                ->one();

            if ($voucherCode) {

                $priceAdjust = (new \craft\db\Query())
                    ->select([
                        'content.field_prePayDiscount'
                    ])
                    ->from('content')
                    ->innerJoin('giftvoucher_codes', '[[giftvoucher_codes.voucherId]] = [[content.elementId]]')
                    ->where(['=', 'giftvoucher_codes.codeKey', $voucherCode])
                    ->all();

                $discount = $priceAdjust[0]['field_prePayDiscount'];
                if($discount > 0) {

                    foreach ($this->_orderLineItems as $item)
                    {
                        $origAmt = $item->price;
                        $saleAmt = ($discount / 100);
                        $discountAmt = $saleAmt * $origAmt;
                        $discountPrice = $origAmt - $discountAmt;

                        $item->saleAmount = $saleAmt;
                        $item->salePrice = $discountPrice;
                    }
                }
            }
        }

        return $adjustments;
    }
}

One important note is that this custom adjuster needs to be installed first before the Verbb Gift Voucher plugin so that the Gift Voucher amount will be applied after the Line Item adjustments are made.

The docs state:

  You could have a project level event listener, that could reorder these adjusters, and not append any new ones.

But installing in this order works, too.


Plugin's setting template not found I have made a simple plugin (with pluginfactory.io) that has been working perfectly so far. But after taking it to our live test-site it is causing the /admin/settings page to stop working, throwing the error that the plugin's settings template cannot be found.

  [error] [exception.Craft\TemplateLoaderException] Craft\TemplateLoaderException: Unable to find the template “pluginname/pluginName_Settings” in "settings/_index" at line 8. in /craft/app/etc/templating/twigextensions/TemplateLoader.php:123

I have dumped the production DB and imported it locally, I have checked that the files exists both in git and on the server, but I still only get this error on the server, everything is working fine locally.

Any ideas what could be causing this?

public function getSettingsHtml() {
    return craft()->templates->render('pluginname/pluginName', array(
        'settings' => $this->getSettings()
    ));
}

Sounds like production has a case-sensitive file system and locally you don't.

For example, you're trying to render a template called mytemplate.html on the file system, but you're using myTemplate.html in the plugin code.


Error with model validation Hi I'm getting this error when I try to validate a model.

Craft\mymodelModel and its behaviors do not have a method or closure named "getTableSchema".

I'm using the following code in the controller function that calls the save. It saves the data fine but I want to validate the model first before it does so but this is throwing the above error. What am I missing?

$model->setAttributes($attribute);

if($model->validate()) {
    // code that sends model off to be saved
} else {
    $model->getErrors();
}

Cheers

Model class code:

namespace Craft;

    /**
    * myModel Model
    *
    * Provides a read-only object representing a myModel, which is   returned
    * by our service class and can be used in our templates and controllers.
    */
    class myModels_myModelModel extends BaseModel
   {
    /**
     * Defines what is returned when someone puts {{ myModel }} directly
     * in their template.
     *
     * @return string
     */
     public function __toString()
   {
       return $this->name;
   }

   /**
     * Define the attributes this model will have.
     *
     * @return array
     */
     public function defineAttributes()
     {
        return array(
            'id'    => array(AttributeType::Number, 'required' => true, 'unique' => true),
        'field1'    => array(AttributeType::Number, 'required' => true),
        'field2' => array(AttributeType::Enum, 'values' => "value1,value2"),
        'field3'  => array(AttributeType::Enum, 'values' => "value1,value2,value3", 'required' => true, 'default' => 'value1'),
        'field4' =>  array(AttributeType::Name, 'maxLength' => 255, 'required' => false),
        'field5' =>  array(AttributeType::Name, 'maxLength' => 255, 'required' => false),
        'field6' =>  array(AttributeType::Name, 'maxLength' => 255, 'required' => false),
        'field7' =>  array(AttributeType::Name, 'maxLength' => 255, 'required' => false),
        'field8' =>  array(AttributeType::Name, 'maxLength' => 255, 'required' => false),
        'field9' =>  array(AttributeType::Name, 'maxLength' => 255, 'required' => false),
        'field10' =>  array(AttributeType::Name, 'maxLength' => 255, 'required' => false),
        'field11' =>  array(AttributeType::Name, 'maxLength' => 255, 'required' => false),
        'field12' =>  array(AttributeType::Name, 'maxLength' => 255, 'required' => false),
        'field13' =>  array(AttributeType::Name, 'maxLength' => 255, 'required' => false)
        );
    }

    /**
     * Get User
     */
    public function getmyModel()
    {
        if ($this->userId)
        {
            return craft()->users->getUserById($this->userId);
        }
    }

}

I just had a bit more of a look into this, I got the same error as you but by changing

'id' => array(AttributeType::Number, 'required' => true, 'unique' => true),

to just

id => AttributeType::Number

It fixed the issue and I was able to validate on it no problem, I don't think you need to worry about the ID being unique or being set on the model as this will be handled automatically by your record when you use it to save to the database, so you can be certain that every models id will always be unique.


Is it possible to get another Craft's webApp from within a Craft plugin controller I have two instances of Craft on the same server. From within a plugin controller in Craft #1, I want to be able to get entries from Craft #2. Can this be done and if so, how?

Indeed... this will do it:

$craft = require '../other/craft/app/bootstrap.php';
$entry = $craft->entries->getEntryById($id);

echo 'Other Craft install entry title:'.$entry->title;


Counting included child blocks in the Neo plugin In the Neo plugin, I've made a block that has the option to add 3 child blocks underneath it.

This is the code from the parent block:

{% extends 'neo/default' %}
{% block blockContent %}

{{ block.mainTitle }}

    {% if block.children %}
     {% for item in block.children %}
     {% if loop.first %}
     {% include "neo/children/" ~ item.type %}
     {% endif %}
    {% endfor %}
    {% endif %}

{% endblock %}

So the parent block can have up to 3 child blocks. You'll get 3 blocks on one row, each block has a 'col-sm-4' (Up to 12 fit on one row if aren't familiar with Bootstrap) class so it fits on one row.

But if a user only chooses to have 2 child blocks the classes 'col-sm-4' will remain the same. I'd like to change this class to 'col-sm-6' and when only one child block is selected, 'col-sm-12'.

Okay so this is the code for the child block:

{% block blockContent %}
{% for block in entry.body %}
{% switch block.type.handle %}
{% case 'serviceItem' %}

  {{ block.text }}
  LEARN MORE

{% endswitch %}
{% endfor %}
{% endblock %}

What I tried first is set the length of the child block. And with that number defined, with the help of if statements, change the layout like this:

{% set numberOfItems = block.serviceItem|length %}
 {% if numberOfItems == 1 %}

   {{ block.text }}
   LEARN MORE

 {% elseif numberOfItems == 2 %}

   {{ block.text }}
   LEARN MORE

Etc...

Unfortunately that method doesn't work since it won't count itself more than once since it is being looped outside of the code file.

I hope my explanation was sufficient of what I hope to achieve.
Does anyone perhaps know the solution?

Thank you for your time.

The answer by Tom Bauer given to my question here should be of help.

You're not far off. You need to set a variable and count the blocks in your neo loop. Then use if statements in the loop depending on the counter variable.

The other option is you add a columnWidth dropdown field, and give them the option to choose between 2 or 3, the values are the css (2=col-sm-6, 3=col-sm-4.)

Then your code code look like:

{% block blockContent %}
{% for block in entry.body %}
{% switch block.type.handle %}
{% case 'serviceItem' %}

  {{ block.text }}
  LEARN MORE

{% endswitch %}
{% endfor %}
{% endblock %}


Create a dynamic select element I want to build a dynamic html select element that includes the prior five years, given the current year. So, since it is now 2020, the result would be:

<select>
<option value="2015">2015</option>
.
.
<option value="2019">2019</option>

Basically want a "loop while" function, but Twig does not do that. I know I did something like this once before with a macro, but can't for the life of me remember and can't find anything on Stack Exchange.

I know I could do it with Javascript, but would prefer to use Twig. Have the feeling I am missing something obvious, just not obvious to me!

You can do something like this (with lots of refactoring possible):

{% set thisYear = now | date("Y") %}
{% set startYear = thisYear - 1 %}
{% set endYear = startYear - 4 %}

{% set yearRange = startYear..endYear %}

<select name="">
{% for year in yearRange %}
    <option value="{{ year }}">{{ year }}</option>
{% endfor %}
</select>


Link to Global Fields like you can with the entries fieldtype Is there any way to link to a global using a field in a entry form, much like you would use the "Entries" fieldtype to link to entries?

Not directly. You could have a dropdown of all the global set handles (use Dynamic Fields Plugin if you don't want to maintain this dropdown manually), and then in your template fetch the global set from its handle with getSetByHandle:

{% set globalSet = craft.globals.getSetByHandle(entry.globalSetHandle.value) %}
{% if globalSet %} {# could conceivably be null #}
  ... {{ globalSet.someField }} ...
{% endif %}


Drag and drop-able "components" I'm totally new to Craft (having previously developed on Silverstripe) but have read through the basic docs, have a local version installed and have set-up a HelloWorld plugin.

What I am now wondering is how to produce a flexible layout that provides editors with "drag & drop" components each in, for instance, Bootstrap style rows.

For instance a page layout that allows components for
- an advert
- a list of customers
- a block of custom text with a custom image etc. etc.
(e.g. https://www.salesforceiq.com/ which is Craft driven I believe).

The editor provides the relevant content for each custom component and can drag & drop them around to change their order as required & that order is reflected on the front end.  And those types of pages can appear anywhere in the site structure.

I'm guessing the answer is a section with a Matrix field, but I'm struggling to make the leap on how that can allow it to call on a set of custom fields that each call on custom templates?

Any help greatly appreciated!

I'm not totally sure I fully understand your question, but what you're describing definitely sounds like a job for Matrix.

Unfortunately I have no experience with Silverstripe, so I can't make any comparisons to Craft or Matrix and similar functionality in that system, but as a basic overview of what Matrix is and does, I'll just quote the official docs:

  Matrix fields allow you to create multiple blocks of content within a single field.

Basically, you can think of a Matrix field as a glorified table of repeating content. If you ever worked with WordPress and Advanced Custom Fields, Matrix is basically the same thing as the Flexible Content field in ACF.

Matrix fields have many use cases, but using them as "layout" builders in modular design is very common, and is (as far as I can tell) what you're looking to achieve here.

A block type in a Matrix field is basically a self contained set of fields. A block is an instance of a block type. After configuring a Matrix field with a selection of different block types (or layouts) such as a WYSYWIG editor, an image gallery, an embedded video, a news feed etc. When a user is editing the entry, he or she can add one or several blocks of each type to the entry, in any order.

For your use case (such as I understand it) let's say you create a Matrix field with the handle pageLayout, and add the following block types to it:

Advert (handle advert)
Customer list (handle customerList)
Text and image (handle textAndImage)

For each block type, you add the fields you need. Since the block types are sandboxed, you can have a field with the same handles in more than one block type, e.g. an image field called image or a text field called text in both the advert and textAndImage blocks.

It's difficult to advise on specific fields you'd need for the three block types above, but for your advert block type you might need a Plain Text field for URL and an Assets field called image. Assuming your customers are Users or even Entries you might need a Users or Entries field for your customerList block type, and the textAndImage field should probably have a Rich Text and an Assets field. You also might want to give the content editor the option to add a custom heading to each block, in which case you could add a PlainText heading field to each block type.

When you edit your entries, you can create one or several of each of the three block types. You can reorder blocks you already created, remove single blocks or add new blocks of either type above or below existing blocks.

To render your Matrix content, you'll usually work with a Twig for loop to run through all your blocks and render their data.

Using the {% switch %} tag to render different code based on the block type is a good way to keep things readable and clean – here's an example where all the individual block type markup is inline:

{% for block in entry.pageLayout %}
    {# Inside here, `block` refers to a single block in the Matrix field #}
    {% switch block.type %}
        {% case 'advert' %}

                {% set image = block.image.first() %}

        {% case 'customerList' %}

                {% set customers = block.customers %}
                {% for customer in customers %}

{{ customer.name }}

                {% endfor %}

        {% case 'textAndImage' %}
           {% set image = block.image.first() %}

{{ block.text }}

    {% endswitch %}
{% endfor %}

Of course, to keep things even more tidy, you might opt for an approach using template partials, where you put the markup for each block type in their own template (e.g. templates/blocks/advert.html), and use the {% include %} tag to render them inside the Matrix for loop:

{% for block in entry.pageLayout %}
    {% switch block.type %}
        {% case 'advert' %}
            {% include 'blocks/advert' %}
        {% case 'customerList' %}
            {% include 'blocks/customerList' %}
        {% case 'textAndImage' %}
           {% include 'blocks/textAndImage' %}
    {% endswitch %}
{% endfor %}

In fact, if you name your templates after your block type handles, you may get away with not having a {% switch %} tag at all:

{% for block in entry.pageLayout %}
    {% include 'blocks/'~block.type %}
{% endfor %}


Updating the postDate field from a plugin? I think I'm almost there with this one but obviously missing something as the postDate is not updating. I have the following in an onSaveEntry event. It's saying it's successful but the postDate does not change. Ideally I want this to update whether the entry is enabled or not.

public function onSaveEntry(Event $event)
{
    $entry = $event->params['entry'];
    // set postDate from assignedDate
    if($user->admin) {
        if($entry->assignedDate && $entry->assignedTimeslot) {
            $timeslot = $entry->assignedDate.' '.$entry->assignedTimeslot.'.000000';
            $params = $entry->postDate = $timeslot;
            $success = craft()->elements->saveElement($entry, $params);
        }
    }
    return $event;
}

$timeslot isn't formatted correctly to be used as the postDate. I'd create a field that takes a date and a time and then use DateTimeHelper::formatTimeForDb() to format for use as postDate.

You can't modify the postDate until after the entry has been saved - so will need to resave the entry with the newly set postDate. More info as to why you have to do this here.

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

  // Grab the entry from post request
  $entry = $event->params['entry'];

  // Get logged in user
  $user = craft()->userSession->getUser();

  if ( $user && $user->admin ) {
    $timeSlot = $entry->getContent()->assignedTimeslot;

    // If the postDate and Timeslot don't match (stops infinite loop)
    if ( !( $entry->postDate == $timeSlot ) ) {

        // Set postDate to timeSlot date
        $entry->postDate = DateTimeHelper::formatTimeForDb( $timeSlot );

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


Can you use a different html template for each system message email? Is it possible to use a different html template for each system message email?

Alternatively can you determine which system email is being sent from within the template that you can set in the Craft email settings?

Alternatively can you determine which system email is being sent from within the template that you can set in the Craft email settings?

Not currently, but in the next (post 2.3.2644) release, there will be an emailKey variable available to the template so you can see which email is being sent.


Adjusters: Conditionally include tax in price I have a question about adjusters: I am working on a shop which has two tax zones (Switzerland and EU) and two tax rates (8% and 19%). The tax should always be included in the item price. From my understanding that is not possible for both tax zones at the same time. So I am having my eye on the adjusters.

I would use an adjuster to do the following:
The client facing cart on the front end gets no adjustments. Only after the shipping address has been confirmed I would apply either one or the other adjustment (8% or 19% included) conditionally via the plugin to the order.

Does that make sense? Is that possible and if so is this even the best way to go or am I missing something which is more awesome?

If the answer is yes then I would invest more time and just dig into it.

Thanks in advance!

Answer is yes, you could use an adjuster to try and make the price "even" while in the cart.


Detect task is finished Is there a way to detect when a task is finished with js, for example I have a task running I can see the progress bar in the top right corner I would like to attach an event so when the task is done to do some js. Is that possible at this stage of craft. Thank you in advance.

In one of my plugins I inject a little bit of javascript that polls Craft.cp.runningTaskInfo for changes to detect if a task is finished.


What could the possible causes be for a mismatch between `craft_fields` and `craft_fieldlayoutfields` MySQL tables? I'm debugging an Internal Server Error on a site developed by, well, not me. :p The site has an absolutely enormous Matrix field called "Modules", and the blocks in said field have so many fields that it reaches some sort of "65,536 char row limit" in the database when trying to add new fields.

Anyway, so the most recent block added to this giant Matrix field causes an internal server error whenever it gets added to an entry. The relevant web.log line is:

2018-08-20 09:25:06 [127.0.0.1][206][h9dtcm3ad2nb50aie3m6t27be3][error][yii\base\Exception] yii\base\Exception: Invalid field handle: resource2Description in [MyProject]\vendor\craftcms\cms\src\base\Element.php:1932

This was odd, as the Matrix block in question didn't have a "Resource 2 Description" field in the backend. It did, however, have "Resource 1 Description" (and 3 other "Resource 1 ____" fields), and the development pattern I've seen in this site leads me to be nearly certain that at some point, someone tried to add or succeeded in adding a "Resource 2 Description" field (side note: consider this my +1 for Matrix-within-Matrix, and yes, I will be converting this morass to Super Table for the time being).

So this led me to poking around the database, trying to figure out why parts of Craft thought this field existed, but it wasn't being shown in the backend.

What I found was that the Matrix block in question, which has a tabId of 3275 as referenced in the craft_fieldlayoutfields table, has only 4 rows in that table (one for each field seen in the backend):

However, when I looked up those field IDs in craft_fields, I saw that they had a common context column, of matrixBlockType:78. Querying that table for all rows with that same context, I found the mystery fields:

So at this point I have two theories about what happened:

Option 1: Craft may have a bug of sorts where, if you try to add fields but hit that previously-mentioned 65,536-char row limit, the fields only get partially added to the database and you end up with a mismatch between tables.
Option 2: This site had, at one point, upwards of 15,000 rows in the craft_queue table, due to some stuck 'Pending image transform' tasks that the developers had ignored during development. This was "resolved" by wiping out the contents of craft_queue wholesale. I suspect that one of those tasks may have been something to do with saving or updating the fields in the Matrix block.

So the actual question is this: Which of those two scenarios (or some other cause I've not thought of) are more likely to result in mismatching database tables?

Bonus question at no extra charge: Which would be wiser, A) Manually (editing the database) "restoring" the missing rows for those fields in craft_fieldlayoutfields, B) Manually deleting those "extra" rows in craft_fields, or C) Trying to recreating those fields as normal, through the Craft backend?

Craft doesn’t do any field operations in the queue, so it must be the first option.

Create a DB backup first, but it should be safe to delete the rows for fields that are not in the Matrix field’s layout. It also wouldn’t hurt to double-check the matrixcontent_modules table to make sure it doesn’t have columns for those fields.

Also worth noting, you can shrink the size of the table by going over all the sub-fields and checking their Column Type settings (under Advanced). If it’s possible to select smaller column types, you should do it.


Can custom entry sources have their own URLs? I can go to http://example.com/admin/entries/sectionHandle, and the Entries list has that source selected, but I can't find a way to do that with sources added through modifyEntrySources.

I've got two extra sources for entries that have been fully translated, and those that haven't, so we can track our progress as we translate the site.

Is there anything I can add to the array so that I could link to something like http://www.example.com/admin/entries/untranslated?

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

        $sources['translations:untranslated'] = array(
            'label' => Craft::t('Untranslated'),
            'criteria' => array('translationCompleted' => array('0', null))
        );

        $sources['translations:translated'] = array(
            'label' => Craft::t('Translated'),
            'criteria' => array('translationCompleted' => '1')
        );
    }
}

After a little more digging, I discovered this can be achieved by adding a data array with a handle value to the source, so that code becomes:

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

        $sources['translations:untranslated'] = array(
            'label'    => Craft::t('Untranslated'),
            'criteria' => array('translationCompleted' => array('0', null)),
            'data'     => array('handle' => 'untranslated'),
        );

        $sources['translations:translated'] = array(
            'label'    => Craft::t('Translated'),
            'criteria' => array('translationCompleted' => '1'),
            'data'     => array('handle' => 'translated'),
        );
    }
}

This doesn't appear to work for nested sources however.


Reverse relationships with entries and users I have a relationship between users and 'locations', and I'm using the code below to output some markers for a map.

This all works fine except for two things:

I'm repeating a couple of 'for' loops. When I try not to repeat
them, the 'markers' and 'markerInfo' return 'undefined'.
Within markerInfo, I'd like to list the names (e.g. 'user.firstName') of the users related to that location, but when I try, I get a list of ALL users that have a relationship with ANY location.

In plain language, what I'm trying to do is:

Find me all the users who are part of the 'family' group.
Find me all the locations which are related to those users and plot each
one (but only once for each location).
For each location, give me a list of the users that have a relationship with it.

--

My source elements are entries in the section 'locations', with the
field 'relatedPeople'.
My target elements are 'users' (from the group
'family').

How can I make this more performant (not repeat things), and get a list of users per location within 'markerInfo'?

{% set people = craft.users.group('family') %}

{% set markers %}
    {%- for person in people.all() -%}
        {% set relatedPlaces = craft.entries.section('locations').relatedTo({
            targetElement: person,
            field: 'relatedPeople'
        }) %}
        {%- for place in relatedPlaces.all() -%}
        ['{{ place.location.address }}', {{ place.location.lat }},{{ place.location.lng }}],
        {%- endfor -%}
    {%- endfor -%}
{% endset %}

{% set markerInfo %}
    {%- for person in people.all() -%}
        {% set relatedPlaces = craft.entries.section('locations').relatedTo({
            targetElement: person,
            field: 'relatedPeople'
        }) %}
        {%- for place in relatedPlaces.all() -%}
        ['
' + '
{{ place.title|e('js') }}
' + '{% if place.startDate|length %}{{ place.startDate | date('M Y') }}{% endif %}{% if place.startDate|length and place.finishDate|length%} to {% endif %}{% if place.finishDate|length %}{{ place.finishDate | date('M Y') }}{% endif %}' + '
'],
        {%- endfor -%}
    {%- endfor -%}
{% endset %}

{% set people = craft.users.group('family').ids() %}
{% set relatedPlaces = craft.entries.section('locations').relatedTo({
    targetElement: person,
    field: 'relatedPeople'
}) %}

Grab all the ids from your users, then find all locations related to those. This way you don't need multiple loops and get each location once and not multiple times


Help with FeedMe JSON I am trying to insert records into the same entry using FeedMe with Matrix and Table for one of the fields.  My table field is a plain text.  So I have one programLevel, one program and a field that collects many text entry lists in a Table field.  No matter what I do, depending on the structure of the JSON.  I either overwrite the record already there or it gets 2 entries into the Matrix field but combines all the plain text entries into the Table field (code below).  Not sure what I am doing wrong here.

Basically I end up with 2 Matrix entries but a combined Table field called Lists.  Basically, Test text 1, Test text 2, Test text 3, etc in the Table field for both Matrix records in the entry. Is there a proper way to get this formatted correctly please?

[
    {
        "title":"Test Entry",
        "programs": [
            {
                "programLevel":"Alpha",
                "program":"Vector1",
                "listItems": [
                    "Test text 1",
                    "Test text 2"
                ]
            },
            {
                "programLevel":"Beta",
                "program":"Vector1",
                "listItems": [
                    "Test text 3",
                    "Test text 4"
                ]
            }
        ]
    }
]

Thank you Verbb for fixing this up. The answer can be found here.

https://github.com/verbb/feed-me/issues/298


Find entries that use a specific block in their Matrix field? Suppose a Mtrix field named MyMatrixField has three blocks called Text, Images, and Buttons.

What MySQL query would list the section and title for all entries whose MyMatrixField field has a Buttons block in-use?

Something like:

SELECT section, title FROM `craft_entries` WHERE `field_MyMatrixField_Buttons` IS NOT NULL

You can join your matrix table and check for elements with a certain type and your owner id

{% set entries = craft
    .entries()
    .section(['your-section'])
    .leftJoin('{{%matrixblocks}} as matrixblocks', 'matrixblocks.ownerId = entries.id')
    .andWhere({'matrixblocks.typeId': 1})
    .all()
%}

replace the correct section and the correct type id of your blocktype


Simple Search form with a few drop-down choices Looked at countless examples here but all seem to be more than I need.

I need the form to have three drop-downs

Make
-Ford
-Chevy

Color
-Red
-Blue

Transmission
-Auto
-Shift

And the search results field would look at the section called 'cars' and return any car with the exact match. One additional point is that 'Transmission' is a category.

Thanks.

I would probably create some categories for make,  color and transmission and relate every entry to it. Then you have the ability to use craft.entries... to fetch the entries as you need them. You can find all specs of the entries method in Craft's docs -  just fetch all entries that are related to the category you want.

Depending on the total number of entries you could just fetch (and cache) all entries every time and use a javascript filter mechanism. I worked with isotope before.

Using js you can achieve a smoother UX once all entries are loaded. However, best practice would be to start coding without js and make it work and then enhance the experience with js. Depends on your budget.


Is it possible to hide a custom field type plugin from the popup tab when double clicking an entry? Is it possible to hide a custom field from the modal that appears when you double-click on a related entry inside a Entries field?

In other words, I don't want my custom field to be visible within the modal that comes from getEditorHtml.

===== Updated based on accepted answer below =====

Based on the accepted answer from @Tyler Willingham I used the following code in my plugin's main plugin file:

public function init()
{
    parent::init();
    if (craft()->request->isCpRequest()) {
        craft()->templates->includeJsResource('myPlugin/js/myJs.js');
    }
}

If you're looking for a setting you can apply to the plugin that corresponds to your custom field, it doesn't look like such a setting exists.

Update: I was just made aware of this Craft CP JS plugin in another question. It looks like you could potentially hide your plugin from displaying. It's not as elegant as a first-party solution but it may be worth a shot


What is the best approach of updating existing Craft installs with new features? I'm currently developing a blueprint for all my Craft websites. It contains a set of sections, fields, plugins etc. All configured the way I need for my websites. The websites itself are basically a fork of this blueprint and only has to have a custom template and content and we're good to go.

The number of features in my blueprint will be growing as time passes along. What would be the best approach of updating all Craft installs so that each website (build upon previous blueprint versions) can benefit from the newly developed features.

I could just backup the DB and code from the blueprint and import them into the website, but then I will be losing all content.

Any idea?
Thanks in advance!

This approach assumes that the individual websites won't diverge from the original blueprint by, for example, modifying sections and fields to suit their specific requirements.

That seems pretty unlikely.

I'd be inclined to stick with the idea of creating a "blueprint" site, to get new websites up-and-running quickly, but ditch the idea of updating previously-created sites whenever the blueprint is updated.


Git configuration for CraftCMS Please excuse this newbie question (newbie to Git that is). I'm trying to set up my CraftCMS environments with Git and wonder about best practices and how others configure your repositories.

In specific, do you have separate Git repos for separate sites, or is it all in one big repo? Do you have separate repos for the outward-facing portion of a single Craft site and its application files or is that all in one repo?

Thank you in advance.

Each project should be a separate repository, definitely. After that - feel free to include what you like. Personally I follow something like this and ignore my /app folder: https://deploybot.com/guides/deploy-craft-cms-to-digitalocean. But you could also include the /app directory and plugins.

Also: Git Workflow and Multi Environment - how to approach

And: https://craftcms.com/support/craft-storage-gitignore


How can I get a lightswitch to work with order() in craft.entries? I'm getting mixed results when using a lightswitch field together with order('RAND()') and I wonder if I'm doing something wrong.

For example, this code gives me the correct results:

craft.entries.section('section').lightSwitchField('1').first()

... but this selects entries from all entries in my channel instead of just the ones with the lightswitch field switched on.

craft.entries.section('section').lightSwitchField('1').order('RAND()').first()

Instead of using .first() try using .limit():

craft.entries.section('section').lightSwitchField('1').order('RAND()').limit(1)

I have just ran a test and this is working fine for me.

EDIT

I am using this code without any errors:

{% set entry = craft.entries.section('lorem').lightSwitchField('1').order('RAND()').first %}

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


How do I output the last matrix block? I am pretty new to craft (just came from EE) and trying to output the last entry from a matrix field in my template:

{% for block in entry.gallery.last() %}
    {% set image = block.image.first() %}
    <img class="lazy" src="{{ siteUrl }}img/assets/loader.gif" data-src="{{ image.getUrl('galleryThumb') }}" data-src-retina="{{ image.getUrl('galleryThumbRetina') }}" alt="{{ image.title }}">
{% endfor %}

So this isn't working as I thought, i've done some snooping but have had no luck, any ideas?

Thanks
-Graham

Twig comes with a last filter which you should be able to use, so with your entry.gallery  you can do:

{% set lastBlock = entry.gallery|last %}

Which will return the last element in the sequence, there's more info in the twig docs:

  The last filter returns the last "element" of a sequence, a mapping, or a string:

Twig last filter


Categories not displaying as nested in control panel Try as I might I just can't seem to get categories to show as nested in the Control Panel as shown on https://docs.craftcms.com/v3/categories.html#creating-and-editing-categories

There's no level of depth set on the category group, so not sure what else is at play?

So, there's no mention of this in the v3 docs that I could see.

I went back to an older project where I'd used categories to find that I set the Category URI format field to {% if object.level == 1 %}read/category/{slug}{% else %}{parent.uri}/{slug}{% endif %}

This was obviously documented at some point for me to implement it on what would have been an original Craft install.

There's no mention of this being needed to enabled nested categories on https://docs.craftcms.com/v3/categories.html#category-groups so it should get added.


ResaveAllElements task generates fatal error after adding locale After adding a new locale to the site, the ResaveAllElements task started going off, and after a while stopped progressing. When i checked the logs it said:

PHP Fatal error:  Maximum execution time of 30 seconds exceeded in .../craft/app/framework/db/ar/CActiveRecord.php on line 694

I thought the point of tasks and subtasks was to prevent this thing from happening, but i might have misunderstood how it actually works.

Unfortunately i have little to no control over the server configs (apache and php).
How can i work around this problem?

Craft Pro 2.3.2644

OS: Debian GNU/Linux 7.8 (wheezy)

PHP 5.4.36

I thought the point of tasks and subtasks was to prevent this thing from happening,

No, a task is just another PHP request subject to the same environmental limitations as any other PHP request.  It just so happens that it runs asynchronously in the background.

I assume you don't have access to a php.ini file to increase values?  You can also try via .htaccess.


Fatal error: Allowed memory size of 134mb exhausted I have a template in my control panel (technically a plugin, but it's just one template) which is running out of memory:

  Fatal error: Allowed memory size of 134217728 bytes exhausted (tried
  to allocate 78 bytes) in
  /var/sites/t/thames-arbitrators.org.uk/craft/app/helpers/ModelHelper.php
  on line 101

In my local dev site, the profiler is giving me the following info:

Time 10.66053s
Memory: 127,544Kb
Total Queries: 381

Is there anything I can do to alleviate this? I've seen the answer to 'PHP Fatal error: Allowed memory size of X bytes exhausted' but there are only two conditionals in this template, it's almost certainly down to the fact that I need to return several hundred entries.

I don't mind posting my template here but there's a big table in it so it's going to make the page super long - let me know which bits you need.

If your plugin is pulling in a lot of data, then most likely you're just bumping into your php.ini file's memory_limit setting.  Try bumping that up to 256M and see if that helps.


How to show entries which are live between dates regardless of postdate or expiry dates? I'm trying to show live entries to user by selecting list of months in a dropdown. Some my entries are live for 2 or 3 months. I having trouble in finding right method. I have tried using after and before but i think these work based on postdate of an entry. Correct me if i'm wrong. This all in template side.

"Live" is determined in part by postDate and expiryDate (in addition to status), so not technically independent, but this may be what you're after. You would still use the technique described in Carlcs' answer, only that the criteria would be searching the entries using the month values passed to your template.

{% if craft.request.param('startMonth') and craft.request.param('endMonth') %}

    {% set startMonth = craft.request.param('startMonth') %}
    {% set endMonth = craft.request.param('endMonth') %}
    {% set startDate = now|date(Y) ~ '-' ~ startMonth %}
    {% set endDate = now|date(Y) ~ '-' ~ endMonth %}

    {% set entries = craft.entries.section('mySectionHandle').postDate('and, >= ' ~ startDate ~ ', <= ' ~ endDate) %}

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

{% endif %}

You could also use .after(starDate).before(endDate) for this.

Update If you want to get entries that are live during a particular month range (rather than posted during the month range) then you could check for postDate before the selected 'start month' and expiryDate after the selected 'end month'.

{% if craft.request.param('startMonth') and craft.request.param('endMonth') %}

    {% set startMonth = craft.request.param('startMonth') %}
    {% set endMonth = craft.request.param('endMonth') %}
    {% set startDate = now|date(Y) ~ '-' ~ startMonth %}
    {% set endDate = now|date(Y) ~ '-' ~ endMonth %}

    {% set entries = craft.entries.section('mySectionHandle').postDate('<= ' ~ startDate).expiryDate('>= ' ~ endDate) %}

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

{% endif %}

Not tested.


Variable variables in Twig I'd like to create a variable from another variable. What I got right now is something like this:

{% set language = fr %}
{% if language == "en"  %}
   {% set fooAddress = en_foobar.globalAddress %}
{% if language == "fr"  %}
   {% set fooAddress = fr_foobar.globalAddress %}
{% if language == "de"  %}
   {% set fooAddress = de_foobar.globalAddress %}

What I'd like to do is:

{% set fooAddress = language  ~ "_foobar.globalAddress" %}

No problem with plain PHP (http://php.net/manual/en/language.variables.variable.php) but is this possible to do with Twig?

In order to pull this off, you'll need to take advantage of the not very well  documented _context variable in Twig.  This should do it:

{% set language = 'fr' %}

{% set foobar = _context[language ~ "_foobar"] is defined ? _context[language ~ "_foobar"] : null %}

{% if foobar %}
    {{ foobar.globalAddress }}
{% endif %}


MailChimp & Sprout Forms I am using Sprout Forms for my contact forms and I want to integrate the MailChimp subscribe plugin but it looks like the MC Subscribe plugin needs to have name="mcvars[FIRSTNAME]" on the input fields and Sprout Forms needs name="fields[LASTNAME]".

Also, they have different hidden fields for the action:

MailChimp Subscribe

<input type="hidden" name="action" value="mailchimpSubscribe/list/Subscribe">

Sprout Forms

<input type="hidden" name="action" value="sproutForms/entries/saveEntry">

Has anyone managed to integrate the two so people can choose to subscribe to a list while also using the power of Sprout Forms?

Currently, this may be a bit challenging to pull of with Sprout Forms v1.1.0

We do have several features and improvements in the works that will help you achieve this in the future though, including:

Full control over customizing the template HTML
The ability to customize the value of the name="" inputs
The option to submit form data to third-party URLs
Control over hidden fields

While I don't have a release date for you — the features above are currently under development.

I'll plan to revisit and update this post once we release those features.


How do you pull a entry field in a global out in a template I am trying to create an easy way to make a sticky post on my blog and I am using an entry field within a global.

Not sure where to even start to pull this out in a template.

You can access and loop the entrie in any template like so:

{% for entry in globalSetHandle.entriesFieldHandle %}
    {{ entry.title }}
{% endfor %}

If you want to change the sort order to show the most recent blog post first use the relatedTo parameter:

{% for entry in craft.entries.relatedTo(globalSetHandle).order('dateUpdated desc') %}
    {{ entry.title }}
{% endfor %}


How to run domain.com and m.domain.com from one install I have an upcoming project where it may be necessary to have a mobile site and a desktop site as the desktop design will not work well responsively.

I built a similar site recently in ExpressionEngine and used Multiple Site Manager (MSM) which allowed me to have separate templates with the same url structure pulling content all from the main site. Since that build I've starting moving new projects to Craft and would like to find a solution to this.

Since Craft does not have a feature similar to MSM, at this point, what would be the best way to approach this. Urls need to be the same on both domain.com and m.domain.com with all content being sharing the same channels.

To use separate templates I created plugin and within init() method I overwritten templatesPath variable. Seems to be working although you need to test it with other plugins as I have tested it with fresh Craft instance only.

public function init() {
    $templatesPath = craft()->templates->getTemplatesPath();

    if(craft()->request->isMobileBrowser()){
        $templatesPath .= 'mobile/';
    } else {
        $templatesPath .= 'desktop/';
    }

    craft()->templates->setTemplatesPath($templatesPath);
}

isMobileBrowser()

This example assumes that templates folder contains mobile and desktop folders. Both have a mirror template files structure. Also you don't need m.domain.com anymore.

But it you need m.domain.com you can use multi environment config variables (environmentVariables) or stick to the previous solution.

return array(
    '*' => array(
        'templatesPath' => 'desktop',
    ),
    'm.domain.com' => array(
        'templatesPath' => 'mobile',
    ),
);

public function init() {
    $templatesPath = craft()->templates->getTemplatesPath();

    if(craft()->config->get('environmentVariables')['templatesPath']){ //this line changed
        $templatesPath .= 'mobile/';
    } else {
        $templatesPath .= 'desktop/';
    }

    craft()->templates->setTemplatesPath($templatesPath);
}

To force mobile URL insert this code to desktop base layout file:

if(craft.request.isMobileBrowser()) {
    {% redirect 'http://m.domain.com' %}
}


Display entry post date How do I display my entry post date, formated as "May 24, 2015"?

I know this is a very basic question, but I can never find these easy answers in either the Craft or Twig documentation.

{{ entry.postDate | date("M d, Y") }}

Inside the date filter, you use the date formatting values documented in the PHP date() documentation.

Also, see Craft's DateTime documentation, and the Twig date() filter documentation for more information on the topic.


map values from checkbox field into category field using SQL In a project I have a checkbox field called gradeLevels with 3 options (k-5,6-8, and 9-12).

Due to design changes, I need to convert this field into a category field. I've made a new category with the same names (k-5,6-8, and 9-12), but I already have data in all of the entries that uses the old checkbox field.

I poked around in mysql and listed all the columns in craft_fields table, but I don't see the newly created categories field in the list, or any categories/entries field for that matter. I'm guessing associations are stored in a different manner?

Is there a possible way using mysql to map all the string values in the check box fields into the corresponding category in the categories field?

FeedMe plugin imports categories, so you could create an xml template file that outputs your entries and their checkbox values(separated by commas), then use FeedMe to import that file back in and map those checkboxes to your categories. They just have to match spelling, otherwise FeedMe will create a new category

FeedMe

Something like:

<xml>
  <blog>
    {% for entry in entries %}
      <entry>
        <title>{{ entry.title }}</title>{# required for import #}
        <category><![CDATA[{% for option in entry.checkboxFieldHandle %}{{ option }}, {% endfor %}]]></category>
      </entry>
    {% endfor %}
  </blog>
 </xml>


Force download of asset file from template I have a template called download that receives an asset ID, looks it up and should force the browser to download the file. I've gotten this far with the {% headers %} tag, but I can't figure out how to read the raw contents of the file and output it.

{% set asset = craft.assets.id(craft.request.getLastSegment()).first() %}
{% header 'Content-Description: File Transfer' %}
{% header 'Content-Type: '~asset.mimetype %}
{% header 'Content-Disposition: attachment; filename='~asset.filename %}
{% header 'Content-Transfer-Encoding: binary' %}
{% header 'Expires: 0' %}
{% header 'Cache-Control: must-revalidate' %}
{% header 'Pragma: public' %}
{% header 'Content-Length: '~asset.size %}
{# How to print raw contents of asset.url ??? #}

Can anyone help?

I don't think you're going to be able to do this out-of-the-box, but should be stupidly simple with a quick plugin that registers its own Twig extension.  See here for an example.

That extension would add a Twig function that's basically just a simple wrapper for PHP's file_get_contents.

Then from your template, you'd do something like:

{# Get the file contents #}
{% set contents = file('/path/to/asset.zip') %}

{# output it #}
{{ contents }}


How much data can craft()->cache hold? How much data can I push into one craft()->cache key?

Let's say I have a json string that's reaaaallly long.

craft()->cache can point to different places, depending on what the cacheMethod config setting is set to.

By default, it's set to file, which means that your cache will be saved to the file system in the craft/runtime/storage/cache folder.

So you can pretty much save as much there as you have disk space available.

Just keep in mind, if you're saving something that's 500MB worth of text, PHP is roughly going need 500MB worth of extra memory to be able to read and write that data.


Can I add another filter option to element index views? What I am trying to do is adjust the entry index page to be more specific for our use case, I have already sorted out extra columns but I want to sort or filter by entry type. Of course I can already sort by typeId using modifyEntrySortableAttributes but this is not ideal.

I either want to be able to sort by an entry type's name using modifyEntrySortableAttributes or better still insert another filter button of all the types in-between the status filter and the search bar, see mock-up below.

Any help greatly appreciated!

I made a small plugin that nests Entry Types under their section in the sources list that might be good enough for what you're after:

https://gist.github.com/mdcpepper/548fd04939e040507960


Get entry url from primary site (using seomatic) We're adding a multi-site config to a website.

All sections are being copied over to the new sites from the primary site.

So for example, we now have these two pages:

mysite.com/services/some-service

mysite-ca.com/services/some-serivice

The mysite-ca.com should have a canonical url of mysite.com/services/some-service

I'm using seomatic and I'd like to insert the correct dynamic canonical url in the Content Seo Settings.

Is there a way to get an entry.url from another site?

So probably you don't want to use canonical URLs there, but rather hreflang -- and the good news is that as long as all of your localized sites are in the same site group in Craft, SEOmatic does all of this automatically for you:

SEOmatic Multi-Site Language/Locale Support


Order of draggable entries and assets won't save Hello Craft Community,

I have a site which has just over 300 entries but most entries have several asset fields, entry fields, or complex matrices.

My problem is that when on an existing entry, I cannot drag-to-reorder any items in an asset or entry field-type. The CP will let me reorder, but saving the entry does not retain my new ordering.

There are no console errors related to this problem, so I'm looking for advise on where to start troubleshooting.

Thanks!

Edit: additional note that my PHP runtime config variables seem to be in order, 256M memory, 3000 max_input_vars, etc.

From your description, if I had to guess, you're running into a php.ini max_input_vars, post_max_size or some other related environmental limitation.  I'd try bumping those as a starting point for debugging.


Is the length filter required when checking if a field has content or not? When checking if a field has content or not in my templates I usually write something along the lines of:

{% if entry.fieldHandle|length %}

{{ entry.fieldHandle }}

{% endif %}

Writing the same code without the |length filter does also work, so can I just exclude the use of the filter from my code altogether? Are there any caveats with not using the filter?

As an aside, I am aware that |length does have its uses. You can use this to check the exact value of something, etc etc.

This question was more suited for a simple yes/no check to see if a field has any content and outputting something if it does.

Another example of the |length filter in my code would be something like:

{% set homepageServices = craft.entries.section('services').type('serviceGroup').level(1) %}
{% if homepageServices|length %}

Output the services here

{% endif %}

Would removing |length (which does work at the moment) cause me any headaches down the line?

You can probably get away with removing |length for most conditionals that check for the existence of content in a custom field and just check on entry.fieldHandle instead.

One exception to this would be for lightswitch fields, which always return true for a |length check, but return true or false when checking on entry.fieldHandle depending on whether the lightswitch is on or off.

StraightUpCraft has a great article on Testing if something exists and another on How to check if a variable or value exists using Twig, which cover a multitude of cases and ways of accessing variables using Twig.


Trying to relate 2 Entries together I have two channels, Courses and Instructors. In Courses I'd like to have a an entries field called "Instructor" so that this will display on the courses page.

I can't seem to figure out how to do this. I have found a few tutes but nothing I have tried has worked. Whats the best way of doing this?

Everything you need to know is in the Relations part of the official documentation.

You essentially want to add an Entries field to your Courses channel and then when you set it up pick Instructors as the source. If you only want to pick one instructor, just set the limit to 1. How you then use this in the templates can be found here.


How to store value of checkboxes without predefining them in the SproutForm plugin I'm using a block matrix to display items of a to-do list.

Each item has a checkbox input. Number of items can vary.

I'm trying to use SproutForms to save the state of the checkbox. This would need to record the currentUser and the to-do list ID.

I've made a form within the SproutForms plugin to include a checkbox and a  to-do list ID, but how can I associate the checkbox on the to-do list item with the checkbox on the SproutForm form?

If I were to use displayField to show the checkbox from the SproutForm, I'd have to make a checkbox for every to-do list item within the SproutForm plugin.

I hope that makes sense! Thanks for any help.

I don't feel I fully understand how you will be using the data on the back end, but here are some ideas.

It sounds like the best way to solve this problem would be to build a custom field-type plugin that stored checkbox data in the way that you need it to be stored on the back end.

A simpler workaround may be to use a multi-line Plain Text field as your "checkbox" field.  You could display things however you want to the users on the front-end, and submit the checkbox data behind the scenes in a way that stores the data in that field in a readable way.  While the data may not behave like a checklist, you would get a snapshot of the checklist items for each submission and the length of items could vary.

To capture the User ID and To-do List ID, you might be able to use the Sprout Hidden Field or Sprout Invisible Field which would just store those IDs in a plain text field.

If you wish to store the ID as relational data, you'll need to create the appropriate relational field (such as a Users Relations field) and submit the ID as an array:

<input type="hidden" name="fields[usersFieldHandle][]" value="{{ currentUser.id }}">

Additional examples of inputs to submit data from the front-end can be found in the Craft Field Guide


Adding items to an array Is it possible to insert items into specific positions in an array (rather than at the beginning or at the end), a bit like javascript splice? Say, if I wanted to add a value between items 2 and 3? Please note I want to add keys to the array rather than replace anything.

You can accomplish this with slice and merge, although it's not very pretty:

{% set myArray = ['a', 'b', 'd' ] %}
{% set myArray = myArray|slice(0,2)|merge(['c'])|merge(myArray|slice(2,myArray|length)) %}

{{ myArray|join(', ') }}

To explain what's happening above:

{% set myArray = ['a', 'b', 'd' ] %}

This just sets an array we can work with.

|slice(0,2)

The first slice filter "chops off" and returns the first two items in the original array (namely "a" and "b"). We do this because we want to add a value after the "b" (i.e. the second index).

|merge(['c'])

The first merge filter appends the value we want to add – the letter "c" – to the first two items. As merge is only able to merge arrays, we need to wrap the c in another array.

|merge(myArray|slice(2,myArray|length))

The inner part of this statement – the slice – pulls all the remaining values from the original array after the first two that we chopped off at the beginning, until the end of the array.

These values are then appended to the a, b and c with another merge statement.

{{ myArray|join(', ') }}

This is just a test, and will print a, b, c, d.


Can't output an image just getting start with Craft, and I can't figure out why my images won't output. Any time I try to output even the path to the url of my image, I get an internal error: Craft\AssetFileModel and its behaviors do not have a method or closure named [...].

I can successfully do this:

{% if entry.pageImage | length %}
    {% for pageImage in entry.pageImage %}
        {{ pageImage }}
    {% endfor %}
{% endif %}

Which just outputs the title of the image. But I want to display the image. I was expecting to be able to be able to use {{pageImage.getUrl()}} or {{pageImage.url}} or {{pageImage.fileName}} but these will throw the aforementioned error. How do I output an image?

You would usually display the image with

{% for pageImage in entry.pageImage %}

{% endfor %}

But this only works if you enabled the public url option for the asset source. There is a light switch if those assets should have urls or not in your cp

It also has a getImg() function

/**
 * Returns an  tag based on this asset.
 *
 * @return \Twig_Markup|null
 */
public function getImg()
{
    if ($this->kind == 'image' && $this->getHasUrls())
    {
        $img = 'getUrl().'" width="'.$this->getWidth().'" height="'.$this->getHeight().'" alt="'.HtmlHelper::encode($this->title).'" />';
        return TemplateHelper::getRaw($img);
    }
}


How can I filter which children I want to show in a sub navigation menu I have a navigation menu setup but I want to filter out some of the children at level(2) so they aren't showing in the dropdown navigation menu. Here is how I am grabbing the children...

{% set mainEntry = craft.entries.slug(craft.request.getSegment(1)).one() %}
{% set subnav = craft.entries.descendantOf(mainEntry).level(2) %}

Home

Conference

                            {% for page in subnav %}

                                {{ page.link }}

                            {% endfor %}

The way I usually accomplish this is to add a "Hide From Nav" Lightswitch field to the sections I want to filter.

This will filter out any entries where the Lightswitch is "on".

{% set subnav = craft.entries.descendantOf(mainEntry).hideFromNav('not 1').level(2) %}


Sprout Email: Notification unable to create "Craft\WebApp.userGroups just bought the Sprout Business Collection since i've been playing around with Sprout forms during the beta periode and now needed to implement email features.

One problem i'm running into. After installation i tried to create a new notification. First screen no problem. Enter name, template, field layout. After saving the ADD NOTIFICATION ENTRY button appears. But clicking that gives me the following error (translated from dutch so possibly not exact).

The attribute "Craft\WebApp.userGroups" is not defined.

Below you'll find a link to the craft.log since it contained more detailed information about the error.

https://www.dropbox.com/s/svebqtfgppnhvug/sprout_email_error_craft.log?dl=0

Hope someone can point me in the right direction.

Bas

This issue has been resolved in Sprout Email v1.0.4


Filtering by cousins I want to do exactly this: Multi-step & bi-directional relations with relatedTo (#1640)

  Common example: Let’s say you have Books, Authors, and Publishers, and two relationship fields on the Books channel: author and publisher. On a Publisher’s page, you want to list all of the Authors that have published books with them.

Here’s what I’ve tried:

{% set bookIds = craft.entries()
.section('books')
.relatedTo({ targetElement: publisher, field: 'publisher' })
.ids() %}

{% set authors = craft.entries()
.section('authors')
.relatedTo({ sourceElement: bookIds, field: 'books' })
.all() %}

However the code results in an "Undefined offset: 0" error. The error seems to occur in the first block of code.

Additionally, I'm not sure about the field in the penultimate line, shouldn't it be 'authors' rather than 'books'?

The error you’re getting is a bug in Craft. (Just fixed that for the next release.)

To work around it, replace the {% set authors ... %} tag with:

{% if bookIds|length %}
    {% set authors = craft.entries()
        .section('authors')
        .relatedTo({ sourceElement: bookIds, field: 'books' })
        .all() %}
{% else %}
    {% set authors = [] %}
{% endif %}


Something went wrong when processing the logo I've just installed Craft on a new Laravel Homestead environment and all seems to be running fine, with the exception of being able to upload a logo in the General settings.

The logo uploads and displays in the popup for cropping, but when I save it, I get this error flashed up:

  Something went wrong when processing the logo.

I've checked the permissions and everything seems fine - the storage dir is set to 777 on my local box just to be doubly sure and I can see Craft is creating files and folders in there.

The $imagePath variable in the RebrandController::RebrandController() method is as follows:

  /home/vagrant/sites/craft-base/craft/storage/runtime/temp/uploads/Rally-Digital-Logo.png&d=1420216657

Aside from permissions, what could cause this?

There was a problem with the URL of the image.

The RebrandController class removes '?' querystrings from the URL but in my case I had a '&'. Removing that solved the issue and Brad has confirmed this fix has been rolled into the next release.


Updating Craft cause broken git and merge conflict I've got a local db and install of Craft as well as a remote. I'm pushing to bitbucket from my local Mamp environment then pulling from bitbucket to my server via ssh.

I recently updated Craft by clicking the prompt inside the dashboard. When I did this, it editing nearly every file in /craft/app leaving a ton of modified files registered in git.

I should have had craft/app in my .gitignore file but I didn't. Now when I try to pull I'm getting this error:

error: Your local changes to 'craft/app/Info.php' would be overwritten by merge.  Aborting.
Please, commit your changes or stash them before you can merge.

How can I force my remote build to ignore everything in craft/app so I can get back to pushing/pulling.

The error that you are seeing is because you have changes in your local repo that need to be saved (committed) first.

I'm also a huge Git user and wanted to touch on a few items in your question.

The craft/app folder should always be in your Git repository as its the foundation of making your site run Craft.
If you want to see an example Craft Git project, you can take a look at this repository: https://github.com/themccallister/craft-foundation
The only directories that should be ignored are storage (make sure you keep the actually directory using this trick: https://stackoverflow.com/questions/115983/add-empty-directory-to-git-repository) and any directories in public that will contain user uploaded files (i.e public/images/uploads). This will ensure that the directory contents are not overwritten during deployment, ensuring that backups, sessions and user content will remain after the deploy.

As far as your remote build... The typical workflow for Git should look something like this:

Download and update Craft locally
Commit your changes to your local environment (should mostly be updates in the craft/app directory)
Push your changes to your remote repository (typically referred to as origin or upstream)
Deploy the update.

Note: If you are building using a tool like (http://dploy.io) you can login and push the changes to your environment. If you are SSHing into the server and running git pull origin that would work as well.


CDbException: The DB query must contain the "from" portion Seeing the above error, somewhat sporadically, and can't seem to track it down.

Here's the full log entry:

2014/07/03 15:17:22 [error] [exception.CDbException] exception 'CDbException' with message 'The DB query must contain the "from" portion.' in /var/www/topsecret.co.uk/craft/app/framework/db/CDbCommand.php:566
Stack trace:
#0 /var/www/topsecret.co.uk/craft/app/framework/db/CDbCommand.php(160): CDbCommand->buildQuery(Array)
#1 /var/www/topsecret.co.uk/craft/app/framework/db/CDbCommand.php(484): CDbCommand->getText()
#2 /var/www/topsecret.co.uk/craft/app/framework/db/CDbCommand.php(415): CDbCommand->queryInternal('fetch', Array, Array)
#3 /var/www/topsecret.co.uk/craft/app/etc/behaviors/AppBehavior.php(410): CDbCommand->queryRow()
#4 /var/www/topsecret.co.uk/craft/app/etc/behaviors/AppBehavior.php(146): Craft\AppBehavior->getInfo('edition')
#5 [internal function]: Craft\AppBehavior->getEdition()
#6 /var/www/topsecret.co.uk/craft/app/framework/base/CComponent.php(261): call_user_func_array(Array, Array)
#7 /var/www/topsecret.co.uk/craft/app/services/LocalizationService.php(111): CComponent->__call('getEdition', Array)
#8 /var/www/topsecret.co.uk/craft/app/services/LocalizationService.php(111): Craft\WebApp->getEdition()
#9 /var/www/topsecret.co.uk/craft/app/services/LocalizationService.php(141): Craft\LocalizationService->getSiteLocales()
#10 /var/www/topsecret.co.uk/craft/app/services/LocalizationService.php(154): Craft\LocalizationService->getPrimarySiteLocale()
#11 /var/www/topsecret.co.uk/craft/app/etc/web/WebApp.php(824): Craft\LocalizationService->getPrimarySiteLocaleId()
#12 /var/www/topsecret.co.uk/craft/app/etc/web/WebApp.php(291): Craft\WebApp->_getTargetLanguage()
#13 /var/www/topsecret.co.uk/craft/app/framework/i18n/CMessageSource.php(83): Craft\WebApp->getLanguage()
#14 /var/www/topsecret.co.uk/craft/app/framework/YiiBase.php(585): CMessageSource->translate('yii', 'The DB query mu...', NULL)
#15 /var/www/topsecret.co.uk/craft/app/framework/db/CDbCommand.php(566): YiiBase::t('yii', 'The DB query mu...')
#16 /var/www/topsecret.co.uk/craft/app/framework/db/CDbCommand.php(160): CDbCommand->buildQuery(Array)
#17 /var/www/topsecret.co.uk/craft/app/framework/db/CDbCommand.php(484): CDbCommand->getText()
#18 /var/www/topsecret.co.uk/craft/app/framework/db/CDbCommand.php(415): CDbCommand->queryInternal('fetch', Array, Array)
#19 /var/www/topsecret.co.uk/craft/app/etc/behaviors/AppBehavior.php(410): CDbCommand->queryRow()
#20 /var/www/topsecret.co.uk/craft/app/etc/behaviors/AppBehavior.php(371): Craft\AppBehavior->getInfo('maintenance')
#21 [internal function]: Craft\AppBehavior->isInMaintenanceMode()
#22 /var/www/topsecret.co.uk/craft/app/framework/base/CComponent.php(261): call_user_func_array(Array, Array)
#23 /var/www/topsecret.co.uk/craft/app/etc/web/WebApp.php(145): CComponent->__call('isInMaintenance...', Array)
#24 /var/www/topsecret.co.uk/craft/app/etc/web/WebApp.php(145): Craft\WebApp->isInMaintenanceMode()
#25 /var/www/topsecret.co.uk/craft/app/framework/base/CApplication.php(180): Craft\WebApp->processRequest()
#26 /var/www/topsecret.co.uk/craft/app/index.php(196): CApplication->run()
#27 /var/www/topsecret.co.uk/web/index.php(17): require_once('/var/www/topse...')
#28 {main}

Looking through that I'm not seeing any references to any custom plugins or templates so wonder if it's a bug...

Any suggestions would be very much appreciated!

Traced the error back to the from function in Yii's craft/app/framework/db/CDbCommand.php:

$tables=preg_split('/\s*,\s*/u',trim($tables),-1,PREG_SPLIT_NO_EMPTY);

The preg_split documentation states "if matching fails, an array with a single element containing the input string will be returned" but I was just getting an empty array.

This made me suspicious of what the PREG_SPLIT_NO_EMPTY flag was hiding, sure enough without it I got an array with one empty string in it, as if there was a match.

Some trial and error later and adding the PCRE_UTF8 modifier u to the preg_split patterns seemed to solve the problem.

Unfortunately can't explain what's causing the encoding issues yet.


Shipping Method option not showing I've set up a shipping method/zone purely for testing but it doesn't show up during checkout. :/

I created a shipping zone only for the state of Oregon:

And for the shipping method there's just ONE rule with the ONLY condition being that the shipping zone is Oregon:

Here's the code I have for the shipping page of the checkout process:
http://d.pr/n/fizP

Finally, when I go through the checkout process, I make sure that my shipping address uses Oregon as the state. I've confirmed this by using this on the shipping page (not seen in the code above): {{ cart.shippingAddress.state }}

What am I missing??

My issue was that the country wasn't being set properly. Since we're only shipping to the US, I had mistakenly commented out my hidden input for the country field.


Can I set an environment var for SMTP mail servers? Pretty straight forward here, I'd like to use MailTrap for devMode and then use an SMTP service (Mandrill or like) for production. I looked through the General Config Settings docs but didn't see anything that lent itself to being SMTP related. Is this possible?

Not an easy way to do this in Craft 2, but this is possible in the upcomgin Craft 3 (currently in beta) using craft/config/app.php, which is multi-environment aware.


Route to entry in Arabic not working but category route is OK I have successfully managed to route Arabic categories to a custom template. The Arabic URLs appear RTL which is strange (and correct?), but I cannot get the Arabic single entry to pick up the template. The image below is an example of the category route working for French and Spanish but not for a single entry in Arabic. This is on Craft 2.

Does anyone know why this wouldn't work?

So it looks like I made some false assumptions.
In Chrome the Arabic URLs displayed are reversed in segment order.
However, I assumed the same was true for Craft routing - the UI behaves in a RTL fashion when editing Arabic text in routes editing interface. But this is not true - it seems that Craft routes don't reflect the browser behaviour for RTL languages. Craft still keeps the normal order of segments when processing the route. So weirdly the URL is reversed in browser but Craft seems to 'see' the route match as left to right. Once I adjusted the route to 'normal' left to right segments the routing worked fine.


a&m nav - activeNodeId I have the following menu structure:

as you can see, the Item "Clients" points to the same Url as its Child "Client Portfolio" does.

Unfortunately this is not working for my submenu that should consist of the active menuitems childs:

{% set activeNodeId = craft.amNav.getActiveNodeIdForLevel('mainmenu','1') %}

{% if activeNodeId %}
   {{ craft.amNav.getNav('mainmenu', {
    class: 'subnav-inner',
    startFromId: activeNodeId
                }) }}
{% endif %}

The variable "activeNodeId" is always the deepest level child (with that url). So in my case, clicking on "Clients" would result in an activeNodeId = 66. Of course fetching the subitems of this makes no sense because "Client Portfolio" has no children.

Any idea how to force the plugin to take always the correct (parents) id? Or any other way to get the submenu items of the active menu?

I finally found a solution of my problem that makes the A&M Nav plugin the perfect choice for me.

The general problem is that amnav offers this function to fetch the activenode id:

{% set activeNodeId = craft.amNav.getActiveNodeIdForLevel('mainmenu',1) %}

This doesn't help because:

Unfortunately the level1 (last parameter) is related to the structure in craft, not in the plugin. In my case the child of a menuitem is not necessarly a child in craft (e.g. a single content).

That means, this function doesn't help me to get the children of a parent that has active children.

This code works to get the active menu item of the first level in the A&M Nav structure:

{# for first level #}
{% set activeNodeId = craft.amNav.getActiveNodeIdForLevel('mainmenu',1) %}

{# for second level #}
{% set nav = craft.amNav.getNavRaw("mainmenu") %}

{% for item in nav %}
    {% if item.hasActiveChild or item.active %}
        {% set activeNodeId = item.id %}
        {% set activeNode = item %}
    {% endif %}
{% endfor %}


Is there a way to output certain rows (or filter) from a table? Here's an example, I have three columns in a table: ClassQuarter, Course No, Description.

I would like to output rows only with ClassQuarter == '1' in a HTML table, then output rows where ClassQuarter == '2' in another table, then output rows where ClassQuarter == '3' in another table.

Am I able to output rows with a condition for the first column?

Since there are a set number of quarters you can probably just collect the entries in a temporary array. Then use those to build your tables.

{% set quarter1 = [] %}
{% set quarter2 = [] %}
{% set quarter3 = [] %}

{% for row in entry.courses %}

    {% if row.classQuarter == 1 %}
        {% set quarter1 = quarter1|merge([row]) %}
    {% endif %}

    {% if row.classQuarter == 2 %}
        {% set quarter2 = quarter2|merge([row]) %}
    {% endif %}

    {% if row.classQuarter == 3 %}
        {% set quarter3 = quarter3|merge([row]) %}
    {% endif %}

{% endfor %}

    {% for row in quarter1 %}

            {{ row.courseNumber }}
            {{ row.courseDescription }}

    {% endfor %}

    {% for row in quarter2 %}

            {{ row.courseNumber }}
            {{ row.courseDescription }}

    {% endfor %}

    {% for row in quarter3 %}

            {{ row.courseNumber }}
            {{ row.courseDescription }}

    {% endfor %}

You could also add an 'if' clause in the 'for...in' loop. See the twig docs on adding a condition for more info.

    {% for row in entry.courses if row.classQuarter == 1 %}

            {{ row.courseNumber }}
            {{ row.courseDescription }}

    {% endfor %}

    {% for row in entry.courses if row.classQuarter == 2 %}

            {{ row.courseNumber }}
            {{ row.courseDescription }}

    {% endfor %}

    {% for row in entry.courses if row.classQuarter == 3 %}

            {{ row.courseNumber }}
            {{ row.courseDescription }}

    {% endfor %}

And could also probably condense that using the range shortcut.

{% for quarter in 1..4 %}

        {% for row in entry.courses if row.classQuarter == quarter %}

                {{ row.courseNumber }}
                {{ row.courseDescription }}

        {% endfor %}

{% endfor %}


How can I dynamically remove some unwanted formatting tags inside rich text fields? I set up a Redactor config to add h3 headings only. If I copy-paste texts from a text edition software like Microsoft Word and uses h1 or h2 for example in his document, these un-wanted headings will be pasted in the rich text field. In another way, if I add an heading tag like <h1> in the source code mode of Redactor, this unwanted heading will also be added.

How can I prevent this and set a list of unwanted tags that could be dynamically deleted or converted in <p> ?

There are pasteBlockTags and pasteInlineTags options in the Redactor doc (https://imperavi.com/redactor/docs/settings/paste/#setting-pasteBlockTags), but it doesn't seems possible to add these options inside the JSON file stored in craft/config/redactor.

I also tried to add a new formattingAdd option, which I called Remove format, and replace unwanted tags by <p>, but this is an annoying solution because it needs to review each pieces of texts.

Not a "real" answer because it won't fix your actual content, but I wrote a plugin that would make it easy to remedy your issue on the front end (i.e. in the template) –

To remove all <h1> and <h2> tags (content inside tags will not be removed):

{{ entry.someRedactorField|retconChange(['h1','h2'], false) }}

To change <h1> and <h2> tags into <p> tags:

{{ entry.someRedactorField|retconChange(['h1','h2'], 'p') }}

You can read more about the rectonChange filter used in the two examples above here.


Including Zii in Craft CMS I have a large dataset of active records (not Craft entries) that I'd like to display in the admin frontend. Yii comes with a widget called CGridView, found here: framework/zii/widgets/grid/CGridView.php, which would fit the bill perfectly.

I've discovered that zii is not available in Craft, even though it's built on Yii. Is there an alternative to use in Craft that can provide a paginated grid view of active records or is there a way to include zii without affecting Craft core code?

This is for version 2.6 PRO of Craft CMS.

Craft 2.x ships with a subset of the Yii framework files with things like zii and Yii widgets stripped out.

If you wanted to utilize them, you'd have to create a Craft plugin and manually include the files that you're looking to use.


How do you set a different icon per entry in SmartMap? And how do you set a different icon and infoWindow when a lightswitch or entry type?

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

{% set options = {
    'zoom': 5,
    'height': 750,
    'markerInfo': '_includes/infoBubble',
    markerOptions: {
        icon: 'http://maps.google.com/mapfiles/ms/icons/green-dot.png'
    },
} %}

{{ craft.smartMap.map(locations, options) }}

That's a tricky one... Natively, all of the options are applied to all markers equally. But you can do a little workaround using something like this pseudo-code:

{% set markerIconJs  %}

    // On page load
    $(function () {

    {% for entry in locations %}

        {% if entry.lightswitch %}

            // JavaScript: Override the default icon with your own
            smartMap.marker['smartmap-mapcanvas-1.{{ entry.id }}.myAddressField'].setOptions({
                icon: '{{ entry.icon }}'
            });

        {% endif %}

    {% endfor %}

    });

{% endset %}

{% includeJs markerIconJs %}


How do I use Plain Text Field in URL Format? I'm creating an events system & I want to include the venue in the url of the event along with the event name.

For now the venue name is just stored using a plain text field.

Is there an easy way in craft to convert a string & slugify it? Could I use any filter I add to Craft? Can I do it without a plugin of some sort?

I've tried the following

{ (eventVenue ? "-" ~ eventVenue | lower | replace(' ', '-') | replace('/[^\w]/','')) }

along with using Twig PCRE

{ (eventVenue ? "-" ~ eventVenue | lower | preg_replace('/[^A-Za-z0-9-]+/') ) }

Both of which give the error Expecting name or number

The Slugify plugin has a Twig filter that should do what you're looking for.


Issue uploading files I have completed a website for a school who can't upload files when in school.
When they upload a file the status bar loads the full way across the screen but at the top right it just keeps spinning. Nothing more happens - the files doesn't become available.
I can upload fine from home and the staff can upload fine at home as well.
What is the likely cause of this issue - I have log files to check if need be - I deleted the log files then asked them to try and upload a file - then I took a copy of the log files with Dev Mode on.

Is this likely to be a Firewall Issue in the school? I did a website for another local school who would have the same IT provider but have no issues there.

I'm glad you identified and resolved the issue!

I stumbled across this post because I had the same GUI response/result in Craft CMS and want to share how I resolved it for others that may have the same issue without being a firewall problem.

See my answer here


Make exponent style in Riche Text field I want to provide an easy way to make exponent style text in the Redactor field type.

Is there a Redactor plugin to do that?

If no what is the best way to handle that?

1/ HTML superscript tag

This text contains superscript text.

or
2/ CSS custom Redactor class

.sup {
    vertical-align: super;
    font-size: smaller;
}

In craft/config/redactor you can either add your own setting file, or edit one of the ones already there. If you add the following JSON:

"formattingAdd": [
  {
    "tag": "sup",
    "title": "Superscript"
  }
]

You will have access to a Superscript choice under the Formatting buttons dropdown menu. This will wrap the selected text in a <sup> tag.

While I'm not sure if this is the correct way of adding stuff like this, I just tested it and it does work.


How can I remove all text content and assets from a duplicated site? I duplicated a site.  What is the easiest way to delete all assets and text data but keep fields and sections in place?

You can delete all of your existing entries and assets by executing this SQL query:

DELETE FROM craft_elements
WHERE type IN ('Entry', 'Category', 'Tag', 'Asset')

All associated content, relationships, etc., will automatically be deleted.

If you have a bunch of users you want to delete, you should at least spare your own admin account, so figure out your user ID and do this:

DELETE FROM craft_elements
WHERE type IN ('Entry', 'Category', 'Tag', 'Asset', 'User')
AND id != 1

(The admin account created during installation will have the ID of 1, assuming you haven’t deleted the account.)

You should also delete existing asset sources, assuming those are going to need to change and will have their own sets of files. You can either do that from the Control Panel, or execute this SQL query:

DELETE FROM craft_assetsources


Editing images in Rich Text Field I used to be able to resize and select align attributes for images in Rich Text and now that feature is completely gone since my last update. Do I need to change settings or has that feature actually been removed?

Actually, image resizing and alignment is still available in Redactor II
(at least it is by now, might have been different a year ago)

It seems that in Reactor II both of those have to be enabled explicitly in the config. See Redactor docs

In Craft CMS you can modify the config in craft/config/redactor. Or create a new file and select it in the Control Panel. More details

My Standard.json looks something like this:

{
    "buttons": [...],
    "plugins": [...],
    "imageResizable": true,
    "imagePosition": true
}


How do I add more account fields for user registration? I'm using the default form found in the Craft CMS docs, however I'd like to create more fields other than username, password and email. How would I add more custom fields to capture user data like address, phone number etc?

Create the input fields as you would any other, maybe add them to a 'users' group, then you can go to:

/admin/settings/users/fields

and add them via the layout designer, you should then see them appear when viewing a user in the admin area, under the profile tab I believe :)


How can I add custom validation rules to a new User registration? For example, how might we ensure that firstName is set.

At the time of writing the users.onBeforeSave event runs after validation, which means that we can’t add errors to the user easily.

The solution I’ve currently come up with is a plugin that adds custom validation rules to a user model, as well as a controller to handle the form submission.

Model

Firstly, I’ve extended the UserModel and added custom validation rules as needed.

<?php

namespace Craft;

class MyPlugin_UserModel extends UserModel
{
    protected function defineAttributes()
    {
        // Get the rules defined in UserModel
        $rules = parent::defineAttributes();

        // Add custom rules
        $rules['firstName'] = array(AttributeType::String, 'required' => true);
        $rules['lastName'] = array(AttributeType::String, 'required' => true);

        // If it’s a new user, require the password
        $isNewUser = !isset($this->id);
        if ($isNewUser) {
            $rules['password'] = array(AttributeType::String, 'required' => true);
        }

        return $rules;
    }
}

Controller

Secondly, I’ve created a controller action that will handle form submissions. This populates our custom user model with the input and runs the standard validate() flow.

<?php

namespace Craft;

class MyPlugin_UsersController extends BaseController
{
    protected $allowAnonymous = array('actionSaveUser');

    public function actionSaveUser()
    {
        $this->requirePostRequest();

        // Get input
        $post = craft()->request->getPost();

        // Create an instance of our model
        $user = new MyPlugin_UserModel($post);

        if (!$user->validate()) {
            // Add any errors from the validation to the user
            $user->addErrors($user->getContent()->getErrors());

            // Respond with errors
            if (craft()->request->isAjaxRequest()) {
                $this->returnJson(array(
                    'errors' => $user->getErrors(),
                ));
            } else {
                craft()->userSession->setError(Craft::t('Couldn’t save user.'));

                // Send the account back to the template
                craft()->urlManager->setRouteVariables(array(
                    'account' => $user
                ));
            }
        } else {
            // If all is well, run the default UsersController method
            craft()->runController('users/saveUser');
        }
    }
}

Template

For reference, here’s the action input in the template. Essentially, it’s just prepending the plugin handle before the default action.

<input type="hidden" name="action" value="myPlugin/users/saveUser">


How to register a new System Message email I want to send a welcome email to the user when they sign up (not an activation email).

I can see the email and edit its text in the Control Panel, but the email doesn't send when a new user registers.

Here is my code:

Event::on(SystemMessages::class, SystemMessages::EVENT_REGISTER_MESSAGES, function(RegisterEmailMessagesEvent $event) {
    $event->messages[] = [
        'key' => 'after_activate_user',
        'heading' => 'When someone registers:',
        'subject' => 'Subject',
        'body' => 'Message text',
    ];
});

My question, is there anything else I need to do to get this email to send? Do I need to define a recipient?

This will only register your message with Craft. To then send it you would do something like this:

Event::on(
    Elements::class,
    Elements::EVENT_AFTER_SAVE_ELEMENT,
    function(Event $event) {
        if ($event->element instanceof \craft\elements\User) {
            $user = $event->element;
            if($event->isNew) {
                Craft::$app
                    ->getMailer()
                    ->composeFromKey('after_activate_user')
                    ->setTo($user)
                    ->send();
            }
        }
    }
);

This will listen for the EVENT_AFTER_SAVE_ELEMENT event, make sure it's a User being saved, check that it's a new user then send the message.


Undeleting entries (or restore previous version of deleted entry?) Is there a way to "undelete" an entry that has been deleted? (Kind of like the "Trash/Recycling Bin" functionality of our computer OS.)

I don't see any obvious way to do this, but since Craft Pro has page versioning it seems like perhaps there should be a way to restore an old version of a page that has since been removed?

In the toolbar above the element index you can use the "status" dropdown to filter by trashed elements. From there you can select the entries you want to recover and click the "Restore" button.


Reference tags in rich text fields parse and converted on save In my rich text field, I have a reference tag: {globalset:34:address}.

When I save and open the entry back up, the content is no longer a reference, but the parsed content, which sort of eliminates its usefulness.

Correct... they currently only work on plain text fields, not rich text fields.

I just updating the documentation so it's a more clear.


How to make a separate RSS feed for each entry type of a section? I would like to make a separate RSS feed for each entry type of a section, for example:

http://mysite.com/posts/feed.rss

http://mysite.com/videos/feed.rss

...

Rey - depending on how you've setup your enries and folder structure you could create feed.rss as a template in both of those folders.

Inside the template you can setup the entry loop to output whatever information you need the RSS feed to include. It's not automated but completely within your control.


Matrix field validation on guest entry submission First I illustrate the way I set up guest entry form.

Let's say I have channels blog product and comment cart.

Guest entry submits to the comment cart channel. Form lives in template which I use to show blog's product's entry.

Now I just send required field title which won't get passed by validation unless it isn't blank.

According to Guest Entries settings to show my blog's product's content along with my guest entry form I have to change the name of entryVariable key from entry to whatever not taken variable name let's say entryError in an event of validation error to not overwrite blog's product's variable entry.

In short this is how the template looks like when blog product entry load. This is just part of the form which is executed when first item is added to the cart matrix field in cart channel.

{# Product's title #}
{{ entry.title }}

{# Product's text #}
{{ entry.text }}

{# Show form error #}
{% macro errorList(errors) %}
    {% if errors %}

            {% for error in errors %}

{{ error }}

            {% endfor %}

    {% endif %}
{% endmacro %}

{% from _self import errorList %}

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

    <input type="hidden" name="title" value="Some dynamic title">

    {# Matrix field "cart" #}
    {# Block type field we want the product to save in. #}
    <input type="hidden" name="fields[cart][new1][type]" value="product">

    <input type="hidden" name="fields[cart][new1][fields][productTitle]" value="{{ entry.title }}">

    {# Quantity #}
    Quantity *
    <select id="qntySlct" name="fields[cart][new1][fields][productQuantity]">
        <option value="">--Please, select the quantity--</option>
        {% for i in 1..10 %}
            <option value="{{ i }}"{% if productQuantity == i %} selected{% endif %}>{{ i }}</option>
        {% endfor %}
        <option value="">I need more</option>
    </select>

    {# Error message #}
    {% if entryError is defined %}

            {{ errorList(entry.getErrors('productQuantity')) }}

    {% endif %}

</form>

Form submits if title quantity is defined and if not I get entryError defined but don't get the title's quantity's  error shown.

The warning of title's quantity's error is logged in the Application Log.
Have anyone came accross this unlikely issue?

CORRECTION UPDATE

Thanks to the Robin's comment bellow to debug it with {{ dump() }} function I found out that input quantity field with variable title is returning the error value. However I didn't mentioned in my question that I'm actually posting/retrieving to/from matrix field as I didn't want to make the question pointlessly complicated with all those fields I've set.

I've been misleaded/figured that to access field's variable in

{{ errorList(entry.getErrors('variable')) }} for example, is not valid for matrix field.

Now I can't find any info on how to access matrix field for entry validation using:

{% macro errorList(errors) %}{% endmacro %}.

To grab validation error of a matrix field -> first block type -> field, you must access entry's matrix field with the function first() and than access block type field using getError("fieldHandle") function at the end of ElementCriteriaModel like so.

{{ entry.matrixField.first().getError("customFieldHandle") }}

or to the question related problem

{{ entryError.cart.first().getError("productQuantity") }}

Doing this way you don't have to loop through Matrix's blocks and it make sense if you need to access first block type only or you have only one block type.

To show validation error under each block.type of a custom field you'll have to loop in MatrixBlockModel of the cart channel like so.

{% if entryError is defined %}
    {% for block in entryError.cart %}
        {% if block.getErrors() %}
            {{ block.getError('productQuantity') }}
        {% endif %}
    {% endfor %}
{% endif %}

Like Brad pointed out to me in support ticket "you can decide how you want to display them".


Do I need a model when I have a record? I have a record so I can save my data to the DB but do I need a model for services and stuff ? Or can the record do that too ?

Records can do that too (where that = hold data), but, according to Craft docs, Records should never ever leave Service layer. So, yes, you do need a model too.


Solspace Calendar: List only recurring events I have a calendar for a location that combines recurring events with individual events. I'm trying to list out the upcoming events for the next 90 days, but I'm running into issues with the repeating events. I'd like to list the individual events by dates, and then have the repeating events listed once, with their rule (i.e. Every Monday: Event Title).

{% set eventOptions = {
    calendar: 'otherEvents',
    dateRangeStart: 'today',
    dateRangeEnd: '+90 days',
} %}
{% set otherEvents = craft.calendar.events(eventOptions) %}

This gives me a list of all events, but it is overwhelmed by recurring events. I can turn them off by adding loadOccurrences:false, but I'm having trouble loading them on their own.

 {% set eventOptions = {
    calendar: 'otherEvents',
    loadOccurrences: false,
} %}
{% set otherEvents = craft.calendar.events(eventOptions) %}

This gives me a list of individual events and a single instance of each repeating event, but it also shows expired events. As soon as I add a date range, the recurring events go away.

Is there any way to get JUST the recurring events, listed once, with their repeat rule? Essentially, i need a loadOnlyOccurrences option.

The limitation here is that the loadOccurrences: false parameter only checks for "Primary" events (first occurrence) within the specified timeframe. So if the first occurrence is outside of the specified timeframe, the event won't show at all.