Upgrading Craft 2 to Craft 3 Yii Issues I tried searching for an answer for my situation but I could not find one. I tried following the steps here https://docs.craftcms.com/v3/upgrade.html#preparing-for-the-upgrade but whenever I get to the browser step to complete upgrade, I get this error:

  !/usr/bin/env php
  Exception 'yii\base\UnknownPropertyException' with message 'Getting unknown property: craft\console\User::enableSession'

  in /Users/avalosju/craft/vendor/yiisoft/yii2/base/Component.php:154

  Stack trace:

  0 /Users/avalosju/craft/vendor/craftcms/cms/src/helpers/App.php(372): yii\base\Component->__get('enableSession')

  1 /Users/avalosju/craft/vendor/craftcms/cms/src/config/app.php(214): craft\helpers\App::logConfig()

  2 [internal function]: {closure}()

  3 /Users/avalosju/craft/vendor/yiisoft/yii2/di/Container.php(503): call_user_func_array(Object(Closure), Array)

  4 /Users/avalosju/craft/vendor/yiisoft/yii2/BaseYii.php(351): yii\di\Container->invoke(Object(Closure), Array)

  5 /Users/avalosju/craft/vendor/yiisoft/yii2/di/ServiceLocator.php(137): yii\BaseYii::createObject(Object(Closure))

  6 /Users/avalosju/craft/vendor/yiisoft/yii2/base/Module.php(742): yii\di\ServiceLocator->get('log', true)

  7 /Users/avalosju/craft/vendor/craftcms/cms/src/console/Application.php(146): yii\base\Module->get('log', true)

  8 /Users/avalosju/craft/vendor/yiisoft/yii2/base/Application.php(508): craft\console\Application->get('log')

  9 /Users/avalosju/craft/vendor/craftcms/cms/src/base/ApplicationTrait.php(1133): yii\base\Application->getLog()

  10 /Users/avalosju/craft/vendor/craftcms/cms/src/console/Application.php(62): craft\console\Application->_preInit()

  11 /Users/avalosju/craft/vendor/yiisoft/yii2/base/BaseObject.php(109): craft\console\Application->init()

  12 /Users/avalosju/craft/vendor/yiisoft/yii2/base/Application.php(206): yii\base\BaseObject->__construct(Array)

  13 /Users/avalosju/craft/vendor/yiisoft/yii2/console/Application.php(89): yii\base\Application->__construct(Array)

  14 /Users/avalosju/craft/vendor/craftcms/cms/src/console/Application.php(53): yii\console\Application->__construct(Array)

  15 [internal function]: craft\console\Application->__construct(Array)

  16 /Users/avalosju/craft/vendor/yiisoft/yii2/di/Container.php(383): ReflectionClass->newInstanceArgs(Array)

  17 /Users/avalosju/craft/vendor/yiisoft/yii2/di/Container.php(156): yii\di\Container->build('craft\console\A...', Array, Array)

  18 /Users/avalosju/craft/vendor/yiisoft/yii2/BaseYii.php(349): yii\di\Container->get('craft\console\A...', Array, Array)

  19 /Users/avalosju/craft/vendor/craftcms/cms/bootstrap/bootstrap.php(252): yii\BaseYii::createObject(Array)

  20 /Users/avalosju/craft/vendor/craftcms/cms/bootstrap/console.php(31): require('/Users/avalosju...')

  21 /Users/avalosju/craft/craft(21): require('/Users/avalosju...')

  22 /Users/avalosju/craft/web/index.php(19): require_once('/Users/avalosju...')

  23 {main}

The issue appears here

$isConsoleRequest = Craft::$app->getRequest()->getIsConsoleRequest();
if (!$isConsoleRequest && !Craft::$app->getUser()->enableSession) {
    return null;
}

For whatever reasons Craft::$app->getRequest()->getIsConsoleRequest(); does not return true -> !false becomes true -> it tries to grab the user which should be an instance of craft\web\User to have the property enableSession but since it is a console request you receive craft\console\User which has not such a property.

I guess it's a bug or something


Pre-fill fields when creating an entry in CP I am using redactor plugin for my field type and I want to use global values of the same field type to be used as pre-fill value when creating a new entry.

Use case:

Each year there is an edition of a program with more or less the same text (multiple fields), but minor adjustments can occur.

So by creating a new edition (entry) in the control panel, I want to already pre-fill the standard values of the fields (configured as a global)
Then I can update, if necessary, some text for this new edition and save it.

Thanks a lot!

This functionality could be created in a plugin or module, but why wouldn't you duplicate the entry and change the fields you need to change?


Can an entry have multiple authors? I'm trying to create a multi user blog, where multiple authors can edit the same entry. Is this possible with Craft CMS? Is there a way to assign multiple authors to an entry? I only managed to assign one user as an author.

No, there can only be one author. But what you can do is to add one or more custom user fields to your entry type and use these to assign different type of users to your entry (all contributing authors, photographers, etc.).

Set user privileges like Douglas describes in his answer, to allow multiple authors to edit entries in your section.


Solspace Freeform query for submission assets returns all site assets I'm attempting to query for all assets associated with a specific form submission like this, where 'submission' has been set based on a URL parameter:

{% for field in submission.fieldMetadata %}
    {% if field.type == "file" %}
        {% set assetId = attribute(submission, field.handle) %}
        {% set assets = craft.assets.id(assetId).all() %}
           {% for asset in assets %}
                {% if asset %}
                    {% if asset.kind == "image" %}
                        <img src='{{ asset.url }}'>
                    {% endif %}
                {% endif %}
            {% endfor %}
    {% endif %}
{% endfor %}

The above code returns all site assets rather than just the assets associated with the submission. All other fields associated with the submission are returned correctly. Is this a bug or is my template incorrect?

The following template code resolved this issue for me:

{% for field in submission.fieldMetadata %}
     {% if field.type == "file" %}
        {% set assetIds = attribute(submission, field.handle).value %}
        {% if assetIds %}
           {% for assetId in assetIds %}
              {% set asset = craft.assets.id(assetId).one() %}
              {% if asset %}
                 {% if asset.kind == "image" %}

                 {% else %}
                    {{ asset.filename }}
                 {% endif %}
              {% endif %}
           {% endfor %}
        {% endif %}

     {% else %}
        {{ attribute(submission, field.handle) }}
     {% endif %}
{% endfor %}


Development and Production License Key Is there a specific way I can have a development and live version of a website with Craft Pro running simultaneously.

We have multiple clients, and so using craft.dev for our development is not really feasible.

Can I duplicate the production license over to dev to unlock all features?

We have multiple clients, and so using craft.dev for our development is not really feasible.

How about client1.craft.dev, client2.craft.dev etc?


Craft CMS development licensing issues I have a Craft CMS installed in a development environment thewebsite.test.

I can't get it to trial paid plugins and Craft Pro.

It appears Craft doesn't recognise it's in a development environment?

Application Info

PHP version  7.4.2
OS version   Linux 4.15.0-74-ubuntu
Database driver & version    MySQL 5.5.5
Craft edition & version  Craft Pro 3.4.6.1

I'm running Windows 10 with Vagrant/Homestead with Craft installed on a Virtual Machine in VirtualBox.

The same setup on a Mac does not have any issues with licensing.

I have copied the database and updated the .env file from the Mac install, and everything appears to be working except for the licensing issues.

Is there any way to force Craft CMS to recognise a dev environment?

did you copy the license.key from your Mac environment to the Windows/Vagrant environment? Maybe deleting the license.key would help in this case.


How to show variations of a single entry? Even possible? We are building a Commercial Real Estate site for a fairly large commercial real estate company and we're coming from an older custom-built site and there is a work flow and associated data logic we're having trouble figuring out how to best replicate in Craft.

When they list properties for sale or lease, they have a set of common fields for a given building (ex. address, photos, city, etc) and then sometimes need to add Units within that building, each with its own set of fields (ex. size, unit number, price, etc).

Sometimes these Unit(s) get listed all together on the one listing (or in the Craft sense, entry) on the front end. However, sometimes they need to be listed separately on the front end (ie. individual Units can be chosen to show up as their own listing (or separate entry)). This is in varying combinations (ie. any Unit could be flagged to show as separate - but not all Units need to). In this case, those separate Units still share (and display) the common building fields (ex. address, photos, city, etc).

What this means from an entry point of view, is we potentially need multiple URL slugs to get to each listing when some Units are flagged to show separately (for example: sale/building1, sale/building1-unit200, sale/building1-unit303 ...or whatever).

So what we're trying to solve us how to handle this. We are trying to preserve an intuitive and easy workflow for the editor, where they go add a new listing on one entry page, and via a Matrix field could add multiple Units - and within each Matrix Unit block, could have a toggle field that says "Show this unit as a separate listing").

The question then is how to access those "show as separate" units on the front end as they technically all share the same URL slug?

We briefly considered using related fields (separating out units as entries and the common building data as entries) but that would become incredibly difficult to remember, maintain and organize for which units belonged to what buildings across many hundreds of listings and thousands of units. As well, many buildings do not even have units.

We also considered a custom plugin that would create a duplicate entry for each flagged Unit when the entry is saved (and conversely remove duplicated entries when a Unit is unflagged). That seems kludgy and possibly complicated but maybe we're wrong on that? Also, not certain if there'd be a way to hide those duplicate entries from users in the CP so they're not confused by those (as they're always thinking that they work on one single entry for each building with its units).

Any thoughts on how to tackle this would be greatly appreciated.

One option to consider would be to use a structure, with the 'building' as a parent entry and the 'units' as children entries (with corresponding entryType of 'building' or 'unit' to set a unique field layout if needed).

Based on whatever logic makes most sense you could then display the building, the building with some subset of data from the units (children), or just the unit. The logic could be either an explicit checkbox or switch on the building or unit entries, or just the mere presence of unit entries (children).

In the structure's settings you can also set whether the 'unit' (child) URI pattern is building/unit (i.e. {parent.uri}/{slug}) or building-unit (i.e. {slug} or {parent.uri}-{slug}).

This should keep everything organized in the CMS and give you a lot of flexibility in terms of what to display where. The building can access the unit data and the unit can access the building data as needed.


Content Modeling for Site Architecture Recommendations I am doing some content modeling for a site with over 100 pages with a pretty deep tree. The site has a lot of what I refer to as "General Pages" as well as a collection of channel type content in the form of news, blogs, and such. In addition there are many unique pages such as contact and application form pages.

My main question is: How to section the over 100 general pages for best balance for client friendliness?

Do I create one "General Page" channel section and then use or build
some sort of nav add-on to create the appropriate heirarchy (This is
how we'd roll if we were building this in EECMS for example)?
Do I use multiple structures, one for each primary nav item? And then figure out how to mix in the other unique singles and entries?
Tons of singles? (my least favorite option)
Something else?

I know the answer to these questions given a CMS as flexible as Craft is simply "Yes"; however, would love to get some thoughts on how people have dealt with a well branched site map and lots of "General Pages".

Thanks!

It sounds like you have 3 different general buckets of entries to consider:

Streams of similar entries (News section, blogs, etc.)
General content pages (100+ of them)
Unique/one-off pages (Contact Us, application forms, etc.)

Streams

First, the easy ones: the streams of similar content (news, blogs, etc.) should each get their own Channel sections. A News channel, Bill’s Blog, Sally’s Blog, etc.

General content pages

For the 100+ general pages, I think putting them all in a single “Pages” section makes sense. Find out what different types of pages there will be, and give the section different Entry Types based on those, so authors have the flexibility of choosing what type of page they want to create.

URL format-wise, you can either require that these entries follow a particular slug-based URL format (e.g. every page will have a url such as http://example.com/some-slug), or give them a custom “Page URL” field where authors can choose what the entry URL would be. For the former, the section’s Entry URL Format setting would get set to {slug}; for the latter, it would be {pageUrlFieldHandle}.

As for the type of section Pages should be (a Structure or a Channel), here’s a good rule of thumb: Do you want all of the pages in this section to be shown in the navigation, or just certain ones? If you want them all in the nav, then use a Structure, and use the built-in Structure View on the Entries index to sort out the navigation. Otherwise make it a Channel, and manage the navigation separately (a&m nav and Craft Nav are your two navigation options at the moment).

Unique pages

Finally, the unique pages like Contact Us and application forms. If you have any pages that are truly unique, which you would never conceive needing two of (e.g. a Contact Us page that has a bunch of custom fields that really only apply to that specific page), create Single sections for those pages. Otherwise you may just prefer to lump these in with the Pages section, with the help of a new entry type(s) (e.g. “Application Form”).


Use blog index template as category template I have a blog listing page which works correctly. I also have categories that I would like to use the same template rather than creating a whole new template since the design is exactly the same.

However when I set the category template to blog/index the page loads correctly but doesn't limit by categories.

Looking at my simplified template code, I'm not sure how to get it to display only the category being viewed or all if on the blog index page.

My urls are

/blog/
/blog/p2 (pagination)
/blog/{{ slug }}

I would like the following url's to use the same template code:

/blog/category/{{ category_url }}
/blog/category/{{ category_url }}/p2

My template code:

{% paginate craft.entries.section('blog').limit(6) as pageInfo, pageEntries %}
{% for entry in pageEntries %}

    some code

      more code

    Keep Reading

{% endfor %}

If necessary I can create a category.html template, but then I'd essentially have duplicate code. Is there a way to do what I want to?

Yup, you can totally re-use the same template. When it is a category page, you will have access to a category variable which is a CategoryModel, and you can use that to filter your entries by category.


How to populate Category field form frontend form? I have a frontend form that has a select list for language. This field will allow for one language to be selected. In the backend I have a field set up for my entries as a category field populated by country categories set as required. I can not seem to get the database to update this category field from my frontend form. The select field is set up as follows for the form field handle language.

<select id="language" name="fields[language]">
    <option value="English">English</option>
    etc
</select>

Anything I am missing to get this to populate correctly.

Cheers

Couple things. First, I believe you need to add an extra set of brackets to the name attribute. The reason being that category fields (as well as all 'related' fieldTypes) store more than one element, even if as in this case there is only one category being assigned. Secondly you'll need to assign the category id as the value.

<select id="language" name="fields[language][]">
    {% for category in craft.categories.group('languages') %}
         <option value="{{ category.id }}">{{ category.title }}</option>
    {% endfor %}
</select>


getNextSibling for next product in product type I’m setting up a Craft Commerce website, and at the end of the product pages, I’d like to add a link to the next product in the same product type as the current product.

For regular entries, I used {{ entry.getNextSibling().url }} to get the next entry in the current section, but I can’t figure out how to get the same result for the products.

Thanks!

getNextSibling works in the context of a Structured Section for Entries and for Categories because both of them have the concept of a hierarchy.  i.e. in a Structured Section and a Category Group, each element can have parents and children.

Commerce Products don't have hierarchy natively.  Could be a bit of a pain to maintain, but you could simulate it by adding an "Order" number field to your product field layout and manually enter the order for each product in a product type, grabbing all of them in Twig and doing the sorting there.


Using Twig to merge an array and remove duplicates Problem

I'm building a .json file for a search component of a used cars website. The file needs to be built from the output of two sections within CraftCMS, Used Cars and Vans & Trucks. It outputs the "make" of vehicle and it's "models".

My problem is that there are duplicate "makes"/"models" because they exist in both sections.

Code:

{% set allStock = craft.entries.section(['usedCars','vansTrucks']).level(2) %}
{% for stock in allStock %}
{% set models = stock.getChildren() %}
"{{ stock.make }}" : "{% for stock in models %}{{ stock.model }}{% if not loop.last %}, {% endif %}{% endfor %}"
{% endfor %}

Output:

"Holden" : "Commodore, Ute, Viva"

"Nissan" : "ATLAS, CARAVAN"

"Mazda" : "ATENZA, Axela, CX-7, MAZDA 6, MPV, RX-8, mpv"

"Nissan" : "CARAVAN, DUALIS, FAIRLADY, Liberty, Maxima, NAVARA, NOTE"

Updated

{% set allStock = craft.entries.section(['usedCars','vansTrucks']).level(2) %}
{% set newArray = [] %}
{% for stock in allStock %}
{% set models = stock.getChildren() %}
{% if stock.make not in newArray %}
"{{ stock.make }}" : "{% for stock in models %}{{ stock.model }}{% if not loop.last %}, {% endif %}{% endfor %}"
{% set newArray = newArray|merge([stock.make]) %}
{% endif %}
{% endfor %}

This code will remove the duplicate 'make' and merge but it also removes the models with it.

Output:

"Holden" : "Commodore, Ute, Viva"

"Mazda" : "ATENZA, Axela, CX-7, MAZDA 6, MPV, RX-8, mpv"

"Nissan" : "CARAVAN, DUALIS, FAIRLADY, Liberty, Maxima, NAVARA, NOTE"

Any help or direction on how to go about merging the models would be greatly appreciated.

You could do it in the twig template

But a template isn't really the best place for something that is this codey, it gets pretty unreadable pretty quick.

Notes:

I start by building arrays of models and afterwards I convert those arrays to the comma seperated strings you require.
It is case-sensitive, you probably have models or makes likes HILUX, hilux, Hilux, these sort of duplicates will not be removed. You can achieve a modicum of case-insensitivity by chucking a few lowers in there.
Instead of hand-writing the json, this uses twig's json_encode filter, tweak the options to suit you.

The template code:

{% set makes = craft.entries.section(['usedCars','vansTrucks']).level(2) %}
{% set data = {} %}

{% for make in makes %}
    {% set make_name = make.make %}

    {# Get the list of models for this make if we have already seen it before, otherwise an empty array #}
    {% if data[make_name] is not defined %}
        {% set data = data|merge({(make_name):[]})%}
    {% endif %}
    {% set make_data = data[make_name] %}

    {# Build an array of model names #}
    {% set models = make.getChildren() %}
    {% for model in models %}
        {% set model_name = model.model %}

        {# Only add this model if we have not seen it before #}
        {% if model_name not in make_data %}
            {% set make_data = make_data|merge([model_name]) %}
        {% endif %}
    {% endfor %}

    {% set data = data|merge({(make_name):make_data}) %}
{% endfor %}

{# Replace the arrays of models we previously built with a comma seperated string of models #}
{% for make_name, models in data %}
    {% set models_string = models|join(",") %}
    {% set data = data|merge({(make_name):models_string}) %}
{% endfor %}

{{ data|json_encode(constant('JSON_PRETTY_PRINT'))|raw }}

Or do it with code

Add your own plugin as per the instructions here: Setting things up

Add a template variable as per the instructions here: Template variables

Your template variable could look like this:

namespace Craft;

class MyAwesomePluginVariable
{
    public function getSearchData()
    {
        // find all makes
        $make_criteria = craft()->elements->getCriteria(ElementType::Entry);
        $make_criteria->level = 2;
        $make_criteria->section = array('usedCars','vansTrucks');

        $data = array();

        $makes = $make_criteria->find();
        foreach ($makes as $make)
        {
            // build array of models for this make
            $model_names = array();
            $models = $make->getChildren();
            foreach ($models as $model) {
                $model_names[]= $model->model;
            }

            // combine with previous models for this make and remove duplicates
            if (array_key_exists($make->make, $data)) {
                $data[$make->make] = array_unique( array_merge($data[$make->make], $model_names) );
            } else {
                $data[$make->make] = array_unique( $model_names );
            }
        }

        // convert model arrays to comma separated strings
        foreach ($data as $make => $models) {
            $data[$make] = implode(",", $models);
        }

        return $data;
    }

}

And then in your template:

{{ craft.myAwesomePlugin.getSearchData|json_encode(constant('JSON_PRETTY_PRINT'))|raw }}


Folder Permissions denied with Nitro I’m getting this error when accessing/writing images. It’s only just come along suddenly after one or a couple of updates.

League\Flysystem\Exception
Impossible to create the root directory
"/Users/username/Sites/project-name/craft/web/images/folder". mkdir():
Permission denied

Running Nitro with Multipass 1.5
Multipassd has all Full Disk Access (but had to add this manually from Application Services)
Craft CMS 3.5.16
MacOS Catalina 10.15.7
Composer version 2.0.8
Unable to change file permissions in Finder/Transmit etc
Not new installs
Unable to load an image through CP. Same message as above

Nitro running other simpler site fine, so no problems there.
At a loss, any site running locally that needs images will fail to load, but /admin runs all fine.
Thanks :)

This could be because you are setting your Settings → Assets → your volume File System Path to an absolute location outside the VM.
Create an alias (or hard-set webroot) using:
'aliases' => [
    'webroot' => dirname(__DIR__) . '/web'
],

In your config/general.php (changing web if you have a different public root).
With this in place, change the File System Path of your volume to @webroot/your/path which should solve you issue.


Related Items in a Category not Appearing in Results I am still having a problem looping through related posts.

I get zero, not even the HTML. And there are no Craft template errors. There are plenty of entries that were assigned the same market, so there should be something.  AND this exact approach worked perfectly before !@$!@#!

Similar Projects

{% set relatedMarket = entry.market.first() %}
{% set relatedEntries = craft.entries.section('posts').relatedTo({ targetElement: relatedMarket, field: 'market'}).id('not'~entry.id) %}

{% for relatedEntry in relatedEntries %}

 Entry title goes here. {{ relatedEntry.title  }}

{% endfor %}

I double checked.  My entry section handle is posts. The handle for the posts entry type is notifications. The category group handle is markets.  The category entry field handle is market.  I included the entry type and category group handles just in case I am missing something.

The code above was missing a space after not

.id('not'~entry.id) should have been .id('not '~entry.id)

This one is an easy one to miss and I have done it a million times.


How can I get a list of unique products a Craft Commerce customer has purchased? I'm trying to figure out a way from Twig to get a distinct list of products purchased by a user. Help?

Something like this should work:

{# Grab the currently logged in users past orders %}
{% set pastOrders = craft.commerce.orders.customer(craft.commerce.customer).find() %}

{% set uniqueSKUs = [] %}

{# loop through the orders #}
{% for order in pastOrders %}

    {# loop through the line items #}
    {% for item in order.lineItems %}

        {# did we find a unique one? #}
        {% if item.purchasable.sku not in uniqueSKUs %}

            {# add it to the list #}
            {% set uniqueSKUs = uniqueSKUs|merge([item.purchasable.sku]) %}

        {% endif %}
    {% endfor %}
{% endfor %}

Unique SKUs for customer ID {{ craft.commerce.customer.id }}:

    {% for sku in uniqueSKUs %}

{{ sku }}

    {% endfor %}


How can I output a timeframe in fully written notation nicely? Let's say you have two dates and want to output the timeframe in fully written "day month year - day month year" notation, but want to leave out the month and year parts of the start date if unnecessary.

Examples:

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

How can I get the desired notation of the timeframe?

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

Example:

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

The macro:

{% macro timeframe(dateStart, dateEnd) %}

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

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

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

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

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

{% endmacro %}

Example usage:

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

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

.

Edit:

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

Examples:

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

The updated macro:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    {% endif %}

{% endmacro %}


How do I get the url of single pages? I've been struggling all evening with getting the urls of my singles in a menu generator. At first I thought I nailed it, but it turned out it used the title of the singles instead of the url. When I tried to get the url I an error, so clearly I'm doing something wrong.

This is the code to generate the menu:

{# generating menu #}

        {# Get all Sections #}
        {% set sections = craft.sections.getAllSections() %}

        {# Loop through all single sections #}
        {% for singleSection in sections if singleSection.type == 'single' %}

            {# Output #}

{{ singleSection }}

        {% endfor %}

It is the singleSection.url that causes the error.

Craft\SectionModel and its behaviors do not have a method or closure named “url”.

I presume the SectionModel does not have an Url, but that doesn't bring me any close to solving my problem of getting the url of single pages.

Craft creates an EntryModel for each Single Section, that allows you to access the URL property you are after. You can get the (one) EntryModel using the Section's ID and the first() method:

{% set singleSectionEntry = craft.entries.sectionId(singleSection.id).first() %}

{{ singleSectionEntry.title }}


Filter entries by multiple field ranges I am trying to filter entries based on multiple field value ranges.
For example: All entries where my customField (type: number) is between 0 and 10 OR 20 and 25.

It's straightforward to filter by one range:

{% set results = craft.entries({
  customField: ['and', '>= 0', '< 10']
}) %}

How would I add multiple ranges for the same field to the above query?

It's not possible to do both an "and" and an "or" in a single query going though the ElementCriteriaModel.

Here are a few other posts that go into more detail and provide some potential workarounds.

How can I create an ElementCriteriaModel with 'and' and 'or'

How to fetch specific users OR admins with the ElementCriteriaModel?


Extending options for different plugin types? This may be more of a feature request but I was curious if this is on the roadmap.

I have seen a lot of plugins that are more of a “utility” than something users would interact with. For example look at Audit Log, Dump and other miscellaneous.

Currently the only real option that exists for plugins is hasCpSection. It would be really helpful as the plugin ecosystem continues to grow to have plugins that are a “utility” or “settings” with the option to show on the settings page in the Control Panel.

Naming aside as this is just a quick thought, I was thinking something along the lines of this:

public function isSettingsPlugin()
{
    return true;
}

public function getSettingsPluginCategory()
{
    return Craft::t(’Tools');
}

public function getSettingsIconPath()
{
    // return the path to the settings icon
}

Any thoughts on adding the ability to have plugins as a settings or utility?

IMHO, there is no need for this and I don't think that there is a problem that needs to be solved by Craft based on what you've outlined. Additionally, putting this on the roadmap may lead to a confusing API or at the very least, it might get us into a convoluted plugin philosophy like in EE, where we have plugins, modules, addons, etc.

Currently, plugins can decide whether they have settings or not and the API that enables that seems very eloquent to me.

Having said that, properly categorizing plugins will be very important and I would bet that the plugin store will address that; )

Please let me know if I misunderstood what you were trying to communicate.


How reference "Craft" js object in jquery scope I have this function within my <script> tags:

$('.btn').click(function()
{
    var data = {
        title: "This is a title"
    };

    Craft.postActionRequest('plugin/controller/action', data, function(response) {
    });
});

The "Craft" function returns as "TypeError: Craft is undefined". I'm guessing I somehow need to reference the scope to the function but I can't seem to get it to work.

I tried adding _self = this outside my jquery click function and reference Craft like "_self.Craft" but that didn't do it.

What am I missing here?

The "Craft" javascript global object can only be used in the backend, not on the frontend.


GeneratePendingTransforms stuck every time I get a stuck GeneratePendingTransforms task over and over again. In the first place, I don't know why any transforms are getting created at that point. By now, almost every image transform for every image on the site must have been create once. And it seems like those generations happen on the weirdest moments. It can't be the images of a freshly posted entry that had to be created, because there's always +300 steps in the tasks (and there are 5 images at most on a new entry).

Anyway. It seems that those tasks also get stuck every time. I don't know why they get stuck. And yes, I know you can change the status to pending. But I can't keep doing this 10 times a day. The craft log doesn't give me much more information. Right now I have a GeneratePendingTransforms task that is stuck at step 333 from 341. And this is the latest info in the craft log file:

2016-10-08 21:55:00

Level   error
Category    exception.Craft\HttpException.404
Message Craft\HttpException in /srv/users/ijnluser/apps/ijnl/craft/app/controllers/TemplatesController.php:59

I don't know if stuck tasks also prevent the execution of pending tasks? But I also noticed cached items don't get cleared at all, and I have to clear them manually. Could this be because they are waiting to run, after the stuck task is done?

I think to solve your issue we're going to need a bit more of information. A couple of things you can try:

set a higher max execution time. I think normally the max execution time is 120 sec. and this sometimes blocks other transforms
try using the craft task manager plugin to remove any tasks that get stuck.
try reindexing the images, remove all the cached items, check your folder permissions

That being said, I stopped using the image transforms Craft provides out of the box and started using Imager. Imager provides a handy way to do transforms in your template. Works like a charm and lots of handy options.


Resolve url from inside template Can I resolve full URL to some object - entry or category, from inside Twig template?

Mind you, I don't mean searching for something by slug, but by full URL. So, for example, instead of passing 'some-slug' to function, i want to pass 'some-category/some-subcategory/some-slug'.

I need to to this, because i want to create breadcrumbs links based on craft.request.segments object. So, i need to look up for entry object for some-category, then entry for some-category/some-subcategory/ and then for some-category/some-subcategory/some-slug (well, i dont really need last one because its just page im on currently).

Usually I have a {{baseUrl}} defined in config or .env available globally;
then {{baseUrl}}/{{entry.uri}}


Is it possible to change one segment of the current url and keep the rest of it the same in a cleaner way? How would you go about changing one segment of the current url? I have a select in the footer that you can click on a country name and then it redirects you to the homepage of that country version of the website.

<!-- language: lang-twig -->
<form action="" name="dropdown">
    <select name="country-select"  id="country-select" class="form-control" onchange="location = this.value;" autocomplete="off">>
        {% set locales = craft.i18n.getSiteLocaleIds() %}
        {% set locale = craft.locale %}
        {% for loc in locales %}
            {# checking if current loop has active locale #}
            {% set isHome = (loc == locale) %}
            {% if isHome %}

                {% if loc == "en" %}
                    <option value="/{{ loc | replace({'en': 'eu'}) }}" selected>Europe</option>

                    {% set myJs %}

                        var currentCountryLocale = "Europe";
                        var currentCountryLocale = "{{ loc | replace({'en': 'eu'}) | trim('_') }}";

                    {% endset %}

                    {% includeJs myJs %}

                {% else %}
                    {% set subTags = locale|split('_') %}
                    {% set territory = subTags|length > 1 ? craft.i18n.getLocaleData(craft.locale).getTerritory(subTags|last) : '' %}
                        <option value="/{{ loc | replace({'en': ''}) | trim('_') }}" selected>{% if territory %}{{ territory }}{% endif %}</option>

                    {% set myJs %}

                        var currentCountryName = "{{ territory }}";
                        var currentCountryLocale = "{{ loc | replace({'en': ''}) | trim('_') }}";

                    {% endset %}

                    {% includeJs myJs %}

                {% endif %}

            {% else %}

                {% if loc == "en" %}
                    <option value="/{{ loc | replace({'en': 'eu'}) }}">EU</option>
                {% else %}
                    <option value="/{{ loc | replace({'en': ''}) | trim('_') }}">{{ loc | replace({'en': ''}) | trim('_') | upper }} </option>
                {% endif %}

            {% endif %}

        {% endfor %}
    </select>
</form>

I have been trying to figure out how to switch only the country/region part of the url, which is segment(2), but all of my experiments so far have been extremely complicated and confusing and I haven't found a good solution yet. Am I missing something? There must be a more efficient way to accomplish this, as it's probably not a good idea to wrap conditionals inside of conditionals inside of more conditionals.

I also have the added complexity of needing to include a continent (Europe) as one of the versions of the website, for which I'm using the "en" locale, as you can see in the bit of code above.

So!!!! I was getting confused about the various craft properties pertaining to urls, and I thought that even if I grab the path, that it would include the region segment, but surprise! {{ craft.request.path }} grabs the remaining portion of the url, after the region segment! So, I can use code that I've written above and I only need to add:

<!-- language: lang-twig -->

    /{{ craft.request.path }}

Example:

<!-- language: lang-twig -->

    <form action="" name="dropdown">
        <select name="country-select"  id="country-select" class="form-control" onchange="location = this.value;" autocomplete="off">>
            {% set locales = craft.i18n.getSiteLocaleIds() %}
            {% set locale = craft.locale %}
            {% for loc in locales %}
                {# checking if current loop has active locale #}
                {% set isHome = (loc == locale) %}
                {% if isHome %}

                    {% if loc == "en" %}
                        <option value="/{{ loc | replace({'en': 'eu'}) }}/{{ craft.request.path }}" selected>Europe</option>

                    {% else %}
                        {% set subTags = locale|split('_') %}
                        {% set territory = subTags|length > 1 ? craft.i18n.getLocaleData(craft.locale).getTerritory(subTags|last) : '' %}
                            <option value="/{{ loc | replace({'en': ''}) | trim('_') }}/{{ craft.request.path }}" selected>{% if territory %}{{ territory }}{% endif %}</option>

                    {% endif %}

                {% else %}

                    {% if loc == "en" %}
                        <option value="/{{ loc | replace({'en': 'eu'}) }}/{{ craft.request.path }}">EU</option>
                    {% else %}
                        <option value="/{{ loc | replace({'en': ''}) | trim('_') }}/{{ craft.request.path }}">{{ loc | replace({'en': ''}) | trim('_') | upper }} </option>
                    {% endif %}

                {% endif %}

            {% endfor %}
        </select>
    </form>

Yay!! I wanted to share my answer because I've been working on this issue for a few days and couldn't find a solution anywhere. Maybe it will help someone else that runs into this issue when building a multi-country website with Craft. Cheers!


Compose URL POST parameters to filter entries by category? How do you update an URL with new params?

I'm working on a search / filter entries page. I have multiple menu lists with categories in it. Like this:

Size:
Small
Medium
Large

Color:
Blue
Red
White
Yellow

So if the URL is product?size=m and I click on a link "Size → Large" then the URL needs to update to product?size=m,l. Click again on "Large" the l value of the sizes parameter needs to delete.

If I then click on "Color → Red" the URL must be product?size=m,l&color=red.

I'd split the parameter string into an array and then loop through the categories and use a conditional to check if the value already exists in the parameter. It's not so easy to describe in detail, that's why I added lots of comments to the code (untested!).

To work in your other parameters (size, etc.), simply add them to your links exactly how craft.request.getParam() returns them. Conditionally skip the output completely if the param is empty.

{# Get the parameter (e.g. 'red,blue,black') #}
{% set currentParam = craft.request.getParam('color') %}

{# Split the parameter string #}
{% set arrCurrentParam = currentParam|split(',') %}

{# Loop through categories to output the links #}
{% for catOut in categories %}

    {# Define newParam var before loop #}
    {% set newParam = '' %}

    {# Loop through categories to compose the new parameter #}
    {% for catComp in categories %}

        {# Check if changes could happen in this loop #}
        {% if catOut.slug == catComp.slug %}

            {# Add category if it was currently NOT selected #}
            {% if catComp.slug not in arrCurrentParam %}
                {% set newParam = newParam ~ ',' ~ catComp.slug %}
            {% endif %}

        {% else %}

            {# Add category if it was already selected #}
            {% if catComp.slug in arrCurrentParam %}
                {% set newParam = newParam ~ ',' ~ catComp.slug %}
            {% endif %}

        {% endif %}

    {% endfor %}

    {# Remove leading comma #}
    {% set newParam = newParam|slice(1) %}

    {# Conditionally add param to link output #}
    {{ category.slug }}

{% endfor %}


Display a copyright year (or range) I have an old php code in the footer of my site like below. Will like to convert that to twig (which I suspect will be cleaner). I don't know a lick of php hence my question here.

<p>
    <?
      $startyear = 2010;
      $currentyear = date("Y");

      if ($startyear == $currentyear)
   {
      echo "&copy; $startyear Site Name. All Rights Reserved\n";

      }
  else
   {
     echo "&copy; $startyear - $currentyear Sitename. All Rights Reserved\n";

    }
      ?>
</p>

You can use Twig's date filter:

{{ "now"|date('Y') }} Sitename. All rights reserved.

More info in the Twig docs


Craft 3 Plugin Controller - returnJson() replacement? In Craft2, when making an ajax request to a plugin controller action, you would use the returnJson() method which is part of the BaseController class - which your plugin controllers extend.

This sets some headers, echo's the response and kills any further processing.

public function actionDoStuff() {

    $response = (object)[
        "message" => "Look at me! I'm JSON!"
    ];

    $this->returnJson($response);
}

In Craft 3/Yii 2 I'm having trouble finding the equivalent.

I wasn't rtfm'ing hard enough. In the docs for \yii\web\Controller, which is what the \craft\web\Controller class extends (which is what your plugin controllers extend) there is a method asJson().

return $this->asJson($response);


How to integrate an image haystack replacement technique I'd like to use a tokenised image replacement technique which is commonly adopted in ExpressionEngine. This is where the author can add image tokens such as {image_1}, {image_2} etc into their content, and these get replaced by images defined in a matrix in the same publish form (with additional information such as image size etc). What technique can I use to achieve this?

This generally isn't necessary in Craft. You can use a Matrix Field and combination of Matrix Blocks to build advanced content with flexible images. This is really the best way to go if it's an option.


How to require stronger passwords? I am having a real hard time understanding why there is not a way to control the password strength of a front-end user registration form. With Craft 3, are there no settings anywhere to control this? I have a project that would include Craft Commerce to handle subscription payments, and during the subscribe portion, the user would need to register first. It seems so strange that a user can register with a weak password.

AFAIK, there’s no current first-party policy enforcements, but there is this plugin we’ve used in the past to make sure passwords aren’t easily guessed or previously pwned. I would give it a go in the meantime.


Outputting Navigation I need some help with coding the navigation.

This is the markup:

home

about

services

signs

printed decals

vehicle &amp; fleet graphics

banners &amp; posters

magnetics

vinyl graphics

construction and job site signs

business cards &amp; flyers

sign hardware

testimonials

contact

get quote

And here's a sample of my entries, channels and structures: http://grab.by/Awx8

This is what I have so far, but it's not really working at all:

{# get menu items #}
{# {% set pageItems = craft.entries.section('services').level('<= 2') %} #}

{% set pageItems = craft.entries.level('<= 2') %}

{# Output the sub menu #}

Home

    {% nav page in pageItems %}

                {% if page.navigationTitle %}
                    {{ page.navigationTitle|nl2br }}
                {% else %}
                    {{ page.title }}
                {% endif %}

            {% ifchildren %}

                        {% children %}

            {% endifchildren %}

    {% endnav %}

testimonials

contact

get quote

Any help is much appreciated.

My Solution uses:
1. LJ Dynamic Fields Plugin
2. 1 Structure I called SiteMenu

What I did is:
1. Install LJ Dynamic Fields
2. Setup a MenuLinkPage Field of fieldType Dynamic DropDown
    - In the Drop Down Options is like this because am pulling links from entries and category

{% set menuIds = craft.entries.section('siteMenu').ids()%}
{% set menuIdsString = menuIds | join(', not ') %}

{ "value":"#","label":"Select Page"},
{%for category in craft.categories.limit(null) %}
      { "value":"{{category.id}}" , "label":"category-{{category.group}}--{{category.title}}"},
{%endfor%}
{%for entry in craft.entries.limit(null).id('and, not '~menuIdsString).order('type ASC')%}
      { "value":"{{ entry.id }}" , "label":"{{entry.type}} - {{ entry | raw }}"
      }
      {% if not loop.last %},{% endif %}
{%endfor%}

Setup a SiteMenu Structure on its layout I added MenuLink Field.
Then added Pages I need for my Menu by selecting from MenuLinkPage field.
Call the menu in my _layout template like this

{% block menu %}

{% set pages = craft.entries.section('siteMenu').level('<=2') %}

 close menu

{% cache %}
  {% nav page in pages %}

        {% set entryId = page.menuLinkPage %}

        {% if entryId > 0 %}
          {% if craft.categories.id(entryId)|length %}

{{page.title}}
          {% else %}

{{page.title}}
          {% endif %}
{% else %}

{{page.title}}

        {% endif %}

            {% ifchildren %}

                    {% children %}

            {% endifchildren %}

    {% endnav %}

{% endcache %}

{% endblock menu %}

I hope this helps


Return entry where matrix field is not empty I am trying to get a random entry which has the quote matrix field populated.

I've tried this:

{% set entry = craft.entries.section('entries').quote(':notempty:').order('RAND()').limit(1) %}

That isn't working. What do I need to do?

Currently the only way to find entries that have Matrix rows is with the search param:

{% set entry = craft.entries.section('entries').search('quote:*').order('RAND()').limit(1) %}


Getting Entry By Category for Landing Pages In A Structure I have a site governed by a structure, including the homepage.  I have several "parental" landing pages with research areas (Atlantic, Pacific, Midwest etc ) intended to be the gateway to  the children entries in that area. (Boston, New York, DC etc).

I have categories (without urls) corresponding to the landing pages (Atlantic, Pacific, Midwest etc ) and would like to pull teasers from each child entry onto the landing page, so that the Atlantic landing page has teasers from the Atlantic children's entries pulled in via the category field, the Pacific landing page has teasers from the Pacific children's entries via category etc...)

But I would like to do this in one template, rather than using multiple entry types.

I know I can get entries by an array of sections

{% for entry in craft.entries.section([atlantic, pacific, midwest]) %}

My mind cannot bend around how I could start at

{% for entry in craft.entries.section('pages') %}

and trek on from there to grab both the appropriate landing page and the categories that go with it dynamically.  Can I keep using arrays in both the page id's and the categories?  How would can I make a template know to grab the Atlantic and fill it with teasers from the Atlantic category?  Is it even possible?

You need to find a way to get the right category model to be able to receive all entries related to it.
As you didn't set up our categories to have their own URL, you could find it using the relevant slug in your URL.
Assuming that maches your categories slugs:

{% set categorySlug = craft.request.getLastSegment() %}
{% set category = craft.categories.slug(categorySlug).first() %}

{% if category %}

    {% set entries = craft.entries.relatedTo(category).limit(12) %}
    {% for entry in entries %}
        {{ entry.title }}
    {% endfor %}

{% endif %}

Another, probably more elegant way would be to access a token set via a dynamic route:

'regions/[SLUG]' => 'regions/_index'

You would now be able to access that token from a variable "slug":

{% set category = craft.categories.slug(slug).first() %}


Feedme Pagination by Token Has anyone used a pagination token when paginating Feedme? I currently use Firestore and they don't use a full pagination URL but a token you append onto your next URL.
Initial URL
https://firestore.googleapis.com/v1/projects/YOUR_PROJECT_ID/databases/(default)/documents/cities/LA
Pagination URL
https://firestore.googleapis.com/v1/projects/YOUR_PROJECT_ID/databases/(default)/documents/cities/LA?pageToken=Ab7e2991jej91od727
In the Response
"nextPageToken": "AFTOeJwxKBJYSXXPpKyhOmB4_-SifKCDzUH0mhJchn1u5hknl3iutUKaPez8OVyR99PZM2014ZU1EpZt4GnUHwHBnwM0P1B9Z-yDhTyqTrmsVt4SIffOXCyxq1Yl7iZQJ0c1ltGHpuV9KWgUH6mvl6rHdCA"

First, you'll want to make sure you're on the latest FeedMe release as a bug around this was recently fixed: https://github.com/craftcms/feed-me/issues/694
You might also need a plugin that hooks into the EVENT_AFTER_FETCH_FEED event to do some offset transformation based on the tokens passed in.


How to I set the location folder of Control Panel resources? I'm trying to use the ./craft clear-caches/all CLI command.

Everything is working fine, except that I always get this error:

  Error clearing cache Control Panel resources: Unable to clear Control
  Panel resources because the location isn't known for console commands.

How can I set this resources folder?

Thank you @Brandon Kelly for the solution:

  That’s because @webroot is only reliable on web requests. To fix,
  update your resourceBasePath config setting to a real path:

  'resourceBasePath' => dirname(__DIR__) . '/web/cpresources'


Set Parameters from User Input Is there a way to set parameters from front-end user input?

Let's say I have a page that displays a list of entries. On that page, I have a form select called paidStatus with options notReceived, received, and paid; and another form select called order with options asc and desc.

Then, in my template code, I want to grab the list of entries:

{% for entry in craft.entries.section('sectionName').order('postDate post.order').find() if entry.paidStatus == post.paidStatus %}

with order and entryStatus being populated from the submitted form selects. That way I can change the criteria used to generate the list of entries on the fly.

Yes, you can pass in a variable into the parameters and to get the query string values use craft.request.getQuery().

I can recommend this blog post by Jérôme Coupé for a great introduction to setting up the form and the criteria model filters:

Combined searches and filters using Craft

You should also have a look at other questions tagged with "form".


Craft 3 automatic update Does anyone think there will be an automatic update from 2-3? Or as the file structure is different do you think it'll be unlikely?

As far as I know, there are no plans for an automatic update from Craft 2 to Craft 3. I'd suggest following the instructions from the docs to perform the update manually: https://docs.craftcms.com/v3/upgrade.html


CP Session expires after short time Our Craft installation is now working on the Production Cloud-Server, except that if I'm logged in the CP, after maybe 30 sec the login-modal pops up and says that the session has expired.
If I just reload the CP, I'm in again without the need to login.

That behaviour didn't show up on the development server.
I didn't make any Configuration Settings like userSessionDuration or something like that, that's all default.

Any idea?

99% of the time when you see this behavior, it's because wherever your server is configured to save PHP's session files to either doesn't exist or isn't writable by PHP.

You can check where that path is by going to yourdomain.com/admin/utils/phpinfo and searching for session.save_path.

If you have the overridePhpSessionLocation config setting set to true, then Craft will set that path to craft/storage/runtime/cache.


When does Craft change or delete template caches? My question is regarding template caching in Craft. I want to know when does Craft actually change the cache or delete old cache.

Let's say that I am caching a chunk that just displays the entry title.  Does Craft detect this change when I reload the page and hence change the cache as well? I don't know if that makes sense.

Also, I wanted some insight into the cache structure. I was caching some chunks that displayed an entry's title, description etc. The code is something like this:

{% for document in resultset %}
    {% cache using key document.entryId ~ "searchresult" %}

        {% set entry = craft.entries.id( document.entryId )[0] %}

        <div>{{ entry.title }}</div>
        ...
    {% endcache %}
{% endfor %}

When I looked into the cache tables in the database it seems like the cache is associated with an entry using the entry id.

I wanted to know how Craft knows which entry this cache relates to since the key that I have passed could have been anything and I could have cached a category or something instead of an entry. I am very confused as to how this magic is occurring.

Craft can delete caches in a few different ways:

When somebody manually clears the cache via Settings->Clear Caches
When Elements within {% cache %} tag are saved or deleted
When a new Element is created

Regarding #2 and #3, when Craft can identify which Elements you are caching, it stores them in the craft_templatecacheelements table.  If you save or delete an Element that matches one of the Element IDs that Craft has stored, Craft will clear the related template caches immediately.  In the case where you are creating a new Element, it takes Craft a little bit longer to determine if that Element could be part of a related cached query and once Craft determines that is the case, will clear the cache.

Craft knows which Element IDs exist if your queries are taking place between the {% cache %} tags.

If you'd like to explore a bit more, a few places to explore would be the craft/services/TemplateCacheService.php and craft/app/etc/templating/BaseTemplate.php.


Create assets subfolder on upload based on entry field value? I have a projects section on my website, there can be multiple projects from one client. Each project has at least one image.

I wanted to know if it is possible when uploading assets to a new project entry to be able to create a new subfolder within my specified assets folder for that particular client?

So can I either:

a) Create a subfolder when uploading assets.
b) Use the value of the "client" field to dynamically create a subfolder when uploading images to the entry.

Any help/direction this would be appreciated.

Jay

Yes that's totally possible, you just need to set your asset field to upload all assets to a single folder and then you can set a sub-folder path that's created dynamically. (→ Restricting Uploads to a Single Folder).

In your case that path would be something like this:

assets/images/projects/{{ object.client.first().friendlyName }}

or with fallback to a default sub-folder:

{{ object.client.first()|length ? object.client.first().friendlyName : 'Other' }}


Output assets within a matrix block using Imager and Craft 3 I'm having trouble trying to output assets from an Assets field that's within a Matrix block, using Imager. The code below is only outputting the first image that has been added, over and over for each asset, rather outputting each different asset. What am I doing wrong?

I did try changing {% set logo = block.logos.first() %} to {% set logo = block.logos.all() %}, but that gave me an internal server error.

{% for block in entry.modules.all() %}

  {% if block.type == "logosBlock" %}

    {% for image in block.logos %}

          {% set logo = block.logos.first() %}
          {% set transformedImage = craft.imager.transformImage(logo, { width: 312, height: 200, }) %}

      {% endfor %}

  {% endif %}

{% endfor %}

Why do you try to fetch the image multiple times?

{% for image in block.logos %}

Will fetch the images and loop them {% set logo = block.logos.first() %} -> will fetch the first image again and again.

{% for image in block.logos %}
    {% set transformedImage = craft.imager.transformImage(image, { width: 312, height: 200, }) %}
    <img src="{{ transformedImage.url }}" alt="{{ logo.title }}">
{% endfor %}

Should work


entry is available without query when templates are set in the CP, is this an acceptable method? Craft Pro 3.4.20

New to craft development. I was following the documentation and calling my entries via the suggested method as outlined https://docs.craftcms.com/v3/dev/element-queries/entry-queries.html#example.

However I have found that I can access any fields via entry.<fieldName> within my twig templates without setting the entry query, so long as that template has been assigned to that section.

For example, my homepage has a template set in the cp, and I can access all its field entries without any query within the twig template, I just call entry.title like anything else and it works.

My question is this—is this an acceptable method? Are there any performance issues with this?

the simple answer is: yes it is an acceptable method!

In single sections or in a single entry of a structure or channel, this is totally fine.

You need the entries query if you want to do something like having a list of all recent blog posts on your homepage. So on your index.twig the "entry" object has got all data for the homepage, like title, url and all fields!

Example index.twig:

<h1>{{entry.title}}</h1> <---(the title of your site)

{% set blogPosts = craft.entries().section('blog') %}
{% for entry in blogPosts.all() %}
  {{ entry.title }} <---- (the title of a blogpost)
{% endfor %}


Shortest code to link to CSS and JS file Is there a helper tag to output a complete stylesheet link.

I used helper tag for lack of knowledge. Helper tag is used in Statamic.

In Statamic {{ theme:css src="style" tag="true" }} outputs

<link rel="stylesheet" href="/site/themes/redwood/css/style.css" />

I've seen <link rel="stylesheet" type="text/css" href="{{ siteUrl }}assets/css/happylager.css"> in Happy Lager's template but I'm looking for something shorter.

In Craft there's {% includeJsFile %} and {% includeCssFile %} which get injected on the getHeadHtml() and getFootHtml() functions on your templates.


Where can I download example templates? This will be my first time using Craft, where can I download free templates from or find instructions on how I can create my own templates?

To add to Matt's answer there are example templates which contain enough code to get you started in the templates folder craft/templates.

There is also a repo on Github called 'HappyLager' which contains more example templates along with annotations.


Check if Visitor show logon button I am trying to figure out how to check if a visitor is not logged in so that I can show the correct button. E.g

{% if craft.session.isLoggedIn %}
    Logout
{% else %}
    {% craft.session.isGuest %}
    Client/a>
{% endif %}

What is the best method to display a "sign in" button for a visitor that takes them to a login page and then once logged in, show "Logout"?

I believe you'll want something like this...

{% if currentUser %}
    Logout
{% else %}
    Login
{% endif %}


'cacheDuration' => false, sets cache file expiration date to 1 year So I noticed that by setting the 'cacheDuration' => false it seems to set, by default, the expiration date to 1 year from when the cache is saved.

I found this in /app/services/TemplateCacheService.php starting from line 263:

if($duration <= 0)
{
  $duration = 31536000; // 1 year
}

I know a longer duration could be achieved by setting the expiration to something like 4Y. But I wanted to raise this and ask if it was an oversight or what the reason was for setting it to a year and overriding the specific value of not setting an expiration at all...?

Thanks.

Yeah, it's slightly awkward.

First off it should be '0', instead of false if you want it to cache indefinitely (documentation bug, just fixed).

It's slightly awkward because the cacheDuration config setting is used for multiple things, but when the TemplateCacheService uses it, it requires an expiration date (not optional).

So if it sees 0, it will just pick one reasonably far out (a year), but you can set it to something higher if you want.

What should probably happen is everywhere that uses the cacheDuration config setting should have its own, separate config setting.

Not going to happen for Craft 2, but make a note to look at it once Craft 3 launches.


Craft\EntryModel and its behaviors do not have a method or closure named "siteUrl" Getting the above error when trying to add a new entry to a structure section.

The Section has an Entry URL Format of:

{siteUrl}/{slug}

In my general.php in the config folder I have:

return array(

    '*' => array(
            'omitScriptNameInUrls' => true,
        ),

    'local.ontherocks.dev' => array(
        'devMode' => true,
        'environmentVariables' => array(
            'basePath' => 'C:/Users/User/Documents/My Websites/Sitename/public/',
            'baseUrl'  => 'http://local.ontherocks.dev/',
            'siteUrl'  => 'http://local.ontherocks.dev/',
        )
    )

);

I don't see why I am getting this error - I have the same set up in another site I did.

Environment variables are only available in specific settings, and Entry URL Formats are not one of them.

There’s no need to include your Site URL in there anyway, though. The field’s label might be a little misleading – it’s really more of a URI format than a URL format.

If you want your entries to get URLs like http://example.com/entry-slug, then all you need to put in your section’s Entry URL Format setting is:

{slug}


Cannot create entry when Entry Type has Title field hidden I have created an Entry Type with the "Show the Title field" option not checked.

When creating an entry of this type, I am given a generic "Couldn't save entry" error message.

Looking in craft.log, I see the Title field is failing validation.

2015/08/18 18:07:29 [trace] [system.CModule] Loading "templates" application component
in /Users/Sites/craft-test/web/craft/app/etc/web/WebApp.php (584)
in /Users/Sites/craft-test/web/craft/app/services/EntriesService.php (157)
in /Users/Sites/craft-test/web/craft/app/controllers/EntriesController.php (450)
2015/08/18 18:07:29 [trace] [system.db.CDbConnection] Starting transaction
in /Users/Sites/craft-test/web/craft/app/services/EntriesService.php (160)
in /Users/Sites/craft-test/web/craft/app/controllers/EntriesController.php (450)
in /Users/Sites/craft-test/web/craft/app/etc/web/WebApp.php (784)
2015/08/18 18:07:29 [trace] [system.CModule] Loading "elements" application component
in /Users/Sites/craft-test/web/craft/app/etc/web/WebApp.php (584)
in /Users/Sites/craft-test/web/craft/app/services/EntriesService.php (176)
in /Users/Sites/craft-test/web/craft/app/controllers/EntriesController.php (450)
2015/08/18 18:07:29 [warning] [application] Craft\ContentModel->title failed validation: Title cannot be blank.
in /Users/Sites/craft-test/web/craft/app/models/BaseModel.php (510)
in /Users/Sites/craft-test/web/craft/app/models/ContentModel.php (89)
in /Users/Sites/craft-test/web/craft/app/services/ContentService.php (218)
2015/08/18 18:07:29 [trace] [system.db.CDbTransaction] Rolling back transaction
in /Users/Sites/craft-test/web/craft/app/services/EntriesService.php (183)
in /Users/Sites/craft-test/web/craft/app/controllers/EntriesController.php (450)
in /Users/Sites/craft-test/web/craft/app/etc/web/WebApp.php (784)

This is on Craft Pro 2.4.2684 on Apache/2.4.10 (Unix) PHP/5.5.24.

I've tried clearing caches to no avail, and confirmed that the same issue exists with newly created Entry types with the Title field hidden.

I was using the Twig template syntax ({{varName}}) in the Title Format field on the Entry Type instead of the proper syntax ({varName}).


Fetching & Displaying an API Request using 'Fetch' I'm currently in the process of calling an API endpoint and trying to display the data relating to it. But I'm having a bit of trouble using 'Guzzle/Fetch' in this scenario. I have the following code but it seems to be outputting nothing at all. (Plugin is all installed)

Template.html

{% set client = {
    base_uri : 'https://api.tickets.com/rest/v2/Events/2704/Reviews?order=1&count=30',
    timeout : 10
} %}

{% set options = {
    headers: new Headers({
      'Content-Type': 'application/json',
      'apiKey': 'aaabbbcccdddeee',
    })
} %}

{% set request = fetch(client, 'GET', options) %}

{% echo $request->getReasonPhrase(); %}

So there are two things wrong with your code snippet.

First off, the fetch() method takes four parameters in the following order: client, method, destination, and options. In your example above, you're passing your options object in as the destination (because that is the third parameter), which is not going to work.

So you'll want to do something like the following instead:

{% set client = {
    base_uri : 'https://api.tickets.com',
    timeout : 10
} %}

{% set destination = 'rest/v2/Events/2704/Reviews?order=1&count=30' %}

{% set options = {
    headers: {
        'Content-Type': 'application/json',
        'apiKey': 'aaabbbcccdddeee',
    }
} %}

{% set request = fetch(client, 'GET', destination, options) %}

We've made the client.base_uri actually the Base URI (by removing the segments and query strings) and moved those to a separate variable (which is technically where they belong). This allows us to now have four parameters that we're passing into fetch() in the right order (notice our options object is now the fourth parameter like it should be).

In addition, it should be headers: {, not headers: new Headers({ in your options hash. headers: new Headers({ is not valid Twig. Not sure where you got the new Headers() from but a simple hash should work well (similar to the PHP example in the Guzzle docs).

Your second issue (and this is the bigger one) is this:

{% echo $request->getReasonPhrase(); %}

That is not proper Twig at all. Looks like you grabbed a bit of PHP code from somewhere and popped it inside {% ... %}, which is never going to work.

If you take a look at the Fetch README, it shows you what a response is going to look like:

{
    "statusCode":200,
    "reason":"OK",
    "body": {
        "credits_left":30,
        "test_id":"JDHFbrt7",
        "poll_state_url":"https:\/\/gtmetrix.com\/api\/0.1\/test\/JDHFbrt7"
    }
}

What this snippet means is after you run {% set request = fetch(...) %}, the request variable is now going to equal a Twig object (more properly known as a hash) containing the status code of the response, the reason phrase (which is basically just a description of a status code; so the corresponding reason phrase for a status code of 200 is OK, for a 404 it's going to be Not Found, etc.), and then finally the body of the response returned from the API endpoint.

You'd access these variables no differently than you would any other hash in Twig. To get the status code and/or the reason phrase, do:

{{ request.statusCode }} - {{ request.reason }}

To access any property of the request body, you would do:

{{ request.body.myProperty }}

Depending on the structure of the API response, you might have to dig down into several levels of nested hashes:

{{ request.body.oneHash.subHash.somethingElse.myProperty }}

You get the idea...

If you're not sure what the API response looks like (often times the API you're using will show you an example of what the response body will look like, so I'd look at the API docs first), you can just dump() the whole body property to see what it contains:

{{ dump(request.body) }}

Hopefully that helps!


DevMode causing stuck entry saves Ok so this is part I need help part heads up for others. The back story... I a client messaged me saying that they couldn't save posts anymore for specific entries. I noticed the ones that were having issues were the larger ones. The entries are fairly complex with the supertable plugin. I tried EVERYTHING I could to diagnose the problem, modifying every server setting etc. I realized it worked locally but not remote. I also realized it worked fine on my phone but not my machine. it worked on a co-workers air but not my macbook pro. craziness. I did eventually get it to work but I'm not sure why.

Switching out of DevMode made everything work fine, but that isn't a real acceptable solution for me because I use devMode. I hope anyone struggling with this, sees this but I appeal to some of you more seasoned Craft devs, why the heck is this happening in devMode and only remote on some machines?

Dev Mode introduces a lot of extra overhead for many processes. It profiles and logs all MySQL queries to the browser's console. For a detailed description of what Dev Mode does, please check out this page of the docs...

  What Dev Mode Does

Specifically, this line is critical...

"Dev Mode is definitely not suited for production environments."


How to auto obfuscate email addresses in rich text field I'm used to this feature in ExpressionEngine either natively or via the Auto Linker plugin, where you just wrap it around all the text fields. I've seen the Sprout Encode Email addon but that doesn't search through text and apply it.
I don't mind if it doesn't create a mailto link, I just want to obfuscate every email address that appears in any of the text fields in a template.

I wrote a really quick Plugin for you to use that uses the _encodeStringRot13 function from the Sprout guys to use on any variable you want in Craft. What the Plugin does is to give you a new Twig filter that you can apply like this {{ entry.body|protectEmails }} and voila! - all <a href="mailto:"> will be encoded in ROT13 (reference: http://snipplr.com/view/6037/) on output.

Download it here: http://www.naboovalley.com/craft/toolkit.rar


Smart Map - Outputting locations from a Matrix field for all entries within a single section I'm using the Smart Map plugin, and I can't seem to figure out how to output all the locations of my entries from a single section onto one single map.
I think the issue I'm having is trying to get the information out from a Matrix block within each entry or knowing where to start!
The section is 'buildings' which contains all the building entries. For each entry, there is a matrix block called 'buildingContent' which has 5 matrix blocks, and the one I want to pull information from is 'howToGetThere' (last block out of the matrix array). In this block, I have a field 'smartMap' which contains the location of the building.
How would I extract the location from the 'smartMap' field for all my entries and output them onto one single map?
I know the code below outputs the location of one entry (St Bartholomew The Great), but thought it might be useful to include what I've tried so far. I adapted it from the documentation:
{% set entry = craft.entries.slug('st-bartholomew-the-great').first %}

{% set locations = entry.buildingContent %}

{% set options = {
     height: 600,
     zoom: 13,
     draggable: true,
     markerInfo: '_includes/mapInfoBubble',
     markerOptions: {
        icon: 'images/map-marker2.svg',
     }
 } %}

{{ craft.smartMap.map(locations[4], options) }}

Any help much appreciated, thanks!

Great question! While seemingly tricky, the solution to this should be relatively simple...
Per the documentation, the locations parameter can come in a variety of different forms. But the one we're looking for here is this one...

As an array of elements

Collecting Matrix blocks from across different entries can be complicated, but I think you have (fortunately) described a fairly straightforward use-case. We'll need to do the following:

Loop through relevant entries.
Build an array of Matrix blocks.
Use that array to render a map.

{# Initialize locations array #}
{% set locationsArray = [] %}

{# Loop through all relevant entries #}
{% for entry in craft.entries.section('buildings').find() %}

    {# Get all relevant Matrix blocks #}
    {% set matrixBlocks = entry.buildingContent.type('howToGetThere').find() %}

    {# Append blocks to locations array #}
    {% set locationsArray = locationsArray|merge(matrixBlocks) %}

{% endfor %}

{# Render map #}
{{ craft.smartMap.map(locationsArray, options) }}


How can I disable sessions for most of my Craft site? We're running a craftcms-backed site that uses sessions only for the admin pages.

For a few reasons, we'd like to disable session logic for all other urls:

the Set-Cookie header that craft uses to initiate a session makes responses uncacheable in our fronting cache layers
the code path under Craft\UserSessionService is unnecessary overhead for most of our logic, and occasionally adds considerable latency

We've been using HeaderHelper::removeHeader('Set-Cookie'); on a per-controller basis to turn off this behavior, but that only gets us so far - for example, 404 responses seem to try to initiate user sessions as well, before any of our custom logic can be used:

(This is a screenshot of newrelic transaction trace for a 404 response)

How can we get craftcms to stop trying to set these sessions?

I should note that we're looking into getting session storage out of the filesystem and into redis, which should also help - but most of the sessions we're keeping are meaningless, and I'd rather not keep track of them at all.

I'm not sure there is going to be an easy way to do this in Craft 2, unfortunately.

In the upcoming Craft 3, we refactored the session logic so that a session will only get started on requests that actually need session, which is basically what you're looking for.


Using data within a mixed attribute type to query Craft entries dates I wish to have a custom fieldtype which contains the standard datetime field abilities along with storing an extra piece of data. I have created a custom fieldtype for this with a mixed attributetype to store the data as JSON.

However I am having problems when I try to query some of the data from the frontend.

For example to pull out a specific piece of data I am currently doing:

variableName.date

This correctly pulls out the date I have stored. However when using this in the example:

craft.entries({ type: 'sectionName', customFieldtype.date: '>=' ~ now|date(c) }).order('customFieldtype.date asc').first()

I get errors as when Craft converts this to SQL it's converting these to column names and customFieldtype.date doesn't exist.

Is there any way around this bar having to re-create the built in craft entries calls in pure SQL?

Just in case anyone else comes across this problem in the future I actually managed to figure it out myself.

I created kept the fieldtype as a DateTime field and grabbed the date/time and the extra value within the prepValueFromPost function then pushed the extra data into a custom table and post just the datetime to the craft_contents table.

Then within the getInputHtml function I grabbed the extra data from the custom table to display along with the date/time.


How to set entries to auto-expire after certain # of days from post date? Is there any way to set entries of an certain entry type to auto-expire after a certain number of days from the original post date?

There's no build in functionality for this, but you could make a custom plugin that automatically sets the expiration date expiryDate when you first save an entry with a specific entry type.

Another option would be to simply filter your entries from your template:

{% set entries = craft.entries.type('myEntryType').postDate('>= ' ~ now|date_modify('-10 days')) %}

.

Edit:

Here's a description for the expression used as the value for the date_modify parameter.

Have a look at the syntax for parameter values in the Craft docs. And also how the date_modify filter works. now|date_modify('-10 days') returns a string which is then concatenated with the string '>= ' and then passed as a value to the postDate() parameter.


How to use multiple different instances Element API "Load More" button? Following up on a previous question of mine:
How to skip the first few entries in a "load more" scenario with Element API?
I have a website that utilizes the "load More" (button) method shown here:
http://craftsnippets.com/articles/infinite-scrolling-and-lazy-loading-with-craft-cms
On my site, I have a homepage that displays the first 6 post in a featured way, then below I have a "more posts" area. In my previous question, I was shown how to deal with skipping the fist 6 posts in the loop of the "load more" area.
However, I want to use the "load more" button elsewhere on the site. Such as:

Category Page – Same as the Homepage, but only showing more entries in whatever category the page is.
Individual Entry Page – In this instance I need the "Load More" area to not skip the first 6 entries.

I can't seem to figure out how use this method in different ways across the site, because the settings for one instance bleeds into the other instances. So, how can I accomplish this? (sorry if this is basic stuff. dealing with API is still new to me)

You could add a new param to the request called skip and use that on your homepage, and default it to zero to allow you to reuse the endpoint elsewhere.
$skipEntries = Craft::$app->request->getParam('skip') ?? 0;
$criteria = [
    'section' => $settings['section'],
    'limit' =>  $settings['limit'],
    'offset' =>  ($settings['limit'] * Craft::$app->request->getParam('offset')) + $skipEntries,
    'order' => $settings['orderBy'],
];

You'll need to add the skip parameter to the data object in the jQuery $.ajax request options object for your homepage implementation:
$.ajax({
    // some params here
    data: {
        skip: 6,
        offset: lazy_offset,
        settings: lazy_settings,
    },
    // some more params here
}

Other pages would omit the skip parameter. That's one way of solving the problem.


Create filters from Matrix Blocks on entries or products I have a range of products on a product collection page. Each product has a matrix block (ageRange) with a group of checkboxes (values 1-10).

I am currently trying to get loop through all products, get the matrix block values and push them into a new array, with the amount of times the value appears!

{% set myArray2 = [] %}
{% for product in craft.commerce.products({relatedTo: category}) %}
  {% for block in product.ageRange %}
    {% for option in block.options %}
      {% set myArray2 = myArray2|merge({ ('key'): option }) %}
    {% endfor %}
  {% endfor %}
{% endfor %}

{{dump(myArray2)}

This seems like a very bad approach. Even if I can get this working, it is clunky and no doubt un-performant.

Essentially I am looking for a way to attached fields to products, and easily get the total amount of times that that field is used.

Have I overlooked something simpler?
if not, is twig the right place to do this?

Desired output would be:

1 (6)
2 (3)
3 (3)
4 (6)
5 (0) // i'd hide this
6 (1)

Ok, so It's totally possible to do this utilising the array|merge feature of twig.
Firstly, we do a for loop over all our products (or whatever), loop over our matrix block(s), loop of the fields(s) and spit those values into a new array. We should end up with every value applied to every product in a big array:

{% set ageArray = [] %} // array for all your values
{% for product in craft.commerce.products.relatedTo(category) %}
  {% for block in product.ageRange %}
    {% for option in block.options %}
      {% set ageArray = ageArray|merge({ (loop.index): option.value }) %}
    {% endfor %}
  {% endfor %}

for me, I had multiple values set from 1-10 on all products, so ended up with something like: [2,3,4,5,6,3,4,5,6,7,1,2,3,4] etc etc

Now we sort and loop over this new array, counting how many times we come across the same number. The original value, as well as the amount of times we count it, gets spat into another array:

{% set counter = 1 %}
{% set ageArray = [] %}
{% for age in ageArray|sort %}
  {% if currentAge is defined and currentAge != age %}
    {% set counter = 1 %}
  {% endif %}
  {% if currentAge is defined and currentAge == age %}
    {% set counter = counter + 1 %}
  {% endif %}
  {% set newArray = newArray|merge({ ('age'~age): {'age': age, 'counter': counter} }) %}
  // ('age'~age) has to be string key, integer wont overwrite
  {% set currentAge = age %}
{% endfor %}

CurrentAge is basically the last iteration's value, so we do some checks against the current value and either reset the counter or increment. If it is the first time we see this number - the counter should be 1. If it matches, we add 1 on!

We then merge these values into the final array, overwriting any with the same key. Finally, we update currentAge with the actual new value, ready for the next iteration.

finally, you can just use this new array:

  {% for reducedAge in newArray %}

         {{ reducedAge.age }} ({{reducedAge.counter}})

  {% endfor %}

Twig really does not seem like a clever place for this logic. However, this will provide a nice fallback for an ElementApi / JS solution. I'm surprised it wasn't easier, I'd have though alot of people need this sort of functionality!


How to clear the database of unused fields? I have one section with different entry types. One entry type uses two matrix fields, another one only one, and so on.

Since the frontend layout is always the same, I use one template for the whole section:

{% extends "_layouts/main" %}

{% set title = entry.title %}

{% block content %}
    {% include "_fields/content__circles" %}
    {% include "_fields/content__body" %}
    {% include "_fields/content__links" %}
{% endblock %}

This works great, except when I change an entry to another entry type: Because the field-data isn't deleted from the db and shows up anyway, even though the field isn't added to the new entry type.

This is actually great, because that way your data isn't gone if you delete a field by mistake etc., but over time the db gets bloated, which I want to prevent.

Question: How can I delete data of fields which aren't used without editing each entry by hand or going in the db?

Clearification: entrytype 1 has content__circles and content__body, entrytype 2 has only content__body. After switching from type 1 to 2, the data of content__circles is still kept in the database, and is even accessible inside the entry-variable.

You can get the fields that aren’t in use anywhere by running this SQL query:

SELECT f.*
FROM craft_fields f
LEFT JOIN craft_fieldlayoutfields l ON l.fieldId = f.id
WHERE l.id IS NULL

The easiest way to delete them would be from the Control Panel, but if you really want to limit your work to the database, you would need to delete those fields’ rows in craft_fields, and their corresponding column (“field_TheFieldHandle”) in craft_content. For Matrix fields, you would also need to drop the corresponding DB table (“craft_matrixcontent_TheFieldHandle”).


Multiple Tag Groups/Sets for separate channels I have two separate channel types, let's say "News" and "Reviews" and each of those can have tags.

Is it possible to have separate tags for each of those? So News has it's own set of tags, that can't be selected when creating a new Review.

I'm coming from a Wordpress background, and in Wordpress these custom post types would have their own taxonomies. (Or News would use tags, and I would create a new one for Reviews).

Sounds like two different relation fields - linked with two different categories - would fit much better for your needs. When you create Tags/Taggroups everybody can insert everything so you can't forbid equal tags unless you hook into an event with php to prevent the saving process. When you create two different tag fields their autocomplete sources will be different but you can insert whatever you want.

So what you want to do is: create 2 different categories: The first News the second Reviews and add your keywords there. Then you create two relation fields, one linked with News, the other one linked with Reviews. Then you add those to your field layout


How to export 1 Entries type ("news") from Craft to Wordpress I have a lot of News entries in a Craft 2.6.2990 website that I would like to export and then import into Wordpress.
Most of the advice out there is for doing this the other way round.
I need Title, Post content, featured image and date created for each entry.

I am thinking that I should be using the Sprout plugin to export to a csv file. Can anyone offer any advice on this and confirm if this is the right way to go about it? I am not very familiar with Craft.
Thanks in advance

Most people are going the other way. Is there a particular reason you want to downgrade? ;-)

Being serious though...

If you need the entries in a CSV format then yes you could use an export plugin such as Sprout or Export. Or you could make a template that outputs your content in the format required.

If you choose a plugin, then you'd need to read the documentation to find out how to set that up.

As for importing into Wordpress. That's dependent on your Wordpress setup and what you are using to do the import and is probably outside the scope of this particular Stack Exchange site.

But bear in mind that Craft is incredibly flexible so if the reason you're wanting to switch is related to particular functionality it could almost certainly be achieved with Craft.


Redactor 2 integration with code mirror I'm getting a nn string when I just click on HTML (code mirror),
is there a bug from redactor ?

I have put in hide function of Redactor these lines of code:

code = code.replace('nn
', "
");
code = code.replace('
n<span', "
<span");
code = code.replace('nn<p', "<p");
code = code.replace('
n
', "");
code = code.replace('

', "");`

Is there another solution?

Thanks in advance.

Adding Code Mirror to a Redactor field is a bad idea.

The entire point of a WYSIWYG field is to allow a content editor to easily format text to be displayed on the front-end. Conversely, the entire point of Code Mirror is to colorize a snippet of code. It's hard to imagine a use-case where you'd want to colorize the value of your WYSIWYG.

Instead, I'd recommend using a plugin like Ace Freely to store code snippets. This will allow you to easily view your code snippet in the control panel, without giving it unnecessary paragraph tags and awkward spacing.

You can then apply Code Mirror on the front-end to render a colorized version of that code snippet.


Rendering HTML Heading Elements in Twig I am rendering some headings using twig and want to know if there is a better and more readable way of doing the following...

<{{ block.headingType }} class="measure-wide">{{ block.headingText }}</{{ block.headingType }}>

{{ block.headingType }} is the value of the heading selected in the editor. The values are h2, h3, h4, h5 etc.

The way the HTML headings are templated looks ugly (even though the rendering works). Is there a better way of rendering out the heading tags in twig based on the value selected?

Is there any reason you dont use a rich text field like redactor?
You can make a custom config so that field only has h1,2,3 and no links, lists etc.

And instead of having the class "measure-wide" on the heading element you can wrap it.

Something like {{ block.heading }}
Where block.heading is a custom redactor field.


Changing some letters in entry's uri before save it I need to replace some characters in my entry's URI because we have some letters which do not exist in English like "ş" or "ç". It is a problem for SEO and we have to change each time manually. I tried something with entries.onBeforeSaveEntry but I couldn't solve the problem. I'm confused with getting URI and set the new URI. Any suggestion?

I solved like this, maybe any of you will use with different types of it.

craft()->on('entries.onBeforeSaveEntry', function(Event $event) {
  $entry = $event->params['entry'];
  $turkishCharacters = ['ı', 'ü', 'ö', 'ş', 'ç', 'ğ'];
  $englishCharacters = ['i', 'u', 'o', 's', 'c', 'g'];

  $entrySlug = $entry->slug;
  $entrySlug = str_replace($turkishCharacters, $englishCharacters, $entrySlug);
  $entry->slug = $entrySlug;
});


Call a public function within a FieldType file, from a variables files I have a plugin called "myPlugin", this has a variables file. Within there, I have a something like this:

public function helloWorld() { return "Hello World"; }

Also within this plugin, I've created a new fieldtype. From the "getInputHtml" function, I'd like to call the "helloWorld()" function.

How can I do this? This was my initial trail of thought:

$testing = craft()->myPlugin->helloWorld();

or

$testing = craft()->myPlugin->myPluginVariable->helloWorld();

From what I understand about plugin development on Craft, this isn’t possible. The idea of the variables file is to provide methods which are accessible from within your plugin or users templates.

The idea being that the methods you define here are actually references to your service methods (Taken from Craft docs)

  Many of your template variable methods will likely be simple wrappers for your service API methods. It’s important to remember not to expose state-changing methods, however.

So from that I would actually create a service class for your plugin and access the methods in your getInputHtml function from that.

For example:

services/MyPlugin_PluginService.php

<?php
namespace Craft;

class MyPlugin_PluginService extends BaseApplicationComponent
{
 public function helloWorld()
 {
   return ‘Hello World’;
  }
}

In your getInputHtml function

$testing = craft()->myPlugin_plugin->helloWorld();

Call the same method in your templates

Add this to your variables/MyPluginVariable.php file to call the method in your templates:

public function sayHello() {
  return craft()->myPlugin_plugin->helloWorld();
}

Then you could call the service method in your templates like so:

{{ craft.myPlugin.sayHello() }}

Hope that helps!


Is there an equivalent to IOHelper::ensureFolderExists in Craft 3? Migrating Plugins to Craft 3 starts bugging me, seems that really everything changed.
Is there an equivalent to IOHelper::ensureFolderExists in Craft 3?

In Craft 3, the IOHelper class has been replaced by the FileHelper class.

The closest Craft 3 equivalent to IOHelper::ensureFolderExists() is

FileHelper::createDirectory($path);


Craft CMS shows disabled entry page Entry is disabled
https://monosnap.com/file/l8tgvr5Fxpw0OXPbpcwiI57JmZjL51

But despite that on its address I see its template loaded only without entry data.

I expected to see 'Page Not Found'.

Try adding this to the beginning of your case study entry template:

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

Do you have a route set up for your case studies?

I've got routing set up on a client site that has the route /case-studies/* pointing to template /_cs/entry.twig

That makes it try to the load the template, whether or not there's an entry at all. So it needs the extra bit to check if the entry is real/published.


Asset uploads failing on new installation of Craft CMS New (local) installation of Craft on Mac OSX Yosemite, working well except uploading an asset doesn't complete. The progress bar hangs and the spinner never stops spinning.

Craft index.php is located in /Users/Penguin2/Sites/craft.dev/
Craft application files are in /Users/Penguin2/Sites/craft/
PHP open_basedir is /Users/Penguin2/Sites/

The PHP log indicates the following:

[21-Jan-2015 18:04:02 UTC] PHP Warning:  Unknown: open_basedir restriction in effect. File(/var/tmp/) is not within the allowed path(s): (/Users/Penguin2/Sites) in Unknown on line 0

I assume I need to change the location where Craft stores temp files to a directory under the PHP open_basedir but I can't find the setting anywhere.

Thanks!

You probably just need to set upload_tmp_dir in your php.ini file to be a path under your openbase_dir paths.

Or just remove the openbase_dir restrictions.


Seeking information on the largest Craft sites built We're writing an article on the largest Craft sites built and I'm having some challenges finding this information. Ideally, we want to compile a list of the top 20. "Largest" is determined by certain criteria like: Traffic (uniques/month; and pages/month); Number of Entries, Number of Members; Number of forum posts, etc.

I came across this article https://straightupcraft.com/articles/who-uses-craft-cms as a start to find out some basic info on sites built in Craft but it doesn't provide me with any info that would suggest these are some of the largest sites. In fact, when I entered in some of the names from that list into Alexa https://www.alexa.com/siteinfo their global ranking was quite low. I'm seeking help on how to surface this info.

Stack Exchange is generally for more technical questions, so you might not get many replies here.

Have you contacted the folks at Pixel & Tonic directly?

You could also join the Craft CMS Slack. Plenty of developers hang out on there that might not look here, so it'd be worth your while asking the same question there.


How do I find the path to the public folder? Within my Craft plugin code, how do I find the path to Craft's public/ folder? There doesn't seem to be a constant listed in Craft Docs: PHP Constants like there is for all the other key folders.

Lots of good discussion on how to do this and the pros/cons of each here: https://stackoverflow.com/questions/4645082/get-absolute-path-of-current-script

In short, the most reliable way is to use PHP's debug_backtrace.

$debugTrace = debug_backtrace();
$initialCalledFile = count($debugTrace) ? $debugTrace[count($debugTrace) - 1]['file'] : __FILE__;
$publicFolderPath = dirname($initialCalledFile);