Old ticket, I know, but thought I'd answer.

Personally, I use a channel for carousel slides as clients for me have tended to mix and match them on multiple places on a site or stop using them then reusing them a few months later.

This way they have a pool of instances of reusable slides that won't disappear. Hopefully saving redoing work they've already done a few months prior.

If I've understood your question, I'd have a channel with two entry types. "Image slide" or "Text slide".

So when they add a new one they can choose if they want one with an image or just text.

Then depending on how you're constructing your pages you just need a Matrix component type that is named 'carousel' with an entries field with the slides channel selected as it's source or just an entries field on it's on in the page entry types you want this carousel to be. (I'd limit it to three or four for UX purposes).


Memory issue when updating all entries from a channel (allowed memory size of X bytes exhausted (tried to allocate Y bytes))

If you just want to re-save a large number of entries without modifying them, you can run a ResaveElements task, which takes some basic parameters and re-saves all the entries that match them.

You can do that like this:

// Queue up a new ResaveElements task
craft()->tasks->createTask('ResaveElements', null, array(
    'elementType' => ElementType::Entry,
    'criteria'    => array('section' => 'mySectionHandle', 'limit' => null, 'status' => null, 'localeEnabled' => null)
));

// Start running tasks
craft()->tasks->runPendingTasks();


If I remember correctly, you will see urls similar to this http:\/\/mysite.dev\/cpresources\/404?x=CjvOQxsnA if you have generateTransformsBeforePageLoad as false.

It could genuinely be the case that the original file is not there so it's 404ing (as the link suggests it is).
If you are running multi-environments, have you got all the assets on your locale env?

Maybe try clear your cache, or, your storage/runtime folder if you have all the assets and try again?


I'm on a Windows 10 environment with WAMP installed and I had exactly the same problem. Front End failed. Back End worked fine. News links failed. Clicking on website name link from the Localhost screen reveals directory contents. No matter how many times I kept clean installing Craft and tweaking and adding .htaccess files, the problem remained.

I solved the problem in the following way, without the need to add any .htaccess files. It's best to do a complete clean install of Craft.

You'll need the original, untouched, craft and public folders. Apologies if these following points go over what you already know.

Copy the craft and public folders into the wamp/www/sitename folder as normal (or the Mac equivalent)
Remove all the files from the public folder and place them at the base level (i.e. same level as the craft folder)
Delete the public folder.
Rename the root htaccess file to .htaccess
Open up the .htaccess file and add this line

RewriteBase /

after this line

RewriteEngine On
In the root index.php file change line 4 to $craftPath = './craft';
Create your localhost database.
Set up your database connection details within craft/config/db.php.
Via your browser, enter localhost/sitename/index.php/admin/install
Click on the Begin button.
Create your account page, fill out as normal.
When you get to the Setup your site page, complete the Site URL details like this:

http://localhost/sitename

Finish off the install as normal and when your dashboard gets displayed, click on the Website name (top left) to go to the Front End and it will work. Click on the News link and it will work. As will Live Preview. Go to the Localhost page, click on the website name and you will go to your home page instead of having directory details displayed. Finally, if you upload this whole website to your live site it will still work.

Hope this helps someone.

As a slight caveat, I have only been testing Craft for a couple of days and installing it is about as far as I have got to at the moment. So if I've broken Craft no-no's like 'never delete the public folder, then I apologise (obviously, it doesn't have to be deleted and just remain empty)


How to filter entries by slug in url segment?

I think there is just some confusion between what should be a string or not. From the docs on Parameter Value Syntax:

  To exclude entries with a given value, you must pass in a string, prefixed with not

To that end the following should work for your example:

{% for entry in craft.entries.section('news').slug('not ' ~ craft.request.getSegment(2)).limit(6) %}...


Is a backup needed before updating?

It's definitely recommended.

Regardless of it is an auto-update or a manual update, Craft will attempt to perform a database backup if the backupDbOnUpdate config setting is set to true (it is by default).

If that is set to false you'd want to perform your own backup before doing a Craft update.

  Will installing new updates have any affect on the pages already saved or the existing structure?

Updates should not make breaking changes to the front-end of your site.  The ones that do will be advertised as so, such as the Craft 2 => 3 update process.

You can see the steps that Craft goes through to make sure updating is done safely here: How safe is auto-updating?


Sections, Categories, and EntryTypes. Which, when?

Sections are for completely separate areas of content. They have their own URLs, and are conceptually different. Like blog posts and press releases would be different sections. Your sections could easily be one section with a different set of categories defining web development and general writing. This is entirely up to you.

Categories are for separating entries into smaller groups. Your use of categories is correct. You just use it to categorize entries.

Entry types are when you have common content that require different field layouts. Think Tumblr and how it has one stream that shows text, pictures, links, and quotes as separate types. For your setup, if no entry will be both an article and a tutorial at the same time, you can remove the tutorial entry type and simply use the article one. Then in your template, use the category to decide how to lay it out. The link has a different field layout so it can stay separate.


Odd error message when editing field settings (Variable "targetLocaleFieldHtml" does not exist)

This had me stumped for a while, but it turned out to be a custom fieldtype extending BaseElementFieldType, in which the settings attribute targetLocaleField apparently was renamed targetLocaleFieldHtml with Craft 2.5.2750.

Not sure why the error was thrown for all fields and fieldtypes (even PlainText fields), but in any case the fix was simply replacing the targetLocaleField attribute with targetLocaleFieldHtml in the returned array for the getSettingsHtml() method in the custom fieldtype.

Edit: It just occurred to me that the reason for getting the error on all fields/fieldtypes is – of course – due to Craft actually pre-rendering the settings templates for all fieldtypes, I assume to make changing the fieldtype (via the dropdown) seamless/instantaneous.


Query entries from two sections, check date field for one section and include pagination

Found the solution.

First get entries from section events as ID's and check endDate < now:

{% set eventsIds = craft.entries()
  .section('events')
  .endDate('< ' ~ now|date('c'))
  .ids()
%}

Then get entries from section news as ID's:

{% set newsIds = craft.entries()
  .section('news')
  .ids()
%}

Then merge those two together:

{% set entryIds = eventsIds|merge(newsIds) %}

Then paginate by id, set orderBy postDate and limit to 9:

{% paginate craft.entries()
  .id(entryIds)
  .orderBy('postDate desc')
  .limit(9)
  as pageInfo, pageEntries
%}


Limiting form entries per day in FreeForm

I managed to get this working in the end. Here is my final code;

{# Calculate entries per day #}
{% set form = entry.form %}
{% set todaysEntriesIndex = 0 %}
{% set submissions = craft.freeform.submissions({
    form: form.handle
}).all() %}

{# Count each submission from the day #}
{% for submission in submissions %}
    {% if submission.dateCreated | date('d/m/Y') == 'now' | date('d/m/Y') %}
        {% set todaysEntriesIndex = todaysEntriesIndex + 1 %}
    {% endif %}
{% endfor %}

Once this has been setup you can use the following to check the amount:

 todaysEntriesIndex >= 200


Selecting entries with min value through search param

You are currently passing a string '>= pers' to the array. Change this to:

'>= ' ~ pers

This "concatenates" the string '>= ' and the value of your pers variable (converted to a string).


Price formatting thousands/decimal signs

The thousands/decimals signs are based on the current users locale and can not be configure at the moment. The number is formatted based on the currency and locale. You would need to make your own currency formatter as a twig extension.

You could set format=false in the craftCommerce filter, then pass the value to your own number formatter filter.


Display categories which only contain entries

A simple but effective solution would be to just wrap the output in a conditional.

{% if entryCount %}
    <li>...</li>
{% endif %}


Which section type for Craft Commerce customer account pages

If you need user profile data, the obvious place to store that is in Craft Users.  Add the fields you need etc.

Commerce has a field you can add to a User to show that user's addresses and orders on the back end.

For the front end, you then just make user profile page templates as you need them.

I see no good reason to use Structures,Channels or Singles here really, although I guess it depends on what other content you might want to have on those pages.  For the most part you're probably either just looping over the addresses and orders, or showing a single entry page for one of those.

Of course Craft is so flexible, you could use a structure for some of it, if you have fuller content needs, and then dynamic templates for those more transactional pages...there's an almost limiteless variety of ways you could do it, but user fields plus some templates for those sorts of pages would be the 'most standard' approach.....certainly it's what we're using.


How can I order a sections entries by their children entry postDate?

This should do what you want.

{% set videos = craft.entries({
    section: 'articles',
    type: 'video',
    level: 2,
}) %}

{% set articleIds = [] %}
{% for video in videos %}
    {% set article = video.getParent() %}
    {% set articleIds = articleIds|merge([article.id]) %}
{% endfor %}

{% set articles = craft.entries({
    id: articleIds,
    fixedOrder: true,
    limit: 6
}) %}

You go through all the videos and collect the IDs of the parent article entries. Once you have the IDs, make sure to set fixedOrder in the final criteria model and the entries are retuned in the same order as the IDs in the id param.

Note that the getParent function queries the database for each video in your section. You might want to consider caching that piece of code.

And you can also test if replacing the code in the for loop with the following performs better.

{% set articleId = video.getAncestors(1).ids()[0] %}
{% set articleIds = articleIds|merge([articleId]) %}


There's only one entry named Transforming Work.

That might be true, but you’re telling Craft to store the entry with an URI

fort-collins/weekly/buddhist-meditation-classes/_entry

Change your entry URI format back to something that’s going to be unique for each entry, probably you’ll want to replace the hardcoded string _entry with the dynamic variable {slug} again, or better, do what is actually described in that Stack Exchange answer you linked to and don’t use the default Entry routing at all (disable “Entries in this section have their own URLs”) and rebuild the route with a custom one (see the Craft docs on Dynamic Routes).


If your entries field is in the layout of your category

{% if object.level == 1 %}
    {% set entry = object.entriesFieldHandle.one() %}
    {slug}-{{ entry? entry.slug : '' }}
{% else %}
    {slug}-{parent.uri}
{% endif %}


I believe you can use getLastInsertID to fetch the ID:

Craft::$app->db->getLastInsertID();


There is a PhpStorm plugin that adds “Missing translations”, “Unused translations” and “Translation message correctness” inspections to the IDE.

https://github.com/kalessil/yii2inspections

But unless I am missing something, it’s currently missing support for “Missing translations” inspections in Twig files. Both other features work well with Twig:


This article was helpful getting us started when we tackled an advanced search. Though their example uses dropdowns, you'll probably want to use checkboxes for your "Herbs" and "Live Plants" categories.

Combined searches and filters


Only fetch structure entries that are first level or sub level that don't have a parent

You can use the hasDescendants() method to filter out any parent entry with children. You have to use an ElementCriteriaModel with .getPrev() and .getNext().

{% set entries = craft.entries.section( 'pages' ) %}
{% set entryIds = [] %}

{% for entry in entries %}
  {% if not entry.hasDescendants() %}
    {% set entryIds = entryIds|merge( [entry.id] ) %}
  {% endif %}
{% endfor %}

{% set criteria = craft.entries.id( entryIds ) %}

{% set prevEntry = entry.getPrev( criteria ) %}
{% set nextEntry = entry.getNext( criteria ) %}

You will also need to add logic to get the first and last entry is next or previous is null.


How to delete old content in a Craft CMS database?

"Personally I'd just use the 'select all' checkbox at the top of entries and delete them all at once."
That's what I've been doing - deleting all entries in the system. I've always thought that by deleting entries in the system it would clean the database.
But when looking in the database there is so much information that is still saved even though everything is deleted in the system.
Now I have a database that is over 300mb, with old content in Matrix columns, craft_elements and more.
UPDATE:
This is what I've done so far:

In craft_elements I deleted all rows with type LIKE "Entry".
Emptied all my matrix tables.

Because I cleaned all entries from the craft_elements I also removed the single section entries. By saving those sections again the entries where created.
The database have gone from 318mb to 16mb. The system seems to be working great now and I hope it will be in the future :)


This currently isn't possible natively in Craft, but if you think it should be,  you can create a feature request!


You need to start with and, and put not in front of each ID...

{% for entry in craft.entries.section('boardOfDirectors').id('and, not 12, not 18') %}


Is it possible to allow logging at LEVEL_INFO without logging all the SQL queries?

This is what we ended up using.

<?php
    return [
        'components' => [
            'log' => [
                'targets' => [
                    [
                        'class' => PsrTarget::class,
                        'logger' => $logger,
                        'levels' => [YiiLogger::LEVEL_ERROR],
                        'logVars' => [],
                        'addTimestampToContext' => true,
                    ],
                    // Split the targets to specifically exclude classes which spam the logs, while
                    // ensuring errors thrown in those classes are still logged.
                    [
                        'class' => PsrTarget::class,
                        'logger' => $logger,
                        'levels' => $logLevels,
                        'except' => [
                            'yii\base\View::renderFile',
                            'yii\db\Command::*',
                            'yii\db\Connection::*'
                        ],
                        'logVars' => [],
                        'addTimestampToContext' => true,
                    ],
                ],
            ],
        ],
    ];


How to get asset URL from field in template

Hey Jeremy give this a shot to see if it works (from craft.assets)

{% for asset in entry.imagePrimary %}
     <img src="{{ asset.url }}" alt="{{ asset.title }}">
{% endfor %}

If this doesn't clear it up, I'd double check the field Handle to make sure it's spelled correctly and there is an image within one of your entries.


How do I list entries from a single author?

Try this:

{# First, grab the username from the URI #}
{% set username = craft.request.segment(2) %}

{# Then, grab the user based on the username %}
{% set user = craft.users.username(username).first() %}

{# Make sure we actually found a user #}
{% if user %}
    {% set blogPosts = craft.entries.section('blog').authorId(user.id).find() %}

    Found: {{ blogPosts|length }} blog posts.
{% endif %}


What is the most efficient way to code matrix blocks by type in a template?

The right syntax to filter matrix blocks by block type is this (see Craft docs here):

{% for block in entry.myMatrixField.type('text') %}{% endfor %}

So you only have to remove the extra .block you have in your example code. I'd save the returned array of MatrixBlockModels to a variable and use the length filter to see if there are any blocks of this type.

{% set twoSeaterSofas = entry.sofa.type('twoSeaterSofa') %}
{% set threeSeaterSofas = entry.sofa.type('threeSeaterSofas') %}

<!-- some HTML -->

{% if twoSeaterSofas|length %}
    {% for block in twoSeaterSofas %}
    {% endfor %}
{% endif %}

<!-- more HTML -->

{% if threeSeaterSofas|length %}
    {% for block in threeSeaterSofas %}
    {% endfor %}
{% endif %}


Use dropdown field to add a class to the body tag

Set up your dropdown so that the Option Labels are default, yellow, green, etc. and the Values are page-project, page-project bg-yellow, page-project bg-green, etc. Then, you can
{% set bodyClass = entry.backgroundColor %}

This will set bodyClass to whatever the value is for the chosen dropdown element, i.e. page-project if you pick the default option.


Per current conversation on Github, this isn’t possible. https://github.com/craftcms/cms/issues/2854


Craft 3 multisite - are entries accessible between sites?

Yes it is. Just include the site id of the the site in your query

set siteId = 2
set entries = craft.entries.section('foo').site(siteId).all()

if you want to get the current entry for another site

set currentEntrySiteB = craft.entries.id(entry.id).site(2).one()

If you want to search for disabled entries (for example in CP templates) for other sites you can do

craft.entries.id(entry.id).site(2).enabledForSite(false).one()


Maybe you're just looking for a bootstrapped Craft instance?

Something like:

$craft = require '/path/to/craft/app/bootstrap.php';

From there you'll have access to the Craft instance as usual:

$craft->entries->saveEntry();

Along with your models, records, etc.


Filtering by categories AND tags with full match

You are always one level too deep. Craft is able to proceed parameters like

[
    'and',
    ['targetElement' => [1, 2, 3],
    ['targetElement' => ['or', 1, 2, 3],
    ['targetElement' => 1],
    ['targetElement' => ['and', 1, 2, 3]
]

And so on.
Yours is

'targetElement' => ['and', [1,2,3]]

I would suggest you to dump your array

<pre>
{{ dump(array) }}
</pre>

To see the result. If you don't care about performance just using .one() instead of all() might solve the problem.


Craft 2

The Date/Time formatting in the Control Panel is based on what locale you're using when you're viewing the Control Panel.

If you have eb_gb as a locale defined under Settings->Sites->Locales, then you can go to your user account settings and set your "Preferred Locale" settings to "British English" and you'll get the DD/MM/YYYY format.

Craft 3

The locale you're site is currently set to and the language your viewing the Control Panel in are now separate concepts.  If you go to your user account, click "Preferences", you'll see a "Language" dropdown, which controls the date/time formatting of the Control Panel for you.

If you want to set this globally for users that haven’t yet set their preferred language then you can use the defaultCpLanguage config setting. This is also useful when migrating a site from Craft 2.x to 3.x as all existing users won’t have set that preference and it will default to en-US.


Numbers have certain limits in computer systems and storing (as well as working with) exceptionally large ones is cumbersome.

In the database, the int (integer, a whole number) is limited to a range from -2147483648 to 2147483647. A bigint can range from -9223372036854775808 to 9223372036854775807 but is less common. And I don't think Craft uses bigints anywhere.

I know it's purely numerical, but could your ISBN numbers use a text field? Unless you're doing math on it then this should suffice. If you really want you could a new fieldtype that validates an ISBN number but saves as a varchar in the DB.


Changing a product's Tax Category ID onSaveProduct event

Setting the new field value onSaveProduct meant that the only the general element and its custom field data was being saved and not the tax ID on the product model.

To solve this, the onBeforeSaveProduct event should be used. This allows modification of the product model before it's saved.

craft()->on('commerce_products.onBeforeSaveProduct', function(Event $event){
    $product = $event->params['product'];
    $criteria = craft()->elements->getCriteria(ElementType::Entry);
    $criteria->id = $product->productFilterArtist[0]->id;
    $artist = $criteria->first();
    if ($artist && $artist->getContent()->vatRegistered) {
        $product->taxCategoryId = 1;
    }
})


How do I get the siteName in a module (Craft 3)

When searching the Craft 3.5.x docs for siteName, I see references to Global Variables and General Config Settings. Screenshot: https://cln.sh/egvIXhxZSzaFjeCgNLxX
However, AFAICT, it works differently for modules/plugins. As per the Sites section in the Craft 3.5.x Class Reference docs at https://docs.craftcms.com/api/v3/craft-services-sites.html, you would do something like one of the following:
Craft::$app->sites->currentSite->name;
Craft::$app->sites->primarySite->name;
Craft::$app->sites->getSiteByHandle('default')->name;
Craft::$app->sites->getSiteById(1)->name;

I'm getting the name part because I'm using PhpStorm with autocomplete set up as per article at https://nystudio107.com/blog/auto-complete-craft-cms-3-apis-in-twig-with-phpstorm
Screenshot of autocomplete in action: https://cln.sh/T77W1Y69SmR3qPUPv0sb
I'm successfully using Craft::$app->sites->getSiteById(1)->name; in one of my custom modules.


renderTemplate in a plugin for front end request using front end template

Craft will only serve templates from craft/templates/ by default if it’s a front-end site request.

To explicitly tell Craft to serve templates from there, you can use PathService::setTemplatesPath():

$path = craft()->path->getSiteTemplatesPath();
craft()->path->setTemplatesPath($path);

$this->renderTemplate('path/to/template', $variables);


Entry not saving when date isn't changed using frontend form

Something I'd not done with the edit form was replace [new1] with [{{variant.id}}] for the variant inputs. As I said, the form was saving correctly anyway if I changed the date, so I didn't expect correcting these to fix the issue I'd been having.

It turns out that correcting these does in fact fix the issue I was having with saving products with an unchanged custom date field. Here is the corrected template code:

{% if variant is defined %}
  <input type="hidden" name="variants[{{ variant.id }}][unlimitedStock]" value="">
  <input type="hidden" name="variants[{{ variant.id }}][minQty]" value="">
  <input type="hidden" name="variants[{{ variant.id }}][maxQty]" value="">
  <input type="text" value="{{ variant.stock }}" name="variants[{{ variant.id }}][stock]">
  <input type="text" value="{{ variant.price | number_format(0) }}" name="variants[{{ variant.id }}][price]">
{% else %}
  <input type="hidden" name="variants[new1][unlimitedStock]" value="">
  <input type="hidden" name="variants[new1][minQty]" value="">
  <input type="hidden" name="variants[new1][maxQty]" value="">
  <input type="text" value="" name="variants[new1][stock]">
  <input type="text" value="" name="variants[new1][price]">
{% endif %}

I'm left wondering whether only having a single default variant allowed still permits new variants to be submitted, which might explain why I wasn't getting any errors? Similarly, I'm not sure why correcting the variant field names fixed the problem I was having with the custom date field not saving when the date wasn't changed.


Bad Request Unable to verify your data submission and unstyled CP

There isn't really enough information here to give a full answer, but 'Bad Request Unable to verify your data submission' means that Craft is not getting supplied the correct CSRF token.
To confirm, try turning off CSRF protection in your config:
https://craftcms.com/docs/3.x/config/config-settings.html#enablecsrfprotection


Craft 3 validate new password in change password

I believe what you're looking for is this:

if ($newPassword != $confirmPassword){
    Craft::$app->session->setError('Confirm password does not match new password');
    $event->isValid = false;
}

Setting isValid to false will stop further processing of that element (the user in this case).


Not sure if this is the best way to do it, but I created this little function in a Variable class.  I get all the necessary info (username and score) in an array.  Works fine for what I needed.

public function leaderboard(ElementCriteriaModel $criteria)
   {
       $query = craft()->elements->buildElementsQuery($criteria);

   if ($query)
   {
      $query
          ->select("authorId, SUM(field_score) as score, users.username as username")
          ->join("users", "users.id = authorId" )
          ->group("authorId")
          ->order("score DESC");

               return $query->queryAll();
       }
   }


Outputting .relatedTo() total entries number

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

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

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

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

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

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

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

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


Show Entries Based on Category - Localised Site

The slugs for the different locales were not the same. Changed those and all fixed.


Customer details revealed at base order URL

As a rule in Commerce, when retrieving orders on client side templates, you should limit the retrieved orders to orders for the current customer only, using the customer parameter:

{% set number = craft.request.param('number') %}
{% set order = craft.commerce.orders.number(number).customer(craft.commerce.customer).first() %}
{% if not order %}
    {% redirect 'login' %}  {# or wherever #}
{% endif %}

(...if the included example templates aren't doing that, you should let Luke know.  I haven't looked at them in ages and don't have them to hand here...)

(One slightly random side thing I have noted with time is that you should really limit loading of the order complete page to a single time, i.e. only specifically at the actual order completion - if you don't, you tend to get issues with re-submissions of orders to your analytics and so forth.  E.g. if the customer completes an order, goes somewhere on the site, then comes back to the complete page using the back button - it can create issues - so I remove the number parameter from the url using some JS and make sure I check for a number in the url in the cart/complete template:

{# Show empty cart if they somehow get back here without a number.... #}
{% set number = craft.request.param('number') %}
{% if not number %}
    {% redirect 'cart' %}
{% endif %}

And the JS would be something like:

if(window.location.pathname == "cart/complete"){
    var cleanedUrl = utilities.removeURLParameter(window.location.href, "number");
    window.history.pushState('',document.title,cleanedUrl);
}


How do you query entries by field values?

You can do the same like with the section, if the query param exists in the field layout

$widgets = Entry::find()->widgetColor('blue')->text(':notempty:')->anotherField(':empty:')->section('widget')->all();

Will search for entries where widgetColor is blue, text is not empty/null and anotherField is empty/null

Edit: just for people who like to understand the behavior

Just to explain you the where parameter in the ElementQuery. The where function uses the Yii2 Query function directly and works directly at the database layer. When you take a look at your content table you'll see all custom fields have a certain prefix (if you didn't change it) so your widgetColor column will look like field_widgetColor when you do

where->(['widgetColor' => 'blue');

it will query

where `content`.`widgetColor` = `blue`

which will throw an error since the column name is field_widgetColor. The __set function in the Yii/component/ QueryBuilder class will set magic property that exists because of the field handle in your field layout... Or to keep it simple: you can access any "magic" property with the same name like an existing field handle.

Doing

->widgetColor($property)

will call the __set function that calls a wrapper that will wrap/attach the field content prefix (field_) to the where function. Thus you can use

where->(['field_widgetColor' => 'blue');

or

where->([Craft::$app->getFields()->oldFieldColumnPrefix . 'widgetColor' => 'blue');


Parse html on first and last occurrence of a matrix block type in a series of that same block type

You need to define the block previous/next variables outside of your for loop. Also you should check for the last element in the loop.

You can find a great working example on the happy lager demo website (https://github.com/pixelandtonic/HappyLager).

The relevant code part is here: https://github.com/pixelandtonic/HappyLager/blob/master/craft/templates/_includes/article_body.html.


Uploading Asset Doesn't Clear GraphQl Cache with VueJS/Axios

Welp, as they say, "There's a config setting for that" - :facepalm: - If you add the following to your /config/general.php file it will disable GraphQL caching completely:

  //Disable GraphQL Caching
  'enableGraphQlCaching' => false,

To reference it from a .env environment variable use this instead:

  // Disable GraphQL Caching from .env variables
  'enableGraphQlCaching' => (bool)getenv('ENABLE_GQL_CACHING'),

Got this info from the amazing folks over at nystudio107 via this post:
https://nystudio107.com/blog/using-the-craft-cms-graphql-api-on-the-frontend

Ideally if there was a way to flush the GraphQL cache at the time I need it that would be more precise, but disabling the GraphQL cache all together solves the problem.


You are trying to install a Craft 2.x plugin, which you can see, among other things, by looking at its composer.json. Craft 3 plugins will always have a "extra property with a "handle" defined.

"extra": {
    "handle": "plugin-handle",
}

The currently latest release of the Import plugin is v0.8.33, and is not compatible with Craft 3:
https://github.com/boboldehampsink/import/blob/0.8.33/composer.json

Until the plugin store goes live, most plugin developers note their compatible plugins in this list:
https://github.com/craftcms/plugins


It seemed that for some reason my fields said they were Redactor I but were in fact Redactor II.

Reinstalling Redactor I did the trick.


How do you set up Craft CMS to back up your site automatically?

Options:

1) Craft will automatically run a backup of the database anytime an update is performed and save it to craft/storage/backups

2) You can manually create a database backup by going to Settings->Tools->Create Database Backup.

3) You can install something like the Dump plugin and create a cron job that points to it to run the backup on a automated schedule.


Listing all entries in one section related to entries written by currentUser in another section

I think this is what you mean:

{% set sectionBEntries = craft.entries.section('B').authorId(currentUser.id) %}

{# 'relatedTo' works both ways, so we can use sectionBEntries
    as input for relatedTo to get all section A entries that have
    a relation to one of the section B entries by currentUser #}
{% set sectionAEntries = craft.entries.section('A').relatedTo(sectionBEntries) %}

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


User registration; validate email but don't activate automatically

I think the approach Johannes posted as an answer to the question you linked to is a good one.

Let the user activate the account via email. It makes sure the address exists and he has access to it, because he can't guess the activation URL without the mail.
This activation only makes him become a member of a Users Group without any permissions at all (e.g. 'unverifiedUsers'). To restrict front end access do something like this:

{% if currentUser.isInGroup('unverifiedUsers') %}

You don't have access rights. Please wait until an admin verifies you account. Thank you!

{% else %}
    {% include 'partial' %}
{% endif %}

Then let an admin do the manual verification: add the user to a group with the permissions you want.


Querying Global fields using CraftQL and Gatsby JS

In looking at this, the first thing I notice is that your query has a field called globals, but your error has the singular global.

If you open Gatsby’s GraphiQL instance (http://localhost/8000/___graphql in develop mode), can you see the Craft CMS data in the docs? That might help zero in on the query to use in Gatsby.

Hope that helps!


Can you update your composer.json to require "vlucas/phpdotenv": "^3.4.0" and run composer update again.


The mod_geoip2 Apache module with a redirect in .htaccess file.

See: http://dev.maxmind.com/geoip/legacy/mod_geoip2/


How do I set a class if entry is a child of a particular parent?

If you want to test whether entry-with-id-X is an ancestor of entry, do this (assuming x = 13):

{% set entryWithIdX = craft.entries.id(13).first() %}
...
{% if entryWithIdX.isAncestorOf(entry) %} ... {% endif %}
{# or #}
{% if entry.isDescendantOf(entryWithIdX) %} ... {% endif %}

isAncestorOf and isDescendantOf take an entry as parameter, not an entryId.

It would be a good idea to test to see whether craft.entries.id(13) returns anything before calling first() on it, but that's a separate issue.


Serving Craft from a sub-directory on Nginx

If you want to just adjust the folder for the webroot set the root to

/srv/www/webroot/articles/

And in the index.php file make sure the path to the craft folder is

'../../app/craft'

UPDATE:

If you instead want to leave the webroot as is and just have craft run from yourdomain.com/articles you would need to also update the index.php to make sure the craft path is set correct

and in the nginx file add this

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

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

put that directly above this line, everything else can be the same

location ~ \.php$ {


Dynamically setting a channel's Entry URL Format with Craft tags

I've successfully used this entry url format and it works great:

{{ craft.entries.id(65).first.uri }}/{slug}

I would advise using the entry id over a slug, as it will never change. You also don't need to specify the section if you've included the id.

For a multi-lingual site, you can specify the locale for each entry url format:

{{ craft.entries.id(65).locale('en_us').first.uri }}/{slug}
{{ craft.entries.id(65).locale('de').first.uri }}/{slug}
{{ craft.entries.id(65).locale('fr').first.uri }}/{slug}

As you mention in your comment, you do need to beware of updating the parent entry's slug as uri's are parsed before being stored in the database so it is not truly dynamic. I'm not aware of any workarounds for this that don't involve a plugin.


How do I pass custom field contents from cart to order

This was a bug in commerce and it has now been fixed.


Exclude most recent entry type from a loop

Best practice is to only query for the data once, then perform any necessary filtering on the result, rather than making multiple expensive calls to craft.entries...

So in your case you could take the first entry using [0], and then use Craft's without filter to filter out the first entry from the list:

{% set posts = craft.entries.section('blogPosts').all() %}
{% set firstPost = posts[0] %}
{% set otherPosts = posts|without(firstPost) %}


You've got your two obvious choices nailed down.  You're either offloading the filtering to MySQL (running 3 separate queries so that MySQL filters the data) or you're grabbing all of the data and filtering it on the Twig/PHP side.

Which one is more performant likely depends on 1) how much data you're talking about and 2) your environment (resources allocated to MySQL vs. PHP).

For your particular case, I'd enable devMode and analyze the performance metrics between the two methods while taking into account how fast the data might increase in the future and make an educated guess based on that information.


Does EntryLocaleRecord.php exist in craft/app/records?  My guess is that it didn't copy/FTP up to your server properly or its corrupted.

I'd try re-uploading the entire craft/app folder to make sure there aren't others missing.


Fetch Craft Commerce purchasable element type

By default, Commerce only provides 3 custom element types to Craft... products, orders and variants.

My guess is you're looking for products, in which case the syntax you're looking for is:

$productsCriteria = craft()->elements->getCriteria('Commerce_Product');


The first one example should work as long as the last BrowserDetection segment maps to the actual BrowserDetection.php file on the file system.

  Fatal error: Class 'Craft\BrowserDetection' not found in /Volumes/Mark Notton/Clients/The STC/Website/craft/plugins/myPlugin/MyPlugin.php on line 33

You'd still even get that error on the first one because the BrowserDetection class is in PHP's global namespace.

You need to do:

$browser = new \BrowserDetection();


There is no out-of-the-box way to do this, but you can make use of a plugin like Lindsey Diloreto's CPCSS to set display: none on the body.ltr .matrixblock > .titlebar > .preview class.


Forgot password URL in email returns an error

I know why this happens - we have the same problem. It is related to the escaping of the & in the password reset URL not being escaped:

http://yoursite/admin/actions/users/setpassword?code=abcd&id=1234

somehow, this arrives at our (and your I guess) server as:

http://yoursite/admin/actions/users/setpassword?code=abcd&amp;id=1234

Then the code is abcd and a parameter called amp;id is 1234.

In our case, we have craft setup to send HTML emails, and have an email template like:

Click here to reset your password: {{link}}

and end up with the link http://yoursite/admin/actions/users/setpassword?code=abcd&id=1234 directly in the HTML - this is WRONG, since the & symbol has to be escaped as &amp;.

Now, we could compensate, and make our template:

Click here to reset: {{link|escape}}

Then we get correct HTML, but the plain-text version of the email is now broken.

AFAIK there is no way to have separate templates for text and html emails in craft?

I guess your problem is also HTML emails, OR you have a user with an overzealous email client, that adds the escape of the & for you.


Front End Entry Form - Proper Syntax for Custom Fields

The second parameter of the input function is the name attribute, which you currently have as contactName. Assigning it in the options like you have does not override the initial supplied parameter. Try this:
{{ input('text', 'fields[contactName]', entry.contactName, {
    id: 'contactName'
}) }}


Multiple image transforms of same image in template

You might consider setting a variable for the image, then one for each transform type.

{% set thumb = { mode: 'crop', width: 300, height: 300 } %}
{% set large = { width: 600 } %}

{% for photo in photos %}
    {% set p = photo.image.first() %}

{% endfor %}


Running Craft alongside another CMS on the same domain

You're asking a loaded question. I don't think there's a wrong answer here but if it were me, you have a couple options.
Addressing the Elephant in the Room
How good of a salesman are you? ;) You mention the e-commerce CMS isn't getting the job done but replacing it is off the table. I've gone down this road before.  Since you've got your team interested in Craft, why not consider Craft Commerce too? I know what you're thinking. It's a tough sell. But then again, so is integrating 2 CMS and making sure things don't break between them. What happens if that 3rd party CMS vendor doesn't "approve" of what you're doing and cuts support?  Not saying it'll happen but like you mentioned... politics has a way of messing with people.
I don't know how much business logic that the current e-commerce solution has that you'd have to replicate or how many products and variations you're dealing with but if anything is up for the challenge, it's Craft and Craft Commerce. Just demoing the seamless integration between the two might be enough for the sales/marketing team. Time is money for them.
If you can't go with Craft Commerce, it really depends on what the other software does and how you integrate the two.
Integrating the Two
I'm assuming both CMS will live on the same physical server? Indeed, Craft could  play alongside the other CMS. That's the easiest option. If it were me, I'd probably setup all new marketing pages within Craft and then link to the actual ordering pages in 3rd party CMS.
By default, most CMS including Craft are going to suck up any request that isn't a static file, query the database, and then return the "virtual" page from the database. The actual page doesn't really exist on the server, so Craft looks for "would-be" 404s. That's basically what the rewrite rules in a .htaccess file does—it tells Apache to send any 404 back to the application (usually index.php).
Why is this important? If you have any flexibility with the 3rd party CMS, I'd "quarantine" it to a folder on the server, like /store/ so any request within that folder (like /store/black-leather-jacket/) would go to the commerce CMS (assuming the CMS is sane and doesn't do something stupid like have absolute URLs).
Craft would handle everything else. You could quarantine "Craft" to a folder, but like you mentioned, any page you create would have a URL like /marketing/black-leather-jacket/demo/ or whatever you decide. That's sub-optimal in my opinion. As far as SEO and flexibility go, you probably want people to hit your marketing/landing pages first. People won't buy if they don't have info.
(And it's probably easier to do a 301 redirect to the already existing pages... you could setup Craft so that if it can't find a file, have it take a look if the page exists in the other CMS and redirect if it does.)
Tapping into the Data
Assuming the e-commerce database design/schema is easy to tap into, I'd write a Craft plugin to grab product data directly from the database, based on whatever parameters you need to feed a Twig template. That's beyond the scope of this question but the dev is relatively straightforward.
Craft is built on Yii, an excellent PHP framework so whatever Yii can do Craft can do as well. Craft also ships with Guzzle which would make it easy to "scrape" the actual page or as Matt P mentions building or tapping into some sort of bridge between the 2 systems.
Speaking of scraping, if the 3rd party e-commmerce solution is a hosted solution, then you might have to set that one up on another domain and let Craft handle the marketing pages. In this case, you might consider something like store.domain.com.
Again, all comes down to what the other e-commerce solution does. Craft is relatively flexible any way you slice it.


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

$ sudo a2enmod rewrite
$ sudo service apache2 restart


How to update front end Craft new row - stuck on JavaScript

You can get the number of rows you already have from the DOM, then use that to determine how many you'll have after you add a new one.

$('#addPerson').click(function(e){
  e.preventDefault();
  console.log('clicked addPerson');

  var newPerson = "

";
  $('.newBlock').append(newPerson);
  $('.newBlock .newperson:last-child').load('/store/newperson');

  var blocknum = $('.newBlock .newperson').length;
  $('.newBlock .newperson:last-child').replace('new_0','new' + blocknum);
});

Also note that in your example you were replacing using $blocknum, but you had defined it to be blocknum without the $. You've already fixed this :)

Hope this works out!


Can you store a table field within a matrix field?

I figured it out. You can do it. Here is my example.

{% for block in mainNavigation.navigationLink %}

                {{ block.linkName }}

                {% if block.childLinks | length %}

                    {% for row in block.childLinks %}
                        {{ row.childLinkName }}
                     {% endfor %}

                 {% endif %}

        {% endfor %}


Passing Querystring Variable to PHP Code in Plugin

If you have a URL like this:

mysite.com?username=jsmith

You can retrieve it from your plugin via craft()->request->getQuery('username');

See here: https://craftcms.com/classreference/services/HttpRequestService#getQuery-detail

  My second question is - can Craft (Twig template) pass to the PHP plugin by including the PHP file (service)?

I'm not actually following this question, but we generally try to keep to one question per post.  I'd suggest posting a new one for that with some additional details of exactly what you're trying to do.

Would also suggest giving the official plugin documentation a read-though: https://craftcms.com/docs/plugins/introduction


SPA style entry rendering, SEO implications

The best solution is to create actual pages for the content that is being loaded. Not only will this help with SEO, it will act as a fallback for anyone who is not using javascript. You can link to these pages from your current links so that search engines can crawl through them, but for those with javascript you can load the content asynchronously.


How do I grab the label of a LJ Dynamic dropdown fields

The LJ Dynamic fieldtype only stores the value as a string, or as an array of values for the multiselect fieldtypes. The label in the settings is there just for displaying in the admin.

Either you could use the store.title instead of store.storeId as the value, if you only need the store name in your template. Or you could use the store id to get the data from the store in your template. Something like:

{% set store = craft.entries.section('stores').storeId(entry.stores).first() %}
{{ store.title }}


How can I insert images into a Redactor rich text field in a front-end form?

It doesn't seems possible natively, you should write a custom upload script.

→ Example #1

→ Example #2

If it doesn't matter to add the images inside your rich text field, one more simple workaround could be to allow image upload to your assets using a separate upload field.

→ Uploading Files from Front-end Entry Forms


To resolve this we added a new config setting for the upcoming 2.2 release called maxSlugIncrement.

It defaults to 100, but you can bump it if you need it to keep finding more unique URIs.


Headless mode/ElementAPI: how to set the frontend's baseUrl in the backend endpoint?

Apparently, the answers are the following:

Redactor doesn't know how to output slugs/URIs instead of full URLs
Possibly a solution comes up with craft in the future
My API setup is suboptimal: In fact, I did set the baseUrl including the language: https://frontend.com/de. The recommendation is to not do that at the moment but keep one "Site" for all endpoints in all languages. This can be added as another, separate site in craft! So we'd have 3 language sites in craft and a separate site for the endpoint. The language is then part of the endpoint's data. And the endpoint's URL is https://endpoint.site/api/de/foo instead of https://backend.site/de/api/foo. Yes, I guess that makes sense! Thanks again, Oli!


Looping on the User Field added to Entry

You are setting variables within the scope of the for loop – they only exist there. You can fix this by setting up empty variables before the loop, like:
{% set webinar = block.webinar.all() %}
{% if webinar is not empty %}
    {% for entry in webinar %}

        {# Setup empty variables #}

        {% set name = null %}
        {% set avatar = null %}
        {% set job = null %}
        {% set linkedin = null %}

        {% set url = entry.url %}
        {% set title = entry.title %}
        {% set desc = entry.previewDescription %}
        {% set img = entry.previewImage.one() %}

        {% for expert in entry.eventHost %}
            {% set name = expert.name %}
            {% set avatar = expert.avatar %}
            {% set job = expert.personJobTitle %}
            {% if expert.linkedInProfile %}
                {% set linkedin = expert.linkedInProfile.url %}
            {% endif %}
        {% endfor %}

        {{ title }}
        {{ name }}
        {{ job }}

    {% endfor %}
{% endif %}

Or in one line, for neatness:
{% set name, avatar, job, linkedin = null, null, null, null %}

This one has got me many times ;)


Solution:

    {% set myReverseConnections = craft.users.relatedTo({
        targetElement: currentUser,
        field: 'yourCustomRelationshipField'
    }) %}


Unable to access site after importing DB

Ended up getting this resolved, by downloading DB from Craft staging site and importing, instead of using Sequel Pro. Also make sure your configs in general.php are correct.


Impossible to access an attribute ("url") on a null variable in search results

You should check if there is a next and previous element. Most likely you reach the end or the beginning of your list and there is no element thus these variables are null so you receive an exception when you try to grab attributes from null


includeCssFile and includeJsFile doesn't output {{ siteUrl }}

When you want to output Twig variables inside another Twig tag, you shouldn't include the braces around the variable.

So this:

{% includeCssFile "{{ siteUrl }}css/modul.min.css" %}
{% includeJsFile "{{ siteUrl }}js/ui.min.js" %}

Should be this:

{% includeCssFile siteUrl ~ "css/modul.min.css" %}
{% includeJsFile siteUrl ~ "js/ui.min.js" %}

These examples use the concatenation operator (~) to join the value held in the siteUrl variable to the string holding the path to the CSS or JS file to be included.


Can I have non-boolean TargetBlank output using HTMLPurifier and the Redactor plugin?

And this solved the problem:

"Attr.AllowedFrameTargets": ["_blank"]


Send activation email only for users created over the Control Panel

You'll need to create a small custom plugin to do this. You can create the scaffolding for a plugin using the excellent Plugin Factory site. You'll just need to create a basic plugin, with none of the component options selected.

What you need to do is to use Craft's events to detect when a new user is created using the Control Panel.

The specific event you need to listen for is the users.onActivateUser event.

You'll need something like this in your plugin's init() method:

/**
 * @return mixed
 */
public function init()
{
    // When creating new users through the control panel, send them a password reset email.
    craft()->on('users.activateUser', function(Event $event) {

        // only fire if this is a CP request
        if (craft()->request->isCpRequest()) {

            // retrieve the userModel from the event
            $user = $event->params['user'];

            // send password reset email
            craft()->users->sendPasswordResetEmail($user);
        }
    });
}


Plugin Controller actions for entering data and redisplaying form or redirecting

I have something working, although I'm not sure it's the "correct" way of doing this.

I've got rid of the actionSaveName() method and my actionName() method in the Controller is now like this:

public function actionName()
{
    $templateVars = array();

    if (craft()->request->isPostRequest())
    {
        // The form was submitted.
        $post = craft()->request->getPost();
        $nameModel = MyForm_NameModel::populateModel($post);

        if ($nameModel->validate()) {
            // Successfully posted the name.
            // TODO: Store in session.
            $this->redirectToPostedUrl();
        }
        else
        {
            // Something was wrong with the submitted names.
            $templateVars['errors'] = $nameModel->getErrors();
            $templateVars['nameModel'] = $nameModel;
        }
    }

    // Either the first time viewing the form, or there were errors.
    $this->renderTemplate('myForm/forms/dob', $templateVars);
}

And then plugins/myform/templates/forms/name.html is like this:

<form method="post" action="" accept-charset="UTF-8">
    {{ getCsrfInput() }}
    <input type="hidden" name="action" value="myForm/form/name">
    <input type="hidden" name="redirect" value="{{ actionUrl('myForm/form/dob') }}">

    {% if errors is defined %}
        {% if errors.firstname is defined %}
            {{ errors.firstname[0] }}
        {% endif %}
        {% if errors.surname is defined %}
            {{ errors.surname[0] }}
        {% endif %}
    {% endif %}

First name: <input type="text" name="firstname" value="{% if nameModel is defined %}{{ nameModel.firstname }}{% endif %}">

Surname: <input type="text" name="surname" value="{% if nameModel is defined %}{{ nameModel.surname }}{% endif %}">

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

This seems to work fine but feels wrong in a few little ways:

The hidden action input is ignored; I can put anything in that and nothing changes; I really don't understand how that is supposed to be used.
If the submission is successful the URL redirected to is like /index.php?p=actions/myForm/form/dob rather than /actions/myForm/dob.
Mainly, that it feels quite different from the description in http://buildwithcraft.com/docs/plugins/controllers .


Craft request returns null in test, but works locally

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

getParam not working on live server?


The UserSessionService::getUser method returns a UserModel.

You can retrieve the custom fields from a UserModel as follows:

$userModel->getContent()->getAttribute('fieldName');

Or, following on from your example:

craft()->userSession->getUser()->getContent()->getAttribute('fieldName');


How to pass the matrix attributes to views without too much ceremony

The short answer is no.

The longer answer is you will probably get used to it. Craft twig templates in general look like {{entry.title}} (or {{data.title}}) rather than just {{title}}. I find it easier to read, though you may not.


You'll want to use siteId for this.
query {
    entries (section: "newsIntranet", siteId: "2") {
        title
        postDate
        expiryDate
        contentText
    }
}

Swap out "2" with whatever the siteId of the French site is on your system.


Static translations not working on Craft 3 since upgrade from Craft 2

From what i see you maybe have a typo. I think it should be en-GB. At least this is the folder name in the git repo : https://github.com/craftcms/cms/tree/69bafb027b9e2dc9c8dbede5ad6b4da2706f0650/src/translations/en-GB


Can I send a status message from an external (standalone) PHP script to the Craft engine?

Probably the easiest way to do this would be to add another segment to your URI.
i.e /bla/bla/bla/message-1
Then in your template, read the segment and display the appropriate message.
You could do it all in the template with a switch or conditional or the segment could be the entry slug for the message and you can pull from Craft entries.


You could try customizing the order parameter. MySQL allows ordering randomly by using .. ORDER BY rand(). So you could try the following:

craft.entries.section('featured').order('rand()').first()


Technically the data you're seeking are under the first matrix block (not the first data of your .companyName - which is not valid)

{% set relatedCaseStudy = reviewFeatured.relatedCaseStudy.first %}
{% set firstCompany = relatedCaseStudy.companyInformation.first %}
{{ firstCompany.companyName }}

Note: If you plan to have only one company, think about a SuperTable field in 'static' mode (only one occurence).


UPDATED RESPONSE...

We were finally able to get to the bottom of this and traced the issue down to your site likely having a DateTime field with the handle date, and this was apparently something Craft was choking on.

The next version of Calendar will fix this, but you can resolve this by renaming that DateTime field or patch this by looking for this code in calendar/services/Calendar_EventsService.php around line 100:

public function getEventList($criteria = null)
{
    if (!isset($criteria['allowedCalendarsOnly'])) {
        $criteria['allowedCalendarsOnly'] = false;
    }

And right after that, add this:

    if (isset($criteria['date'])) {
        unset($criteria['date']);
    }

Let me know if this resolves the issue for you. :)


PHP Exception for errors on Craft Contact Form with additional fields

I think this:

{% for error in errors %}

{{ error }}

{% endfor %}

  ... is where the error originates.

  I memory serves me right, errors is an array like this:

[
    ['fieldHandle' => ['Something went terribly wrong!', 'Really, two errors in ONE FIELD?']],
    ['orderFieldHandle' => 'I AM REQUIRED, y\'all!'],
];

  In which case {{ error }} would dictate Twig (and therefore PHP) to
  echo an array (['fieldHandle' => ['Something went terribly wrong!',
  'Really, two errors in ONE FIELD?']]), resulting in the error you
  mentioned.

  You can fix this, by using the following code:

{% for fieldHandle, fieldErrors in errors %}

{{ fieldHandle }}: {{ fieldErrors |join(', ') }}

{% endfor %}

My original answer was not what caused the error (so, apparently, errors was not what I thought it was).

This type of error is caused by an array being echoed by PHP, and not a string. In this case, the cause of the problem is {{ message.message ?? '' }}, which turned into an array because it contains multiple field values.


The Containment Operator helps with this...

  It returns true if the left operand is contained in the right

{% if craft.request.getSegment(2) in ['knowledge', 'search'] %}

OR

{% if craft.request.getSegment(2) not in ['', 'sale'] %}


I think this is partially related to a question I raised recently, even though my site won't have that many languages per country but some countries will have 2 languages.

How can I add in new Locales to the locale list?

Then you would do something like this in your config

return array(
    'example.com' => array(
        'siteUrl' => array(
            // Global locales
            'en' => 'http://example.com/en/',
            'es' => 'http://example.com/es/',
            'fr' => 'http://example.com/fr/',
            'de' => 'http://example.com/de/',

            // Canada locales
            'ca_en' => 'http://ca.example.com/en/',
            'ca_es' => 'http://ca.example.com/es/',
            'ca_fr' => 'http://ca.example.com/fr/',
            'ca_de' => 'http://ca.example.com/de/',

            // UK locales
            'gb_en' => 'http://uk.example.com/en/',
            'gb_es' => 'http://uk.example.com/es/',
            'gb_fr' => 'http://uk.example.com/fr/',
            'gb_de' => 'http://uk.example.com/de/',
        ),
    ),
);

This should work, I haven't tested it as yet as my site is still in planning stages and I have not gotten into the development phase as yet.

Edited answer based on comment.

For all countries to use the same English, you can set your array to look like below, however this will not allow individual countries to have different English copy since we are pointing them all to the same Locale now.

return array(
    'example.com' => array(
        'siteUrl' => array(
            // Global locales
            'en' => 'http://example.com/en/',
            'es' => 'http://example.com/es/',
            'fr' => 'http://example.com/fr/',
            'de' => 'http://example.com/de/',

            // Canada locales
            'en' => 'http://ca.example.com/en/',
            'ca_es' => 'http://ca.example.com/es/',
            'ca_fr' => 'http://ca.example.com/fr/',
            'ca_de' => 'http://ca.example.com/de/',

            // UK locales
            'en' => 'http://uk.example.com/en/',
            'gb_es' => 'http://uk.example.com/es/',
            'gb_fr' => 'http://uk.example.com/fr/',
            'gb_de' => 'http://uk.example.com/de/',
        ),
    ),
);


There is a Zendesk plugin for Craft CMS that could be of use:

https://plugins.craftcms.com/zendesk

  This plugin can work either as a dashboard widget on your clients website, or you can post to it from a frontend form on your own website.


This is not currently possible out of the box with Commerce at time of writing (Sept 2016).

You could write a custom plugin to do it, which would basically keep a table of these people-to-contact, and run a task (or use a controller you trigger by cronjob) -> to send out the emails at such a time the product is re-stocked.

It wouldn't be spectacularly difficult to implement.  Here's a rough sketch:

A form on the site to accept the email addresses -> that form posts to a controller in your plugin - which stores a record of the product, customer email, and date emailed (date emailed is initially null).

You then have a task that periodically runs and checks these records - for each record, if there is no date emailed, check the stock of the product - if greater than zero, send an email and log when it was sent.


How can I group entries based on a dateTime field?

You're currently grouping on the myDate field, which essentially creates a new array index for each date (e.g. 2016-01-01) which is why you're getting your current output.

To group by year, this should do the trick:

{% for year, entries in entries|group('myDate.year') %}

{{ year }}

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

{% endfor %}


PayPal Currency - Item bag total price does not equal the orders totalPrice, some payment gateways will complain

Luke very helpfully got back to me to sort the problem, but in case it helps anyone else.

The immediate fix is to disable sending the item bag (cart information to PayPal) and using it purely to change the payment amount. But I will attempt to explain in full below.

You disable the cart info being sent to PayPal in your commerce.php settings with:

'sendCartInfoToGateways' => false

Strangely this is the first time we have seen this issue. But it is due to the following in Commerce:

Commerce stores all values in the system in a single base store currency. This means the cart, the discounts, shipping, and anywhere a currency amount is stored is stored as the default base currency.

The payment currency feature is purely designed to allow the charging of the order price in a different currency. The feature allows the customer to know the exact amount to be charged to their card in the currency of their card - without any surprise conversion rate determined by their bank.

Paypal, when it receives the cart information (line item prices etc) is being supplied amounts in that base currency from commerce. Paypal adds up the cart amounts and compares it to the amount that we want to charge the customer in the chosen payment currency. Obviously, the amount we are changing is in the other currency differs from this total.

At first the thought might come as a solution to convert the line items amounts to the other currency for PayPal, but this doesn't work; we do the conversion of the totalPrice of the order for the payment currency feature, and converting each line item and adding them up would usually come up with a different total due to rounding.


Error using environment variable for email setting

I think you're getting a few conventions mixed up.

Using an @ is typically reserved for aliases https://docs.craftcms.com/v3/config/environments.html#using-aliases-in-control-panel-settings

What you're probably looking for is environment variables in your .env file.

You could set:

EMAIL_HOST=myhost
EMAIL_PORT=myport
EMAIL_USERNAME=myusername
EMAIL_PASSWORD=mypassword

Then from Settings->Email in the control panel, you can reference them with $ https://docs.craftcms.com/v3/config/environments.html#control-panel-settings

$EMAIL_HOST
$EMAIL_PORT
$EMAIL_USERNAME
$EMAIL_PASSWORD


Or will I have to write a temporary custom controller action that I can trigger to loop over all entries to redo their slug?

This one.

The plugin could then just use StringHelper::asciiString($slug); to do the ASCII conversion and re-save it back to the database.


So instead of using the dot syntax ., this would be a good place to use the subscript syntax [].

{# dot syntax #}
{{ foo.bar }}

{# subscript syntax #}
{{ foo['bar'] }}

When you use the subscript syntax to access a variable's attributes, you can safely use variables (by just removing the single quotes surrounding the attribute).

{% set bar = 'helloWorld' %}
{{ foo[bar] }}
{# functions just like foo.helloWorld #}

So for your example, you would do this:

{% if block.listImageRatio == '16by9' %}
    {% set imageRatio = 'imageVariants16by9' %}
{% endif %}

{% set optimizedImages = item.itemImage.one()[imageRatio] %}

(Twig docs)


Rendering a template from a controller - unable to find template

Yes I was being dumb....
I wasn't returning the rendered template. Controller should be
public function actionLoadHolidays()
    {
        $request = Craft::$app->request;
        $destination = $request->post('destination');

        $holidays = [];

        $oldMode = Craft::$app->view->getTemplateMode();
        Craft::$app->getView()->setTemplateMode(View::TEMPLATE_MODE_SITE);

        return $this->renderTemplate('how-to-book/holidays-for-destination-options.twig', array(
            'destination' => $destination,
            'holidays' => $holidays
        ));

    }


I recently found that if your deleting an entry on the entries list, you need to use the onBeforePerformAction event. Then break this down, like J Thomas states on this -

Get the type of action and the elements(s) that an action is being performed on when listening to elements.onPerformAction?


Recommended way to organize product types and fields in Craft Commerce

I read and reread #15930 and it suggested that I should create one Product Type for each unique kind of product -- which would be something like:

Product Types

Sewing machine
Chair
Scissor

Each of these product types would then have their own set of fields - some being reused accross all or multiple product types, while some being specific for one product type:

Field Groups

General

Name
Image
Manufacturer
Product Family <-- category
etc.

Sewing machine

Usage area
Machine type
etc.

Thread

Thickness
Material
etc.

Product Family (from General) would be a Category-field that lets me select one or multiple categories that the product would belong to. Product Family would look something like this:

Product Family

Textile

Sewing Machines
Steam pressers

Cabinets
Tables
Dollies
Accessories

etc.

Profiling

Embroidery
T-shirt printers
Laser engraving machines
etc.

I've verified this with Nathaniel Hammon from Pixel & Tonic. He adds that "An added benifit of using categories", what I call Product Family, "is that you are able to use them in conjunction with the promotions (sales & discounts) functionality that is built into Commerce"

Field layout

I went ahead and created the following categories:

General: Product Family
General: Supplier (manufacturer)
General: Intended audience
Sewing Machine: Application
Sewing Machine: Stitch type
Sewing Machine: Type
...

I then created the following field groups:

Product
Sewing Machines
...

Then I created the folloing Product Types (in Commerce):

Other products
Sewing Machines
...

Then I split the field layout for Sewing Machines into two tabs: One for general data, not specifically associated with sewing machines and one for sewing machines specifically:

The general fields come from the general field group and the details-fields come from the Sewing Machine field group.

Final thoughts

I have not yet implemented a filter, like the one in the question. I'll revisit this post and update you when I've progressed.


Successfully installed Craft 3 via Composer but can't access site or admin

On the public_html/index.php file, try replacing

define('CRAFT_BASE_PATH', dirname(__DIR__));

with

define('CRAFT_BASE_PATH', ('/home/pathToCraftFolder/craft'));

The structure of my folders is as follow:

/home/username/
  - public_html, or just html / this is where the content of your web folder goes
  - config
  - modules
  - storage
  - templates
  - vendor
  - (and then the composer/env files)

Then on the index.php file (which can be found under /home/username/public_html/index.php),you'd replace:

 define('CRAFT_BASE_PATH', dirname(__DIR__));

with

 define('CRAFT_BASE_PATH', ('/home/pathToCraftFolder/'));

If you only have access to the public_html folder or would like to install craft3 on a subfolder this is how you can structure it:

on your public_html (/home/username/public_html),
create a craft subfolder((/home/username/public_html/craft)), then send your craft3 web folder into the public_html. It should look like this:

/home/username/public_html/
               -index.php
               -web.config
               -.htaccess
               /craft/

In your index.php file, replace

define('CRAFT_BASE_PATH', dirname(__DIR__));

with

 define('CRAFT_BASE_PATH', ('/home/pathToCraftFolder/craft'));

Hope this helps.


Front End Asset Upload to Custom Element Type not working

I looked into this extensively and the one thing I found is that if your element type uses a custom content table, the save procedure will be done properly but when Craft needs to display the asset in the index, inside an asset selection modal, or an asset field, it simply won't look in the right place and unless you copy your asset's locale and title to the Craft content table from your custom content table, it won't show up.

I've made @Brad aware of this but they haven't fix it yet, at least not in the last release that I can tell.


Cycle outputs plain text, should be html

You can use Twig's "raw" filter to prevent the HTML from being escaped

{{ cycle(['

', '2', '3', '4'], loop.index0)|raw }}


These are simply low level operations you can do to more specifically filter the elements that should be returned. It is generally more common to use them in plugins/modules than in Twig templates, but the use-cases are numerous. A few trivial examples are below.
{{ set entries = craft.entries.where(['authorId', 1]).all() }}

{{ set entries = craft.entries.where(['in', 'authorId', [1, 2, 3]]).all() }}

{{ set entries = craft.entries.where(['>=', 'dateCreated', '2021-01-01']).all() }}

{{ set entries = craft.entries.where(['like', 'title', 'prefix%']).all() }}

Detailed docs for where and other DB query parameters can be found here:
https://www.yiiframework.com/doc/guide/2.0/en/db-query-builder#where


There is a Documentation structured section with three entry types.

Heading Only
Page
Link

The Getting Started, Core Concepts, etc. headers are the Heading Only entry type. The only field is has is a title.

The majority of the docs are using the Page entry type.

The Link entry type is used for the entries like Full Templating Reference and Plugin Development that open into a new window, and those are their own separate structured sections.


I can't think of a way to do this with Twig's replace filter but it is possible to do it by splitting the text into an array and iterating over it like so:

{% set content %}

Duis mollis, est non commodo luctus.

Nulla vitae elit libero, a pharetra augue.

Donec sed odio dui. Maecenas faucibus mollis interdum.

{% endset %}

{% set inserted %}

Inserted text

{% endset %}

{# Split text into array on closing
 tags #}
{% for paragraph in content | split('
') %}
  {# Add the closing tag back, except for possible empty lines  #}
  {% set paragraph = paragraph | trim | length ? paragraph ~ '
' : '' %}
  {# Render the text as raw html #}
  {{ paragraph | raw }}
  {# Render the inserted paragraph on the first loop #}
  {% if loop.index == 1 %}
    {{ inserted }}
  {% endif %}
{% endfor %}

Edit: Per your question in the comment about the context, this is a good use case for a macro. This code is untested, but you might try something like this.

{% macro insertAfterFirstParagraph(content, insertContent) %}
  {% for paragraph in content | split('
') %}
    {% set paragraph = paragraph | trim | length ? paragraph ~ '
' : '' %}
    {{ paragraph | raw }}
    {% if loop.index == 1 %}
      {{ insertContent }}
    {% endif %}
  {% endfor %}
{% endmacro %}

{% from _self import insertAfterFirstParagraph %}

{% set addThisHtml %}

Add this paragraph

{% endset %}

{% set isAdded = false %}
{% for block in entry.myMatrixField %}
  {% if block.type == 'body' and loop.index > 5 and isAdded == false %}
    {{ insertAfterFirstParagraph(block.bodyField, addThisHtml) }}
    {% set isAdded = true %}
  {% else %}
    {{ block.bodyField }}
  {% endif %}
{% endfor %}

Robin's suggestion to build a custom Twig filter in a plugin (or module) would be the cleanest solution, but the Twig code above should get the job done.

Aside: Craft overrides the default Twig replace filter to use PHP's preg_replace() function but that filter doesn't accept the last two optional arguments, limit and count. If it did, then something like this could have worked:

replace('/<\\/p>\\s+?
/', '

', 1)

Maybe a feature request is in order.


How to extend a variable name to fetch another?

There may be other ways also, but one approach is to use an array with key value pairs, which can be assigned and accessed more dynamically.

{{ sizeVars[imgSize ~ 'x2'] }}

You also might want to check out twigs attribute method.

{{ attribute(array, item) }}

Where 'item' can be a concatenated string.


Displaying assets from Craft's cart AJAX response

The cart response definitely does not include direct access to fields on the product.  You will need to make an extra request for the information...of course you'd need to make an extra request for the image itself anyway.

One easy way of implement what you want is to simply update your cart view by ajax instead loading a template into it (rather than targeting values and using the response.cart object).  In that template you would just get the cart as normal, and therefore have access to all the product fields via that as you loop through the lineitems.


How can I time-profile the page load for a Craft request?

If you enable devMode, then database profiling information (number of queries, SQL executed, execution time, etc.) as well as PHP script benchmarking information for the request will be output to your browser's console as well as the craft/storage/runtime/logs files.

  Also, as I understand it, every plugin is loaded on each request

Installed and enabled plugins are initialized on every request.  The only time what you are describing is a problem is if a plugin is doing some time/resource intensive operation in it's init() method, which is generally considered bad form.


How can I perform a RegEx match in Twig?

Currently Twig uses regular expressions only with Comparisons:

{% if string matches '{^[\d\.]+$}' %}
    Do Stuff
{% endif %}

Craft itself currently doesn't have any custom Twig filters or functions either.

But there are third-party plugins which might help you:

Twig PCRE Filters
Low Regex


Retrieving all users with specified permission

I don't think there is a clean or particularly efficient way of doing this using Craft's current services.

It'd have to be something like:

1. Grab all users
2. Loop through them calling craft()->userPermissions->doesUserHavePermission()
3. If true, save user in success array.

Alternatively you could use DbCommand to query the database directly for the info you're looking for.


How to set up a social media feed with vue and axios

It looks like one of two things:

Its possible that you are not actually injecting your accesstokem with the following string

'https://api.instagram.com/v1/tags/search?q=mnbasel&access_token={access-token}'

I believe it should be :

`https://api.instagram.com/v1/tags/search?q=mnbasel&access_token=${access-token}`

If you still get the oauth error, you may need to ensure that your access token has the correct scope in instagrams dev


Can you get only fields marked as required via a plugin?

Your $entry variable – i.e. an instance of EntryModel – has an attribute called fieldLayout, which will return the field layout (FieldLayoutModel) for this entry.

Via the field layout, you can loop over all fields for the entry (each field will be an instance of FieldLayoutFieldModel), checking their required attribute:

// Get all fields for this entry
$fields = $entry->fieldLayout->fields;

// Loop over fields, check required attribute
$requiredFields = array();
foreach ($fields as $fieldModel) {
    if ($fieldModel->required) {
        $requiredFields[] = $fieldModel->field;
    }
}

In the above example, $requiredFields will be an array of required fields, i.e. FieldLayoutFieldModels. If you only need an array of the required attribute names for your entry, you can opt to only store the field handles:

$requiredAttributes = array();
foreach ($fields as $fieldModel) {
    if ($fieldModel->required) {
        $requiredAttributes[] = $fieldModel->field->handle;
    }
}


Is it possible to bcc/cc an admin on every system email?

You can easily do that without any plugin by using a transactional email provider like https://mandrill.com/ or http://sendgrid.com/


Freeform plugin unique submission amount

Looks like there's a Craft 2 plugin that exposes PHP's array_unique method to Twig.

So to continue on the example you linked to, it would be something like this with that plugin installed:

{# Initiate the hash in which we'll store matching submissions. #}
{% set matchingSubmissions = [] %}

{#
    Loop through all submissions, checking if the specified field
    matches the desired value.
#}
{% for submission in submissions if submission.fieldWithValue == '123' %}

    {# If the field matches, add it to the hash #}
    {% set matchingSubmissions = matchingSubmissions|merge([submission.fieldWithValue]) %}

{% endfor %}

{# Count the size of the resulting hash and save it. #}
{% set totalUniques = matchingSubmissions|unique|length %}


Set navigation menu item to active for child pages

Try using:

   {% set pageIsActive = (page.id == entry.id) %}

and then testing for that in your if statements.

This article covers pretty much every eventuality when it comes to classes and navigation and should help you achieve the markup you are after.


Imagemanager plugin doesn't show up in toolbar

The redactor toolbar can be configured in yourprojectfolder\config\redactor\ and you can choose the toolbar type when you configure your Field. By default, there is Standard.json file, where is the image toolbar button. For example, in menu Settings -> Fields create a new Field named Text, set Field Type to Redactor and now you can select in Redactor Config the Standard toolbar. I hope it helps.


ElementCriteriaModel andWhere() with different comparison operators?

You shouldn't need to use nested array syntax, just normal strings should work.

100% untested, but something like this:

if ($criteria->upcomingOnly) {
    $query->andWhere(['or',
            'events.eventStart >= :date',
            'events.eventEnd => :date',
        ],
        [':date' => new DateTime('now')->format('Y-m-d')]
    );
}

(I fixed the missing quote, so no, there is nothing else I would like to add to this post...)


Most user validation happens in UsersService::saveUser(), so restructure your code to this:

$success = craft()->users->saveUser($newUser);

if (!$success)
{
    return $newUser->getErrors();
}

If this is happening in a controller action, you’ll want to make the UserModel available to the original template, so it can access and display those errors.

$success = craft()->users->saveUser($newUser);

if ($success)
{
    // Redirect to whatever URL the 'redirect' param specified
    $this->redirectToPostedUrl($newUser);
}
else
{
    // Make the UserModel available to the original template
    // so it can access the submitted values and validation errors
    craft()->urlManager->setRouteVariables(array(
        'account' => $newUser
    ));
}


I think:

{% redirect "/visit/index?artwork="~workTitle %}


How to change the locals name in Localized Sites

You could add new pseudo localization files to Craft craft/app/framework/i18n/data/ and rename (translate) the name of your "language" and other things in these files.

I'd use en.php as a starting point and save it as en_custom.php. Then add a new key/value pair 'en_custom' => 'My Custom Country' to the languages array (line 205 ff.), which is responsible for the translation of the language names.


You can set the URL format to be anything you want really, just setup your templates and then setup some routes; then it's all going to work automatic for your client and they never have to worry about it.


Query a Supertable using MySQL Stored Function

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

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

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

where GeocodeCalcDistance is my stored function.

et voila!

ANOTHER SOLUTION

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

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

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

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

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


With Craft Commerce, how can I call getAllStates from my own plugin via ajax?

Instead of calling getAllStates() to get the same data back as the twig call:

var states = {{ craft.commerce.statesArray|json_encode|raw }};

Within your plugin you need to call getStatesGroupedByCountries()

MyPlugin.php

if (craft()->request->isAjaxRequest()) {
    return $this->returnJson(['states' => craft()->commerce_states->getStatesGroupedByCountries()]);
}


Frontend form database error with empty Users field

Figured it out. If you want to return an empty Users field, the field name attribute has to look like this:

<select name="fields[teacher]" value="">

But if you want to return a non-empty Users field, the name attribute is different:

<select name="fields[teacher][]" value="{user.id}">

So, I'm starting with the first example, and using an onChange event to switch the name attribute depending on whether the value is a valid user ID or not. Here's my final template code:

{% set teachers = craft.users.group('teachers') %}
<select class="ui search dropdown" name="fields[teacher]" id="teacherselect">
<option value="nA">n/a</option>
{% for teacher in teachers %}
  <option value="{{ teacher.id }}">{{ teacher.name }}</option>
{% endfor %}
</select>

And the jquery if anyone wants it:

($(this).val() == "nA") ? $(this).attr('name', 'fields[teacher]') : $(this).attr('name', 'fields[teacher][]')

This works.


Getting PHP errors to log in Nginx/PHP-FPM

I'm only 80% confident in this answer, but I'm pretty sure that runtime PHP ini_set calls won't work with nginx running with FastCGI (which is what Craft uses to change the error_log path.

Try setting that path directly in your /etc/php5/fpm/php.ini file.


Dedicated channel for news? or a channel for blog with a news category?

Not every website has a 'blog' section. If your site's other content would, for instance, be something completely different like general company info, it would make perfect sense to have a news section.

In case you do have a blog, it would be perfectly possible to delete the 'news' section and give the blog section an entry type called 'news'. That way you would be able to give news entries their own fields, which is convenient.

It's all possible with Craft, so it really is up to you.


That depends on the RTE you're using and what kind of features it supports. With the default Redactor, it should be possible via the configs in craft/config/redactor/ folder.
Peronally I don't think a content-editor should have that ability. This should be handled with classes or different fields/elements. They can really mess up your site.


$event->params['content] will return a ContentModel object.

You can either access specific fields directly, like you found, or loop through them all with ->getAttributes() grabbing the ones you want to save externally.


Showing just the child category titles of a parent

You should actually already have a variable named "category"
pre-assigned by Craft, if you've set up your categories to have URLs in the category settings.

So this simplified code is probably all you need.

{% set subCategories = craft.categories.descendantOf(category) %}

{% if subCategories|length %}

        {% for category in subCategories %}

{{ category.title }}

        {% endfor %}

{% else %}
    {% exit 404 %}
{% endif %}

To have different template code for your sub-category pages you're linking to, I would
put the code above in a partial _partials/mainCategory and include it with the include function.

{% if category.level == 1 %}
    {% include '_partials/mainCategory' %}
{% else %}
    {% include '_partials/subCategory' %}
{% endif %}


You can use CP CSS to accomplish that...

  https://github.com/lindseydiloreto/craft-cpcss


okay, guess I got it.
as soon as I kick the Preparse Field-plugin, everything works smooth. but i guess it's not the plugin that causes the trouble, it's the way craft is writing its logs for deprecated code?

another solution: RTFM..
in Preparse Field-plugin: activate "Disable all Preparse field columns on all element indices".


Is there a way to find out if images (assets) are landscape or portrait?

How about just using the getHeight() and getWidth() methods available on the AssetFileModel? Something like this:

{% set myImage = entry.imagesField.first %}

{% if myImage.getWidth() < myImage.getHeight() %}
  {# portrait #}
{% elseif myImage.getWidth() > myImage.getHeight() %}
  {# landscape #}
{% else %}
  {# square #}
{% endif %}


Creating an .txt file for every entry dynamically

You can write a plugin that listens to the onSaveEntry event.

When that event fires, you can grab any of the data you need for the text file from any of the custom fields and your plugin can write it out to the filesystem at whatever place it needs for JW Player to consume.


The problem is that both onSaveUser and onBeforeSaveUser get fired from UsersService->saveUser() and user group assignment happens in the UsersController->actionSaveUser() after UsersService->saveUser() has already been called.

You should probably be using onBeforeAssignUserToGroups and onAssignUserToGroups instead.


Using Solspace Craft Calendar plugin, how can I get random events within a defined timeframe?

UPDATE: This issue has been fixed as of Calendar 1.8.4 on April 21, 2017.
https://solspace.com/craft/calendar

Your above code should work. I think there might be a bug with the loadOccurrences: false parameter used in conjunction with the limit: 3 parameter. Try increasing the limit to something higher and see if you get results. :)

In the meantime, I've logged this bug and we'll have a bug fix for this in the near future. Sorry for the inconvenience.


Is it possible to change a loop if mobile browser is detected?

You should close your for-tag pair within the {% if ... %}.

So:

{% if craft.request.isMobileBrowser %}
    {% for batch in craft.entries.section('afval')|batch(2) %}
        ...
    {% endfor %}
{% else %}
    {% for batch in craft.entries.section('afval')|batch(3) %}
        ...
    {% endfor %}
{% endif %}

Or, even better:

{% set batch = craft.request.isMobileBrowser ? 2 : 3 %}

{% for batch in craft.entries.section('afval') | batch(batch) %}
    ...
{% endfor %}


In the entries listing (backend), how can I disable the preview button in Craft 3?

You'll want to leave the Entry URI Format field in the section settings blank. That will disable the "world icon" in the entry index as well as the Live Preview and Share buttons on the individual entry edit pages, as well as several other things (for example, there will be no {{ entry.url }} available in the templates).


Show related entries grouped by category with category title and description

Your example is a trifle confusing, but in answer to your general question about grouping entries by a category field, Tim Kelty's groupBy plugin may help.

For example:

{% set groupedEntries = allEntries|groupBy('myCategoryField.title', 'Oddments') %}
{% for categoryTitle, categoryEntries in groupedEntries %}
    <h2>{{ categoryTitle }}</h2>

    {% for categoryEntry in categoryEntries %}
        {{ categoryEntry.title }}
    {% endfor %}
{% endfor %}


Sounds like you need to get in touch with the developers or find some new developers. But run a test purchase for peace of mind anyway.


Dynamic Reply-To In Sprout Forms Notification

It looks like you might need to update your dynamic values. Sprout Forms supports two types of syntax for dynamic information.

1) Shorthand syntax:

{formFieldHandle}

2) Object syntax:

{{ object.formFieldHandle }}

Submitted values from your form entry should be available in all of your notification fields:

Email Recipients
Subject
Sender Name
Sender Email Address (although you probably don't want to set this dynamically as it can affect deliverability)
Reply To Email Address


How do you use a Matrix to toggle between multiple fields from multiple blocks?

Using switch is a good way to handle this, but it looks like your conditionals are just a little off:

{% for block in entry.contentBlock %}
    {% if block.type == 'text' %}
        {{ block.text }}
    {% elseif block.type == 'photo' %}
        {% set photo = block.photo.first() %}
        {% if photo %}

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

The same thing with the switch syntax would be:

{% for block in entry.contentBlock %}

    {% switch block.type %}
        {% case "text" %}
            {{ block.text }}
        {% case "photo" %}
            {% set photo = block.photo.first() %}
            {% if photo %}

            {% endif %}
    {% endswitch %}

{% endfor %}


What are the advantages/disadvantages of the various cloud storage solutions for assets?

Allright, I'll bite. First, I'll get the cost argument out of the way, then I'll cover each type with their specifics.

Costs

Amazon S3: USD 0.03 per GB (up to 1TB, where the price drops as you store more and more data)
Rackspace: USD 0.12 per GB (up to 1TB, where the price drops)
Google Cloud Storage: USD 0.026 per GB (No price reduction for large amounts)

In conclusion - pricing will not be a deciding factor, as the difference, while having a rather noticeable amplitutde, only matter when storing such an absurd amount of data, that the price is the least of your problems.

S3 Specifics

Superb integration with AWS. If you're hosting there, then your choice has been made.
CDN - Amazon Cloud Front is super-easy to set up and is a breeze to use.
Different types of storages available.

Regular
Reduced Redundancy Storage - cheaper, however Amazon guarantees "only" 99.99% durability of data
Glacier - super-cheap storage for archiving. Super long data recovery, though. I'm talking 3 to 5 hours. Also, as Matt Stein pointed out, in some cases, the data retrieval could get super-expensive. (more info, expensive retrieval case)

Supports object versioning (more info)
Cache headers - you can set up cache duration per Assets source for files uploaded to the source via Assets

Rackspace Specifics

CDN built right in - no set-up necessary.
CDN comes at a cost - you can purge only up to 25 files from the CDN per day, so be careful with frequent file changes. (blog post)
Supports object versioning (blog post)

Google Cloud Storage Specifics

Cheapest of them all.
Offers Durable Reduced Availability storage. Cheaper, but stores data on further servers, so the data recovery time is slightly longer.
Cache headers - you can set up cache duration per Assets source for files uploaded to the source via Assets
According to google, CDN is built in at no extra cost. (Google groups post))
Supports object versioning (more info)

Overview

I am biased, I'll admit that, but I've had nothing but joy working with Amazon S3, a lot of frustration working with Rackspace and mixed feelings when it comes to Google. For Google it's mainly of their unbelievably clunky UI, but that might be just me.


ElementCriteriaModel exclude list of ids

This should do the trick:

$idList = [1, 2, 3, 4];
$criteria->id = 'and, not ' . implode(', not ', $idList);

In plain text, the id property would then look like this:

'and, not 1, not 2, not 3, not 4'

The syntax may look a little odd, but it essentially makes Craft compile an SQL query with an AND (elements.id!=$elementId) statement for each ID you want to exclude.


Login - Bad Request: The CSRF token could not be verified

I have exactly the same issue, clearing cookies worked for me


How to integrate custom statuses in a workflow style custom element type?

I looked into this a little bit... It looks like the color of the circles is dependent on one of these CSS classes by default:

.status.live - Green
.status.pending - Orange
.status.expired - Red
.status.disabled - White

I'm assuming (haven't checked this) that the status gets applied to the color dot as a lowercased version of the name. So for example, if you have a status called "Awesome", you would end up with a dot with the class .status.awesome.*

* If I'm mistaken about how this works, anyone is welcome to correct me.

Now that you've got your .status.awesome classes applied to the <span> which produces the color dots, you get to make your own dot! The default versions are pulling from two sprite files... You'll be served up the version which best matches your display:

/app/resources/images/status.png
/app/resources/images/status_2x.png

Since you're not going to be changing anything in the app folder, you'll need to make your own image to represent your dot. One great bonus of this: Your dot doesn't have to be dot shaped! You could just as easily make a star, question mark icon, etc. I'd suggest making both a "regular" and "2x" versions, to stay compliant with the native Craft handling.

Put your new image files into your plugin's resources folder:

/myplugin/resources/images/customstatus.png
/myplugin/resources/images/customstatus_2x.png

Then, you'd reference those in your plugin's CSS:

.status.awesome {
    background: url(/myplugin/resources/images/customstatus.png);
}

The default .status class handles a lot of the generic positioning, so you shouldn't have to override much.

Anyway, most of this is speculative and untested... But let us know if it works out for you!


Entries loop that doesn’t take the status into account?

Short answer

Change this line:

{% for caseStudy in entry.featuredCaseStudies %}

to:

{% for caseStudy in entry.featuredCaseStudies.status(null) %}

Long answer

If “featuredCaseStudies” is an Entries field, then typing entry.featuredCaseStudies will give you an ElementCriteriaModel object, configured to return all of the entries related to entry via that “featuredCaseStudies” field (using the relatedTo param). Just like the ElementCriteriaModel object you get when typing craft.entries, you’re free to chain in additional parameters after entry.featuredCaseStudies.

By default, entry-targetting ElementCriteriaModel objects will only return “live” entries – entries that are enabled, and whose Post Date is in the past, and whose Expiry Date is either not set or set in the future. You can alter that behavior using entries’ status criteria param. Setting it to null tells Craft to not factor entries’ statuses into the query whatsoever, which is what you’re looking for here.