Multi-Environment Configs in CraftCMS 3 I am at the very early stages of using CractCMS but I'm keen to get off to the correct start, writing notes as I go along etc but I cannot figure this issue out.

I have setup the Multi-Environment Configs to allow me to use, dev, staging and production sites, staging and production appear to work correctly but development site is causing issues.

I know it's something to do with the .env file and

ENVIRONMENT="production"

If I change that to

ENVIRONMENT="dev"

The development site will work.

What I can't understand is, both staging and production work so why not development?

I thought by using db.php and general.php I could do away with .env? Other than this line I can.

Here's my General.php code

<?php

return [
// Global settings
'*' => [
    // Default Week Start Day (0 = Sunday, 1 = Monday...)
    'defaultWeekStartDay' => 1,

    // Enable CSRF Protection (recommended)
    'enableCsrfProtection' => true,

    // Whether "index.php" should be visible in URLs
    'omitScriptNameInUrls' => true,

    // Control Panel trigger word
    'cpTrigger' => 'admin',

    // The secure key Craft will use for hashing and encrypting data
    'securityKey' => '*******************************',
],

// Dev environment settings
'dev' => [

    // Base site URL
    'siteUrl' => null,

    'basePath' => '@webroot/cpresources',

    'baseUrl'  => 'https://mydomain.test',
],

// Staging environment settings
'staging' => [
    // Base site URL
    'siteUrl' => null,

    'basePath' => '@webroot/cpresources',

    'baseUrl'  => 'https://staging.mydomain.co.uk',
],

// Production environment settings
'production' => [
    // Base site URL
    'siteUrl' => null,

    'basePath' => '@webroot/cpresources',

    'baseUrl'  => 'https://mydomain.co.uk',
],
];

Here's my db.php code

<?php

return array(
'*' => array(
    'tablePrefix' => '',
    'driver' => 'mysql',
    'schema' => 'public',
),
'dev' => [
    // Base site URL
    'server' => 'localhost',
    'user' => 'myusername',
    'password' => '*************',
    'database' => 'mydatabasename',
],
'staging' => array(
    'server' => 'localhost',
    'user' => 'myusername',
    'password' => '*************',
    'database' => 'craft_cms_staging',
),
'production' => array(
    'server' => 'localhost',
    'user' => 'myusername',
    'password' => '*',
    'database' => 'craft_cms_production',
),
);

Now before anyone says anything about uploading db.php and general.php to git etc because of passwords, I have put both these files in the .gitignore file. I felt this was the best option but if I'm wrong, please explain?

For anyone interested, I had set web/index.php to production.

The reason why both staging and production were working was due to me using the same username and password for the database.

Once I had changed this to dev, it now works so I no longer need the .env file.


Partial Dates within Craft Is it possible to store partial dates? EG i want to create a document that covers a date range, sometimes that range could be Jan/2013 to JUN/2014 other times we may need it more specific EG 20/JAN/2013 to FEB 2014 and sometimes even less specific like 2013-2015.

Would i need to create a new custom field type?

I'd set this up with regular date fields. You can then display the dates in whatever format you require on the front end using Twig's date formatting filter.

With the data stored as dates you can do a lot more with it compared to simply storing strings.

If you need to show a date range, such as "2013-2015" then it would probably be best to use 2 fields. A "date from" and a "date to" field. You could then use some logic to display one, or both, depending on whether there was something in the "date to" field.


Multiple sources on category field type - possible? We're trying to setup a category field type to allow the selection of 1 category but from multiple category sources. Is there a simple way to achieve this without writing a custom plugin / fieldtype?

Currently we've set up 4 Category fields to allow a selection from the 4 sources with instructions to only use one of these fields at a time but it feels messy.  Thanks!

You cannot allow selection from multiple category sources in a category field.

I would keep the 4 category fields but set each field to limit to one (1) category selection.

Then, when you add the field to the field layout, make the field required to ensure they select a category for each field.


Issues using the elements service in console commands I'm having trouble getting the elements service working correctly in a consolecommand. The same code works as expected in a controller, so I expect there is either a bug, or some extra config I'm missing.

<?php
namespace Craft;

class ShoppingCommand extends BaseCommand {

    public function actionListOrders() {
        $c = craft()->elements->getCriteria(ElementType::Entry);
        //$c->locale = craft()->i18n->getPrimarySiteLocale();
        $c->section = 'orders';
        $c->limit = 5;
        foreach($c as $o) {
            print $o->orderId . ": " . $o->title . ", " . $o->price . "\n";
        }
    }
}

running this results in the following

$ ./app/etc/console/yiic shopping listorders
: blah,

running the same action with a Controller in the webapp results in the expected output:

10: blah, 123

Anyone have any ideas if it's possible to get around this? For now I can just build my functionality into a controller, but it would be much more convenient if I could run it from the command line like this.

Also, there is another issue with this relating to the locale. Originally I needed to use the commented out line above because my site's default locale was en where as the consolecommands default to en_us and without forcing the locale my queries were not returning any results at all. I changed my default locale to en_us to test whether the other issue was something to do with the locales as well, but it didn't make a difference.

Cheers

-Tristan

There was a bug in Craft where custom fields weren't being loaded when using the ElementsService in the context of a console command.

Just fixed it for the next (post 2.2.2598) release.

Am I'm not sure I'm following the locale issue.  Can you post that as a separate question with some more clarification?


Twig syntax highlighting in PHPStorm? Does anyone know of a way to instruct PHPStorm to treat Craft templates as Twig files, without globally assigning all .html files to be interpreted as Twig? Since Craft templates don't use the .twig extension, PHPStorm thinks they're HTML.

On that note, why doesn't Craft use .twig extensions? I assume P&T doesn't want to scare away users who are comfortable with HTML but not Twig?

Under the PhpStorm preferences, go Editor->File Types->Twig and add *.html as a Registered Pattern.


Bad Request POST param “redirect” was invalid I'm creating a user profile form on the front-end of our website. I've removed all template code and replaced it with the documentation code from the Craft website. I updated the docs code to reflect fields that we're using, rather than the example fields.

Upon clicking the Save Profile button, the next thing I get is this error:

**Bad Request**

POST param “redirect” was invalid.

I've changed the redirect action input to multiple values, but none work.

I'm running Craft 2.6.3008.

Update: Here's the form:

<form method="post" accept-charset="UTF-8">
    {{ getCsrfInput() }}
    <input type="hidden" name="action" value="users/saveUser">
    <input type="hidden" name="redirect" value="account/profile?m=updated">
    <input type="hidden" name="userId" value="{{ currentUser.id }}">

    First Name
    <input type="text" id="firstName" name="firstName" value="{{ currentUser.firstName }}">

    Last Name
    <input type="text" id="lastName" name="lastName" value="{{ currentUser.lastName }}">

    <input type="submit" value="Save Profile">
</form>

The form is located at account/profile. I'm asking it to return to the same template, just with a parameter appended to the address to verify the form was updated.

UPDATE and final answer: The culprit was having the general config setting validateUnsafeRequestParams => true and not having my redirect value hashed ({{ 'account/profile' | hash }}). I had completely forgotten I had that setting turned on. Mijingo has a good explainer of how this setting works: https://mijingo.com/blog/hashing-redirect-params-in-craft

I'll still use the flash notice below for this particular case, but now I know what this error message comes from.

My goal was that I was trying to redirect the form back to the same template, only with an appended parameter on the URL so I could write an update notice.

I never found out why I got the error, but ultimately it didn't matter as I found a better way of creating that notice through this answer here. Just by adding this to my template.

{% if craft.session.getFlash('notice') == 'User saved.'|t %}

Success message!

{% endif %}


Does "preprod" count as a dev sounding sub-domain? I would like to avoid the licensing error modal on a preproduction environment. Would preprod.random.domain work?

No, it doesn't match anything on the list:

UPDATE
After filing this request, the documentation has been improved to more clearly state that this is, in fact, an exhaustive list.
I have update the screenshot above accordingly.


How can you return elements between two values? I my be in a bit of a "wood for the trees" situation but how is it possible to return elements based on a custom field being between two supplied values.

For example returning users based on a number field. Let's say the number field is between 1 - 100 and I want to return users that have between 5 and 10 selected.

I could do it like the following

$users = craft()->elements->getCriteria(ElementType::User, array("customNumberField"=>array(5,6,7,8,9,10))->find();

However that sets OR

I know that you can use parameters eg "customNumberField"=>"<= 10" but obviously specifying that key twice causes it to be overwritten.

You can also specify an array with the parameters (avoiding the overwriting) like so

 $users = craft()->elements->getCriteria(ElementType::User, array("customNumberField"=>array(">= 5", "<= 10"))->find();

But again this just creates customNumberField >= 5 OR customNumberField <= 10.

Is it possible to use the array as above but tell it to use AND instead of OR?

Am I on the right track or way off?

You’re close! You just need to begin the array with "and":

$criteria = craft()->elements->getCriteria(ElementType::User);
$criteria->customNumberField = array('and', '>=5', '<=10');

$users = $criteria->find();

This same thing could also be accomplished from your templates like this:

{% set users = craft.users.customNumberField('and', '>=5', '<=10') %}


Does Craft support a custom authentication backend for Admin? Scenario:
I want to use Craft to build a community website for an organisation which uses LDAP and Google Apps. I'd like to users to be able to login to Craft Admin via their existing LDAP account (or via Google Apps OAuth, which is easier).

The ideal workflow would be something like this:
1. John Doe is a member of the community and requests access to the Craft site.
2. Admin user logs into Craft and adds John Doe as a new user with his SSO email address
3. John Doe can then login to Craft using his SSO login details (either via a custom front-end form, or directly via Craft admin).

Looking at the available Craft events & hooks, this doesn't seem possible currently without hacking up the Craft internals.

My question: Is there any way to implement this sort of SSO in a modular fashion in Craft? Or, will it require extensive hacking of Craft internals in a 'brittle' fashion?

Cheers,
Sam.

Is there any way to implement this sort of SSO in a modular fashion in Craft?

Yes.

I'm not aware of any LDAP plugin for Craft, yet, but OAuth has already been done (https://dukt.net/craft/oauth).

See here for a bit on how you'd approach it.


Craft 3 Plugin Index No Template Found I'm looking to have a basic index page for my plugin, yet I can't seem to get index.html working for my plugin. But when I head to site.local/admin/plugin it displays 404 Template Not Found

I have the folders set up like so:
plugin/templates/index.html

I've read here that CP templates automatically get set up for this folder so there's no need to define routes for it.

  Plugins get a Control Panel template root added automatically, named
  after the plugin handle, which points to the templates/ folder within
  the plugin’s base source folder.

Am I missing something here?

did you register the routes in your plugin's init() ?


Display entries related to a category (only bottom level) I have a 2 level category system. Some have children, some do not.
How can I display entries related to the last level only?

If a category has no children, it should show the entries related to the 1st level. And if there are children, it should show entries related to that child category only.

The code below currently shows both levels, which I don't want. How can I tell Craft to look for the last (bottom) level only?

{% set entries = craft.entries.relatedTo(category).order('dateYear','comp_opus','title').limit(0) %}
{% for category in craft.categories.group('compositions').relatedTo(entries) %}
    {% for entry in entries.relatedTo(category).limit(7) %}
        {# Do stuff #}
    {% endfor %}
{% endfor %}

You can loop through your top level categories and check if descendants are available. Then collect the relevant category IDs that you can later use to filter the ElementCriteriaModel.

{# Define array before loop #}
{% set bottomLevelCatIds = [] %}

{# Get top level categories only #}
{% set topLevelCats = craft.categories.group('compositions').level(1) %}

{# Loop through categories and collect relevant IDs #}
{% for topLevelCat in topLevelCats %}

    {# Check for child categories #}
    {% if craft.categories.descendantOf(topLevelCat).descendantDist('1')|length %}

        {# Merge child category IDs #}
        {% set 2ndLevelCatIds = craft.categories.descendantOf(topLevelCat).descendantDist('1').ids() %}
        {% set bottomLevelCatIds = bottomLevelCatIds|merge(2ndLevelCatIds) %}

    {% else %}

        {# Merge to level category ID #}
        {% set bottomLevelCatIds = bottomLevelCatIds|merge([topLevelCat.id]) %}

    {% endif %}

{% endfor %}

{# Get the bottom level category models #}
{% set categories = craft.categories.id(bottomLevelCatIds) %}


How to create a faceted search/facet filter in Craft Commerce I want to create these kinds of filters on my Craft Commerce site:

I have poked around with the Faceted Navigation plugin, but haven't gotten it to work the way I want yet (posted an issue about high bandwidth usage) (Fixed in version 1.1.80), and it seems to work nicely- and it's quite fast. However, I wanted to check out 3rd party enterprise search as-a-service.
I also see there is pretty good support for a third party enterprise search service called Algolia through the Scout and Algolia plugins. I have no previous experience with Algolia, but it seems that they should be able to spit out these kinds of filters.
There also seems to be a somewhat abandonned plugin called Search Plus (which I believe stalled at Craft 2.5) and the ElasticSearch-plugin which also seems to be stalled because of a dependency on a YII2->ElasticSearch plugin.
So... should I build my own? NyStudio107 talks about using React with the GraphQL API or the Element API and Webstoemp has an example of building this using Twig.
How would you go about doing this?

Algolia is excellent, and I've found the scout plugin to be solid. Algolia will give you pre-built faceted navigation with instantsearch.js so there is very little development time.

Elastic search comes with the added complexity of running/configuring an ES server, will likely require on-going maintenance.

However if you have the time and don't want to rely on 3rd parties, I would recommend just DIY with twig. If you want it to refresh the listing 'live' you can use Sprig, or htmx.
Basically your filters/facets will be a form that passes a query string to your listing page. Your listing page will then check for the query string and filter accordingly.
An example from a recent project:
{# Get any URL Parameters #}

{% set keywords = craft.app.request.getParam('q')|default(null) %}
{% set kind = craft.app.request.getParam('kind')|default('*') %}
{% set order = craft.app.request.getParam('order')|default('title asc') %}

{# Run the query #}

{% set query = entries
  .search(keywords)
  .kind(kind)
  .orderBy(order)
  .limit(30)
%}

The difficulty will be the UI for sliders etc, but there are plenty of libraries for this kind of thing.


Errors occuring with Assets and Amazon S3 I've just set up a new S3 account and want to move my assets folders there. But when I try to upload a file, I get the following error:

S3::getObjectInfo(mikkelbang, shallowtree.png): [400] Unexpected HTTP status

And the same goes for when I try to update the Assets index:

S3::getBucket(): [InvalidRequest] The authorization mechanism you have provided is not supported.
Please use AWS4-HMAC-SHA256.

I've never used S3 before, so it might be something I need to set up there. But I couldn't find any documentation on setting up S3 with Craft...

There are a few regions that support only S3's v4 of signing requests without the possibility of falling back to v2.  The S3 library that Craft 2 uses only supports S3 v2. Check this table for reference - if it says "Version 4 only" in the last column then that region can't be used in Craft 2.

We're not switching out that library in Craft 2.x, but it won't be a problem in Craft 3, so currently your best bet is to move your bucket to a different region, which also supports S3 v2 signing of requests (any other one, really).


Set Recipient in Sprout Email Notification Okay, so similar issue to this question (Sprout email notifications - setting the recipient?). I must be doing something stupid here because. Trying to set the recipient from an entry form, with a hidden field:

<input type="hidden" name="recipient" value="{{ 'name@address.co.uk'|hash }}">

Then in the control panel, the Recipients field has {recipient}. That should work right, but I don't receive the email. If I manually set an email address in the control panel Recipients field, it works fine.

This is possible with the Sprout Forms Invisible Field (be sure to update to the latest version). Using the Invisible Field will ensure your email address never shows up in the template. To set this up:

1) Add an Invisible Field (invisibleFieldHandle) to your form and set its value to {recipient}

2) Setup a Notification Email and set your Recipient field to the name of your Invisible Field Handle: {invisibleFieldHandle}

3) Before your Sprout Forms displayForm tag, set the value of the Email Address where you want to trigger the Notification Email:

{% do craft.sproutForms.addFieldVariables({
  recipient: 'email@website.com'
}) %}

{% craft.sproutForms.displayForm('contact') %}


Prevent shipping tax from doubling when item qty goes from 1 to 2 in cart So.. it turns out commerce cannot apply tax to base shipping rates, see Calculating (Product + Shipping) + Tax? previously asked on stack.

I then tried setting the tax to a "Per Item Rate" to 99 and the "Maximum Total Shipping Cost" to 99, which I don't want exceeded no matter what. At first this seemed to work fine with a test product (price 5,-), however that was until I increased the qty to 2. The shipping cost for the cart stays at 99, however the shipping cost of the product doubles, which in this case also doubles the cart tax (20.8 to 41.6). This makes no sense to me.

I have attached a video demonstrating what I mean (I get the same result in the demo templates that come with commerce). See video: watch directly on Google Drive

We are just a week away from launch, and I just discovered this issue. Stressing out right now.

Thank you to anyone who can help enlighten me.

Since taxes apply currently only at the line item level, the tax is correctly applying to the item+shipping cost of the line item.

The shipping max cost is making a order level change to the baseShipping after all line items have been adjusted.

We are looking into supporting order level taxes only, to avoid this, and will update this answer soon with a solution.

Thanks.

UPDATE: This has been fixed, see answer here: Craft Commerce: Calculating (Product + Shipping) + Tax?


Register multiple TwigExtensions in one plugin in Craft 3 In my plugins init() function I have this:

Craft::$app->view->registerTwigExtension(new TestTwigExtension());

If I duplicate that and change the Twig Extension class name, I just get an error:

  Class 'marknotton\test\Test2TwigExtension' not found

In Craft 2.x, this worked:

  public function addTwigExtension() {
    Craft::import('plugins.test.twigextensions.test');
    Craft::import('plugins.test.twigextensions.test2');
    return array(
      new test(),
      new test2()
    );
  }

It seems that approach has completely changed. I can't rename any file names, Craft::import doesn't exist anymore, and I can't pass an array into the registerTwigExtension() function. (Craft 3 is scary).

What I'm trying to achieve is a way of organising my Twig Extension files, rather than having everything in one file.

There are several things going on here. This will be a general answer that can hopefully help you move forward. This example will use Sprout Active as a reference and you can see the code here for an example of a plugin that implements multiple, simple Twig Extensions.

Define your Twig Extension class and Namespace

In Craft 3, you can register a Twig Extension (or multiple Twig Extensions) in your Plugins init. While the line to register the Twig Extension is straightforward, there are a lot of other details that matter in your file and I'll comment the code below to highlight why:

<?php

// In Craft 3, each class you create has a namespace. You need to
// make sure that this is referenced in any other classes that use this class
namespace barrelstrength\sproutactive;

// We're referencing the namespaces of other classes in this class too.
// We use the Craft Plugin class, to create our plugin
use craft\base\Plugin;

// You'll create this file next. We need to identify the namespace
// of the Twig Extension we'll be importing so Craft knows where it is
// when we reference `new TwigExtensions()` below
use barrelstrength\sproutactive\twig\TwigExtensions;

class SproutActive extends Plugin
{
    public function init()
    {
        parent::init();

        // Register the Twig Extensions file. We could name this anything
        // and put this anywhere in our folder structure now. As long as
        // we reference the namespace properly above, Craft will be able to
        // find it. We can create multiple Twig Extensions within this
        // TwigExtensions Class or create multiple files to manage our
        // Twig Extensions and import those classes too.
        Craft::$app->view->twig->addExtension(new TwigExtensions());
    }
}

Twig 2 updated several things too

Once we get the extensions loaded, you can create extensions similar to before, however, Craft 3 uses Twig 2 which introduces several breaking changes on it's own. You can see some discussion of the Twig 2 front-end changes in the Craft docs but the docs don't discuss the API changes.

In Twig 2, Twig_SimpleFunction replaces Twig_Function_Method and Twig_Filter_Method so you'll need to update any Craft 2 Twig Extensions code to use Twig_SimpleFunction

In the Sprout Active TwigExtensions Class you can see how the class creates multiple Twig functions within the getFunctions method.

public function getFunctions()
{
    return [
        new \Twig_SimpleFunction('active', [$this, 'getActive']),
        new \Twig_SimpleFunction('activeClass', [$this, 'getActiveClass'], ['is_safe' => ['html']]),
        new \Twig_SimpleFunction('segment', [$this, 'getSegment']),
        new \Twig_SimpleFunction('segmentClass', [$this, 'getSegmentClass'], ['is_safe' => ['html']])
    ];
}


Number of users online / Who is online We have a site that is running event pages, that will show live content (via Ustream or similar). Users have to be reg'd and logged in to view content.

We would like to establish who is online and how many logged in viewers at the time of the event. Is there a function that will display this to admin users?

Thanks
Dan

I have added a prototype plugin that uses Pusher.com to keep track of online users.

Check out the Git repo.

Basically you need to add this to your frontend template:

{{ craft.whosaround.setup }}

It adds the Pusher library, and also subscribes to the channel name you got in your settings. You need to signup to an account over at Pusher.com as well.

In the CP, you can get a rudimentary list with the name and the count.

I can think of some cool use cases, so I'll probably revisit it soon and add more stuff etc., but it might be a useful starting point, depending on if you want to use Pusher for this.

Pusher is a very neat service for use cases like this, and might be especially interesting if you expect many users online.


In Craft 2.5, how can you sort the entry index page by a custom field? I recently updated a very large site to Craft 2.5. One of the great new features is the ability to view custom fields as columns on the entry index page.

Previously, I used the DashCols plugin to view those columns, but DashCols was rendered obsolete by the Craft 2.5 release. However, there was one other feature that DashCols has, which Craft 2.5 doesn't have...

How can you sort by custom fields on the entry index page?

Currently, the only way to add custom fields to the sortable attributes is to write a custom plugin which makes use of the modifyEntrySortableAttributes hook, e.g.:

public function modifyEntrySortableAttributes(&$attributes)
{
    $attributes['yourCustomFieldHandle'] = Craft::t('Label');
    $attributes['anotherCustomField'] = Craft::t('Another label');
}

The modifyEntrySortableAttributes method would go into your plugin's primary class.

Apart from custom fields, it's also possible to add other attributes in this manner, such as authorId (to sort on author) or typeId (to sort on entry type).

It's also possible to remove a sortable attribute:

unset($attributes['postDate']);

There are corresponding hooks for adding sortable attributes to category, asset and user index tables, see the official docs for details.

One gotcha to note is that since the sortable attributes are source agnostic (i.e. they're the same across all sections), any custom field you add to the sortable attributes should ideally exist for all your entry types, as attempting to sort on a custom field that doesn't exist for the entries in the current index table will throw an error.

Moving into opinionated waters here, but to close: While the Customizable Element Indexes (CEI) is a great thing to have in core (and with a brilliant UI), I personally feel there's room for improvement; especially pertaining to sortable attributes. On that note, there are a few relevant feature requests:

http://feedback.craftcms.com/forums/285221-feature-requests/suggestions/7274973-add-a-source-parameter-to-modifyentrysortableattr
http://feedback.craftcms.com/forums/285221-feature-requests/suggestions/10943841-sortable-custom-columns
http://feedback.craftcms.com/forums/285221-feature-requests/suggestions/11533941-sort-filter-entries-by-entry-type
http://feedback.craftcms.com/forums/285221-feature-requests/suggestions/10579029-add-custom-fields-in-customizable-element-indexes

EDIT

I just published a new plugin which will add any (sortable) custom field or meta value in any given element index to the index' sortable attributes:   https://github.com/mmikkel/CpSortableCustomColumns-Craft
The plugin is source aware, so it should avoid the issue with sorting on non-existing fields (as described above) in most cases. Like most Control Panel-specific plugins, it's basically one big hack – but it works until we can have better sorting abilities in core. Hopefully it's useful to someone!


Search result based on a specific field in a related entry in a matrix On this product list page: https://www.alfa.no/shop/skisko/ I need to add a size filter, to only show products that are size 45 for example AND that are in stock.

The structure is built with products and productVariants in separate channels, and productVariants (individual shoe sizes) are added to the product inside a matrix field (colorVariants), with sizes as related productVariants entries to each color. All those words look a little something like this:
https://www.dropbox.com/s/2kyvfxq7xv843v6/Screenshot_2014-10-23_09_53_00.png?dl=0

So what I need in the template is to search for products that have a related productVariant in the colorVariants matrix, matching 45 in the variantSize field AND > 0 in the variantStock field.

I have only come as far as being able to list products that match the size in the matrix, with a way too simple search. It searches for the size in the colorVariants matrix field, but the approach is not targeting specific fields, like stock, in the related productVariants entries in the colorVariants matrix:

{% set filteredProductList = productList.search('colorVariants:45') %}

Yes, you're right to better not use the search parameter for such things.

Instead get all the product variants that match your criteria first (e.g. size, color) and then query for all related products. Be careful with the field parameter, as your relation is between a Matrix field and your product variant entries.

Code is not tested (as you might guess, hehe):

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

{% set sizeParam = craft.request.getParam('size') %}
{% set colorParam = craft.request.getParam('color') %}

{#
 # Get product variants matching our search
 #}

{% set variantParams = {
    section: 'productVariants',
    variantStock: '> 0',
    variantSize: sizeParam,
    variantColor: colorParam,
} %}

{% set variants = craft.entries(variantParams) %}

{#
 # Get the products related to these variants
 #}

{% set productParams = {
    section: 'products',
    relatedTo: [
        'and',
        {
            targetElement: variants,
            field: 'colorVariants.myRelationField',
        },
        {
            targetElement: category,
            field: 'myCategoryRelationField',
        }
    ]
} %}

{% set products = craft.entries(productParams) %}


How should I organize/structure my channel sections? To me, I have a large dataset of 2,000 - 2,400 entries.  It's a static dataset.  I only need to update a few fields annually.

I plan to use channels.   But, how should I organize the channels?

Option 1  The entries can easily be divided between development and production.  Each production entry has a corresponding development entry.  This makes it easy to setup related records. This would result in roughly 1,000 to 1,200 entries in each channel.

Option 2
The entries can also easily be divided between 4 entities.  Entity 1, Entity 2, Entity 3 and Entity 4.   This would result in 4 channels of roughly 500-600 entries per entity.  So, the development and production relationships would exist within in the same channel.  (I think - assume - this does not present any challenges.)

Which channel structure might be easier to build out and manage?

Thanks

Some of this depends on what the content is for each item. If all these pages are essentially the same sort of thing, but they differ in how you're categorising them - it's just one channel, and you can use Categories to organise them. Given that it seems you could categorise your content either by "production / development" and also by "Entity 1 / 2 / 3 / 4" it sounds like you may be better creating two Category Groups ("Entities" and "Status"), then creating a Category Field for each, which you add to your Entry Type.

There's not really enough to go on in terms of what content you have to advise much more clearly than that though.


Front End Entry Form - Proper Syntax for Custom Fields I'm working on a front-end entry form with custom text input fields. From the Entry Form knowledgebase docs, I read "Any custom field handles must be provided in a fields[] array like body is above." On that page their example 'body' field is a textarea field, and when I use this with my own textarea fields it works fine. However I'm having trouble formatting that same logic to make a simple plaintext input field work properly.
My current (non-working) code is:
 <label for="contactName">Contact Name</label>
  {{ input('text', 'contactName', entry.contactName, {
    id: 'contactName',
    name: 'fields[contactName]'
  }) }}

No errors are being thrown when I submit the form, but the values from the plaintext input area are not being saved. What's the proper way to format such that the input values are saved properly?

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'
}) }}


trying to use loop.length with some dynamic css I'm using CSS calc to help make my links the proper width and still account for the margins that separate them. The number of links here will vary between 3 and 5 and I wanted to not have to update my CSS when this changes. The code below works except the code is written after CSS is run and therefore doesn't set the width for the links as I'd want. Is there a way to get this to work using Craft or is this a problem with the way calc works?

{% set contactLinkCSS %}
    {% for block in contactLinks.contactLinks.type("contactLink") %}
        {% set count = 100 / loop.length %}
        .{{ block.contactLinkName | slugify }}:hover {
            width:calc({{ count }}% - 0.625rem);
            background-color: {{ block.contactLinkColor }}
        }
    {% endfor %}
{% endset %}

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


Order twig array by date and time I have a section called "events" in which I have a table field that contains dates and times of these events.

So I want to order my events by date and within each day by time.

I thought of mergin an array that contains only the basic stuff and the Id to output the rest of the entry. (yes! I will cache the template).

This is how far I got, but I am struggling on how to first order by date, and then within a day, by time.

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

{% set dates = [] %}

{% for entry in entries %}
    {% set table = entry.cf_dates_table %}

    {% for row in table if row.startDate %}
        {% set dates = dates|merge(
            [{
                'startDate': row.startDate,
                'startTime': row.startTime|date('G:i'),
                'endTime': row.endTime|date('G:i'),
                'id': entry.id,
                'uniqueId': entry.id ~ '-' ~ loop.index,
            }]
        )%}
    {% endfor %}
{% endfor %}

    {% for date in dates|sort() %}
        {{ date.startDate|date('l, d. F') }} {{ date.startTime }} – {{ date.endTime }}, {{ date.id }}

    {% endfor %}

I could imagine grouping the array by the day and then sort them within each day. But I can't get it to work.

Could somebody point me into the right direction?
Is this a viable approach?

Cheers
Stefan

Thanks to brad I got the whole thing working.
Here's the stripped down code:

{#

    Get all Dates from within the table field in the section veranstaltungen
    ------------------------------------------------------------------------
    We have a section called veranstaltungen with a table field that contains dates and times
    In order to get all occurences of the dates wihin the table field, we first get all of the
    table dates and attach the entry to each table date.
    Then we sort this array (dates) first by day and within a day by time.

    This is a simple Calendar without the need for a plugin.

#}
{% set entries = craft.entries({
    section: 'veranstaltungen',
    with: [
        'cf_veranstaltungs_cat',
        'cf_veranstaltungsDatum_table',
        'cf_veranstaltung_asset',
        'cf_veranstaltungsLinks_table',
        'cf_veranstaltungs_assets',
        'cf_coVeranstalter_user'
    ],

    relatedTo : relation_param,
    authorId: veranstalter_param|trim,

    limit: null
}) %}

{#
    The dates Array will contain all occurences of the entries - we will order it first by date and then by time
#}
{% set dates = [] %}

{% for entry in entries %}

    {% set table = entry.cf_veranstaltungsDatum_table %}

    {% for row in table if row.startDate %}
        {% set dates = dates|merge(
            [{
                'date': row.startDate|date('Y-m-d'),
                'time': row.startTime|date('G'),
                'startDate': row.startDate,
                'startTime': row.startTime|date('G:i'),
                'endTime': row.endTime|date('G:i'),
                'entry': entry,
                'links': entry.cf_veranstaltungsLinks_table,
                'image': entry.cf_veranstaltung_asset,
                'files': entry.cf_veranstaltungs_assets,
                'categories': entry.cf_veranstaltungs_cat ?? null,
                'categoryColor': entry.cf_veranstaltungs_cat[0].cf_veranstaltungsCatColor ?? null,
                'categoryIcon': entry.cf_veranstaltungs_cat[0].cf_veranstaltungsIcon_asset.first.url ?? null,
                'author': entry.author,
                'coVeranstalter': entry.cf_coVeranstalter_user,
                'id': entry.id,
            }]
        ) %}
    {% endfor %}
{% endfor %}

{#
    ------------------------
    Veranstaltungen Listing
    ------------------------
#}

    {% set datesSortedByDay = dates|group('date')|supersort('ksort', 'date') %}
    {% for key, day in datesSortedByDay %}

{{ key|date('l, d. F') }}

        {% for date in day|supersort('sort', 'time') %}
            {% include "veranstaltungen/_common_tableDates" %}
        {% endfor %}
    {% endfor %}

Crazy what you can do with twig!


Structure entry position in url Is it possible to include the entry position (Structure) via the Entry Type Title Format?

This is the current format:

published in {postDate|date('F')} {postDate|date('Y')}

which renders: published-in-april-2018

This is what we need it to render:

number-3-published-in-april-2018

I could create an actual Number field called “numberTitle”, attach it to the Entry Type, and set the Entry Type’s title to be dynamically generated using the template “{numberTitle}”, but why does this need to be done manually?
You would think that the entries in a Section have a natural order in sequence or maybe they don't?

If the EntryVersion Model cannot deliver could Twig offer a solution?

You can include the level

number {level} published in {postDate|date('F')} {postDate|date('Y')}


How to get entries related to current category only (not children) I need to get entries which are only in current category, not child categories.

So if I have a category structured like this:

Food
----Fruit
-------Apples
-------Bananas

I've got a categories template and I'm on the page for the Fruit category I want to know whether there's any entries just in the Fruit category and not all the entries in the Apples and Bananas categories.

Current I'm doing this

 craft.entries.relatedTo(category)

But I'm getting all the entries from the children categories as well, how do I get only the entries related to this specific category not child categories?

Since Apples and Bananas are children of Fruit, all entires that are related to Apples or Bananas are also related to Fruit, which is why you are getting the the results you are getting. If you need to exclude entries related to the subcategories, you can do something like this:

{% set dontInclude = [] %}

{% for child in craft.categories.descendantOf(category) %}
    {% set dontInclude = dontInclude|merge(craft.entries.relatedTo(child).ids) %}
{% endfor %}

{% set str = dontInclude|join(', not ') %}

{% set fruitEntries =  craft.entries({
    relatedTo: category,
    id: 'and, not '~str
}) %}

The above code will loop through Fruit's categories (Apple, Banana) and retrieve all the related entires and merging them into one array. Using the expanded craft.entries, you can exclude the entries related to Apple or Banana using the id: 'and, not' code. Hope this helps!


Can we use Active Directory for Access Control? We have a quite elaborate set up for Active Directory, and would like to use this to provision & deprovision access to the Control Panel. Would this be possible in Craft core or in a plugin? Are there hooks to use alternative access methods?

No, this is not available in the core. There is a plugin which deals with OAuth which may help you.

You can view a list of hooks which Craft provides out of the box here.

I imagine you will need to develop your own plugin for this. There is some guidance in the Craft documentation on creating hooks/events in a custom plugin if that's the route you'd prefer go down.


Craft 3 – Render template as if it were a site request I have a Craft 3 plugin that renders a portion of an entry after save in order to index the resulting information. The plugin needs full access to the Twig extensions on the site to render the template, however several plugins that add such extensions check:

if( Craft::$app->getRequest()->getIsSiteRequest() )

As a result not all Twig extensions load when renderTemplate is called from the control panel. I set the template mode using:

Craft::$app->getView()->setTemplateMode(View::TEMPLATE_MODE_SITE)

but that only updates the path to the template. Is it possible to render the template as if it were a site request?

I suspect not without manually manipulating the path before the Request class is initialised.

One possible alternative solution would be to use Guzzle to call the front-end URL rather than the CP URL, which will render the template with getIsSiteRequest set to true, for example:

$client = new \GuzzleHttp\Client();
$response = $client->request('get', 'http://url/front-end-template');
$body = $response->getBody();

It would also be possible to create your own controller which fetches the template and to hit it with a front-end action request:

$response = $client->request('get', 'http://url/actions/plugin/controller/action');


How to use paginate with a date filter? Assuming that I’ve a total number of 10 entries in my section('exhibitions') where 8 of them have their entry.endingDate < now, I limit the display to 8 entries but the paginate shows a next button whereas the next page is empty:

{% paginate craft.entries.section('exhibitions').limit(8) as pastExhibitions %}
    {% for entry in pastExhibitions %}
        {% if entry.endingDate < now %}
            …
        {% endif %}
    {% endfor %}

    {% if paginate.prevUrl %}
        &larr; Précédent
    {% endif %}
    {% if paginate.nextUrl %}
        Suivant &rarr;
    {% endif %}

{% endpaginate %}

How can I add a date filter, in this case < now, to the paginate configuration in order to only paginate on entries that are < now?

{% paginate craft.entries.section('exhibitions').endingDate('< ' ~ now).limit(8) as pastExhibitions %}
  ...
{% endpaginate %}

This will paginate the entries in section exhibiitions with endingDate < now. That ~ is string concatination operator. The string '< 2014-08-04' queries for entries with endingDate in the past.


Difference between chained and batch element queries? I apologize if this has been asked or addressed already, but I have a question concerning Element Queries. The docs show two possible ways:

Chained Methods

{% set query = craft.entries()
    .section('news')
    .limit(10) %}

Batch-set Parameters

{% set query = craft.entries({
    section: 'news',
    limit: 10
}) %}

The examples shown above (from the docs) obviously accomplish the exact same thing--but what is the difference, if any?

It is my assumption that the batch-set way of querying elements allows for more options, is that true? And does either way have an effect on performance?

general

The first way creates an object of type EntryQuery, you then call the 2 functions section and limit

In PHP you would do the following:

$query = Entry::find()->section('news')->limit(10);

The second creates an array section => 'news', 'limit' => 10 you then call Yii2::configure($query, $array) with your EntryQuery which does:

public static function configure($object, $properties)
{
    foreach ($properties as $name => $value) {
        $object->$name = $value;
    }

    return $object;
}

Thus you don't call functions but define the properties directly. In PHP it would look like

$query = Entry::find();
Craft::configure($query, ['section' => 'news', 'limit' => 10]);

Performance

Because of the above it's important what you do. The first way calls functions the second way calls properties.

As for your comparison the first way is a little bit faster because you didn't attach functions that requires the use of magic methods => __call (in the ElementQueryBehavior) as soon as you search/filter for custom fields the Craft::configure way will always be a little bit faster because it can set the values directly instead of using the resource heavy __call function

For example:

// faster
$query = Entry::find()
    ->section('news')
    ->limit(10)

// slower
$query = Entry::find();
Craft::configure($query, [
    'section' => 'news',
    'limit' => 10
]);

Against

// slower
$query = Entry::find()
    ->section('news')
    ->limit(10)
    ->multiselect('test')
    ->subline('foo');

// faster
$query = Entry::find();
Craft::configure($query, [
    'section' => 'news',
    'limit' => 10,
    'multiselect' => 'test',
    'subline' => 'foo'
]);

Conclusion

Keep in mind when I say "slower" or "faster" I'm talking about a few milliseconds (when I run the last example 1000 times its 511ms vs 497ms) so in the end it does not really matter. If it's really important in terms of speed: as soon as you use the __call method because you need to change properties in the ElementQueryBehavior you would prefer to use Craft::configure.

Besides that: there is absolutely no difference between those two.. There are no hidden "benefits" you don't have more options, you can't do something "better"


Plugin Variable can't find template I'm new to Craft template development and one of the first things I'm trying to do is create a Variable that renders a template into the template its called from.

My directory structure looks like this:

/craft
  /plugins
    /test
      /templates
        _headers.html
      /variables
        TestVariable.php

Here is the Variable:

<?php

namespace Craft;

class TestVariable
{
    /**
     * Get header for test code
     *
     * @return string
     */
    public function headers()
    {
        return craft()->templates->render('test/_headers');
    }
}

And I'm calling it in the template with a simple: {{ craft.test.headers }}

My template is erroring with Unable to find the template “test/_headers”.

What am I misunderstanding here?

Just added this note to the Plugin Templates documentation, which should answer your question:

  Craft will only automatically look for templates within the plugin folders for CP requests. If you are going to be calling TemplatesService::render() from a front end site request, you will need to manually tell Craft where to find your template using PathService::setTemplatesPath() first:

$oldPath = craft()->path->getTemplatesPath();
$newPath = craft()->path->getPluginsPath().'pluginHandle/templates';
craft()->path->setTemplatesPath($newPath)
$html = craft()->templates->render('path/to/template');
craft()->path->setTemplatesPath($oldPath);

  If you do this, you won’t be needing to begin the template path with your plugin handle.


Email notification on field value change? Currently, I have the need to get an email notification, only when a particular field(s) have changed value. In my use case, a few light switches. Is there currently any way to get notified of this?

Sprout Email allows you to create Custom Events where you could add a new rule that allows a user to set the options needed to meet your use case.

Additionally, the entire EntryModel will be handed off to the Notification when your Custom Event fires, so you could have logic in your notification template that sends customized messages depending on the different conditions that were met, just like in any other Twig template.


Remove page link from navigation Trying to output navigation:

Home
About
Services

Sub 1
Sub 2
Sub 3

List item
Testimonials
Contact
Get Quote

I'd like to remove the link to the Services page, preferably to  and if accessed through url, redirect to homepage.

Here's how I'm currently outputting nav:

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

        {# Output the sub menu #}

Home

            {% set entry = craft.entries.slug('about').first %}

{{ entry.title }}

            {% nav page in pageItems %}

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

                {% ifchildren %}

                        {% children %}

                {% endifchildren %}

            {% endnav %}

            {% set entry = craft.entries.slug('testimonials').first %}

{{ entry.title }}

            {% set entry = craft.entries.slug('contact').first %}

{{ entry.title }}

            {% set entry = craft.entries.slug('get-a-quote').first %}

{{ entry.title }}

Any help is much appreciated. Thanks in advance.

There are two very different questions here, but I will try my best to answer them both!

The first being "How do I hide a page from the navigation?"

The simplest way I can think of for this, that is also controllable through Craft, is to create a simple "Hide from navigation" Lightswitch field, and add this to your entry types.

When looping through entries for the navigation, you can check whether the lightswitch has been checked, and if it has, don't show that entry in the nav:

{% for entry in craft.entries.section('lorem').hideFromNavigation(0) %}
    --
{% endfor %}

The second question is "How do I redirect to the homepage if someone visits /services?"

This can be achieved with the redirect tag. In your services/index.twig template file, you can simply add:

{% redirect siteUrl %}


Best Caching strategy Part of our go live process is to put caching in place for the site. It is a great feature. But I am unsure on the best strategy, not from a technical perspective but from a non-technical cms editor perspective...

For example, we usually setup the cache on the header and footer includes on our templates. I like to set it up for 1 hour, that way it will clear reasonably often. That way if the editor changes some header or footer markup they just need to wait an hour for the new content to appear. Which brings me to the issue, our cms editors find this all a bit confusing, they are never sure what will be cached and what won't, if you show them how to clear the cache they end up doing it almost every edit just to be sure. Or they make edits and when it doesn't look they way they want they think it must be the cache and leave it looking odd for days before they admit something must be wrong.

So how do other people deal with this? I am thinking we might write a plugin to clear the entire cache on any entry save or structure modification. But this seems a bit crude.

I am by no means a caching expert, but here's what I do know...

When you wrap a chunk of Twig code in a cache tag, it processes that chunk of code all the way down to HTML, then stores that HTML in the database. A cache key references this pre-parsed HTML code, so it can be easily called up later.

But in addition to the HTML itself, two other pieces of data are stored alongside it:

A list of criteria used to generate the HTML
A list of elements used to generate the HTML

The main reason that criteria and elements are also recorded is for the purpose of cache invalidation... So for example, if someone were to change an element associated with a cached chunk, that chunk would immediately become invalidated. You wouldn't need to write a separate plugin in that case, the cache would be invalidated simply by updating a corresponding element. Something similar happens to criteria, if the criteria results would have changed.

Check out this question which I asked awhile ago... It goes into greater depth about the related caching tables, and how they work together to make sure your cache stays fresh.

Also, make sure you've reviewed the official recommendations about the proper usage of cache tags, to figure out the best times to use (and not to use) the tag.

Lastly, I'd recommend taking the time to watch this excellent video from Barrel Strength Design about the wonders of the cache tag. There is a lot to be learned from that video, and it's a great way to get your bearings on caching in general.


Setting cookies from CTA before directing to url? I need to set some cookies based on some CTA button links. I will later be checking for these cookies to determine what content to display on the entry with the cta on the next visit and other entries etc. Seems like I would need to set the cookie via javascript on click event and then direct them to the url they clicked, anyone know of a way to do this without javascript and have an event handler for the cta clicks?

One option would be to set a query string on your cta urls, have your template look for that, and change your content accordingly.

You can't set a cookie in Twig directly but there's a few plugins to help you out, like the handy LJ Cookies.

So on your CTA you might do something like:

Buy now!

Then in the template it links to:

{% if craft.request.getParam('cta') is not empty and craft.request.getParam('cta') == "button2" %}
    {# set the cookie #}
    {% do craft.lj_cookies.set('ctabuttonclicked', 'button2') %}
{% endif %}

To check for the cookie later on:

{% if craft.lj_cookies.get( 'ctabuttonclicked' ) == 'button2' %}
 .. do something ...
{% endif %}

As a quick aside, depending on how you want to track things, you may want to throw in a quick redirect to dump the query string off the URL before you spit out the subsequent page. Something like:

{% if craft.request.getParam('cta') is not empty and craft.request.getParam('cta') == "button2" %}
    {# set the cookie #}
    {% do craft.lj_cookies.set('ctabuttonclicked', 'button2') %}

    {# redirect to the same page but dump the query string#}
    {%redirect entry.getUrl() %}
{% endif %}

But it really depends on your campaign and how you want that content shared and consumed.

(Just a quick example: if someone hits your CTA from an e-mail you sent and really likes what they see and posts that link with the special query string to all their friends on Facebook, everyone is going to get that event cookie set and those deals, for better or worse.  It could also piss people off if you don't have it... "What? I don't see those deals you sent me..." But that's a can of worms for another time...)


Having a plugin trigger on entries.onSaveEntry if a Lightswitch is turned on Essentially I want the plugin to trigger on entries.onSaveEntry which I have working fine at the moment. I want to add a Lightswitch field that will be a condition however. i.e. The plugin will only trigger on save if the Lightswitch entry is turned on.

However I'm having trouble finding use of how to get the status of a field (specifically Lightswitch). Is that data available to be in $event->params['entry']?

Thank you.

Yes, it's available in $event->params['entry'].

$entry = $event->params['entry'];
if ($entry->myLightswitch) {
    // do things
}


Convert a PHP image resource to a new Asset I am trying to merge two images and save it as a new asset and I am using the PHP function called "imagecopymerge" (https://www.php.net/manual/en/function.imagecopymerge.php) however thats returning a "resource" and I have tried figuring out how I can turn that "resource" into something I can use to save using perhaps $tempath?

$newAsset = new Asset();
$newAsset->avoidFilenameConflicts = true;
$newAsset->setScenario(Asset::SCENARIO_CREATE);
$newAsset->tempFilePath = $tempPath;
Craft::$app->getElements()->saveElement($newAsset);

You'll need to save the image to the filesystem and use that path as $tempPath.

https://www.php.net/manual/en/image.examples.merged-watermark.php


Troubleshooting paginated content cached globally Looks like caching paginated content globally forces any following pages (p2,p3, etc) to just echo the same content as the first page. Using a regular cache tag works as desired, but I don't want to cache the same content across all locales, nor generate new cache any time the same template is accessed through one of the several locales. Has anyone run into this? Is this a problem or am I confusing the functionality of the cache globally tag?

I ran into this today. I thought craft.request.path used to include the pagination page number but it doesn't appear to anymore. Maybe it was always like this though.

Regardless, this is how I'm now handling it:

{% cache globally using key craft.request.path ~ '/p' ~ craft.request.getPageNum %}
...
{% endcache %}


Hide or obfuscate Digital Product file path? What's the best way to hide the URL from the user/browser task bar? The only way I can get the link to work for a customer is to select the "Assets have public URL", which I really would prefer not to.

Even though the link to the files are on a protected My Downloads page surrounded by If License, it wouldn't be hard for a knowledgeable internet user to start guessing other file paths. I already have the filenames closely related, but not exact to the product title and the products are in a subfolder by entry id.

A preferred way would be to have the product file directory be above the web root, but I can't seem to find any way to do that with the plugin as it is. Am I missing something?

I suppose I could just make my download folder a string of 30 random characters so at least you can't see the full URL in the bottom of a browser as it would get cut off. But a smart user could still copy the link to the clipboard.

I see there is the Internal Assets plugin that looks to do what I want, but it's based on User Permissions. So I assume I would have to write a plugin that assigns a user permission to a file once they get a license generated, but it would be nice to have that feature be a part of the Digital Products itself.

Any other options?

Well, I figured out a way to do this. This works.

{% set file = variant.songFile.one() %}
{% if file %}
  <form method="post" target="_blank">
    {{ getCsrfInput() }}
    <input type="hidden" name="action" value="assets/download-asset" />
    <input type="hidden" name="assetId" value="{{ file.id }}" />
    <input type="submit" value="Download" />
  </form>
{% endif %}

Courtesy of this old answer: https://craftcms.stackexchange.com/a/22850


Is the 'find and replace' feature (found in the control panel settings screen) documented? I see the feature, but would like to read about what and where it finds before replacing.

There's a short description of what it does in the 2.0 release notes.

  Added a new Find and Replace tool in Settings, for finding/replacing text within all Rich/Plain Text fields (including ones in a Matrix field).


CP search for entries where a specific field is empty In the control panel, is it possible to search for entries where a specific field is empty? The Craft search syntax page doesn't help here, and the logical values used in twig don't seem to work here. I haven't been able to find any other info about this either.

Side note: the search syntax is a bit out of reach for many non-dev users (read clients). An advanced search/filter form for entries would be awesome.

We use Zenbu for this exact thing. As we're importing a lot of data, we need to find which entries are missing data - https://zenbustudio.com/software/zenbu-craftcms


Modifying Slug on FeedMe Import I have the following Module loaded into my system, following the Event's on the FeedMe documentation I've implemented the following to change the slug per entry import but unfortunately, it's returning a strange error that I just can't fix.

Here's the module:

<?php

namespace modules;

use Craft;

use craft\feedme\base\Element;
use craft\feedme\events\ElementEvent;
use craft\feedme\services\Process;
use craft\feedme\events\FeedProcessEvent;

use yii\base\Event;

use craft\helpers\ElementHelper;
use craft\elements\Category;
use craft\elements\Entry;

class TitleChangerModule extends Module
{
    public function init()
    {
        parent::init();
        Event::on(
          Process::class,
          Process::EVENT_STEP_BEFORE_ELEMENT_SAVE,
          function(FeedProcessEvent $event) {
            switch($event->feed['name']){
                case 'merchants':
                    $element = $event->element;
                    $element->slug = ElementHelper::createSlug($element->title.' '.'Coupon Codes & Promo Codes');
                    break;
            }
        });
    } // Close Public Function
} // Close Module Off

It returns the following error on each import via the feedme logs.

  Class 'craft\feedme\base\ElementEvent' not found - Element.php: 58

There is a PR to fix this, in the meantime, you can add use craft\feedme\events\ElementEvent; at the top of vendor/craftcms/feed-me/src/base/Element.php


Limit characters in redactor wysiwyg field I'm trying to limit the amount of characters by adding the 'limiter' plugin to the redactor field which can be found here:

http://imperavi.com/redactor/plugins/limiter/

I've added the limiter.js file to my /craft/app/resources/lib/redactor/plugins folder.

Next I changed the Standard.json in /craft/config/redactor/Standard.json to

{
 focus: true,
 limiter: 20,
 buttons: ['html','formatting','bold','italic','unorderedlist','orderedlist','link','image','video'],
 plugins: ['fullscreen','limiter'],
 toolbarFixedBox: true
}

Unfortunately it doesn't work. Anybody a good suggestion how I can fix this easily. Thanks!

You have to add the JS with a Craft plugin, either a custom one making use of includeJsResource (see this answer for code example) or with the Control Panel JS plugin.


Is it possible to change the default text for a Charge plugin checkout button I'm trying to set up a simple subscription based site using the Awesome Charge plugin and am wondering if I can change the button text using Stripe Checkout.

There doesn't seem to be any documentation around Checkout Options on the Squarebit site that indicates I can pass a value, through the options list, that changes the text 'Pay with card' to something else.

I understand I could customise the whole process using the Strip.js method but was hoping to just use the out of the box version.

Thanks.

Developer of Charge here.

Yes - you absolutely can control the label generated for the checkout button.

When setting the details for the checkout option, you just need to pass a sub-array called checkout, along with the extra parameters that get passed straight down the modal js.

Specifically you'd want do some thing like this :

{% set options = {
    planAmount : 99.99,
    description : 'This is an optional description for the modal',
    checkout : {
        name: 'Company Name ltd.',
        image: 'https://s3.amazonaws.com/stripe-uploads/hSYxIZGM3U0DbmPKsJszRHm3OU3D4CtHmerchant-icon-641868-add-on-icon.png',
        label: 'Pay with Stripe Checkout'
    }
 } %}

 {{ craft.charge.setCheckoutOptions(options) }}

In that above example you can see we're passing values for name, image and label to the Checkout modal.

That'll return a button that looks something like this :

The full details of all the configuration options you can pass through to the checkout modal are detailed in the Stripe Checkout documentation. Just pass the values you want within that checkout array in the twig.

NB. We're working on updating the docs on this usage right now, and they'll be up shortly too here


Trying to achieve a row column layout with batch I tried to code an output in twig that should look the following ( 2 columns in one row), i figured that i will need the batch function

Content

Content

Content

Content

My attempt is :

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

    {% for block in row %}

Content

    {% endfor %}

 {% endfor %}

but it doesn't work like that, i looked it up in the twig documentation, the error from craft i get is "Variable "row" does not exist", so i tried changing it to {% for entry in block %} but that doesn't work either.

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

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

   {% for block in row %}

Content

   {% endfor %}

{% endfor %}

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


Entries Fields inside a Neo Field I have again some trouble with a Neo field.

I've a Neo field with different layouts. In one I will output content from some entries with a entries field.

The problem is: Sometimes I get output, sometimes I get only some of the selected entries as output and sometimes I don't get any output.

Here is my code:

{% nav block in entry.myContent.level(1) %}
    {% switch block.type.handle %}

        {% case 'team' %}

                    {% include "_includes/elements/teamGetMember" %}

    {% endswitch %}
{% endnav %}

And here is the call of the entries field

{% set entries = entry.teamGetEntres %}

{% if entries | length %}
    {% for entry in entries %}

{{ entry.description }}

    {% endfor %}
{% endif %}

So it should be:

{% set entries = block.teamGetEntres %}
 {% if entries | length %}
  {% for entry in entries %}

{{ entry.description }}

  {% endfor %}
{% endif %}

replace "entry" in entry.teamGetEntries with "block"


Dates Expiring By Custom Field date_modify Can I somehow set the expiration date of an entry based on a custom-field. I ask this because I don't want the site-owner to have to manually set the expiration date (for multiple reasons)but they are setting a 'start' date in a custom field. I am currently outputting entries and limiting them by doing this:

{% for event in entries %}
                    {% set count = 0 %}
                    {% if count < 5 and event.dateTime|date_modify('tomorrow 5am')|date('U') > now|date('U') %}

It would be really fantastic though if i was able to use that same date_modify to expire the entry and remove the entries from the loop all-together due to being expired.

You could write a fairly simple plugin to automatically set the expiration based off of another field value or calculation.

In your plugin's main file:

public function init() {

    parent::init();

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

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

        if ($entry->section == 'Events') {

            if (empty($entry->expiryDate)) {
                $date = new DateTime($entry->dateTime);
                $modifiedDate = date_modify($date, 'tomorrow 5am');
                $entry->expiryDate = $modifiedDate;
                craft()->entries->saveEntry($entry);
            }

        }

    });

}

Updated Code fixed syntax errors and added a check to see if expiration date is already set, otherwise created an endless loop (and may overwrite a manual setting).


CP Asset thumbnails delivered by PHP When listing entries with lots of assets (and therefore thumbnails), the server slows down significantly.

I realized, that the assets all have the path:
https://mypage.url/index.php?p=admin/actions/assets/thumb&uid=a59e2c6f-1d32-4568-ab34-8655d33427d8&width=30&height=30&v=1559381105. However, I thought they were located in the cpresources folder?

Is there a way to make Craft use direct links to the thumbnails instead of using PHP to deliver the images?

Not everything in the Control Panel gets published to the cpresources folder, especially things like dynamically generated images (thumbnails are basically just image transforms).

  Is there a way to make Craft use direct links to the thumbnails instead of using PHP to deliver the images?

Not currently.


contactform.php messing up site I've tried creating a contactform.php file with the P&T Contact Form plugin and using the code in the documentation to be able to programmatically add recipients. However, when I use this code:

<?php
    namespace Craft;

    $toEmail = craft()->request->getPost('toEmail');
    $toEmail = craft()->security->validateData($toEmail);

    return array(
        'toEmail' => ($toEmail ?: null),
        ...
    );

I end up getting a white screen of death and a 500 Internal Server Error. I don't know why it's doing this, I tried editing the permissions of my craft folder and the contactform.php file, but nothing has worked and I keep getting a white screen.

How can I fix this?
Thanks!

The problem is the ... in your contactform.php file.

The docs use it because they assume you might have some other valid config settings you want to include in that config file, but it's not real code, which is why PHP is choking on it.

Remove the ... and you should be set.


Successful login with 'requireLogin' redirects to 404.shtml I have recently migrated an intranet to its production environment, and the requireLogin is misbehaving:

I'd go to intranet.example.com/
Log in with my details
Craft will redirect me to intranet.example.com/404.shtml, showing 'Layout file - This content should not be seen.'

this page doesn't exist, and I can't find any reference to 404.shtml on any page.

If I reload intranet.example.com/, it will show me the homepage, logged in. It works fine after that
I can log out and in again, it will work fine. I need to log out, close the browser and log in again to replicate the error

I have no redirects or have changed anything on the Craft config. Basically is a default 2.5 installation with new templates.

It works fine both locally (MAMP) and on my dev environment, but not on the server I just migrated it to.

I checked the http headers, and apparently my server was redirecting to a 404 page because the favicon.ico was missing.

As soon as I uploaded one it all worked fine again.


How to include Inline JavaScript? Is there any way to add javascript in craft

You can use {% js %} Twig tag.
It is essential to using JS in Twig. It takes JS code passed to it and appends it at end of the template, right before ending body tag. Multiple js tags can be used - content from each of them will be concated with the rest. You don't need to wrap code passed to {% js %} into <script> tags - js will do that for you.
{% js %}
    console.log('Hello World');
    /* you can add your js code here */
{% endjs %}


Getting entries related to current entries categories Trying to get 10 entries related to the current entry categories excluding a category called featured. I don't have the category name(s) in the url.

This currently what I tried but this does not work, confused about how to do this.

{# Fetch all of the categories related to this entry excluding the featured category#}
{% set categories = craft.categories.relatedTo(entry) %}

{# Output them #}
{% set thecategory = [] %}

{% for category in categories %}
    {% set thecategory = craft.categories.group('resource').slug(category.slug) %}
{% endfor %}

{# Set featured category name to exclude #}
{% set category = craft.categories.group('resource').title('featured') %}
{# Set featured ID's we dont want to show... #}
{% set featuredArticleIds = craft.entries.section('articles').relatedTo(category).ids() %}
{% set featuredArticleIdsString = featuredArticleIds | join(', not ') %}

{% set entries = craft.entries.section(articles).relatedTo('and', thecategory|join(',')).id('and, not '~featuredArticleIdsString).limit(10) %}

This solution should also remove your "featured" category entries:

{% set categories = craft.categories.relatedTo(entry) %}
{% set featuredCategory = craft.categories.slug('featured').first() %}

{% set allIds = [] %}
{% for id in categories.ids() if id != featuredCategory.id %}
    {% set allIds = allIds|merge([id]) %}
{% endfor %}

{% set entries = craft.entries.relatedTo(allIds) %}


RelatedTo with users The RelatedTo function keeps puzzeling me. I got it working with categories, but now I want to do something in reverse with users. But I don't fully understand the RelatedTo function.

I have a channel called "downloads". I also have some users in the back-end. I have added a custom field to the user section called "selectDownloads". This field is a relatedEntry field where the admin can select entries from the downloads channel.
Now I want to list all downloads in my template that the current logged in user may see (so the entries that were selected when creating the user).

I read the docs multiple times allready and with some luck and trial and error I got it working on categories. But there I loop through all my products and relate them to a targetSource which is my category by a field that is part of my products channel.
In this case however, I want to loop through all my downloads, related to a field that is part of my users section (instead of my downloads channel). So the relation is different.

A more dummy proof explanation with some examples of the RelatedTo function would be welcome. I never know which elements I should address:

 {% set ingredients = craft.entries.section('ingredients').relatedTo({
     sourceElement: cocktail,
     field: 'ingredients' }) %}

sourceElement or targetElement:

Is this a section or field you have to give in?

field:

Is that a field from the ingredients section or the cocktail section?

You can just use:

{% for entry in craft.entries.section('downloads').relatedTo(currentUser) %}
    {{ entry.title }}
{% endif %}

This is essentially returning an ElementCriteriaModel of reverse related entries sorted by entry date by default. You can also access the related entries through the field itself:

{% for entry in currentUser.selectDownloads %}
    {{ entry.title }}
{% endif %}

This will loop through the related entries in the order they are sorted in the CP.

But to answer your other questions. sourceElement and targetElement can be elements of any element type: entry, category, asset, user, globalSet, tag, etc are all elements. sourceElement simply refers to which is the source of the relationship; and targetElement is what it's related to. field further specifies that you only want to match a specific field rather than using any relationship defined in any field (if you have 2 or more entries fields defined in a channel that are used for different purposes for example).


Locale case sensititvity on AWS instance I have a multilingual Craft CMS site working perfectly on my local instance, OS X 10.10.5 running Apache 2.4.16, and so I moved the site to AWS, Amazon Linux 4.1.13-18.26.amzn1.x86_64 also running Apache 2.4.16, however, all of my locales are now case sensitive!

On my local I have
http://<site>/en_us/page
on AWS this gives me an error, The requested URL /en_us/page was not found on this server., a hard 404. [i.e. not the templated 404 page I have configured in craft for missing content]

However, when I use http://<site>/en_US/page, i.e. using the ISO standard capitalisation for the country code, I get all of the content perfectly fine. All of my links, and configuration, is of course based upon the lowercase way that Craft normally uses locales, and so the links are all broken on AWS.

I have also noticed that the CP URL is using a querystring on AWS instead of rewriting; i.e. /en_US/index.php?p=admin/settings/locales instead of en_us/admin/settings/locales [which may be a related issue]

As the rewriting for the CMS works, /en_US/page actually gets the right template and content, I am puzzled as to what I may have missed in configuring my AWS instance.

Has anyone seen anything like this, or have some pointers?

Oh, I am blind.

Rather than delete this embarrassment, I will post this mea culpa for anyone else that may experience a similar brain fart.

I had subconsciously typed the directories in html/ using the common POSIX/ISO standard without realising it, so html\en_US\. Of course, this works on OS X because the OS is case insensitive by default, and does not on Linux, because it is case sensitive. Renaming to all lowercase solved it.

As for the CP rewrites, it was simply that Craft was not picking up that rewrite was correctly enabled. Simply adding omitScriptNameInUrls fixed that immediately.


LJ Dynamic Fields unable to output title I’m using the LJ Dynamic Fields plugin and have a dynamic multi select setup for the client to select predefined tags, which is working all fine in the cms using the following code.

{% for tags in craft.tags.group('default').limit(null).order('title') %}
{ "value":"{{ tags.id }}" , "label":"{{ tags | raw | capitalize }}"
}{% if not loop.last %},{% endif %}
{% endfor %}

However, in my template I can only seem to output the id, but I want the tag title. I’m using the following code in my template:

{% for tags in entry.tagsMultiSelect %}
{{ tags }}
{% if not loop.last %}, {% endif %}
{% endfor %}

Can anyone tell me where I’m going wrong?

The values in your tagsMultiSelect are the tag ids, not the tags.
So, what you need to do in your template is convert that id to a tag:

{% for tagId in entry.tagsMultiSelect %}
  {# get the tag with that id #}
  {% set tag = craft.tags.id(tagId).first %}

  {{ tag.title ?? 'no such tag' }}
  {% if not loop.last %}, {% endif %}
{% endfor %}

If what you want is a predefined set of tags, you might also consider changing that tag group into a category - that would let you use a regular category field for your tagsMultiSelect.


SEOMATIC v1.1.45 install Finally making progress into a production environment (Pro license installed) and I see that the SEOMATIC has an update - 1.1.45 - I followed the instructions but am lost, as SEOMATIC is already installed in my instance of Craft; instructions want me to install it...is there a step I am missing to get this update complete?

Please let me know what I am I missing here -- thank you a ton! =)

Edit @10:00 03/29/2017

Thank you everyone for your answers! =)

If I am reading all the comments/answers correctly, I should do the following:
rm -R /var/www/html/craft/plugins/seomatic
cp -rv /home/psa/Zips/seomatic /var/www/html/craft/plugins
service apache2 restart

Is that correct? Thanks again for the assistance here!

To update plugins like SeoMatic, just download the latest (either clicking on the direct download link from the /admin/updates/ page in your admin area or from github).

Then you just then need to upload the new folder, overwriting the old one, to your server in the /craft/plugins directory (make sure you rename the download to seomatic as before, removing the '-master' that github adds).


SimpleMap plugin - How to render it on a webpage? This question is coming from a complete noob, so pls bear with me.

I am using SimpleMap plugin in a Craft site. I am able to install and configure the plugin, create a field, add it to a section etc. I am not sure how to embed the map as shown in CP, into an article on the site.

In short How to display the map frontend as it is displayed in the control panel?

Someone asked this question on the Simplemap Github issues, read the answer here.

I've copy/pasted pasted the answer below in case that link dies, but stress this is not my code, the credit goes to Tam

The plugin returns an array containing lat, lng, and others (see docs). You can use these as the location for any front-end map library (e.g. Google Maps or Mapbox).

Using Google Maps as an example:

And Mapbox:

<link href='https://api.mapbox.com/mapbox-gl-js/v0.21.0/mapbox-gl.css' rel='stylesheet' />


Template fails to load intermittently I have a template that fails to load intermittently, resulting in a 404. I haven't been able to debug it since 99% of the time the page loads perfectly.

  2015/07/18 12:18:57 [error] [exception.Craft\HttpException.404] exception 'Craft\HttpException' in /var/www/html/cotm_2015/craft/app/controllers/TemplatesController.php:59
  Stack trace:
  0 [internal function]: Craft\TemplatesController->actionRender('30-days-of-pray...', Array)

Anyone have any ideas?

When a connection to the database can't be made Craft throws a 404. This sound like it might be your problem because you say it happens intermittently.


hide section entries from one section I’m new at Craft CMS and I hope someone of you could help me a little.
At the moment I get all entries from my blog by

{% paginate craft.entries.section('blogItem').limit(globalSettings.postsPerPage) as pageActive, pageEntrys %}

Actually I have 5 categories (catA, catB, catC, catD, catE) at one level, but now I have another category Nr. 6. (catF)
All 5 categories are shown at the blogpage, but catF sound just shown at an separate page (pageF).

I did not find a way to hide all entries from catF at the blogpage and just show these entries at pageF.

Thy four your help.
smueller

New Answer based on our discussion:

<!-- Step 1. get the category you want to exclude
     since I still don't know your structure I'll just grab it
     per id. You can see that in your cp edit url (the last number) -->
{% set category = craft.categories.id(108).first() %}

<!-- Step 2. get all entryIds related to that category -->
<!-- this should be an array of ids you can dump it to check them -->
{% set entriesInCategory = craft.entries.relatedTo(category).ids() %}

<!-- Step 3 exclude those ids from your last query -->
{% set entries = craft.entries.section('blogItem').id('and, not ' ~ entriesInCategory|join(', not ')) %}

<!-- just for debugging and testing if these are the correct one -->
{% for entry in entries %}
    {{ entry.title }}<br>
{% endfor %}
<!-- then you can use your paginate with those entries -->

old Post

You can grab all entries that are related to category F and exclude them in your query

{% set catF = craft.categories.group('categories').ids() %}
{% set entriesForCatF = craft.entries({
    relatedTo: catF,
}).ids() %}

{% set entriesNotInCategoryF = craft.entries.section('blogItem').id('and, not ' ~ entriesForCatF |join(', not ')).ids() %}

{% paginate craft.entries.section('blogItem').limit(globalSettings.postsPerPage).id('and, not ' ~ entriesNotInCategoryF |join(', not ')) as pageActive, pageEntrys %}


Forms are triggering CSRF Protection. Why would CSRF Protection trigger false positives? We've enabled CSRF Protection on a site.

When we do, it sometimes works, but most of the time it gets tripped and triggers false positives and doesn't allow our forms to be submitted.

Things we've observed:

Some forms work, others don't
Sometimes a browser doesn't place the CSRF cookie
Sometimes two different browsers will have the same CSRF cookie
Sometimes if I delete the CSRF Cookie and then refresh the browser, the cookie won't return
Clearing the Craft cache seems to get forms working again in one browser but not another

Why are we seeing this weird behavior?  What is happening?!

We got this sorted before I finished my Stack Exchange question so I figured I'd share if anyone else runs into similar behavior.

After some troubleshooting, we learned that the issue here was that some of our Forms were being cached by Craft's {% cache %} tag and others were not.

CSRF Cookies are unique per user per session, so you don't want to cache them.

In our situation, it wasn't obvious at first that a {% cache %} tag was wrapped around the form, because the {% cache %} tag was actually in a {% block %} in a parent layout file that was being extended.

While searching through the templates helped us track down part of the issue, we also found it helpful to look at what was being cached in the craft_templatecaches table.  In the body column you can see what part of your template code is being cached, and we could see that the form, even though it didn't have {% cache %} tags around it in the template it was in, was being cached within a larger block of code.

Probably not the most mindblowing thing you will ever read, but it came in handy for me one long hour of one short day in history.


What's best practice for creating an index page for Channels? If I have a section called "news" with section type "channel" with entries having their own URLs, what is best practice for creating an index for when people site.com/news?

Do I just create an index file in 'template/news' or should I create a route?

EDIT: Did some more digging! Looks like some users have recommended using Structure to create parent level pages. Is this an ideal method?

If you are using a Structure to manage your site hierarchy, and the news index page naturally falls in that hierarchy, then yes, this can work well. Make an entry type for the index page, and in your template (which is the same for all the entry types),

{% include ['_page/'~entry.type, '_page/_default'] %}

(So if you haven't defined a template for this entry type you will use the _page/_default.html template instead of getting an error).

I think it is a good idea to use an entry for the index page (rather than just an index template) because there is very likely to be some content on that page other than just the list of news items, and you will want the CMS to manage that content for you.


How do I call the getInputHtml() method of a custom fieldtype plugin from another plugin? Plugin 1

I have a plugin that is a custom fieldtype.  It works fine, and has a getInputHtml() method that behaves as expected.

Plugin 2

Now, I have a second plugin, where I want to output the HTML from the Plugin 1 getInputHtml() method.

I have the FieldModel:

$field = $field->getField();

I have the Plugin 1 fieldtype object

$fieldtype = craft()->fields->populateFieldType($field, $element);

And I call the getInputHtml() method:

$fieldtype->getInputHtml($field->handle, $value);

If I place the necessary files at the base of Plugin 2 plugin2/templates/plugin1/_field/input everything works fine.  But I can't seem to access the input HTML template in the context of Plugin 1: plugin1/templates/_field/input

I've tried to update the Template Path in various ways before calling $fieldtype->getInputHtml():

craft()->path->setTemplatesPath(craft()->path->getPluginsPath());
craft()->path->setTemplatesPath(craft()->path->getPluginsPath() . 'plugin1/');
craft()->path->setTemplatesPath(craft()->path->getCpTemplatesPath());

Everything I have tried has resulted in a template error:

Unable to find the template "plugin1/_field/input".

Any ideas on what I'm doing wrong?

The problem as I see it is that the call is happening on the front-end. Because of this, the template renderer is not looking for the template at plugin1/templates/_field/input as it normally would, but at plugin1/_field/input, which explains the error message.

If Plugin 1 is your own plugin then you should be able to include the templates part of the path in the render call, for example:

return craft()->templates->render('templates/_field/input');

I haven't tested this but I think it should work.

Alternatively, and I would recommend this, since this is a front-end call, you could create your own function getFrontEndInputHtml() to return the html appropriately.


How to Cache Globally Except for One Page I have a template element that is used on almost every page of the site. I would like to cache that element globally, except on one particular page I would like it to just be a normal cache based on the page URL.

The current code I'm using is below, which is not working as intended. The global cache is still working on entry id 126.

{% cache globally using key 'entry_' ~ entry.id ~ '_elements' unless entry is not defined or entry.id == '126' %}

What would be the best way to make that functionality work without slowing down any other pages? Thanks!

You could add a variable like globalCacheDisabled and {% cache globally using key 'entry_' ~ entry.id ~ '_elements' unless globalCacheDisabled %} and use a {% set globalCacheDisabled = entry.disableGlobalCache %} on the given page template.

On Craft's side I'd use a Lightswitch field on the entry with handle disableGlobalCache, which is disabled by default which you can then activate on the given entry/ies.

This makes you prone to changing id's and differences across environments. (While testing make sure to purge the cache)


Query only returning 100 records at a time? I am trying to export data from a database to a csv file, I am using the code below to retrieve the data from the DB, but it only returns 100 rows, how can I fix that?

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = 'educators';
$query = craft()->elements->buildElementsQuery($criteria);
$query->order('title asc');
$queryResults = $query->queryAll();
$educators = EntryModel::populateModels($queryResults);

foreach ($educators as $educator) {
   //Write to file
}

Craft imposes a default limit of 100 for element queries. To disable this you need to specify a limit of null.

$criteria->limit = null;


Live Preview error when entry is disabled When the entry is disabled, the Live Preview only shows things which are outer of the main loop. This is a part of my code:

{% include "header.html" %}
{% for entry in craft.entries.section('flashback') %}

Flashback

...
{% endfor %}
{% include 'footer.html' %}

The header and the footer are visible but the section and headline not.

Change:

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

To:

{% for entry in craft.entries.section('flashback').status(null) %}

The 2nd one will grab all entries regardless of their enabled/disabled status.


Problem with open_basedir? Just deployed to a server which has the following open_basedir setting:

{DOCROOT}/:/usr/tmp:/var/www/vhosts/mydomain.com/httpdocs/

The webroot is at

/var/www/vhosts/mydomain.com/httpdocs/public_html

and craft is at

/var/www/vhosts/mydomain.com/httpdocs/craft

So all standard however I'm still getting this:

  Could not find your craft/ folder. Please ensure that $craftPath is set correctly in /var/www/vhosts/domain.com/httpdocs/public_html/index.php

Any suggestions please?

The problem here was the URL in the database was wrong. I had assumed that config was entirely file-based but it seems that the config file is dependent upon the database Site URL. It would be great if this could be avoided as it makes deployment between environments so much easier without paths or URLs in the DB.


How to split a string into an array How can I split (or explode) a Twig string like this:

{% set fruits = "Apples; Bananas; Tomatoes" %}

into an array like this:

{{ ["Apples", "Bananas", "Tomatoes"] }}

You would use the split filter.

{% set fruits = "Apples; Bananas; Tomatoes" | split('; ') %}


Need difference sign up path for 2 groups I see this thread about automatically activating/verify user accounts. However, I have 2 group of users, 1 group is open public which would like to have automatically activating/verify. The 2nd group is private, need activate email and verify. Should I write a plugin or just modify UsersService.php to split 2 directions on saveUser?

Thanks,
Angela

Should I write a plugin or just modify UsersService.php to split 2 directions on saveUser?

The first one.  The second one has many drawbacks:

Any changes you make in craft/app can (and probably will) get overwritten during an update.
Which means you'll have to reapply them after updating.
It's not supported.

Craft has a bunch of events that plugins can listen to and run logic when they fire without hacking core Craft files.  In your case, it sounds like onBeforeSaveUser or onSaveUser might be what you need.


Any ./craft command throws error When I attempt to run any ./craft it throws an error, for example:

$ ./craft resave/entries
Exception 'yii\base\UnknownMethodException' with message 'Calling unknown method: craft\console\Request::getSegment()'

in /var/www/examplewebsite.co.uk/vendor/yiisoft/yii2/base/Component.php:300

Stack trace:
#0 /var/www/examplewebsite.co.uk/plugins/core/src/Core.php(97): yii\base\Component->__call('getSegment', Array)
#1 /var/www/examplewebsite.co.uk/vendor/yiisoft/yii2/base/BaseObject.php(109): cursor\core\Core->init()
#2 /var/www/examplewebsite.co.uk/vendor/yiisoft/yii2/base/Module.php(158): yii\base\BaseObject->__construct(Array)
#3 /var/www/examplewebsite.co.uk/vendor/craftcms/cms/src/base/Plugin.php(130): yii\base\Module->__construct('core', Object(craft\console\Application), Array)
#4 [internal function]: craft\base\Plugin->__construct('core', Object(craft\console\Application), Array)
#5 /var/www/examplewebsite.co.uk/vendor/yiisoft/yii2/di/Container.php(400): ReflectionClass->newInstanceArgs(Array)
#6 /var/www/examplewebsite.co.uk/vendor/yiisoft/yii2/di/Container.php(159): yii\di\Container->build('cursor\\core\\Cor...', Array, Array)
#7 /var/www/examplewebsite.co.uk/vendor/yiisoft/yii2/BaseYii.php(351): yii\di\Container->get('cursor\\core\\Cor...', Array, Array)
#8 /var/www/examplewebsite.co.uk/vendor/craftcms/cms/src/services/Plugins.php(897): yii\BaseYii::createObject(Array, Array)
#9 /var/www/examplewebsite.co.uk/vendor/craftcms/cms/src/services/Plugins.php(230): craft\services\Plugins->createPlugin('core', Array)
#10 /var/www/examplewebsite.co.uk/vendor/craftcms/cms/src/base/ApplicationTrait.php(1375): craft\services\Plugins->loadPlugins()
#11 /var/www/examplewebsite.co.uk/vendor/craftcms/cms/src/console/Application.php(65): craft\console\Application->_postInit()
#12 /var/www/examplewebsite.co.uk/vendor/yiisoft/yii2/base/BaseObject.php(109): craft\console\Application->init()
#13 /var/www/examplewebsite.co.uk/vendor/yiisoft/yii2/base/Application.php(206): yii\base\BaseObject->__construct(Array)
#14 /var/www/examplewebsite.co.uk/vendor/yiisoft/yii2/console/Application.php(89): yii\base\Application->__construct(Array)
#15 /var/www/examplewebsite.co.uk/vendor/craftcms/cms/src/console/Application.php(54): yii\console\Application->__construct(Array)
#16 [internal function]: craft\console\Application->__construct(Array)
#17 /var/www/examplewebsite.co.uk/vendor/yiisoft/yii2/di/Container.php(400): ReflectionClass->newInstanceArgs(Array)
#18 /var/www/examplewebsite.co.uk/vendor/yiisoft/yii2/di/Container.php(159): yii\di\Container->build('craft\\console\\A...', Array, Array)
#19 /var/www/examplewebsite.co.uk/vendor/yiisoft/yii2/BaseYii.php(351): yii\di\Container->get('craft\\console\\A...', Array, Array)
#20 /var/www/examplewebsite.co.uk/vendor/craftcms/cms/bootstrap/bootstrap.php(244): yii\BaseYii::createObject(Array)
#21 /var/www/examplewebsite.co.uk/vendor/craftcms/cms/bootstrap/console.php(34): require('/var/www/examplewebsite.c...')
#22 /var/www/examplewebsite.co.uk/craft(21): require('/var/www/examplewebsite.c...')
#23 {main}

Any suggestions on what I need to do? I'm on the latest version of CraftCMS and also am using PHP7.2.

Thank you!

Looks like you have a plugin called core that is not handling console requests properly.

#3 /var/www/examplewebsite.co.uk/vendor/craftcms/cms/src/base/Plugin.php(130): yii\base\Module->__construct('core', Object(craft\console\Application), Array)


How can I get the type of a field using Twig? I would like to loop through all the fields of a field layout tab form the current entry.

This is working fine to get the field name and value:

{% for fieldLayoutField in entry.getFieldLayout().getFields() if fieldLayoutField.tabId == 50 %}
    {% set field = craft.app.fields.getFieldById(fieldLayoutField.id) %}
    Field name: {{ field.name }}
    Field value: entry[field.handle]
{% endfor %}

But I need to go a step further, by checking the field type, and then handle something different depending of the type.

Example:

{% if field.type == 'dropdown' %}
    <select>
        {% for option in field.options %}
            <option value="{{ option.value }}">
                {{ option.label }}
            </option>
        {% endfor %}
    </select>
{% endif %}

As {{ field.type }} and {{ entry[field.handle].type }} aren't defined, I can't guess properly when this is, for example, a Plain Text field or a Dropdown field.

I could guess some fields type, by some checks like bellow, but it sounds very dirty:

field.columnType
returns text if a Plain Text field.
field.options | length returns true if a Dropdown field.

For some others, like the Lightswitch field, I don't know exactly how to guess the type properly.

You can use the className function

{% switch className(field) %}
    {% case 'craft\\fields\\PlainText' %}
    {% case 'craft\\fields\\Dropdown' %}


How do I set the Post field after manipulation I'm trying to write a simple plugin that will intercept registration form's data, manipulate it and move it forward. What I'm struggling with is how to set the Post content of a field after the manipulation.

I'm trying to achieve something like that, how do I set the Post field after manipulation, setRawPostContent doesn't seem to work here.

 craft()->on('users.onBeforeSaveUser', function(Event $event) {

        if(craft()->request->isSiteRequest())
        {
            $companyId = craft()->request->getPost('email');
            $event->params['user']->setRawPostContent('fields[companyId]', $companyId);
        }

    });

If you're just looking to update a custom field on the user, something like this should do it:

craft()->on('users.onBeforeSaveUser', function(Event $event) {

    if(craft()->request->isSiteRequest())
    {
        $companyId = craft()->request->getPost('email');
        $event->params['user']->getContent()->companyId = $companyId;
    }

});


ElementCriteriaModel combine with 'and' and 'or' filters Saying I want to convert the following SQL query into ElementCriteriaModel:

SELECT * FROM users WHERE fieldA = 1 AND (fieldB = 1 or fieldC = 1)

I can't find a way in ElementCriteriaModel to do so.

{% craft.users({
    fieldA: 1,
    fieldB: 1,
    fieldC: 1, // where can we put the 'or' filter?
}) %}

I can do this using DbCommand, but just curious if there's anyway we can do that via ElementCriteriaModel?

I suspect you're looking for this section on passing parameters to ElementCriteriaModels, in the docs.

The examples fail to highlight one aspect of the query you're building, but I think you'll find the same strategies hold up for many field values, as well as basic Element properties (like id, title, etc.)

For example…

craft.users({ myFieldA: [1, 2, 3] }).all()

…will fetch User Elements with the custom myFieldA matching the values 1, 2, or 3. The or is implicit!