Error when creating a Matrix or installing a Plugin We have 2 computers with a new Craft Pro trial installation. The files are exactly the same on both computers. We both use the same DB with the same db.php config settings.  We can both see the site and login to the /admin section.

The only issue is that on 1 computer I can not create a Matrix field or install a plugin. Then I get the error:

CDbCommand failed to execute the SQL statement: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'COLLATE=' at line 8

The other computer has no problem creating a Matrix field or installing a plugin. Any suggestions? Thanks!

Check to make sure you have a db.php file here:

craft/app/etc/config/defaults/db.php

If not, download a fresh copy of the version of Craft you're using and replace your craft/app folder with the one you just downloaded.

This file was missing in my Git repository because the .gitignore file was set to ignore all db.php files on the site, not just the one they wanted to ignore in the craft/config folder.

If that's the case, make sure your .gitignore file uses a line like this:

craft/config/db.php

Instead of just this:

db.php


Generate EAN13 barcode The project that I'm working on requires that I generate an EAN13 barcode for display on vouchers.

I'm attempting to implement the following as a Craft Plugin: https://github.com/rlt3/php-barcode

The part that I am unclear about is how exactly to define my Model to return an image to the calling template. Do I even need a Model ?

Bit of a late reply (But hope you can use this!), but I created a plugin to output barcodes within Craft templates via Twig:

https://github.com/madebyshape/barcode

I created it because one of our clients required a barcode to be output in to a generated PDF that got sent to their customers.


Craft's answer to {switch} from EE Does Craft have an answer to ExpressionEngine's {switch} tag?

{switch="classOne|classTwo|classThree"}

Yes, you can do the same in Craft using Twig's cycle function:

{% set myClasses = ['classOne', 'classTwo', 'classThree'] %}

{% for entry in entries %}
    {{ cycle(myClasses, loop.index0) }}
{% endfor %}


Can entries be returned based on checkbox selection? I have a section with entries which I wish to push to specific parts of the website.
I know I could filter them with a Category but the section already has a category so I would like to use checkboxes.

The checkbox only has 3 options so I could like to return those that are checked for a specific section.
Is this possible with checkboxes?
Been trying this but not getting anything returned:

  {% set entries = craft.entries.section('newsMedia').order('postDate desc').limit(7).search('zone:pupil')%}

You'd better double check for a typo because you actually got the syntax right for the search parameter.

search('myField:myString') filters all entries where a field with handle "myField" contains a string "myString". What you have should totally work to get the entries with a checkbox field handle "zone" and the value of the checkbox option being "pupil".

If you're sure that there's no typo and you actually have entries that match the criteria, I'd try if it helps to rebuild the search indexes (tool in the CP settings). I actually try to avoid using the search parameter if possible, because things can go wrong with the indexes. Unfortunatelly I don't think there's other ways to filter by a checkbox field.

Other posibillity: If you don't want to paginate the entries or use other methods that are not available on custom arrays of entry models, what about filtering them with a simple conditional:

{% set entries = craft.entries %}

{% for entry in entries if entry.zone.contains('pupil') %}
    {{ entry.title }}
{% endfor %}


Returning an array to Twig from a plugin I'am writing a plugin that has to return an array of data, however Twig does not seem to accept it if I return a PHP array.  I don't want to use an explode in Twig to make it into an array.

I have seen in other plugins i can just call a function from twig like this.

{% set result = craft.winkelwagen.printWinkelWagen(currentUser.id) %}

{% for output in result %}
    {{ output }}
{% endfor %}

However, I get an array to string conversion error.  Does anyone know the correct way to do this?

Thanks in advance.

Your plugin should be able to handle PHP arrays just fine.

craft/plugins/myplugin/variables/MyPluginVariable.php

function getArray()
{
    return array('hi', 'there');
}

craft/templates/template.twig

{% set result = craft.myPlugin.getArray() %}
{% for item in result %}
    {{ item }}
{% endfor %}

The error you're seeing is likely because output itself is an array. If you have devMode enabled you can try a {{ dump(output) }} inside your for-loop to see what it actually is / contains.


Change font of Redactor II How do I change the default font (Trebuchet) of Redactor II to Arial, for instance?

I don't know how to override the default CSS of Redactor. Please help.

Tnx in advance!

You could use the Control Panel CSS plugin that lets you add arbitrary css to the control panel.

Then you could target all redactor fields like so:

.redactor-layer * {
    font-family: 'Arial';
}

EDIT slightly more troubling is that you are getting Trebuchet in the first place, it should be Arial anyway.

UPDATE it turns out this change came about in a recent Craft update (2.6.2963) that updated Redactor II from 1.3.2 to 2.2. My best guess is that it crept in to the Redactor II 2.0 release, which also included the change to the toolbar icons.


Cannot hide redactor strikethrough button when table plugin is enabled I am trying to set a Redactor field so that it only shows the table button, though no matter what I do... the strikethrough button appears, it looks like the correct name is strike though doesn't appear to work (tried multiple variations) though no luck. Are there any suggestions on how to hide it? Here is my redactor config:

{
  "buttonsHide": ["link", "lists", "strikethrough", "Strikethrough", "strike", "italic", "bold", "format", "html"],
  "plugins": ["table"]
}

The name to use to hide the Strikethrough button is deleted.


Commerce - Advanced shipping cost calculations What is the best way to implement advanced shipping cost calculations? Custom adjusters were deprecated right? I need to add shipping costs based on the total price of all products from a specific type.
My client sells products that don't require shipping costs and products that do. The shipping costs are based on the total price of the order. However, products that don't require shipping costs are (obviously) included in the order total which means the shipping costs are higher than they should be.
Is there any way to make this work? Thanks in advance!

products that don't require shipping costs are (obviously) included in the order total which means the shipping costs are higher than they should be.

It sounds like you're only using one shipping class? Commerce can provide multiple ways to ship (methods) but also how to handle different categories of products (shipping categories).
What I'd do is create 2 shipping classes: one that includes shipping, another without.
Then set the products that have the shipping costs built-in to only use the Shipping Included in Price category (whatever you've named it).  That takes care of excluding costs for the products that already include shipping.

You mention the cost for the other products is based on the total of the order. One way to handle this would be to set a percentage per item since those items will end app as the total (ignoring the other products that already have shipping cots.)
You can set this up in the shipping Costs panel. So in the General category in the example below, I set the shipping cost to be 10% of the item (0.1) but you could also do weight or a flat per item. You can also set a minimum or max shipping costs depending on what you're trying to do.

Custom adjustment types are deprecated but the doesn't affect shipping, discount, and tax adjusters—basically items that Commerce knows about.


Migration: Removing field from GlobalSet/Entry Im creating my own migrations to better handle adding/removing fields on all environments.

Is the following safeDown() function the correct way to remove a field from a fieldlayout? It works but im open if their is a better way to archive this.

  public function safeDown()
{
    $tabStructure = [];
    $cartDestinationUrl = Craft::$app->fields->getFieldByHandle('cartDestinationUrl');
    $headerGlobalSet = Craft::$app->globals->getSetByHandle('header');
    $tabs = $headerGlobalSet->getFieldLayout()->getTabs();

    foreach ($tabs as $tab) {
        $fields = $tab->getFields();
        $fieldIds = [];
        foreach ($fields as $field) {
            $fieldId = $field->id;
            if ($fieldId !== $cartDestinationUrl->id) {
                $fieldIds[] = $fieldId;
            }
        }
        $tabStructure[$tab->name] = $fieldIds;
    }

    //remove empty tabs from layout
    $tabStructure = array_filter($tabStructure);

    $globalSetLayout = Craft::$app->fields->assembleLayout($tabStructure);
    $headerGlobalSet->setFieldLayout($globalSetLayout);

    return (Craft::$app->globals->saveSet($headerGlobalSet));
}

Did you consider using Craft 3.1 new Project Config File feature?

https://docs.craftcms.com/v3/project-config.html#enabling-the-project-config-file

Any time a field is added, modified ou removed, every environment will be updated to match the primary one. That could be much more easier than handling it manually with migrations.


Using PHP Redis as Session Store I'm trying to use php-redis as the session store to my craftcms site.
What I've tried:

apt-get install php5-redis
Edited php.ini with the following:

session.save_handler = redis
session.save_path = "tcp://redis:6379?auth=password”

Still, I don't see any sessions saved in redis.

Can anyone help? Thanks!

This may help:

Add the following to the general.php

'cacheMethod' => 'redis',
'overridePhpSessionLocation' => 'tcp://localhost:6379'

Add the following to the index.php

ini_set('session.save_handler', 'redis')


Amazon S3 Images not showing up in Assets I'm developing locally and adding images to my Amazon S3 bucket. I have the same connection to the bucket on my remote environment. On my local environment, I can see the images I've uploaded, but on my remote environment none of the images that I uploaded locally are showing when I browse assets.

On my remote environment, if I attempt to re-upload the image, I get a message: A file with the name “mylogo.svg” already exists. So I know that the assets field is correctly connected to the bucket in the remote environment.

I'd recommend updating the asset indexes via Utilities → Asset Indexes (or Settings → Update Asset Indexes if you're on Craft 2) in your Control Panel.


Add new error to macro errorList - User Registration Using CraftCMS example registration form in the docs.

How would I add a new error message to the macro errorList in the registration form:

    {% macro errorList(errors) %}
        {% if errors %}

                {% for error in errors %}
                    <span>{{ error }}</span>
                {% endfor %}

        {% endif %}
    {% endmacro %}

    {# Output if true #}

    {% if user is defined %}
        {{ _self.errorList(user.getErrors('email')) }}
    {% endif %}

I added a checkbox and need to create a validation for it. I can create an error like this: Craft::$app->getSession()->setError(Craft::t('app', 'Check box is not checked')); which works, but how will I add an error to the macro errorList so I can use it the same as the other errors eg, firstname, password, etc.

CraftCMS: 3.4.6.1

I've done something similar recently... The errors returned by that macro are errors on the user model. Therefore, rather than creating errors on the user session, why not create them on the user model during registration and they'll automatically be available in the same macro...

Here's an example I'm using in a custom module to add extra validation to the user registration form:

// --------------------------------------------
// BEFORE SAVE USER ELEMENT EVENT. Add our own validation
// --------------------------------------------

use craft\elements\User as UserElement;
use craft\base\Element;
use craft\events\ModelEvent;

Event::on(
    UserElement::class,
    Element::EVENT_BEFORE_SAVE,
    function(ModelEvent $e) {
        if ($e->isNew && $e->sender instanceof \craft\elements\User) {
            $errors = false;
            if (!Craft::$app->request->post('firstName')){
                $e->sender->addError('firstName','First name is required');
                $errors = true;
            }
            if (!Craft::$app->request->post('lastName')){
                $e->sender->addError('lastName','Last name is required');
                $errors = true;
            }
            if (strlen(Craft::$app->request->post('fields.phoneNumber')) < 10) {
                $e->sender->addError('phoneNumber','Telephone number should be at least 10 characters long');
                $errors = true;
            }
            if (!is_numeric(Craft::$app->request->post('fields.phoneNumber'))) {
                $e->sender->addError('phoneNumber','Telephone number must be numeric');
                $errors = true;
            }
            if ($errors){
                $e->isValid = false;
            }
        }
    }
);

Then in your template you'd have something like this after every field (I tend to prefer includes over macros but macros would work fine too):

...

    Telephone number &bull;
    {# minlength is not supported in IE11 so add a server side check too #}
    <input minlength="10" required id="phoneNumber" type="tel" name="fields[phoneNumber]" value="{{ user is defined ? user.phoneNumber }}">
    {% if user is defined and user.getFirstError('phoneNumber') %}
        {% include '_partials/fieldErrors.twig' with { errors: user.getErrors('phoneNumber') } %}
    {% endif %}

...

### _partials/fieldErrors.twig:

{% if errors %}

        {% for error in errors %}

{{ error }}

        {% endfor %}

{% endif %}


Craft admin login infinite redirect in cluster We're having a problem logging in the Craft admin tool @ https://www.clearlabs.com/admin when we have more than one server in the cluster.
After submitting credentials, Craft seems to keep 302-bouncing infinitely between https://www.clearlabs.com/admin/login and https://www.clearlabs.com/admin/dashboard.
The few times we are able to log in, we seem to get kicked out of our session back into an infinite redirect loop.
Note this does not affect our website, but only the admin web app.

Upon review of the literature, we tried to set overridePhpSessionLocation=false, but it doesn't seem to help.

Can someone please confirm the configuration requirements for Craft clustering and/or give us some thoughts on what might be going on?
Thank you,
Cyril

TL/DR

It sounds like you need to enable sticky sessions at your load-balancer/router level, so that the users will be sent back to the same server in the cluster that their session originated on.

The long version

In Craft 2.x, every new user gets new PHP session represented by a file on your web server and a cookie in your browser.  By default PHP names that cookie PHPSESSID, but Craft will default set it to CraftSessionId, although you can configure its name with the phpSessionName config setting.

PHP has a way to use sessions without cookies providing a way to append a unique session ID to the querystring of a URL, but (for many reasons), Craft doesn't support that method.

In addition to the PHP session cookie, Craft will create an identity cookie upon a successful login that has a randomly generated name similar to 4190d8c6874f8615f88325f5b285fc40. That cookie is how Craft keeps track that you're successfully authenticated.

The problem with load-balanced setups that don't use sticky sessions is that with all of these default settings, when a session is started on server A and then a user is bounced to server B, server B has no knowledge of the session because it was created on server A.

There are ways around it, of course, the easiest being to enable stick sessions at the load balancer level, ensuring that users will get sent back to the server their session was started on for the lifetime of that session.

Alternatively, if sticky sessions aren't your thing, you can configured a shared network storage location and tell each web server to use it for its session.save_path, ensuring they all have access to all server-side session files.  If you go this route, you'll also want to set the appId config setting to be identical across all web servers, since it is used in decrypting cookie data (including sessions).  By default it it is randomly generated per Craft installation.


Craft 3 version - How to get entries related to current category only (not children) I need some help with syntax on this for Craft 3, please.

I want to use this piece of code:

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

from this answer here:

How to get entries related to current category only (not children)

It's exactly what I need to do but I'm not sure how to code it for Craft 3 so that I can pull in entries from JUST my 'products' section:

craft.entries.section('products')...

Thanks in advance.

UPDATED INFO.

Category Group = Products

Entry Sections using these categories = Products & Case Studies

My category structure is as follows:

Categories are:

Travelling Irrigators

Superseeded Models

Hydrants
Filters
Pontoons
Pumps

I'm trying to return just the product entries (not case studies) under 'Travelling Irrigators' but not including the 'Superseeded Models'.

The other post does exactly what I need but it returns the case studies too.

These two pages should help you from the Craft 3 docs

https://docs.craftcms.com/v3/dev/element-queries/entry-queries.html#relatedto

https://docs.craftcms.com/v3/relations.html


Craft 2.3 new User does not set the default permissions group Hello I do not know if this is a bug or something but we just updated to craft 2.3 and got an issue which we did not have previously.
In user settings we can set the default permissions group but when we do create a new user this group is not applied to that user.Im not sure why this is, maybe something more needs to be done beginning Craft 2.3 but the simple flow of creating a new user worked previously. Upon the user account creation the default group would be set automatically.

EDIT:

Thank you for your answers. I was mistaken it is assigning the group but I cant get that group on an event trigger.

    craft()->on('users.saveUser', function(Event $event) {
        $user = $event->params['user'];
        var_dump($user->getGroups()); exit();
    });

I am doing the above in my plugins main PHP file and for some reason before updating it would give me the users group as the default one already assigned. After the update I get a empty array even though going to the control panel after registering I can see that the new user has the group assigned.

The setting still works, but keep in mind that for it to take effect, A) you have to be registering a user through a custom registration form on the front end, and B) you have to be logged out. Without those conditions, it’s not technically public registration.

Default user group assignment has always taken place after the user was saved, and after the users.onSaveUser event was called. See these highlighted lines from UsersController::actionSaveUser() – the onSaveUser event gets called by craft()->request->saveUser(), and default group assignment happens in $this->_assignDefaultGroupToUser().


Fixing deprecated code, relatedTo issue Working on fixing a lot of deprecated code, enviroment is setup as dev so getting a lot of warnings. Some are easily idetified, others are pretty generic and come from core files. Doesn't show where the issue is... So I have been going through each block template removing code till the page loads to narrow it down.

Example Warning:
strtolower() expects parameter 1 to be string, array given from /vendor/craftcms/cms/src/helpers/Db.php

 $firstVal = strtolower(reset($value));

I have narrowed an existing issue down to the following code from a block template, however I have tried a few different ways but the page will not load with the following code. Anyone know a way to resolve this, it seems to be an issue with the relatedTo

Source of problem? Setting up section

{% for feed in block.feeds %}
    {% if feed == 'all' %}
        {% set data = ['blog', 'caseStudies', 'dataSheets', 'events', 'news', 'webinars', 'whitePapers', 'artices', 'productDemos'] %}
        {% set break = true %}
    {% else %}
        {% set data = data|merge({ (loop.index0):feed }) %}
    {% endif %}
{% endfor %}

Source of problem? Setting up relatedTo

{% for related in block.relatedTo %}
    {% if related == 'All' %}
        {% set reldata = false %}
        {% set break = true %}
    {% else %}
        {% set reldata = reldata|merge({ (loop.index0):related }) %}
    {% endif %}
{% endfor %}

Then Setting up the query seems to be an issue with the section(data) but not sure what needs changed as I do not see a clear deprecation warning, or stacktrace

{% if reldata %}
    {% set tag = craft.tags.title(reldata) %}
    {% set feat = craft.entries.section(data).relatedTo(tag).limit(8).all() %}
{% else %}
    {% set feat = craft.entries.section(data).limit(8).all() %}
{% endif %}

This seems to have fixed the issue.

{% if reldata %}
    {% set tag = craft.tags.title(reldata|join(', ')) %}
    {% set feat = craft.entries.section(data|join(', ')).relatedTo(tag).limit(8).all() %}
{% else %}
    {% set feat = craft.entries.section(data|join(', ')).limit(8).all() %}
{% endif %}


Simple Product Listing Pages by Category Slug I'm new to Craft and I'm trying to create very basic product listing pages based on Categories and I'm not sure where to start.
First, it doesn't look to me like you can create separate templates for each category, only the Category group, correct?
If that's true, then I need that template to be dynamic and list the products in a category that may be nested. The idea being that I will have navigation that will resolve to each category page.
I've gone through the page on Querying Categories and I think querying by Slug is what I want. I altered the code on that page based on this post in order to get whatever the last segment is:
{# Get the requested category slug from the URL #}
{% set requestedSlug = craft.app.request.segments|last %}

{# Fetch the category with that slug #}
{% set category = craft.categories()
    .slug(requestedSlug|literal)
    .one() %}

{% set entry = category %}

{% for entry in entries %}
    {{entry.title}}
    {{entry.url}}
    {{entry.image}}
{% endfor %}

For clarity I didn't put the entry items in HTML.
I feel like my problem is the second bit, setting the entry to category (which I cobbled together from posts here and in the docs) but I can't figure out how to get at the entry details from items in a category.
I also need to paginate the listings if that makes a difference.
Thanks in advance for any advice or pointers to good tutorials on using Categories to generate product listings.

You're nearly there! You are missing the part that fetches the entries related to your category.
With your current set up, you would need to do:
{# Get the requested category slug from the URL #}
{% set requestedSlug = craft.app.request.segments|last %}

{# Fetch the category with that slug #}
{% set category = craft.categories()
    .slug(requestedSlug|literal)
    .one() %}

{# Fetch the entries related to your category #}
{% set entries = craft.entries()
    .section('yourSectionHandle')
    .relatedTo(category)
    .all()%}

{% for entry in entries %}
    {{entry.title}}
    {{entry.url}}
    {{entry.image}}
{% endfor %}

Replace yourSectionHandle with, well... your section handle :)
Alternatively, Craft provides a way to simplify the process a bit.

First, it doesn't look to me like you can create separate templates for each category, only the Category group, correct?

You can manually create a template for each category by making a file named as your category slug but this is tedious to maintain.
The way you could handle that would start when you define your category group's settings.
This is only an example but you should get the gist of it.
First, define Settings → Categories → Your Group → Category URI Format to be categories/{slug}, the Template to categories and make a categories.twig template at the root of your templates folder.
Now, when you access yoursite.com/categories/category-slug (category-slug being an actual category slug), Craft will auto-inject a category variable to the template (like the entry variable on entry pages) allowing you to only have the following in the template:
{# Fetch the entries related to your auto-injected category variable #}
{% set entries = craft.entries()
    .section('yourSectionHandle')
    .relatedTo(category)
    .all()%}

{% for entry in entries %}
    {{entry.title}}
    {{entry.url}}
    {{entry.image}}
{% endfor %}

Hopefully, that makes sense for you!


Category Sources for Craft 3? I'm updating a site from Craft 2 to Craft 3 and can't find the equivalent of the 'Category Sources' plugin? It's really useful when it comes to restricting the source for related entries by the category the entry belongs to. Does anybody know of an alternative solution?

Thanks.

There's a Craft 3 port of Category Sources in the v2 branch for the repo. It doesn't appear to be published to Packagist and the Plugin Store, which means you'll need to add the URL for the plugin's Git repository to your project's composer.json file in order for Composer to find it.

Add the following to the root of your composer.json file:

"repositories": {
    "craftcms/category-sources": {
        "type": "git",
        "url": "git@github.com:pixelandtonic/CategorySources.git",
        "trunk-path": "v2"
    }
}

You might also need to add the following to composer.json:

"minimum-stability": "dev",
"prefer-stable": true,

Then, you can do composer require craftcms/category-sources to actually download the plugin.

Note: I haven't tested this plugin myself, and the fact that it isn't released probably means it's not completely ready for primetime (it might not even work at all, with recent versions of Craft 3). Proceed with caution; you might also want to get in touch with Pixel & Tonic to hear if the plugin is likely to get a proper release anytime soon.


Get draft content in front end form I have a live entry with an 'eventTime' text field having the content '2pm'.

I also have an unpublished draft saved for that same entry with the 'eventTime' field having the content '3pm'.

I use the following code in my front end template to retrieve the draft for the entry:

{% set entry = craft.entries.section('events').type('ofs').status(null).limit(1).first() %}
{% if entry and entry.enabled %}
    {% set drafts = craft.entryRevisions.getDraftsByEntryId(entry.id) %}
    {% if drafts %}
        {% set entry = drafts[0] %}
    {% endif %}
{% endif %}

Yet the following tag in my template:

{{ entry.eventTime }}

Always displays '2pm' - even though I know the draft is being loaded, as:

{{ entry.draftId }}

Outputs the correct draft ID value.

How do I get it to display '3pm' - i.e. the correct content for the draft being loaded? I've noticed that draft data is stored differently in the database (shoved into a field called 'data' in the 'craft_entryDrafts' table). How do I get at it?

Figured this out myself.

The 'getDraftsByEntryId' function is only intended for displaying the list of drafts, so there is no need to populate the model (a potentially expensive task). Indeed, there is a line that unsets the 'fields' part of the data in the EntryRevisionsService.php file:

// Don't initialize the content
unset($result['data']['fields']);

Handily, there is another function called 'getDraftById' that I was able to use, which does populate the model. Therefore, my amended (and working) code is:

{% set entry = craft.entries.section('events').type('ofs').status(null).limit(1).first() %}
{% if entry and entry.enabled %}
    {% set drafts = craft.entryRevisions.getDraftsByEntryId(entry.id) %}
    {% if drafts %}
        {% set entry = craft.entryRevisions.getDraftById(drafts[0].draftId) %}
    {% endif %}
{% endif %}

Boom!


Multisite Craft 3, different entries on different sites Is it possible to show different entries on different subsites?

Currently I can show different versions of the same entry (e.g. translations), but I want entry 1 to show on site 1, entry 2 on site 1, entry 3 on site 2, etc.

As I have different user accounts for the admin for each site, is it also possible to only show the entries for site 1 in the cms of site 1?

In total I'd like to create around 30 subsites.

Update - site setup

I'm working with only 1 locale. I have one primary (default) site, the rest is in the same group, all on a different base URL and handle.

For future reference, this was fixed in 3.0.0-RC15

  Added the “Propagate entries across all enabled sites?” section setting. If disabled, entries will only be associated with the site they were created on.


Getting "Session Ended" popup in admin Every minute or so I get the "Your session has ended" popup in the admin. Entering my password just pops the message back up. If I reload the page I'm still logged in.

I'm running Craft in vagrant so maybe it's a permissions problem?

It could be related to this question since I had that exact problem but setting the permissions in vagrant fixed that particular problem.

I've tried the requireUserAgentAndIpForSession, overridePHPSessionLocation, and userSessionDuration config settings, but none of them seem to solve the popup.

We were experiencing this issue, as well as the randomly logging out issue.

As I answered on that question, we fixed both these issues by switching session.auto_start to Off

session.auto_start = 0


Shipping Adjustment not being added to Total Price I have an adjuster that calculates shipping cost which I can see when I view the order in the backend. The problem is that the shipping adjustment is not being added to the total price. Any help would be GREATLY appreciated.

Turns out it was another plugin interfering with the order total.


Errors when updating Redactor Folks:

I'm slowly working my way through a Craft3/Commerce2 upgrade. My current issue:

When updating redactor I receive multiple errors. I just want to be sure I'm on the right track.

Error 1:

Cannot create cache directory /.composer/cache/files/, or directory is not writable. Proceeding without cache

Cannot create cache directory /.composer/cache/repo/https---composer.craftcms.com/, or directory is not writable. Proceeding without cache

Cannot create cache directory /.composer/cache/files/, or directory is not writable. Proceeding without cache

I assume the vendor > composer folder needs to be writable to make this work, correct?

Error 2:

Package "craftcms/vue-asset" listed for update is not installed. Ignoring.

This seems straightforward but where do I find this? I figured as it seems to be part of Craft it would already be there.

With update issues like this, you'll have to run composer update rather than using the CP update button. You can either SSH into your server to run composer update or update the files on your local computer and push the new files (they'll be in vendor > craftcms > redactor) to your server. Make sure you do a database backup before doing this. After doing this manual update, when you go to your Craft CP, you'll probably get a notice that Craft needs to make changes to your database, so just click ok or whatever it says.

If Composer says there's nothing to update, you'll need to edit your composer.json file. At the top of composer.json under "require" you'll see your Redactor plugin; edit the numbers to the version number you see in the Craft updates in your Control Panel, then run composer update.


I moved my craft site to a subdirectory, and things are broken now, help! I installed craftcms on a regular .com root folder, and everything worked fine. I can go to .com/news and it will go to my /templates/news.html file, etc.

Now my client wants their site on a subdirectory. I copied over all the files to the new subdirectory, but now when i go to .com/subdirectory/news, I get a 404 page. I checked that the .htaccess was correct, I just don't know what else I have to change to make the new site work on the new subdirectory. Please help!

So I figured it out! my htaccess did not have the "." in front of them. So my htaccess in my subdirectory was not being read. Once I renamed it to .htaccess, it worked fine!


Custom Authentication I'm in the process of developing a custom login for a website. Users will not be website users with logins, but rather will be authenticated via an email and a custom token. The process should be as follows:

User arrives at protected page and must enter an email address ending
with @acme.com
If user's email address ends with @acme.com, then generate
a token and send them and email with link including the token.

I am trying to figure out the best way to do this in craft. My initial plan was to create a separate php script which handled the email send and token generation via AJAX, but I figured it's not best practice because it is outwith the CMS, so I should maybe develop this as a plugin.

I wondered if any of you could make some suggestions or perhaps if you'd experience such a process before might shed some light on it.

Thanks

Seems totally doable with a plugin.

The protected page where they enter their email address would post to a controller action in your plugin.

Your controller checks the domain of the submitted email, verifies it's from acme.com then generates a token (maybe using StringHelper::UUID() or craft()->security->generateRandomString() if it should be cryptographically secure).  I'm assuming you'll save that token into the database for later verification.

You can use craft()->email->sendEmail() to send an email with the link they need to click.

When they click the link, you'd also have it point to another controller action that gets the token from the URL, verifies it's valid, then logs the user in similar to how Craft does it in UsersController->actionLogin(), but minus all of the username/password logic.

Keep in mind, if you invalidate the token after one use (which you probably should), then the user will have to go through this whole process every time they want to log in.


Filter for language when using graphQL I try to use graphQL to get language specific entries from my Craft CMS. I (naively?) tried this:
query {
    entries (section: "newsIntranet", language: "fr") {
        title
        postDate
        expiryDate
        contentText
    }
}

because of this part of doc.
How can I get make sure that I only get entries of a given language when using graphQL from an extrernal system?

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

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


How can I convert a date format from my plugin so it saves correctly? I have a plugin that includes a datepicker.

I initialize the datepicker like this

javascript

$('.datepicker').datepicker({
    'format': 'mm/dd/yyyy',
    'todayHighlight': true
});

I am saving the date from my plugin like this:

$myDate = craft()->request->getPost('myDate');
if ($myDate) {
    DateTime::createFromString($myDate, craft()->timezone);
}

$fieldsLocation = craft()->request->getParam('fieldsLocation', 'fields');
$entry->setContentFromPost($fieldsLocation);

Because I have designated this field to be required, I get an error back saying that the field cannot be blank. Even though I have chosen a date.

If I change my datepicker to use this format:

$('.datepicker').datepicker({
    'format': 'yyyy/mm/dd',
    'todayHighlight': true
});

Everything works.
I like how "human/U.S" friendly the top example is vs. yyyy-mm-dd.

Since I am populating the entry with this:

$entry->setContentFromPost($fieldsLocation);

Is there a way to convert what is passed in to the correct format Craft is looking for?

I've tried something like:

$date = date(str_replace('/', '-', craft()->request->getPost('myDate')));

$myDate = date('Y-m-d', strtotime($date));

But that is getting overwritten by this guy still:

entry->setContentFromPost($fieldsLocation);

Thank you for any suggestions!

After $entry->setContentFromPost($fieldsLocation); you should be able to add another line to explicitly set your calculated date.

$entry->setContent(array('fieldName' => $myDate));

Then just proceed with saving the entry as normal.


Check if content in entry has changed Is there a simple way to know if an entry's content changed when it was saved?

I'm pulling data from an XML feed and create/update entries in a section. I need to know which entries has new data. I guess I could check each field value individually, or make some kind of hash and check that. But is there some built-in way in Yii/Craft that is easier?

I don't think there's currently anything in Craft that's going to help you here.

Ideally we'd track for dirty/changed fields in JavaScript on an edit entry page and pass that as a parameter into the onBeforeSaveEntry event.


PayPal Pro In Craft Commerce I am trying to integrate PayPal Pro into Craft Commerce, I have my API details added to the payment gateway and I have disabled test mode. I know these keys work as they have been used before.

On checkout, when I have PayPal Pro selected as a payment method, I receive an error "Invalid payment or order. Please review." when I press checkout.

I have two questions;

Could anyone give me an idea as to why this payment gateway isn't
working but the other payment gateways are working fine? Maybe I'm making a common mistake somewhere.
Are there any ways of dumping out errors, the flash errors don't seem to provide any detail which is making debugging this issue difficult.

Thanks.

Have you tried looking at commerce.log in storage/logs? (With Craft 3/Commerce 2 there is no commerce.log - you'll need to comb through the general web.log)


Redactor I source button no longer working? Running Craft CMS 2.6.2903 and Redactor I 1.1.0

This is my config:

{
    "buttons": ["format", "bold", "italic", "lists", "image"],
    "plugins":["fullscreen", "source"],
    "toolbarFixed": true
}

fullscreen and source no longer work, not sure but possibly a recent Craft update? I have all my rich text fields set to Rich Text (Redactor I) and Standard as Standard.json is the config I edited for above settings. No html or source button shows up, fullscreen shows up but doesn't work.

Anyone know what could possibly be wrong, this config worked a while back.

Updated the files, still didn't work, clicked uninstall, then installed again and its back, not sure what happened.


Use GET parameters to query for array of entry IDs On my client side, I have an array of entry IDs that match with entries in Craft

const myIds = ['230', '249', '256']

I am trying to send that array over to an Element API endpoint and use it in the id criteria to only grab entries with the specified IDs.

I am constructing my GET request and add myIds to the request parameters, then send it to the endpoint.

How would I access that array in parameters within element-api.php? I found a response for Craft 2 that looks like it's similar to what I want:
(Passing multiple parameters to the Element API) which uses the getQuery() or getRequiredQuery() functions, but I'm not sure those still exist in Craft 3?

I found a response for Craft 2 that looks like it's similar to what I want: (Passing multiple parameters to the Element API) which uses the getQuery() or getRequiredQuery() functions, but I'm not sure those still exist in Craft 3?

In Craft 3, you'd use:

Craft::$app->getRequest()->getRequiredQueryParam('myArr')

https://docs.craftcms.com/api/v3/craft-web-request.html#method-getrequiredqueryparam


Craft incredibly slow site performance I am experiencing incredibly slow site performance. This extends to loading the control panel (/dashboard, /login).

This only happens when I put the site on to my hosting, locally using MAMP it runs quickly.

I have done the following which are recommended in other posts:

upped the memory_limit to 512M
used (% cache globally using key 'entry-' ~ entry.id %}
used eager loading for image assets
Disabled/enabled plugins

Can someone please help?

It turned out this was the culprit. Craft was doing a deprecationerrors query (https://github.com/craftcms/cms/issues/2539).

Turning devMode to false fixed this.

Hope this helps someone...


bootstrap.php how to include environment variables for multi-environment configuration? I recently had to run a couple of migrations to move entries from one structure to the other, but had problems when running the migration PHP script being able to get environment variables e.g. DB and stuff in .env. In the end I temporarily replaced my craft/config/db.php and hard coded my DB on local so I could run the script, however this isn't really ideal but did the job. It seemed the script couldn't get the DB environment variables.

I'm wondering what should I be including in my bootstrap migration scripts going forward in order to utilise the environment variables properly. I used a version of the script here:

Move entry from one structure to another with parenting

Slightly modified to take an array of ids, as well as mapping the old and new entry types as an arry, so it could be done in one go.

I essentially tried copying most of the beginning portion of the index.php like this and transplanting it into my migration script

// Composer: https://getcomposer.org/doc/
require_once('../vendor/autoload.php');

// PHP dotenv: https://github.com/vlucas/phpdotenv
if (!getenv('APP_SECRETS'))
{
    $root_dir = dirname(dirname(__FILE__));
    if (file_exists($root_dir . '/.env'))
    {
        Dotenv::load($root_dir);
        Dotenv::required(array('APP_SECRETS', 'CRAFT_ENVIRONMENT'));
    }
}
define('CRAFT_ENVIRONMENT', getenv('CRAFT_ENVIRONMENT'));

However, no matter what I just got a die() error from craft/local/db.php saying the path to the file containing the DB crendentials (secrets.json) couldn't be found, so it seems the environment variables weren't available at runtime. APP_SECRETS is the path to the json file.

Any ideas, what I'm missing for environment variables to be loaded in?

Thanks.

So debugging this a bit, it looks like its to do with the namespace declaration on the original template I was using for the migration. Basically when declaring namespace Craft this causes problems with loading the environment variables that were previously being masked by the die() error, as I was including Bootstrap too early.

Uncaught Error: Class 'Craft\Dotenv' not found

In my case, the phpdotnev stuff is going to need to appear before including Bootstrap otherwise Craft isn't going to be able to connect to the DB.

Moving the vendor and environment variables stuff up before loading the bootstrap file from the Craft folder, seems to work. This a test file I have now:

<?php
namespace Craft;

// Avoid errors when running through console
$_SERVER['HTTP_HOST'] = 'example.craft.localdev';
$_SERVER['REQUEST_URI'] = '/index.php';

// Get the root dir so we can run migrations without worrying about path
$root_dir = dirname(dirname(__FILE__));

// We need to load in phpdotenv stuff before initialising bootstrap.php, otherwise you won't be able to connect to the DB
require_once($root_dir . '/vendor/autoload.php');

// If APP_SECRETS is not set, load in .env file
if (!getenv('APP_SECRETS'))
{
    $envFile = '.env';

    if (file_exists($root_dir . '/' . $envFile))
    {
        // PHP dotenv: https://github.com/vlucas/phpdotenv
        $dotenv = new \Dotenv\Dotenv($root_dir);
        $dotenv->load();
        $dotenv->required(['APP_SECRETS', 'CRAFT_ENVIRONMENT']);
    }
    else
    {
        die("$envFile does not exist.");
    }
}

// Set the Craft environment with the value set in .env
define('CRAFT_ENVIRONMENT', getenv('CRAFT_ENVIRONMENT'));

// Initialize Craft without letting it take over the whole request
$app = require $root_dir . '/craft/app/bootstrap.php';

// Set Craft to Craft Personal so we don't get any errors about Client/Pro-only components not being available
$app->getInfo()->edition = 0;

// CUSTOM CODE FOR MIGRATIONS AND OTHER CRAFT RELATED STUFF GOES BELOW THIS LINE

This then appears to be using the proper environment variables. I tested by editing my db.php file to break one of the variables being pulled from secrets.json to cause the DB connection error and it does appear to be work, as the try and catch statement is responding appropriately.

Not sure if there will be an issue not having the namespace Craft declared or not, but I appear to be able to interact with Craft through $app still. Would this be correct?


Sorting Entries field results by category I have an entries field 'physicians'. I want to output the selections from that field and sort them by category (also named 'physicians') - with the category heading above each category group.

I can't figure out if I should just output the category list and filter the result by the field or if I should output the entries field and then sort them by category. I'm trying the latter right now but not sure of how to get the categories to work.

{% set phyGroup = craft.categories.group('physicians') %}
{% set phyList = craft.entries.relatedTo('physicians').order('lastName asc') %}

{% for physicians in phyGroup %}
   <h3>{{ category }}</h3>
   {% for entry in phyList %}
      {{ entry.lastName }} ...
   {% endfor %}
{% endfor %}

It’s not totally clear from your question where you’re building the relation to the categories,
but I have a feeling that this is the solution you’re looking for.

{% set groupParam = '{ object.categoriesFieldHandle.first() ? object.categoriesFieldHandle.first().title : "No categories" }' %}
{% for groupTitle, entriesInGroup in entry.entriesFieldHandle|group(groupParam) %}
    {{ groupTitle }}

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


How to use Saved Card in Craft Commerce I was able to save cards by using savePaymentSource parameter in my payment form submitting at commerce/payments/pay. But how do I use these saved cards for making payments? I am using Stripe payment method and rendering the form through {{ cart.gateway.getPaymentFormHtml({})|raw }}.

You can submit a paymentSourceId to the payments/pay controller action.

<select id="paymentSourceId" name="paymentSourceId">
    {% for storedCard in storedCards %}
        <option value="{{ storedCard.id }}" {% if storedCard.id == cart.paymentSourceId %}selected{% endif %}>{{ storedCard.description }}</option>
    {% endfor %}
</select>


Display freeform entries with a status on open – on the front end I'm using this code in my template

{% set formHandle = 'toad' %}
                         {% set submissions = craft.freeform.submissions({
                              form: formHandle,
                            status: ["open"],
                         }) %}

                         {#
Submissions for {{ form.name }}
 #}

                         {% if submissions is empty %}

There are no submissions

                         {% else %}

                                        {% set myfield = (submissions|first).fieldMetadata.status('open) %}

                                        {{ myfield.toadName.label }}
                                        {{ myfield.toadProfile.label }}

                                   {% for submission in submissions %}

                                             {{ submission.toadName.value }}

                                             {{ submission.toadProfile.value }}

                                   {% endfor %}

                         {% endif %}

But get the error:

Error Info: Array
(
    [0] => 42S22
    [1] => 1054
    [2] => Unknown column 'sub_freeform_statuses.handle' in 'where clause'
)
↵
Caused by: PDOException
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'sub_freeform_statuses.handle' in 'where clause'

Is it possible to show just form entries with an open status only? without
 status: ["open"],
the template works fine

Have you tried the syntax for one status rather than an array?

{% set submissions = craft.freeform.submissions({
      form: formHandle,
      status: "open",
}) %}

Ref: http://docs.solspace.com/craft/freeform/v2/template-functions/freeform.submissions.html#param-status


How can I get entry id in field I create a new filed type and attached it to entries. Now I need to get the entry id which the field is attached to.

I tried $this->element in my field class, but got an error said that I'm calling an unknown property.

Any way to do that please?

It may depend on where in the request you need to access the element.

If you need to access the element in a Field class on your Entry Edit page, the getInputHtml method may be useful:

public function getInputHtml($value, ElementInterface $element = null): string
{
    // $element stuff

    return Craft::$app->getView()->renderTemplate('my-plugin/field',
    [
        'field' => $this,

        // make the Element available in your field's input template
        'element' => $element
    ]);
}

If you need to access the element in a Field class after the Element is saved there is the afterSaveElement method:

public function afterElementSave(ElementInterface $element, bool $isNew)
{
    parent::afterElementSave($element, $isNew);

    // $element stuff
}

Note: The Entry ID may not exist while a new entry is being created. Accessing the Element via the afterElementSave ensures that the Entry has been saved and has an ID.


Login As User from Frontend In the CP there is a button which allows you to log in as a specific user. Can this be called from the Frontend/plugin or is it strictly a CP function?

You can call it from the front-end, but it requires the currently logged in user to be an administrator.

Just point the form's hidden action input to users/impersonate and have it submit a 'userId' input of the person you want to log in as.


Is there a way to compare what has changed on an entry while it's being saved? I'm taking my first baby steps into the php side of Craft, and my php experience in general is extremely fledgling. But I'm pretty much forced to create a module for a project I have, so here I am flailing around in a space I know virtually nothing about. So thanks for reading.
Basically, I need to send notification emails based on specific (very specific) user actions. Right now I have it running so that I'm catching the EVENT_AFTER_SAVE event in my module's init() function and successfully sending out emails with the Mailer. So that's good. But the issue is I need to be able to see if certain fields have changed on entries to know what email to send out.
Is there a way to compare the pre-saved and post-saved entry, or maybe alternatively to catch the fields that are being sent to /entries/save-entry to determine what the user is doing? I know it's probably likely that what I really should be doing is creating my own controller and/or action that I use on my templates in places that designate what action should be taking place, but I'm so barely holding on to comprehension of what I'm doing as-is that I'd prefer to create something caveman simple first before trying to give it better coding practices. But I'm also open to any advice at all on how to proceed.

You're probably looking for Element::getDirtyAttributes() and Element::getDirtyFields()!
The former is for native class properties/attributes (and is based on an ActiveRecord pattern in Yii, I believe...), and the latter is for Craft's "fields," which may or may not be available, based on what type of Element you're looking at (and what FieldLayout it uses).
You're on the right track! The Element's EVENT_AFTER_SAVE event will fire prior to purging the information with $element->markAsClean().

Note that the EVENT_AFTER_SAVE event emitted by your element is different than the similarly-named EVENT_AFTER_SAVE_ELEMENT event from the Elements service!


Logging in to Craft via Vue/Javascript apps I'm just diving into the world of javascript frameworks (late to the party I know) and can't figure out the missing piece of the authentication puzzle.

What is the preferred way to authenticate users from a Vue or any other javascript app running from element API? My Craft install and the app will be on separate domains.

Is it best to just push them to the craft install to log in then rely on sessions (is this secure?), or is there a preferred way? I have seen JWT's mentioned a few times, but guessing this will be tricky for a non-developer.

And just like that I stumble over this wonderful blog post https://digitalevangelist.net/blog/vuejs-craft-cms-single-page-app-logging-in-to-craft


Plugin loading scheme This is a fairly generalized question, maybe I completely missed where to learn about this, but I've always been curious about it as it'd help me be a little more aware of what would and would not be good practice in plugin development.

I often read the first user request is slowest to Craft Sites point mentioned in articles/posts, what exactly is that referring to?

With each page request are all plugins and their files opened and loaded up? Or are these loaded and stored somewhere for X period of time, decreasing loading time per request?

Some examples of plugin scenarios/questions

1:

I have a fairly decent-sized loop in two plugins via public function registerSiteRoutes() {} that generate 200-1000+ custom routes, as those URL's will not have any content from Craft's entries (and thus don't have URL's,) or are completely dynamic (for forum topics with unpredictable topic urls.)

Is this loop that creates these URL's running every single time a page is requested? Is this bad practice?

2:

I can have some plugin services load large files of data in __construct(), or as var $data; for use in specific scenarios. Under the assumption that these service files are only loaded when a plugin calls to it, it wouldn't be slowing requests down that don't use the data because only the pages calling for them would load the data, such as through craft()->myPluginName_serviceName->getVarWithLotsOfData; requests.

Or do these files get loaded up regardless of being called, and therefore should be re-written into functions so that they don't load the data unless asked?

3:

Plugin count -- does having many small, niche plugins affect load speed versus less but larger plugins that cover more functionality? Is plugin count something that needs to be carefully considered, a common caution when working with a plugin-based CMS like Wordpress?

--

Basically, I guess the question is, I would love to be able to read a detailed explanation of the scheme/process in how plugins and their respective plugin file, config, services, controllers, templates, variables etc are loaded, and if there is a guideline on what is and isn't good practice when designing the flow of plugins for optimization?

If there is documentation that I missed that greatly covers and explains all of this, feel free to link it and put me in a corner for shame. D:

Thanks,

I often read the first user request is slowest to Craft Sites point mentioned in articles/posts, what exactly is that referring to?

Probably missing some context surrounding where you originally read that, but if it was talking about caching, then maybe it was referring to the first user that triggers the request to generate the necessary cached content.

  Is this loop that creates these URL's running every single time a page is requested? Is this bad practice?

Craft will process registerSiteRoutes on every request, so if you have a lot of business logic going on in your plugins around that method, it might be worth caching the results for a time to speed things up.

  Or do these files get loaded up regardless of being called, and therefore should be re-written into functions so that they don't load the data unless asked?

You assume correctly, but generally I'd recommend against haven't expensive operations in class constructors/init() methods.  My personal preference would be to explicitly load the data.

  Plugin count -- does having many small, niche plugins affect load speed versus less but larger plugins that cover more functionality? Is plugin count something that needs to be carefully considered, a common caution when working with a plugin-based CMS like Wordpress?

The more plugins, the more file system access Craft has to do to find and load them. That part is usually negligible performance wise, but there's nothing stopping a plugin from doing something crazy slow in its constructor/init() methods.

This has been alleviated in Craft 3 to a large extent, because Craft doesn't have to instantiate a plugin just to figure out information about it (version number, author, etc.).

  Basically, I guess the question is, I would love to be able to read a detailed explanation of the scheme/process in how plugins and their respective plugin file, config, services, controllers, templates, variables etc are loaded, and if there is a guideline on what is and isn't good practice when designing the flow of plugins for optimization?

Generally speaking, Craft will lazy-load a plugin's Controller, Enum, Helper, Model, Record, Service, Variable, and Validator classes as they are requested, just like Craft's own files are lazy loaded.


Using { slug } to create subfolders won't work I'm running craft locally using MAMP and I'm trying to move assets into a subfolder when unploaded into an image field in my gallery section.

I'm trying to set the path to subfolder so it uses the slug. When I put {slug} into the field settings nothing happens when I upload the images and save the entry, it just pulls them all into the top level folder.

Im not sure if its something in the local file permissions or something but I can bring the images in fine and transforms work okay ie. they create folders and pop the images in fine.

Any help would be appreciated

Got the problem solved, I had wanted to have the option of selecting photos from another folder so in the field settings I had Default Upload Location with the {slug} in there. When I switched it to "restrict to single folder" and set the {slug} then it is all functioning as expected. I don't think it would make sense selecting a photo from another folder in this field as the asset wouldn't be able to move when entry is saved. Hope this makes sense. I just have the same issue as the other post now where I don't see the caption field until the entry is saved.


How to save Matrix data programmatically in Craft 3 How can you programmatically save an entry that has a Matrix field in Craft 3?

(Something like this gist for Craft 2)

Saving Matrix fields programmatically got a lot easier in Craft 3 thanks to all the content refactoring.

use craft\elements\Entry;
use craft\elements\MatrixBlock;

// Figure out the section & entry type
$section = Craft::$app->sections->getSectionByHandle('news');
$entryTypes = $section->getEntryTypes();
$entryType = reset($entryTypes);

// Create an entry
$entry = new Entry([
    'sectionId' => $section->id,
    'typeId' => $entryType->id,
    'fieldLayoutId' => $entryType->fieldLayoutId,
    'authorId' => 1,
    'title' => 'My Entry',
    'slug' => 'my-entry',
    'postDate' => new DateTime(),
]);

// Set the custom field values (including Matrix)
$entry->setFieldValues([
    'summary' => 'Some "summary" custom field value...',
    'matrixField' => [
        'new1' => [
            'type' => 'blockTypeHandle',
            'fields' => [
                // the block's custom field values...
            ],
        ],
        'new2' => [
            'type' => 'blockTypeHandle',
            'fields' => [
                // the block's custom field values...
            ],
        ],
    ],
]);

// Save the entry
Craft::$app->elements->saveElement($entry);


Yearly/Monthy archive listing sorted by month I've got a list of entries grouped by year which is working correctly except that the months are being output in the the reverse order.

This code outputs the years in the correct order but the months in reverse order:

    {# all entries sorted by year/month #}
     {% set allEntries = craft.entries.section('photoblog').limit(null).order('postDate desc') %}

  {% for year, entriesInYear in allEntries | group("postDate.year") %}

{{ year }}

        {% for month, entries in entriesInYear | group("postDate|date('F')" ) %}

{{ month }}&nbsp;({{ entries|length }})

        {% endfor %}

  {% endfor %}

If I change the '''.order('postDate desc') to asc then the months are in the correct order but the years are reversed. is there a way to get it so that the years are descending but the months are ascending?

screenshot of current code results

Add the reverse filter to your inner array of entries in month.
http://twig.sensiolabs.org/doc/filters/reverse.html


How to display entries filtered from more than one category I want to try to learn how I can filter entries by multiple categories. I realise similar questions have been asked in the past, but all the answers are for specific use cases. All I want to do is filter entries by categories from more than one group. I've found code to set up a form that returns the URL with a string, but I understand that the string needs to be converted into an array. That's the part I can't work out how to do.
So the form is like this:

        {# Get the relevant entries #}
    {% set categoryQuery = craft.app.request.getParam('category') %}
    {% set categories = craft.categories.group('candidate').slug(categoryQuery) %}

    {# Set the search parameters #}
    {% set searchParams = {
        relatedTo: categories,
        section: 'candidate'
    } %}

    {# Get the relevant entries #}
    {% set relevantEntries = craft.entries(searchParams) %}

    <form action="{{ craft.app.request.absoluteUrl }}">

Eye colour

        {% for category in craft.categories.group('eyeColour').all() %}
            <input id="{{category.slug}}" type="checkbox" name="category[]"  value="{{ category.slug }}" {{ category.slug in categoryQuery or categoryQuery == null  ? 'checked'}}>
            {{ category.title }}
        {% endfor %}

Hair colour

        {% for category in craft.categories.group('hairColour').all() %}
            <input id="{{category.slug}}" type="checkbox" name="category[]"  value="{{ category.slug }}" {{ category.slug in categoryQuery or categoryQuery == null  ? 'checked'}}>
            {{ category.title }}
        {% endfor %}

<button type="submit">
                Search
        </button>

    </form>

Which gives me a URL like this

/?category%5B%5D=blue&category%5B%5D=black

Here's something I've got for filtering news by author and by category. You might be able to re-work it for your needs?

From a page URL being: http://project.com/news?&cat=CATEGORY&author=NAME

{% set query = {} %}

{% set categoryParam = craft.app.request.getParam('cat') %}
{% set authorParam = craft.app.request.getParam('author') %}

{% set category = craft.categories.slug(categoryParam) %}
{% set author = craft.entries.section('team').slug(authorParam).first() %}

{% if category %}
    {% set query = query|merge(category) %}
{% endif %}

{% if author %}
    {% set query = query|merge(author) %}
{% endif %}

{% if categoryParam and authorParam %}

    {% set results = targetEntries.relatedTo(['and',
            { targetElement: category },
            { targetElement: author }
        ]
    ).orderBy('postDate desc') %}

    {% set noResultsMessage = "Sorry, there are no articles by " ~ author.title ~ " in that category. Try changing your filters." %}

{% elseif categoryParam %}

    {% set results = targetEntries.relatedTo(category).orderBy('postDate desc') %}
    {% set noResultsMessage = "Sorry, there are no articles in that category. Try filtering by a different category." %}

{% elseif authorParam %}

    {% set results = targetEntries.relatedTo(author).orderBy('postDate desc') %}
    {% set noResultsMessage = "Sorry, there are no articles by " ~ author.title ~ ". Try filtering by someone else." %}

{% else %}

    {% set results = targetEntries.orderBy('postDate desc') %}

{% endif %}

It was written a long time ago, so I'm seeing some places where I can streamline it, but this works for me filtering by two fields. I think the key part for your requirements is:

{% set results = targetEntries.relatedTo(['and',
    { targetElement: category },
    { targetElement: author }
]).orderBy('postDate desc') %}

Hope this helps in some way.


Charge Pro not sending Subscription Emails So I've actually created a fix for this, but it's a bit complicated. Wanted to share in case anyone else runs into this problem.

Working in Craft 2.6.2954 and Charge Pro 2.18

When creating new subscriptions, the emails were not being sent properly. I checked the charge logs in the charge plugin and it was giving me an error of "Failed to find email with the handle : Welcome Email". I figured out that "Welcome Email" was the correct name of my email, but it wasn't the handle, which is why it wasn't being found. I created a new function in the Charge_EmailService.php file called _getEmailModelByName, you can see it here:

private function _getEmailModelByName($handle = null)
{
    if ($handle) {
        $emailRecord = Charge_EmailRecord::model()->findByAttributes(
            ['name' => $handle]);

        if (!$emailRecord) {
            return false;
        }

        $model = Charge_EmailModel::populateModel($emailRecord);

        return $model;
    }

    return false;
}

I then updated the sendByHandle function to do a few checks on the handle and try to find the email a different way. Here's the new sendByEmail function:

public function sendByHandle($handle, ChargeModel $chargeModel, $extra = [])
{

    if(is_int($handle)){
        $emailModel = $this->_getEmailModelById($handle);
    } else {
        $emailModel = $this->_getEmailModelByHandle($handle);
    }

    if($emailModel == false) {
        $emailModel = $this->_getEmailModelByName($handle);
    }

    if($emailModel == false) {
        craft()->charge_log->error('Failed to find email with the handle : '.$handle, ['extra' => $extra, 'charge' => $chargeModel]);
        return false;
    }

    $data['charge'] = $chargeModel;
    foreach($extra as $key => $arr) {
        $data[$key] = $arr;
    }

    $emailModel->send($data);
}

Looks like this is now working as it should. Hope it saves someone else some frustration.

I've actually answered the question in the question. Not sure why it's not showing as is, but the solution is updating the plugin file as mentioned above.


Query entries between two values I am trying to query entries (scripts) when a custom expiration date field is within a certain range.

These questions/answers helped me get as far as I am, but I'm still stuck: Advanced query/filter based on date and values and How can you return elements between two values?

Here's the full scenario. On this app's homepage, it lists a handful of recent scripts (prescriptions). It also has sections where it displays scripts that are expired and scripts that are about to expire (within two weeks of the current date).

I did some testing and found that the following conditionals filter the scripts just how I want:

{# When expiration date is between now and 2 weeks #}
{% if expirationDate >= now and expDate <= now|date_modify('+2 weeks') %}

{# When expiration date is anytime before now #}
{% if expirationDate < now %}

Those work great. How can I move this filter into the query itself?

I was thinking something like the following, but it obviously doesn't work because of all the commas. But this is what I'm trying to do. How do I use this correctly in a hash?

{% set scriptsAboutToExpire = {
    section: 'scripts',
    order: 'expirationDate asc',
    expirationDate: 'and', '>=' ~ now, '<=' ~ now|date_modify('+2 weeks')
} %}

I got the answer to this thanks to @BrandonKelly from a comment in this question: How can you return elements between two values?

Turning it into a subarray does the trick: expirationDate: [ 'and', '>=' ~ now, '<=' ~ now|date_modify('+2 weeks') ]

Thanks, @BrandonKelly!


How do I send an email to multiple recipients? In my plugin, I'm sending an email like this:

$recipients = 'person@example.com';

$email = new EmailModel();
$email->toEmail = $recipients;
$email->subject = 'My Email Subject';
$email->body    = 'My Email Body';

craft()->email->sendEmail($email);

Which works great! But when I'm sending to multiple people, the string would look like this...

$recipients = 'person1@example.com, person2@example.com';

... and it generates an error:

Invalid address: person1@example.com, person2@example.com

How do I properly send an email to multiple recipients?

You can loop through a list of your recipients:

// Comma-separated list of recipients
$recipients = 'person1@example.com, person2@example.com';

// Break out recipients into an array
$recipientList = explode( ",", $recipients );

// Create the globally known things about the EmailModel
$email = new EmailModel();
$email->subject = 'My Email Subject';
$email->body    = 'My Email Body';

// Loop through each recipient in the recipient list
foreach ( $recipientList as $recipient )
{
    try
    {
        // Add a specific recipient to the email model
        $email->toEmail = $recipient;

        // Send the email
        craft()->email->sendEmail( $email );
    }
    catch ( \Exception $e )
    {
        // Do nothing
        return false;
    }
}


Craft 3 Custom Set Password Styles I've been building frontend pages for non-admin users with layouts matching the rest of the enduser site. For the "Set Password" page, I was able to build the form and set it up via the setPasswordPath config, no problem.

However, in addition to all my necessary frontend styles, this page also brings in a number of admin-side styles and scripts that greatly interfere with the layouts. Since any users seeing this custom page won't have admin access, these included files are certainly unneeded.

Outside of hacking the core, is there a more friendly way to exclude admin-level content on this non-admin page?

This was a complication due to using the same browser for different user testings. Once all semblance of my admin user session/cookies were absent, the admin styles and scripts no longer appeared on this page.


Custom Fieldtype in a plugin at user profile save I have made a custom fieldtype.

{% import "_includes/forms" as forms %}

{{ forms.textField({
    label: "business"|t,
    required: true,
}) }}

And added it to the user fields.
Where do I need to save data entered in at a user profile.

I would like to hook into the onSaveUser event with my plugin to save my values into the address model of Craft Commerce, but how would I do that?

An example would be appreciated.

The best approach is probably to use the onAfterElementSave hook available to custom fieldtypes. Here's what that could look like (the following method should go into your custom fieldtype class, e.g. myawesomeplugin/fieldtypes/MyAwesomePluginFieldType.php):

public function onAfterElementSave()
{
    $field = $this;
    $fieldId = $this->model->id;
    $fieldHandle = $this->model->handle;
    $element = $this->element; // This is the UserModel, in your case
    $fieldContent = $element->getContent()->getAttribute($fieldHandle); // This is the content for the field

    // Do something awesome with the data above
    ...

}


4 Different HTML from single Craft 3 CMS on 4 different domains? Can we serve 4 different HTML from single Craft 3 CMS on 4 different domains?

working on a client project which has their 4 different domains for their different brands of the same business.

Is it possible, if yes how can we achieve it?

Thanks in Advance ..!!

Yes, you can. How you organize the templates for each site is completely up to you. Here's the docs on setting up multiple sites in Craft.

I would likely use a different layout template for each site. So when I extended at the top of an individual page template it would look like this.

{% extends "layouts/_site_one" %}

Or like this

{% extends "layouts/_site_two" %}


What configuration does Craft need to enable Live View on hoster CloudFlare with SSL/https CP? In a previous question and answer, I've laid out recent experience in bringing up Craft on the combination of CloudFlare and Railgun offered as a free feature for VPS hosting at Arcustech.

The Pingdom-tools-verified performance results are very good, especially in the combination of North American and European customers that the present site is going to serve.

It was natural to test also Craft features, and only one was found to need some help to operate in this environment. This is to have the very client-useful Live View operate properly when using the Craft CP under SSL/https as the secure.domain.com DNS allows from the previous article.

What actually happens at present is that the Live View pane comes up unexpectedly blank. A look at HTTP headers on the iframe ajax loading that pane along with console messages shows why. The CP runs on https://secure.domain.com, while the Live View iframe is called at https://www.domain.com, which can never be possible on free CloudFlare, as it does not support https. It will simply be silent, and then in a long interval time out. As well, there is a CORS error in the console, which suggests that an Access-Control-Allow-Origin header needs to be present.

In fact, experiment shows that besides the unavailability of https on the www site, such an CORS header from a template (general _layout inclusion) isn't accepted, either from Craft header() or from embedded http-equiv. Perhaps this is because other CORS headers would have to be introduced within the Craft side to allow it. There may be other reasons, but clearly the situation isn't remediable from outside, at least as far as I can see. If CORS would work, still the https accesson the www CloudFlare-free coupling never will by design.

However, experimentation proves a solution. I temporarily modified the siteUrl array for some languages (in general.php) to point to the secure.domain.com site, instead of www.domain.com.

Now Live View worked perfectly for each of the languages so modified, because the iframe calls went to a url that could answer, and which was on the same path as the CP ajax caller. Success as tested, but the real site itself would no longer work through CloudFlare/Railgun, as it would no longer be sent as www.domain.com.

The evident solution is to have the CP iframe ajax load Live View pages by the exact same full URL base as it uses for its own pages. Now everybody would be happy, and there would be no need to entangle CORS as the Live View iframes would be on the same basis as their Ajax loader.

If there were any question whether this internal solution would work in all possible cases, it could be introduced by a general.php config element, so that it could also be turned off.

I would happily spend the hour to build a plugin to arrange this, but I think we are not allowed access by code framework or by license to modify Craft's internals in this area.

If anyone can see a solution from outside, to save effort at Craft, that would be a great answer.

In lieu, I'm hoping to have analyzed this problem in a way to make it very easy for our friends to provide what it needs - and if  they don't with better insight than any of us intuit something the matter with such a solution, or realize that there's a better one.

Many very good surprises have indeed come that way, but not necessary here ;)

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

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

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

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


Best way to search users by a custom field inside a plugin? This did work until there’s a significant amount of users:

$criteria = craft()->elements->getCriteria(ElementType::User);
$users = $criteria->search('customField:' . $someValue);

I’m using search as I need to find a value within the custom field. The field is typically 1,2,3 and I need to check for one of those values.

I have also tried to limit it without success.

$criteria->groupId = 1;
$criteria->limit = null;

What’s the best way to do this?

UPDATE:

The users getting missed are those that had the fields I’m searching populated by another plugin. This looks as though the data is not being saved in the same way as when it’s entered manually in the CP.

Does something like this work? You might need to add some wildcards as documented here to run the right kind of search.

$criteria = craft()->elements->getCriteria(ElementType::User);
$users = $criteria->search('customField: *' . $someValue.'*');


For loop with custom order So I'm trying to loop through some entries and order them by in a specific way. For an example let's say I have the following entires:

Example01
Example02
Example03
Example04

I now want to loop through these entries and order them in an order such as: Example03, Example01, Example04 and Example2. The order has to be custom where I can change it.

Is this possible and if so how can I achieve this? Thanks

You have a few options here:

Use an Entries field (as a Global or as a fields on a Single maybe?) to chose the entries and order them
Make the Entries a Structure section, so you can set the order
use craft.entries({ ids: [3, 1, 2], fixedOrder: true }) and query the Entries by ID (if they'll never be deleted and you're cool with hard-coding the order)
create an order field on that entry type to query them by, also with craft.entries()

It's up to you what the best solution would be, given your set-up, but you have plenty of options.


Using ADLDAP plugin in Craft 2.6 - can't bind to LDAP I'm working with the ADLDAP plugin in order to provide frontend authentication against my organizations Active Directory.  The problem is that I continually receive the message "Can't bind to LDAP server!" after attempting to log in.

I tested the LDAP connection first on Windows Server 2016, by using the built in LDP.exe utility, and that test proved successful.
Next, I constructed a pure PHP page, and the LDAP binding was successful.
Here is that code:

<?php

// using ldap bind
$ldaprdn  = '*****';     // ldap rdn or dn
$ldappass = '*****';  // associated password

// connect to ldap server
$ldapconn = ldap_connect("***.***.***.***")
    or die("Could not connect to LDAP server.");

if ($ldapconn) {

    // binding to ldap server
    $ldapbind = ldap_bind($ldapconn, $ldaprdn, $ldappass);

    // verify binding
    if ($ldapbind) {
        echo "LDAP bind successful...";
    } else {
        echo "LDAP bind failed...";
    }

}

?>

In Craft, I carefully followed the installation instructions, per the page: https://github.com/thepitagroup/adldap_craftcms as well as the changes introduced in the thread: https://github.com/thepitagroup/adldap_craftcms/issues/1.
These changes were helpful and got me a little further along, but now, I'm stuck with the error message: "Can't bind to LDAP server!"
The url remains on the 'login' page.

Is there a way to find more detail as to the cause of the error?

Thanks for any help.

In more testing, I was able to eliminate the "Can't bind to LDAP server!" error message from Craft by removing both: Account Suffix and Admin Account Suffix settings from the ADLDAP parameter control panel.
In my particular setup, I left all parameters empty in the 'optional' section of the parameter control panel, with the exception of the port ('389') and 'Follow Referrals.'


Redirects with Craft and nginx I'm running into a few issues trying to set up 301/302 redirects with Craft and nginx. The legacy site has /contact.php paths which I would like to direct to /info/ but when I visit mysite.com/contact.php it gives me the No input file specified. error.

I tried setting this up with Retour plugin, and inside of nginx files, but they both return No input file since there is no contact.php on my server.

Below is my nginx file for reference:

server {
    listen 80;
    listen 443 ssl http2;
    server_name mysite.com;
    root "/home/vagrant/mysite/public";

    index index.html index.htm index.php;

    charset utf-8;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    access_log off;
    error_log  /var/log/nginx/mysite.error.log error;

    sendfile off;

    client_max_body_size 100m;

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

        fastcgi_intercept_errors off;
        fastcgi_buffer_size 16k;
        fastcgi_buffers 4 16k;
        fastcgi_connect_timeout 300;
        fastcgi_send_timeout 300;
        fastcgi_read_timeout 300;
    }

    location ~ /\.ht {
        deny all;
    }

    ssl_certificate     /etc/nginx/ssl/mysite.crt;
    ssl_certificate_key /etc/nginx/ssl/mysite.key;
}

I know Craft is doing some weird things here to avoid index.php, not sure how it affects my situation though. In addition to mapping /contact.php to /info/, I would also like to make /gallery.php?c=category to /?filter=category

Thanks for your help!

To fix the "No Input File" in your Nginx config, you'll need something like this inside if your php location handler:

    try_files $uri $uri/ /index.php?$query_string;

That will cause it to run the query through Craft (via index.php) if the .php file doesn't exist, which then allows Retour to handle it.

You can see this works by hitting a random .php url on my site: https://nystudio107.com/woof.php

c.f.: https://github.com/nystudio107/nginx-craft/blob/master/sites-available/somedomain.com.conf#L106 & Nginx-Craft


How can I test if a field has been assigned to a channel? I've got a generic template that can display entries from different channels. How in the template can I test if a field has been has been assigned to any given channel?

Twig has a "is defined" test that you can apply to a variable to see if it exists:

{% if entry.possibleField is defined %}
    Yup!
{% else %}
    Nope!
{% endif %}

And here is more information on using is defined.


Not able to see the page Create your Account Accessing the ../admin page, it shows me the login page directly instead of create your account page. I don't have any account for Craft so I'll definitely need to create an account of mine in Craft but not able to find the Create Your Account page.

You or the person who setup your system created an user account. See step 5 in the installation documentation (http://buildwithcraft.com/docs/installing). Therefore there should be an account and you could try to reset the password.

If you have access to the DB directly you could get or set the email/username associated to that account. Another option would be to start with a fresh installation.


Element API: Entry field inside a Channel entry being passed into JSON file Hopefully my titles makes some sense but I will try to elaborate.

I have a Channel entry called Movies that I am using the Element API to turn into JSON. There is a field inside that called Movie Genre which is an Entry type field.

When I create this transformer:

'transformer' => function(EntryModel $movie) {

                return [
                    'name' => $movie->title,
                    'genres' => $movie->movieGenre[0]->title
                ];
            },

This is the JSON I get now, which looks to me like it is gathering all entries, not just the ones inside the channel.

  {"data":[{"name":"Harry Potter and The Order of the
  Phoenix","genres":"Fantasy"},{"name":"Jurassic
  World","genres":"Science
  Fiction"},{"name":"Romance","genres":null},{"name":"Science
  Fiction","genres":null},{"name":"Comedy","genres":null},
  {"name":"Fantasy","genres":null},{"name":"Guardians
  of the Galaxy","genres":"Action"},{"name":"Horror","genres":null},
  {"name":"Action","genres":null},{"name":"Home","genres":null},
  {"name":"Thirteen Ghosts","genres":"Horror"},
  {"name":"Movies","genres":null},{"name":"Genres","genres":null}],"meta":
  {"pagination":
  {"total":13,"count":13,"per_page":100,"current_page":1,"total_pages":1,"links":[]}}}

What I need to happen is only the Movies get returned as an item in the JSON and the movieGenre entry type not as its own item.

This is the desired JSON outcome.

  {"data":[{"name":"Harry Potter and The Order of the
  Phoenix","genres":"Fantasy"},{"name":"Jurassic
  World","genres":"Science Fiction"},{"name":"Guardians of the
  Galaxy","genres":"Action"},{"name":"Thirteen
  Ghosts","genres":"Horror"}],"meta":{"pagination":{"total":13,"count":13,"per_page":100,"current_page":1,"total_pages":1,"links":[]}}}

I figured it out. Turned out I had entered the criteria incorrectly, as channel instead of section.

'criteria' => ['section' => 'movies'],

not

'criteria' => ['channel' => 'movies'],


Plugin dev with Sendinblue mailer integration I am trying to integrate with sendinblue API and I installed it with composer as a third party library.
But it still does not work:
Fatal error: Class 'Mailin' not found in /localfolder/www/craft/plugins/stepsprogram/controllers/StepsProgramController.php on line 225

Here is the composer.json file at the root of my plugin:

{
    "name": "/stepsprogram",
    "description": "Steps Program.",
    "type": "craft-plugin",
    "require": {
        "composer/installers": "~1.0",
        "mailin-api/mailin-api-php": "^1.0"
    }
}

The init function of my plugin:

public function init()
{
    // If using composer
    require_once __DIR__ . '/vendor/autoload.php';
}

And the error happen here when trying to call the mailin class in my controller:

        $mailin = new \Mailin('https://api.sendinblue.com/v2.0', 'dqsdsapicode', 5000);    //Optional parameter: Timeout in MS
        var_dump($mailin->get_account());

Looks like you're missing the proper namespace.

Should be:

$mailin = new \Sendinblue\Mailin('https://api.sendinblue.com/v2.0', 'dqsdsapicode', 5000);

And here also is the other syntax for a global call in the controller.
Controller beginning would be:

<?php
namespace Craft;

use Sendinblue\Mailin;

class FooController extends BaseController

Then class call will be:

$mailin = new Mailin('https://api.sendinblue.com/v2.0', 'dqsdsapicode', 5000);


Store Contact Form submissions I am coming to Craft from Perch Runway so am trying to work out how to replicate some functionality from one to the other.

With Runway any form submissions, as well as being emailed to specified addresses, are stored on the database and viewable through the admin area.

I have installed the Contact Forms plugin for Craft (https://github.com/craftcms/contact-form) and was wondering if there is a way to do the same thing with this? Or do I need to look at another plugin / some custom functionality for this?

It is a helpful feature as emails are sometimes missed / fail to deliver etc.

Thanks!

Mike

Yeah. The contact-form plugin of craft is rather rough around the edges. I especially miss a error-handling. The form plugin just fails silently.

As a replacement I'd go for

AM Forms
Sospace's Freeform


URL Redirect Not Working Seems like I can't get the base install URL to work. To get Craft to show posts I have to format the URL as,

/public/index.php?p=news/2015/we-just-installed-craft

Instead of just the /news/2015/we-just-installed-craft

I think the .htaccess is getting read because after putting in garbage the server did error out when I used the /public/ URL but not sure what else I'm doing wrong or how I could troubleshoot this.

Try setting 'usePathInfo' => true and 'omitScriptNameInUrls' => true in your craft/config/general.php file.


Why does craft.request.getQueryStringWithoutPath return an empty string? I'm trying to use craft.request.getQueryStringWithoutPath() to handle query strings on pagination, but for some reason it always seems to return an empty string. If I try craft.request.getQueryString() I get the query string as expected (eg. foo=bar), but with the exact same URL getQueryStringWithoutPath() gives me an empty string.

Am I doing something wrong? Could this be a server configuration issue (I'm using Apache 2.4 with a fairly default configuration)? Or could this be a Craft bug...? I'd be grateful for any help!

Turns out this was a bug that only occurred if the existing URL didn't have an URI associated with it.  i.e. http://craft.dev?foo=bar.

It's been fixed and will be included in the next 2.5 beta release (or the first 2.5 public release if you don't want to swap to the beta track).


Assets indexing from plugin controller I am making a dashboard widget to trigger the assets indexing action.
I got the controller ready but I do not understand then how to trigger the action.

Should I go with AssetIndexTool? Then performAction()?
Or using ToolsController ?

I am really lost. Thanks for help!

I guess you would need to have your own method in your controller to fire up the indexing tool. From what it looks like, you need a few things to get going:

The classname of the tool i.e AssetIndex
An array of asset sources or * for them all
An indexing session id
An array of parameters to send to the tool

So I managed to get something working with the following code (this would go in your plugin controller)

public function actionUpdateIndex()
{
  // Get the AssetIndex tool
  $tool = craft()->components->getComponentByTypeAndClass(ComponentType::Tool, 'AssetIndex');

  // Generate an AssetIndex session id for us to use
  $sessionId = craft()->assetIndexing->getIndexingSessionId();

  // Set up some params
  $params = array(
    'start' => '1', // Tells the tool this is the initial request
    'sources' => '*', // All of them or [1,2,3] just ids1
  );

  // Get an initial response from the tool, will contain an array containing the assets to index
  $response = $tool->performAction($params);

  // See [1]
  foreach($response['batches'] as $key => $value)
  {
    foreach($value as $key => $batch)
    {
       // All the needed params are set in the array to do the index
       $tool->performAction($batch['params']);
    }
  }

}

Each time you call $tool->performAction($batch['params']); you will an array back, something like:

Array
(
 [success] => 1
)

[1] Because this is the initial request craft will return an array with a batches index, which we then have to do a few loops through, it looks something like this:

Array
(
 [batches] => Array
  (
   [0] => Array
    (
     [0] => Array
      (
       [params] => Array
        (
         [sessionId] => 6d08c5ba-169f-4b99-a7bd-cdc26c9428c7
         [sourceId] => 1
         [total] => 12
         [offset] => 0
         [process] => 1
        )

       )

      )

    )

 [total] => 0
)

Not sure if this is the absolute best way to do it, I was learning as I was going, but this worked for me so hopefully it'll work for you too :)


Fallbacks for assets not avilable in a locale I have a site with a lot of asset fields, the assets are translatable. The client has added lots into the English fields but many of the Welsh ones haven't been populated. I want to have things fall back to the English assets in cases where there aren't any in the Welsh.

For the sake of example, lets say we're on an entry page where an image has been uploaded in the English locale but one has not been uploaded in the Welsh locale...

I thought this would work:

{% if entry.assetField | length %}
    {# output whichever the current locale is, if it's populated #}

{% elseif entry.assetField.locale('en_gb') | length %}
    {# fallback to the UK English asset if it exists #}

{% endif %}

It doesn't. It will pull English assets if I'm viewing the English version of the page, but it does not fall back when we're on the Welsh version of the page. Furthermore, if I am on the Welsh page and change the code to only reference English, like so:

Then it doesn't output an image at all. It's like Craft is ignoring the .locale parameter I'm setting.

I'm certain the local values are correct because those are what are in the Locale setting in the CMS.

What am I doing wrong?

I think you have to apply locale('en_gb') to the entry and not to the field. So entry.locale('en_gb').assetField.first().url should give you the correct value for the other locale.


FormBuilder 2 - Notification email to the form submitter I have been using the FormBuilder2 plugin and it's fantastic. I am trying to understand if there is anyway that I can send an automatic email to the form submitter using this plugin. There is a possibility to insert a fixed email address in the plugin setting but this, of course, doesn't answer my need.

Any help would be appreciated a lot!

You could use the also wonderful amforms, which has this standard built in. The only thing is that it will send an exact copy of the admin mail. If you need a custom submitter mail, my guess is that sproutforms + sprout email is the best solution (you'll need them both).


How do I retrieve tags and tag data for an entry in Element API? In Element API v1, I am setting up an endpoint that is trying to expose a news entry including the tags (title, id, slug) associated with it. Thought it could be set up similarly to how you can retrieve categories using an array_map. But my code doesn't seem to work for tags.

'api/news.json' => [
  'elementType' => ElementType::Entry,
  'criteria' => ['section' => 'news'],
  'transformer' => function(EntryModel $entry) {
    return [

      'id' => $entry->id,
      'title' => $entry->title,
      'slug' => $entry->slug,
      'postDate' => $entry->postDate,
      'url' => $entry->url,
      'jsonUrl' => UrlHelper::getUrl("api/news/{$entry->id}.json"),
      'description' => (string) $entry->newsDescription,
      'tags' => array_map( function(TagModel $tag) {
        return [
          'id' => $tag->id,
          'title' => $tag->title,
          'slug' => $tag->slug,
        ];
      }, $entry->newsTags->find()),
      'type' => array_map( function(CategoryModel $category) {
        return [
          'id' => $category->id,
          'title' => $category->title,
          'slug' => $category->slug,
        ];
      }, $entry->newsType->find()),

    ];
  },
],

I took a break from this project. Came back, looked at the code, and saw a simple overlooked error - had a ")" instead if "}".  Grrr.  Starring too much at pixels lately. Fixed the code. So it's all working now. The array_map with the Tag Model does work.


What's the correct way to uninstall a plugin which MUST NOT be enabled? I hadn't allowed Craft to update for a while, and then did, but it broke on a plugin, and I couldn't get into the CP. I figured out which plugin was causing the problem, it turned out I wasn't using it, so I disabled it in craft/config/general.php as follows:
return [
    '*' => [
        'disabledPlugins' => ['embedded-assets-link'],
    ],
];

That enabled me access to the CP, but, being disabled, I couldn't uninstall it through the CP, as explained here.
I tried many things, including

remove references to the plugin in craft/vendor/craftcms/plugins.php
removed references to the plugin from composer.json
run composer update

and probably some other nonsense.
So, having done it the hard way, I'd like to ask, is there a correct way to remove a plugin which cannot be enabled ('cause it's broken) ?

You will need to enable it to uninstall it but you can do everything via CLI.
First ./craft plugin/enable plugin-handle then ./craft plugin/uninstall plugin-handle then composer remove namespace/package-name.
If you really can't enable it as above, you'd need to composer remove namespace/package-name and manually remove any references in your plugins table, project config as well as any tables the plugin may have created on install.


How to link to an entry in a Markdown field in the CMS I want to do something that's perhaps connected to the id so that if the title/slug updates, then I don't have to hunt anything down in entries across the CMS.

Something like this maybe?
[Link to an entry](/section#entry:10725)

I just figured out how to do this. It was vexing me!

Anyway, Craft is awesome and has provided support for Reference Tags.

Write your Markdown like this:

[link text]({entry:20})

Here's the Twig:

{{ entry.markdown|parseRefs|markdown }}

Reference Tags support more than just entries, but this was the bit that I needed.


Craft CMS solo licence It mentions developers can use it for personal usage. Does that include commercial usage as well? It seems so, but am not sure.

I have a few small personal sideprojects running with some Adsense and Affiliate links (currently on CodeIgniter, etc.).

According to Pixel & Tonic:

Can I use Craft Solo for client work?
Technically yes, however, we don’t recommend it. Craft Solo is meant to be a solution for developers to get to know Craft and create one-off sites for themselves and their friends. We do not recommend giving admin access to non-developers and therefore strongly recommend that any professional work is done on Craft Pro. This ensures the best experience for everyone.

So as long as you're ok with everyone having admin access (and no branding and no developer support), it's fine, including for commercial usage.