Craft Commerce payment gateway: general info requested one of our clients requested us to create a global webshop for their business. We have little experience with webshops and as we are avid fans of Craft, we'd like to start on this project with Craft Commerce.

It would be built with Commerce 1.x as their current site is based on Craft 2 and an update to Craft 3 is not possible at the moment.

My questions are a bit broad and is based on our little experience we have with Magento:

how far does Craft Commerce go when a user puts an order?
- The user buys something on the website
- The order is sent to the Payment gateway
- When the payment is processed, the gateway sends a confirmation back.
- What does Craft do next? Does it automatically set a new order status "paid"? It creates an order, but does it handle cancelations or order credit notes?
Or does Craft Commerce quits when the order is created?

Magento has some sort of built-in bookkeeping, but how far does Craft go?

What gateway is best for global/international payments?

How far does Craft Commerce go when a user puts an order?

When an order is paid in full it is marked as complete and gets a default order status that you can configure, after that a store admin would move the order to another status.

An order can also be completed if the payment gateway 'authorizes' the full amount of the order, allowing a store admin to 'capture' that payment at a later time.

But does it handle cancelations or order credit notes?

Cancellations of an order are a manual process. You would usually perform these steps:

Refund the transaction
Change the order status to a status you set up like 'cancelled'.
Have an email automatically go to the customer notifying them of the cancellation based on the order status.

Or does Craft Commerce quits when the order is created?

Not sure what you mean here, but you can manage the order in the CP after the order is completed.

Magento has some sort of built-in bookkeeping, but how far does Craft go?

Craft Commerce does not keep any type of accounting ledger, it simply allows you to manage order and take payments on those orders. Most developer build a custom sql query to export data to their accounting system.

What gateway is best for global/international payments?

Craft Commerce allows a single store with a single currency for all prices entered into that store for products / discounts / taxes etc.

You can have your products be manually translated for other regions since they are multi-locale aware.

Craft Commerce does have the ability to accept payment in currencies other than your primary currency so that your customer gets charged in a currency they expect to show up on their credit card statement - but you control the conversion ratio yourself.

It would be best to find the right payment gateway to use that supports the currencies/global regions for payments and then find out the level of support for that gateway in Craft Commerce. We always suggest Stripe.

Hope that helps.


table field - make one culumn translatable, other common for all languages Lets say i have table field with product technical specification - two columns, one for feature name, one for feature value.

Feature name (for example - "weight") needs to be translated across various languages. Feature value needs to always stay the same (for xample - "1kg").

How can this be achieved?

If there’s a predetermined set of feature names, then you could translate them using static message translations.

{% for row in entry.myTableField %}

{{ row.featureName|t }}

{{ row.featureValue }}

{% endfor %}

If new products will always be introducing new feature names, then that might become impractical, as you’d be constantsly adding new values to your translation file.

You could set up a custom translation message source + category in config/app.php that pulls translations in from a separate, translatable Table field on a Global Set, for instance, but that could be overkill.

The other option is to use Verbb’s Super Table plugin, which will let you mark certain fields as translatable.


How to limit RTF field word count? It is easy to set in the text field, but I don't see such option in RTF. How can I do it?

Alternatively, I can use a text field, though it doesn't output new lines as paragraphs - it is possible?

It can be done manually with Redactor Limiter javascript plugin that would be side-loaded to CP with, i.e., Control Panel JS plugin.

Alternatively, Redactor Extras plugin for Craft can be used, that contains and loads Redactor plugins itself.


When should I run queue/listen instead of queue/run? Definitions from the documentation:

queue/run: runs all the queued-up jobs
queue/listen: listens to
the queue and runs new jobs

Example case:

The runQueueAutomatically config option is set to false, and a cron job is calling queue/run every minute: /1 * * * * /path/to/project/root/craft queue/run.

In this case:

Should I run queue/listen instead of queue/run?
Does calling a new
queue/run when a queue/run job is potentially still in process,
could caused queue issues?

queue/run - should be used if you're going to manually execute this command via a cron job or such, because it runs any pending queue jobs, then exits
queue/listen - should be used if you want it to constantly poll (with a reasonable cooldown interval) for new jobs, and run them, because it runs a listen process that spawns a sub-process to run queue jobs as they come in

More here: Robust queue job handling in Craft CMS


Populate tables on Plugin install I'm using Records to create some new tables for use by my plugin. I now need to add some initial data to one of the these tables. What's the best way of accomplishing this on install?

Looks like overriding the onAfterInstall() method in the main Plugin class is where I should be adding this sort of stuff. Amazing what you find when you actually read the instructions!

More details here


{% requireLogin %} not returning to original page According to the Craft docs {% requireLogin %} on a page should return the user to the same page after login. This doesn't work for me - the returned page is always the one set in 'postLoginRedirect'.

In the config file, I've got this setup:

    'postLogoutRedirect' => 'members/logout',

    'postLoginRedirect' => 'members',

    'loginPath' => 'members/login'

What am I missing?

I may be missing something here, but you probably just want to remove the postLoginRedirect setting from the config?
You could also try adding {{ redirectInput(craft.app.user.returnUrl) }} to the form.
craft.app.user.returnUrl should return the URL that triggered the login.


How to add custom user fields to the front end registration page This question is similar to this post, but more of the next logical step.

I have added custom fields to my user profiles, but would like these attributes to be part of the registration page.

For example I'd like the user to specify their address on sign up, but I haven't found a way to reference this field correctly in the page.

Something like:

Address

<input id="Address" type="text" name="Address"
    {%- if account is defined %} value="{{ account.Address}}"{% endif -%}>

{% if account is defined %}
    {{ errorList(account.getErrors('Address')) }}
{% endif %}

This doesn't work because account.Address doesn't seem to be the correct way to access custom user fields on registration, and the only way I currently know how to access this field would be through currentUser.Address, but that relies on the account all ready being created.

Does anyone know how to access these fields to save during registration, or am I going to have to create the account first then have a second page that allows the user to set these fields?

You need to change your input tag from:

<input id="Address" type="text" name="Address"
{%- if account is defined %} value="{{ account.Address}}"{% endif -%}>

To:

<input id="Address" type="text" name="fields[Address]"
{%- if account is defined %} value="{{ account.Address}}"{% endif -%}>

All custom fields input types should have a name prefixed with fields[].


Best way to use saveCookie and craft.request.getCookie('location') Following up on this question: Prescribed way to set cookies (from plugin or Twig) the following works great.

craft()->userSession->saveCookie($cookieName, $data, $duration);

I can see Location being set as my cookie in the Application Log but when I try to use {{ craft.request.getCookie('location') }} It returns blank.

What am I missing here?

Edit - Upon closer inspection it doesn't look like saveCookie is working correctly either. I see location from when I was using setFlash but I need the data to persist even if the page is reloaded.

You should probably be using something like this:

    $cookie = new HttpCookie($name, $value);
    $cookie->expire = time() + 3600;

    craft()->request->getCookies()->add($cookie->name, $cookie);

Setting whatever properties you want on HttpCookie.

Using UserSessionService->saveCookie is meant mainly for Craft's session identity cookie, so it has some security checks it goes through saving the cookie that craft.request.getCookie('location') is probably failing.


Related entries from a dynamic dropdown I have a Matrix field where one of my child fields is a Dynamic Dropdown that uses the following code to pull in entries:

{% for entry in craft.entries.limit(null).section('dealers').type('online') %}
  { "value":"{{ entry.id }}" , "label":"{{ entry | raw }}"
    {% if entry.uri == '__home__' %} , "default":true{% endif %}}
    {% if not loop.last %},{% endif %}
{% endfor %}

The Matrix field has a handle of mensPDPLinks and the child field has a handle of retailer.

The above code creates a dropdown containing a list of retailers from another section.

When editing an entry containing this field a person can add as many retailers as needed by adding additional Matrix rows. It should be storing the entryID for each of the retailer entries they select. There are additional Matrix child fields to include other data to each retailer they select.

In my templates I'd like to loop through the entries (retailers) they've added in the Matrix field and display some data from the retailers entry.

Can someone point me in a direction? I'm kinda lost as to how I can do this.

You can loop though your "myMatrixBlockName" blocks to get all the retailers' entry IDs. Then use that array of IDs in a craft.entries ElementCriteriaModel to get the entries you're after. Use fixedOrder as a parameter to maintain the Matrix's sort order if you want that.

{% set retailerIds = [] %}

{# Loop `myMatrixBlockName` blocks to get the retailers' entry IDs #}
{% for block in entry.mensPDPLinks.type('myMatrixBlockName') %}

    {% set retailerId = block.retailer %}
    {% set retailerIds = retailerIds|merge([retailerId]) %}

{% endfor %}

{# Convert `retailerIds` array into comma separated list #}
{% set retailerIdString = retailerIds|join(', ') %}

{# Get `retailers` in the same order as listed in the Matrix field #}
{% set retailers = craft.entries.id(retailerIdString).fixedOrder %}

{# Loop `retailers` #}
{% for retailer in retailers %}

    {{ retailer.title }}

{% endfor %}


Translate icon appears but no translations exist I have a site in development that i replicated from another project.
The other project was multi lingual and had some fields that were translated.
This new site does not require any translations but the transalte icon is still appearing next to some fields which is very annoying.
Any idea how I can safely remove these?

You need to set the Translation method to Not translatable for each field displaying the unwanted translation icon, in the field's settings page.

It may be a tedious task if you have a lot of fields.


Formerly email validation What is the correct Validation Pattern format to add to a Formerly email field in the Craft admin control panel if I want to stop any submissions from email addresses with a .ru TLD?

I've tried:

!(\.ru)
/^((?!\.ru).)*$/s

But they do nothing.

Try find the regex string in https://regex101.com/ where you can define your pos and neg examples.

.*(?:(?!ru).).$

See https://stackoverflow.com/questions/16398471/regex-for-string-not-ending-with-given-suffix


What is the least intrusive way to allow a user to change their email address on the front-end? I have a page that will allow the user to change their name, email address etc.

If I have an email field on my page and submit I get this error.

Param “password” doesn’t exist.

I have read that in order to change a users' email, they need to enter their existing password. I don't have the password field on my profile page...I suppose I could.

Or should I make the whole thing an ajax submit, if the email has changed - show a modal or something asking for a password?

How have others solved this?

Thank you for any suggestions!

On the front-end of the site, if you're going through Craft's UsersController->actionSaveUser(), then you're correct... we do require the current user's existing password to create an elevated session for several security purposes.  How you present that to the user is completely up to you (as with anything else front-end related in Craft).

If you absolutely, 100%, don't want that workflow and are willing to accept the security risks of bypassing that behavior, then you can create your own plugin that exposes its own controller action, point your form to it and do whatever necessary business logic needed (modifying email directly in the database, etc.).


Get Related Entries and then filter those by specific category in url segment Channels:
  Photographers
  Photos - entries field handle "photographers"
         - categories field handle "category"

url structure where segment 2 is the photographer slug and segment 3 is the photo category slug:

domain.com/photographers/john-doe/food

On the photographers detail page I need to pull up the photos entries that are related to that photographer and in the category determined by segment 3

Set at the top of the page and used in a couple of different spots

{# set segment variables so we can use shorthand #}
{% set segment_2 = craft.request.getSegment(2) %}
{% set segment_3 = craft.request.getSegment(3) %}

{# get related photo entries #}
{% set photos = craft.entries.section('photos').relatedTo(entry) %}

Then where I want the photos to display I have the following code which outputs 2 entries from the photos channel. These are both related to the current photographer but in different categories. Only the one entry that is both related to the photographer and the current category should be output.

  {# set currentCategory to category id from segment 3 #}
  {% set currentCategory = craft.categories.slug(segment_3).first() %}

  {% set photos = photos.relatedTo(currentCategory.id) %}

  {% for photo in photos %}
    {{ photo.title }} <br>
  {%endfor %}

I'm not sure how to combine and filter these relations. Please advise.

We’ve built a plugin called Router that solves exactly this use case.

For the URL structure you described – domain.com/photographers/john-doe/food – this can be solved by the following configuration for the Router plugin:

/* config/router.php */

return [
  'rules' => [

    // URI pattern with named subpatterns
    '<placeholder:photographers>/<photographerEntry:{slug}>/<foodCategory:{slug}>' => [

      // array of filters that are activated when
      // the key matches a subpattern variable declared in
      // the route's regular expression
      'criteria' => [
        'placeholder' => 'section:photographerPhotos', // Base section
        'photographerEntry' => 'entry:photographers',  // Find slug in section
        'foodCategory' => 'category:food',  // Find slug in group
      ],

      // template file
      'template' => 'photographerPhotos/_entry',
    ],

  ]
];

And in the template:

{# photographerPhotos/_entry #}

{{ entries }} {# array of photos (related to both the photographer and food category) #}
{{ photographerEntry }} {# photographer Entry object #}
{{ foodCategory }} {# food Category object #}


Does Twigs 'addGlobal' exist in Craft? I know Craft gives us access to Twigs getTwig template service; so when I attempt to use the addGlobal function like so:
craft()->templates->getTwig()->addGlobal('var', $var);

... nothing happens. No errors. I had hoped putting this in my plugins init() would allow me to call the variable in a twig template like so: {{ var }}. But that just returns an error.

Variable "var" does not exist

I know of other methods to define global variables. I just wondered where I was going wrong with that quick one-liner that doesn't seem to work.
Maybe Craft has ommitted it?
Thanks,
Mark

Edit: I needed to do a little digging.

Internally, Craft can actually have multiple instances of Twig_Environment running (a Twig_Environment instance is what you get back by calling craft()->templates->getTwig()). Craft caches each instance in a private class variable, with the template loader classname and a hash of the environment's options making up the cache key. If a Twig_Environment instance doesn't exist for the loader classname and options array you pass to getTwig() (null and null, in your case), Craft will actually create a new Twig_Environment instance and return it.

This means that you're probably not getting back the same Twig_Environment instance that Craft is using to actually render your template – which explains why the call to addGlobal() works, but the variable is still undefined in your template.

The solution is to make sure to pass in the same loader classname and options as Craft does, to make the TemplateService return the same instance. The default here appears to be null for the loader classname, and ['safe_mode' => false] for the options.

In other words, this should work:

public function init()
{
    $var = 'something';
    $twig = craft()->templates->getTwig(null, ['safe_mode' => false]);
    $twig->addGlobal('var', $var);
}

Unfortunately, I don't know if Craft can ever be expected to use different options (or even a different loader) in certain circumstances – e.g. if safe_mode would ever be true. In any case, it is false by default in the TemplatesService render() method. Hopefully, someone might clear this up further.

Anyway – for a less hacky way to add globals to the Twig environment, here's my original answer:

You'll need to create a custom Twig extension. In your extension class, add a getGlobals() method, e.g.

<?php namespace Craft;

use Twig_Extension;
use Twig_Filter_Method;

class AwesomeTwigExtension extends \Twig_Extension
{
    public function getName()
    {
        return 'Awesome';
    }
    public function getGlobals()
    {
        $var = 'something';
        return [
            'var' => $var,
        ];
    }
}

Don't forget to actually load your custom extension – in your plugin's primary class:

public function addTwigExtension()
{
    Craft::import('plugins.pluginhandle.twigextensions.AwesomeTwigExtension');
    return new AwesomeTwigExtension();
}

Of course, adding the globals in a custom extension instead of just using your plugin's primary class' init() method is a bit more verbose, but remember that you could easily add a method to your plugin's primary class returning the globals and just call that from your extension, e.g.

// In your plugin's primary class
public function getGlobals()
{
    $var = ...
    return [
        'var' => $var,
        ...
    ];
}

// In your custom Twig extension
public function getGlobals()
{
    return craft()->plugins->getPlugin('pluginHandle')->getGlobals();
}

(You could of course also return the globals from a plugin service, which would be cleaner).

Hopefully somebody else will have an explanation for why the addGlobal() method doesn't work – and perhaps an even easier solution.


Multi-Env Craft Setup sharing DB I've setup a dev site on a subdomain alongside the production site and modified the config.php and db.php files on both installs for a multi-environment config. Since I only need to work on plugins and template files on the 'dev' site, would it be crazy to have the 'dev' site use the same mysql database as the live site? What would be the downfall in doing this?

I wouldn't do it, personally.  Especially if your plugin interacts with the database and you'll be creating/deleting tables, altering the schema, needing to restore the database, etc.

Too much risk in breaking the live site and very little benefit.


Printmaker fails to render images under SSL I am using the Printmaker plugin to print a pdf. Everything seems to be working well when the site is not being forced to use SSL.

I am getting the message "Failed to load PDF document."

If I remove the SSL, the pdf renders correctly. I would really like to have my site be under https - is there any way to help printmaker work?

I don't see anything obvious in the craft.log that would indicate an error, is there a configuration setting I'm missing?

Thank you for any suggestions!

EDIT

It is the actual image(s) in the pdf that are causing the error.

The full path to the S3 bucket is https, and I'm able to access the image just straight through the browser. I've copied/paste into the url bar and the image will render.

If I set the S3 path to http, and set the browser to http - all is well.
If I set the S3 path to https, and the browser to http - all is well.
If I set the S3 path to https and the browser to https - pdf fails to render.

UPDATE

To further test and and attempt to get some kind of error message/log to help trouble shoot, I've moved my image directory to a local path. I now the error "Image not found or type unknown". It looks like this could be a DOMPDF issue. I will continue to update this thread as I uncover more.

UPDATE

It does seem to be something related to forcing requests to SSL. If I remove https, the pdf renders every single time, every browser. If the request is made to the pdf using https, it fails every time.

UPDATE 2/Resolution

I don't really have an explanation for what was happening. Hopefully this will help others if they experience the same. I'm happy to update the answer however if anyone has suggestions.

I am forcing https on my site via .htaccess.

The pdf would render 100% of the time in every browser when the request was made using http. When the pdf was requested using https In Chrome I would always get "Failed to load PDF document". Firefox would always work and Safari would give me a grey screen. For others, it would work sporadically.

All of my images are being served from an S3 source (all https) so all of my assets were secure.

I ended up making my .htaccess file force https for everything except the request to the pdf.

RewriteCond %{HTTP:X-Forwarded-Proto} !^https
RewriteCond %{QUERY_STRING} !(^|&)entryId=(.*?)(&|$) [NC]
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [NC,R=301,L]

RewriteCond %{HTTP:X-Forwarded-Proto} ^https
RewriteCond %{QUERY_STRING} entryId=(.*?)(&|$) [NC]
RewriteRule (.*) http://%{HTTP_HOST}%{REQUEST_URI} [NC,R=301,L]

The url to my pdf looks like this:

https://mysite.com/entry/pdf?entryId=123

When a user makes a request to that url, they are redirected (301) to a non-https version.

http://mysite.com/entry/pdf?entryId=123

Hope this helps someone else!


Conditionally Display Content if Section How can I conditionally display content if its a specific section?

Currently I'm trying this with no luck:

{% if entry.section == 'lettings' %}{{ entry.rentFrequency.label }}{% endif %}

You're close!

SectionModel has 'name' and 'handle' attributes and one of those is probably what you're looking for.

{% if entry.section.handle == 'lettings' %}
    {{ entry.rentFrequency.label }}
{% endif %}


Show events in month by specific category - Solspace Calendar I've set up a category field for events. Multiple categories can be chosen. And I've set up a form to "filter" events to a specific category using query parameters.

The URL looks something like this (simplified; region is the category):

domain.com/events/month?&region=portland

Is there a way to show events that pertain to the category param in the month view?

Been banging my head and can't figure it out.

Figured it out. For anyone else seeing this later on:

{% set regionCategory = craft.categories.group('eventRegions').slug(region).one() %}

{% set month = craft.calendar.month({ relatedTo: regionCategory }) %}


Does "verify email addresses?" have to be enabled in order to fire the users.onActivateUser event? I'm trying to listen for an event when users create new accounts. I have the following code in my init() function in my main plugin class:

craft()->on('users.activateUser', function(Event $event) {
    error_log("user activated");
});

This isn't firing when new users register on the site and I'm wondering if this has to do with the "Verify email addresses?" users setting. I'm not requiring users to verify their email addresses. Does that setting have to be checked in order to trigger that event? If so, is there a different event to listen for?

Use the onSaveUser event instead but check for the flag inside that event called isNewUser

http://buildwithcraft.com/docs/plugins/events-reference#users-onSaveUser


How can I bust a template cached plugin variable in a loop? In my base template i set some variables  like currency , currency symbol based on the IP address detected. This is done from a geolocation plugin which caches the result (ip,currency, currency symbol,lang) and makes them available to the template as {{craft.geo.info.currency}}

The problem:

Our site is in UK
When a visitor from overseas eg. USA comes they get dollar prices and conversions etc

However, in the product list template I am caching the entry loop with cache tags and rendering the currency symbol with the plugins global template variable like this:

{{ craft.geo.info.currency_symbol |raw}} price XX

USA ip addresses sees US dollars - great!

However in the UK view of product list, and within the product page template loop, we suddenly see the dollar symbol too.

In my footer i spit out the {{craft.geo.info.currency_symbol}} with no cache tags and I get UK GBP currency as I expect.

I guess Craft/Twig is just showing the template cache regardless of plugin variable?

Is there a way around this?

My solution for now is to remove the cache tags from the product list - its not that many products and performance is still good - but I'd like to know how to combine the plugin currency symbol variable within the cached loop.

Left to itself, the {% cache %} tag will cache the content per-url. The problem you have is that the same url sometimes has $'s, and sometimes has GBP.

You can use the using key feature to cache based on the url and the currency:

{% cache globally using key craft.request.path ~ craft.geo.info.currency_symbol %}

(craft.geo.info.currency_symbol may not be the best disambiguator string, but this should get you started.)


Why can't I log in anymore when I change primary site manually in database? Because of a bug (https://github.com/craftcms/cms/issues/7657), I got locked out from admin because no site seemed to be marked as primary in the DB, even though one of the site files clearly had a primary:true setting.
This is using latest craft as of writing, 3.6.9.
Changing the primary site directly in the sites-table will cause the problem (WEIRD!), logging me out and refusing to log me in again. This doesn't happen in my dev environment when switching the primary site, so I'm not sure what's up here...

Craft 3.6.10 is out now with a fix for #7657. Note that the fix is not retroactive, so if you already have multiple sites in your project config YAML with primary: true, you should run php craft project-config/rebuild to fix that.


Cannot invalidate template cache (by element) on entries.onDeleteEntry I'm trying to do craft()->templateCache->deleteCachesByElementId on entries.onDeleteEntry, unsuccessfully.

The event listener is working, but the caches don't get invalidated.

Here's the code:

public function init()
{
    craft()->on('entries.onSaveEntry', function($event) {
        $this->clearEntryCache($event);
    });

    craft()->on('entries.onDeleteEntry', function($event) {
        $this->clearEntryCache($event);
    });

}

public function clearEntryCache(Event $event) {
    $entry = $event->params['entry'];
    craft()->templateCache->deleteCachesByElementId($entry->id, true);
}

entries.onSaveEntry works perfectly.
Instead of run deleteCachesByElementId, if I deleteAllCaches, it works (but I don't want to do this)
I've also tried entries.onBeforeDeleteEntry with no luck.
I've tried deleting from the entry, and from the entry listing (bulk delete) screen.

On the surface it seems maybe it isn't working because by the time deleteCachesByElementId, the element is already deleted...though it still seems there should be a way to delete that cache with the elementId reference.

Ok so here's what did it:
In my plugin, I had to manually call:

        craft()->templateCache->includeElementInTemplateCaches($entry->id);

With that, I didn't need had any of my event listeners in place.

Interesting that things seem to be inserted into craft_templatecachecriteria automatically, but not into craft_templatecacheelements...Perhaps that is bug?


How to upload several images & automatically create an entry for each one? I have more than 1000 images that I want to upload on Craft. Is there any way to bulk upload all the images and automatically create one entry for each one of them? Including their fields, like categories and tags?

I was going to suggest using the very handy Import plugin, but I see that it only supports entries, categories, and users. And unfortunately, I don't see another plugin that does this specifically. But have a look at the craft plugins page in case I missed something.

You might also be able to extend the Import plugin (with permission of course) to support assets. I would guess that it would be a similar process. This could potentially allow you to create a CSV file and import it... then upload the images into the location defined in your csv.


Internal Server Error while migrating to new server I'm trying to migrate to a server from my local environment. I keep getting Internal Server Error. I have the latest version of 3+ of CraftCMS. Everything works fine locally but on the server not so much. Here is what I'm seeing in my Craft log file.

    2019-02-08 05:02:35 [-][-][-][error][yii\base\ErrorException:8] yii\base\ErrorException: unserialize(): Error at offset 352 of 93525 bytes in /home/kinoliclients/public_html/jbbls/cms/vendor/craftcms/cms/src/services/ProjectConfig.php:997
Stack trace:
#0 /home/kinoliclients/public_html/jbbls/cms/vendor/craftcms/cms/src/web/ErrorHandler.php(76): yii\base\ErrorHandler->handleError(8, 'unserialize(): ...', '/home/kinolicli...', 997)
#1 [internal function]: craft\web\ErrorHandler->handleError(8, 'unserialize(): ...', '/home/kinolicli...', 997, Array)
#2 /home/kinoliclients/public_html/jbbls/cms/vendor/craftcms/cms/src/services/ProjectConfig.php(997): unserialize('a:17:{s:12:"dat...', Array)
#3 /home/kinoliclients/public_html/jbbls/cms/vendor/craftcms/cms/src/services/ProjectConfig.php(982): craft\services\ProjectConfig->_getStoredConfig()
#4 /home/kinoliclients/public_html/jbbls/cms/vendor/craftcms/cms/src/services/ProjectConfig.php(912): craft\services\ProjectConfig->_getLoadedConfig()
#5 /home/kinoliclients/public_html/jbbls/cms/vendor/craftcms/cms/src/services/ProjectConfig.php(227): craft\services\ProjectConfig->_getConfigurationFromYaml()
#6 /home/kinoliclients/public_html/jbbls/cms/vendor/yiisoft/yii2/base/BaseObject.php(109): craft\services\ProjectConfig->init()
#7 [internal function]: yii\base\BaseObject->__construct(Array)

The PHP log file gives a bit more information.

[08-Feb-2019 13:36:48 UTC] PHP Notice:  unserialize(): Error at offset 352 of 93525 bytes in /home/kinoliclients/public_html/jbbls/cms/vendor/craftcms/cms/src/services/ProjectConfig.php on line 997
[08-Feb-2019 13:36:48 UTC] An Error occurred while handling another error:
TypeError: Return value of craft\services\ProjectConfig::_getStoredConfig() must be of the type array, boolean returned in /home/kinoliclients/public_html/jbbls/cms/vendor/craftcms/cms/src/services/ProjectConfig.php:997
Stack trace:
#0 /home/kinoliclients/public_html/jbbls/cms/vendor/craftcms/cms/src/services/ProjectConfig.php(982): craft\services\ProjectConfig->_getStoredConfig()

Also, just for context. I had the site running on the remote server but then did an update (the one that said, this is a difficult update). The update put it in a vegetative state (internal server error). The same update worked locally, so I then copied the files and database to the remote server hoping that would fix the issue remotely. However, it didn't. Was their a new PHP extension requirement or something, that might have done this?

It ended up being an unserialization issue. After exporting the sql file, I updated it with the new domain. The serialization part within the craft_info table needs to have the correct character length in front of the domain. Fixing that fixed my problem.


Can not login in the control panel: Internal Server Error 500 The website ist working, but I can not login in the control panel.

In the console:

500 Internal Server Error - .../resources/lib/jquery-2.2.4.min.js?d=1493300895
setcookie() expects parameter 3 to be integer, float given (/html/alte gerberei/craft/app/framework/web/CHttpRequest.php:1514)

...

Has anybody an idea? Thanks in advance.

The error was caused by the configuration in general.php, which works fine local and on three other websites.

For production environment, I added

'userSessionDuration' => 'P101Y',
'rememberedUserSessionDuration' => 'P101Y',
'rememberUsernameDuration' => 'P101Y',
'invalidLoginWindowDuration' => 'P101Y',

Now I removed it and can login in the cp - no idea why.


How to toggle main product image from multiple images I'm having some trouble figuring out how to properly update the main product image from a set of images that are available.

Within the product detail page, I have a large default image that is shown with a set of thumbnails below from lopping through all available images associated with the product.

I'm able to loop through and display all available images for the given product using.

{% set relatedAssets = product.productPhoto.all() %}

  {% if relatedAssets|length %}
    {% for rel in relatedAssets %}

    {% endfor %}
  {% endif %}

What I'd like to do it update the large image once a thumbnail of the image set is clicked. I haven't been able to find anything related to successfully doing this which seems like a common pattern for an ecommerce site.

Any advice would be much appreciated!

Something like this (untested):

{% set relatedAssets = product.productPhoto.all() %}
{% if relatedAssets|length %}

    {% for rel in relatedAssets %}

    {% endfor %}

{% endif %}


How to populate a custom checkbox field with tag data dynamically? Hi wondering if this is possible. I have a custom checkbox field for user interests added to the user profile. Is there a way to populate the checkbox options dynamically using tag data?

I don't have enough reputation to post this as a comment, but this should help you pull the data on the front end with the LJ Dynamic Fields plugin.

Install the LJ Dynamic Fields plugin.

Create a 'Checkboxes (dynamic)' field with the following code:

{% for tag in craft.tags %}
   { "value":"{{ tag.id }}" , "label":"{{ tag }}" }
   {% if not loop.last %},{% endif %}
{% endfor %}

Front-end template code:

{% for tag in craft.tags %}
    <label>{{ tag }}</label>
    <input type="checkbox" value="{{ tag.id }}" {{ tag.id in entry.myCheckboxesDynamicField ? 'checked="checked"' }}>
{% endfor %}


How to display an entry id multiple times? I've set up a print template for furniture labels.
I let my client print the labels with a special Link like

/label?ids="x|y|z"

It all works good. Now he sometimes wants to print the same label multiple times, so he and I tried the following:

/label?ids="x|x|x|y|z|z|z"

The underlying code is the following:

{% set ids = craft.request.param('ids')| split('|')|join(',') %}
{% set params =
    {
        section: 'furniture',
        limit : null,
        id: ids

    }
%}
{% paginate craft.entries(params) as entries %}
{% for entry in entries %}
     ...
{% endfor %}

This will only display x and z one time.

Is there a way around this?

Any help appreciated.

I would write something like this:

{% set ids = craft.request.param('ids')| split('|') %}
{% for id in ids %}
    {% set entry = craft.entries.id(id).first() %}
    …
{% endfor %}

Alternatively, to reduce the queries, store all the entries in a variable and then loop through ids and find the right match in this smaller set.


Can access admin page (now), but not any site pages...yii not found http execption Have not accessed my local .test sites in a bit.  I tried today.  I am getting a series of errors.

At first I could not access any page to include the admin page.  I ran Composer update from the command line (within a site's directory) and then updated Craft from the command line (.\ craft update all).  I can now access the admin page and successfully login, but I am still getting errors trying to access the actual site's home page (or any page other than the admin page).

HTTP 404 – Not Found – yii\web\NotFoundHttpException
Template not found: login

All my templates are located here...(according to Finder)  /Users/myname/Documents/Websites/mysite/templates/index.twig

Where should I start?

I am presuming Craft 3 because of composer, but you didn't say.

To start with look in your craft templates folder. I would suggest that you simply don't have the template that Craft is looking for.

If you visit the root of your site this is normally templates/index.twig make sure this is present and has no further includes in it (just until you get it working)

Also try looking in storage/logs/web.log for errors.


How can I tell Smart Map to look at Commerce for entries? I have Smart Map working perfectly within Commerce. Meaning, I am able to show a map, etc. when I'm looking at products.

However, I am trying to build a "product locator" to find products in my area.

I am able to successfully pass the arguments to my results page - I can print out the zip code and distance that was chosen, but I am always getting into my "no results found" case.

{% set target = craft.request.getParam('near') %}
{% set radius = (craft.request.getParam('radius')) craft.request.getParam('radius') : 200 %}
    {% set params = {
    'target': target,
    'range': radius
} %}

{% set entries = craft.entries.address(params).order('distance').find() %}

radius is a drop-down of (miles) to choose from.
near is the name of the text input the user enters the zip.

You need to tell Craft to look within the Commerce section like this:

{% set entries = craft.commerce.products.address(params).order('distance').find() %}


Setting a default entry for the entry field I have an entry field that is a selector tool for the page call to action at the bottom.

I have a channel of four or five entries and I'd like one of them to be the default selection so it's one less thing to setup on a site full of pages.

I haven't seen any details or questions for this sort of request as of yet so I thought I'd ask the question.

Thanks,
Jay

Entry fields do not natively support setting a default entry, but you can use the Globals section to achieve the same effect.

Create a 'Default Call to Action Entry' field in your globals, and set the default entry for all pages there. For extra functionality, I would then also have a 'Call to Action Entry' field on your entries.

With this set-up, a user can select a custom entry to use on that entry if they want, but by default it will fall-back to the entry selected in the Globals.

Your template would look something like this:

{% set ctaEntry = entry.callToActionEntry.one|default('globalHandle.defaultCallToActionEntry.one') %}

If you didn't want to build the ability to override the default entry on a per-page basis, you can just use the field in the Globals:

{% set ctaEntry = globalHandle.defaultCallToActionEntry.one %}


Manually clean database cache Is it possible to manually clean the database caches for templates? Doing it from the CP becomes stuck.

This does not target the database cache specifically but I wrote this simple plugin to clear all caches from outside of the control panel.

https://github.com/themccallister/craft.cache-clear

Would that work for you?


HTML Purifier Config File I noticed the following new feature in Craft CMS 2.6.2973: Added the “HTML Purifier Config” setting to Rich Text fields.

I can't see any mention or any example of config files in the Craft CMS docs for Rich Text fields though, and the only thing I can see in the Rich Text Field settings in the control panel is this:

  You can save custom HTML Purifier configs as .json files in craft/config/htmlpurifier/. View available settings

Can someone help me with a custom HTML Purifier config .json file that I can use with Craft that would allow me to start using YouTube video embed code like this in Rich Text fields?

<iframe width="560" height="315" src="https://www.youtube.com/embed/HdYfAmrzVlc" frameborder="0" allowfullscreen=""></iframe>

At the moment, the above code will disappear when saving an entry unless I disable the Purify HTML? option in the Rich Text field settings. Thanks in advance for any help with this.

Something like this in a .json file should work:
{
  "HTML.SafeIframe": true,
  "URI.SafeIframeRegexp": "%^(https?:)?//(www\\.youtube(?:-nocookie)?\\.com/embed/)%",
  "Attr.AllowedFrameTargets": ["_blank"],
  "HTML.AllowedComments": ["pagebreak"]
}

Note that the first two lines were adapted from https://stackoverflow.com/a/12784081/684 and the last two are the default options that Craft uses if no custom config is set.
Probably also worth giving this a read: http://htmlpurifier.org/docs/enduser-youtube.html


Re-using path segments for an additional domain? I have a Craft installation with two domains pointing at it. The first domain is all working and has a number of sections including a blog located at /blog. What I want to be able to do is have a different blog section for the second domain that is also at the path /blog so naming conventions are all consistent i.e.

domain.com/blog
domain-two.com/blog

Of course in the CP when you add another section it will not let you use the same path which makes sense. As there is a lot of shared information but also a couple of sections/pages that will be different I thought perhaps using the .htaccess to rewrite the URL to include an additional path segment for the second site which could then be used in the CP to distinguish unique paths.

I tried modifying the .htaccess RewriteRule but could not get this to reflect in the information passed through to Craft.

RewriteCond %{HTTP_HOST} ^domain-two.com$
RewriteRule (.+) domain-two/index.php?p=$1 [QSA,L]

or

RewriteCond %{HTTP_HOST} ^domain-two.com$
RewriteRule (.+) index.php?p=domain-two/$1 [QSA,L]

Is there a way to make the rewrite work, I'm probably doing something wrong, or is there a better way to trigger a unique path from the same URL path? I really need to keep the URLs consistent.

In Craft, there is no such thing as a "section path" – there's only the "Entry Template" path (which tells Craft which template to load when the URL for an Entry in that particular section is requested) and the "URL format", which tells Craft how it should construct the URLs for the entries within that section.

It's actually totally possible to have multiple sections use the same URL format – e.g. blog/{slug} – so that part is easy; just use the same format for both of your blog sections, and all your URLs will be consistent out of the box (the only drawback to be aware of is that if you create entries with identical names within both sections, Craft will suffix the auto-generated slug for the newer entry with a number, i.e. my-generic-blog-post-title-2).

I'm assuming your blogs should use different templates for both their index and entry pages, so with the above URL format in place, it's simply a matter of routing the requests to the correct template(s).

The entry template is easy. You can set different paths for the two blog section's Entry Template path settings, e.g. blog/blogA/_entry and blog/blogB/_entry, or you can use the same path, e.g. blog/_entry for both. If you use the same template, you can conditionally {% include %} a blog specific template by testing the entry.section.handle value, e.g.

{% switch entry.section.handle %}
    {% case 'blogA' %}
        {% include 'blog/blogA/_entry' %}
    {% case 'blogB' %}
        {% include 'blog/blogB/_entry' %}
{% endswitch %}

For the blog indexes – i.e. domain.com/blog and domain-two.com/blog – it's important to realize that in Craft, there is no inherent relationship between templates and sections. For instance, even if you have a section with the handle blog and a template templates/blog/index, Craft won't automatically "connect" the template and the section, in terms of, for instance, populating the template with entries or other data related to the blog section.

What Craft will do, is to route all templates (that aren't hidden using an underscore prefix, i.e. _secret.html) to URLs. This means that if you do have a template under templates/blog/index.html or templates/blog.html, Craft will load that template whenever the URL domain.com/blog (and domain-two.com/blog) is requested.

In your case, you can exploit this behaviour by creating a template called templates/blog/index.html. Inside that template, you can add a {% switch %} statement similar to the one in the entry template, but this time looking at the craft.request.serverName variable (I'm assuming you've created index templates for each of your blog sections under templates/blog/(sectionHandle)/index.html):

{% switch craft.request.servername %}
   {% case 'domain.com' %}
       {% include 'blog/blogA/index' %}
   {% case 'domain-two.com' %}
       {% include 'blog/blogB/index' %}
{% endswitch %}

If you're looking for a more robust solution, you should look at Craft's multi-environment features, or possibly make use of the appId config setting; i.e. use different appId values for the two domains, and load templates conditionally based on craft.config.appId instead of hard coding the hostnames in your templates. To have Craft set a different appId based on the different domain names, you could add something like this to your craft/config/general.php file:

return array(
    'domain.com' => array(
        'appId' => 'siteA',
    ),
    'domain-two.com' => array(
        'appId' => 'siteB',
    ),
);


Custom action with Charge I'm trying to use a custom action with Charge. When a successful charge has been made I want to edit a user field. Charge appears to have Actions but little documentation on how they should be used ( http://demos.squarebit.co.uk/charge/actions )

So, I had opened charge/services/Charge_ActionsService.php and created a new one in there, which worked...

private function triggerActionCredits($details, ChargeModel $chargeModel)
{
    craft()->charge_log->action('Credits action triggered successfully');

    if (!is_array($details)) {
        craft()->charge_log->action("Details passed were: $details");
    } else {
        $detailsAsString = print_r($details);
        craft()->charge_log->action("Details passed were: $detailsAsString");
    }

    $userID = $chargeModel->userId;
    $theUser = craft()->users->getUserById($userId);
    $currentCredits = $theUser->creditsAvailable;

    craft()->charge_log->action("Got the user: $theUser");
    craft()->charge_log->action("Current credits: $currentCredits");
    craft()->charge_log->action("Details passed were: $detailsAsString");

    ... do stuff ...

    return true;
}

However, this should really be a plugin - so I've tried to port that code out of the Actions file and into its own plugin as follows:

public function init()
{
    craft()->on('charge.onCharge', function($charge){
        craft()->charge_log->action('Credits action triggered successfully');

        $pounds = $charge->amount;
        ...
}

The problem is that the line $pounds = $charge->amount; is throwing an error:

Property "Craft\Event.amount" is not defined

But; the event should be getting a Charge model? What am I doing wrong? http://squarebit.co.uk/software/craft/charge/usage/developer/hooks-and-events & http://squarebit.co.uk/software/craft/charge/usage/models/charge-model

You want something like this:

craft()->on('charge.onCharge', function($event)
{
    $charge = $event->params['charge'];

    $pounds = $charge->amount;
}


Having problem with installing Craft I am trying to install Craft on my server and I've hit a snug which I can't overcome, because I am just not that technically proficient.

I think I've followed all of the instructions on the Craft website to a t, however when I tried to get to the admin panel, I get the following error:

Could not find your craft/ folder. Please ensure that $craftPath is set correctly in /home/toaeroplano/public_html/index.php

I did some Googling on that and I found out that this might be an issue with open_basedir permissions.

So I went to my php.ini file and I saw that this was edited out. Like this:

; open_basedir, if set, limits all file operations to the defined directory
; and below.  This directive makes most sense if used in a per-directory
; or per-virtualhost web server configuration file. This directive is
; *NOT* affected by whether Safe Mode is turned On or Off.
;open_basedir =

So I changed it to:

open_basedir = ON (and took the ; off)

So now I get a "No input file specified." message.

What can I do? Like I said, this is far from being my area of expertise.

Thank you

It's likely your /craft directory couldn't be found. Out of the box, Craft expects it's /craft directory to be located just outside the root directory of the website. So by the looks of it from your path, your index.php file is located here:

/home/toaeroplano/public_html/

So that would mean you /craft directory should be located here:

/home/toaeroplano/

If I were you I'd put the php.ini settings back to what they were so you get the original error, then make sure you've copied the /craft directory from the installation into the directory above. If you want your /craft directory somewhere else you need to edit the index.php and specify where the directory lives. So edit this line in index.php:

$craftPath = '../craft';

The .. in the path just means the directory above, so if you wanted it to live in the /home directory, you change it to this:

$craftPath = '../../craft';

EDIT: Also make sure the permissions on the /craft/app/, craft/config/ and craft/storage/ are set as per the install docs.


How can I notify store owners when stock levels are getting low? For a Craft Commerce site, the store owners wish to be notified automatically when a stock is starting to get low. Can this be achieved with a plugin, and if so, how?

Just like Craft itself, Craft Commerce has lots of events you can have a plugin respond to. In this case, you'd want to write a plugin that waits for commerce_orders.onOrderComplete (per documentation) that evaluates the stock levels and probably uses Craft's Email Service to fire off notifications to the store owners.

Here's some quick pseudocode:

<?php

namespace Craft;

class StockNotificationPlugin extends BasePlugin
{
    ...

    function init()
    {
        craft()->on('commerce_orders.onOrderComplete', function($event)
        {
            // loop through the items in the order ($order->lineItems),
            // checking the remaining stock ($item->purchasable->stock)
            // against your desired threshold, firing off notifications
            // if applicable
        }
    }

    ...
}


Craft Commerce: Product Options I'm trying to get my head round how Craft Commerce manages product options. My Product has the following (multiple) options.

Material Type
Distance between design
No. of designs per metre
No. of meters (selecting this changes the price, so 1 metre is £100 and 2 metres is 200 etc)

The options can be set independent of each other.
Distance and No. of Designs will have set ranges the customer can choose from.
As this is just one product that effectively gets customised by the options there is no stock level.

Question One: Is multiple options on one product possible?

Question Two: Do I need to create variants for each option - how if so?

Question Three: Do I need multiple products based on the number of Metres (which changes the price)? Ideally I'd like one product that gets adjusted on the options selected. Is that possible?

Normally you would create variations of a product that would then be purchased by a customer. An example could be a plain t-shirt (the product), which is available in small, medium & large (each of these would be a variant of the product). This way you can easily keep track of stock, set different prices (like your No. of meters) and add different field values, if needed.

I would create a variant for each "No. of meters" as this will require a different price to be charged. However, creating a variant for each and every configuration would be overkill.

As you don't need to track stock and each product will be made to order I would instead look at adding the options to the line item using name="options[optionName]".

The following is taken from the default templates that come with Craft Commerce.

<select name="options[giftWrapped]">
  <option value="no">No gift wrap.</option>
  <option value="yes">Gift wrapped.</option>
</select>

These options are then set on the line item for that order. These would be viewable on the order summary page in the control panel.


Craft 2, child dropdown, database I am running Craft 2 CMS for one website. Its in Norwegian for our client.

Its about SKI School. Where Parents reserves sport dates for there children. In database there are parents profile with there children information, date of birth and names in craft_content.

I need to have on website dropdown, when parents login and go to sport dates, they can choose there children, instead of writing it, they choose also dates when there children participate, and price is multiple for chosen dates, on end they see total for payment, they can reserve, and pay later/or at once?

Is there solution for it. I have twig file for templates.

If I understand correctly, you want to create a <select> element with options from fields you already setup in the CMS. In that case you can use something like this to get the data for the field:

<label for="yourField">Your Field</label>
<select id="yourField" name="yourFieldHandle">

  {% set dropdownField = craft.fields.getFieldbyHandle('yourFieldHandle') %}
  {% for option in dropdownField.settings.options %}
    <option value="{{ option.value }}">{{ option.label }}</option>
  {% endfor %}

</select>

…replacing yourFieldHandle with the handle of your field, e.g.: children.


Redactor Images Button Missing I am currently using the Standard JSON configuration. My config is below. I cannot get the image button to show up for my Body Field/Rich Text. This is the same configuration I've used on other CraftCMS sites without issue.

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

not sure if it matters but in my config I have buttons in quotes

"buttons": ["format","bold","italic","underline","lists","link","file","image","horizontalrule"],


How to handle top-level/index pages in structure sections? It seems that currently if you want to avoid the main "about" page at the top of an "about" structure having a slug of /about/about/ then the approach people seem to take is to create an About page as a single, and a separate structure for subpages.

An alternative approach that occurred to me is to give the structure section a URL of just {slug} and then make everything a child of the "About" entry. Is there any particular disadvantage to doing this though?

I can see that it potentially allows URLs from different structures to clash (if someone creates a new top-level entry in a structure), but my feeling is that if I have to choose, the possibility for users to mess up the structure seems less bad than the probability that the "separate single + structure" approach will be confusing for users. Is there some other disadvantage that I'm overlooking here, though?

I recently setup a structure which contains (almost) every page of my site. When I set it up, I specified only {slug} as the URL.

So far, it's working fantastically! And that's with about 30-40 pages created in the structure (some nested within others).


Image Transform in template 'Auto' errors The docs state:

  format can be set to 'jpg', 'gif', 'png', or 'Auto'.

*Why is it 'Auto' not 'auto'?!

https://craftcms.com/docs/image-transforms#possible-values

I'm using a variable to define the transform settings:

{% set small = {
    mode:       'fit',
    width:      800,
    height:     600,
    quality:    80,
    position:   'center-center',
    format:     'Auto'
} %}

But Craft errors with:

  Imagine\Exception\InvalidArgumentException Saving image in "auto"
  format is not supported, please use one of the following extensions:
  "gif", "jpeg", "png", "wbmp", "xbm"

Is this a bug or is my code incorrect?

This was an error in the docs. You get the automatic format assignment by default, no need to explicitly set format: 'auto'.


commerce/cart/updateCart throws page not found Adding products to the cart throws a page not found (404) error that has this header;

Page not found.
↵
Caused by: Invalid Route – yii\base\InvalidRouteException
Unable to resolve the request: commerce/cart/updateCart
in /Users/a/Sites/ae-dev/vendor/yiisoft/yii2/base/Controller.php at line 128

Very strange. Anyone encounter this issue?

Based on your tag, I assume you're using Commerce 2.

Controller actions in Craft 3 use kebab-case, now, so your action should be commerce/cart/update-cart.


How would I setup my plugin to use a unique fieldlayout that is unique to the top level of the plugin? For example: Users. You can only have one fieldlayout per ElementType user which you customize in the settings section.

I've got as far as abstracting out the fieldlayout to it's own view, but when I go to set the field layout in the controller I'm borrowing the following code:

// Set the field layout
$fieldLayout = craft()->fields->assembleLayoutFromPost(false);
$fieldLayout->type = ElementType::MyElementType;

To which I get the following (pretty much expected) error:

 Fatal error: Undefined class constant 'MyElementType' in /controllers/MyElementTypeController.php on line 115

I've looked at how the plugin example "Events" is handling this and Brandon seems to be setting the fieldlayout->type to Assets:

$fieldLayout = craft()->fields->assembleLayoutFromPost();
$fieldLayout->type = ElementType::Asset;
$calendar->setFieldLayout($fieldLayout);

Is this how we're supposed to be setting these up? i.e., borrowing from other elementtypes?

You're bumping into this error because of a minor misunderstanding of how Pixel & Tonic are referencing their Element Types. The problem you have is with this line of code:

$fieldLayout->type = ElementType::MyElementType;

When P&T use that syntax, it's because they've already pre-defined all of their element types as enums. Open up the /app folder and take a look at this file to see what they've done:

  /craft/app/enums/ElementType.php

This allows them to use a syntax like ElementType::Asset.

You don't have that option (unless you create your own enum). What you would do instead, simply use a normal string to specify your element type:

$fieldLayout->type = 'MyPlugin_MyElementType';

This is the same string that you wrote when you defined the Model for your Element Type. It should be one of the first lines of code within your Model:

protected $elementType = 'MyPlugin_MyElementType';

Setting up enums is a different topic, but just go ahead and use the string and it should resolve that error for you!


Can I convert rich text field to have plain text output - with carriage returns? I am exporting some fields to an XML feed. There is a rich text field with typically 4 paragraphs in it.

The default export kicks out:

Some text
 tags as well as stuff like .

This is easy to remove with |striptags.

However, this results in text that doesn't have proper spacing and removes any intended carriage returns.

I can fix the spacing with a

|replace(".", ". ")

But I'd rather have the the Paragraphs to still have carriage returns as intended. I know I can add in the right UTF-8 symbol, but I don't want this in the data, I just want the spacing and carriage returns as if it were a plain text field and not to have the UTF-8 symbols in the feed itself.

http://www.fileformat.info/info/unicode/char/000D/index.htm

Any help, much appreciated.

Completely untested, but you should be able to do use something like the Craft-TwigPCRE plugin and some variation of this code:

{% set text = "
Some text
 tags as well as stuff like .|preg_replace('/\
/', '') %}

{% set text = text|preg_replace('/\<\/p\>/', '\\n') %}

\n is the Line Feed control character for Unix/OSX.


How to filter entries by tags array using ['or'] and by category not using or This works for filtering by tag array

{% set relatedToParam = ['or'] %}

{% for id in selectedTagIds %}
    {% set relatedToParam = relatedToParam|merge([{
        targetElement: id
    }]) %}
{% endfor %}

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

But how can we add another relatedTo param for category so the results only show the selected tag entries from a category?

For example to achieve this:

...WHERE categoryid = 'myid' AND (tag1 LIKE 'green' OR tag2 LIKE 'red' OR tag3 LIKE 'yellow' etc)

The relatedTo function accepts multiple different formats. If you want to search for Elements that are related to a list of categories and a list of tags you can do that like this

relatedTo([
    'and',
    ['element' => [1, 2, 3]],
    ['element' => [4, 5, 6]]
]);

This will return you all Elements that are related to the first array and related to the second array. So you goal should be to create an array of category IDs and Tag IDs and pass them together in the relatedTo

To get Elements that are related to all elements of one array and a single one from another array do the following

relatedTo([
    'and',
    ['element' => [1, 2, 3]],
    ['element' => ['and', 4, 5, 6]]
]);


Image Transforms and AWS I regularly use srcset to serve large images, such as heroes, and take advantage of Craft's image transform capabilities in the implementation, e.g. <img srcset="{{ image.getUrl('img500') }} 500w,...etc.
Curious to know if anyone has a clever solution for doing this when images are stored on AWS? I know I can still use transforms, but they will be saved on the webserver, not AWS. I could create subfolders in my AWS bucket and manually scale the images, but that is obviously not an ideal solution.
Thanks for any insights!

Most likely you have AWS policy issue. Never seen the problem you've described
Craft still will save images copy locally to improve speed. You can disable it using maxCachedCloudImageSize config and set it to 0.


Importing Members from ExpressionEngine I'm experimenting with migrating a large site from EE to Craft to take advantage of the performance improvements for an upcoming site redesign. I see there are some plugins that work well to import entries via XML or CSV, but I have been unable to find a way to import members.

Obviously, the passwords are stored in the database encrypted for the EE logins which makes it a little more tricky. Any thoughts? Thanks!

Tricky is a mild way of putting it.

EE and Craft both hash (not encrypt) their passwords differently. Hashing differs from encryption in a few ways, but the most important one here is that hashing is not reversible, which means that the passwords cannot be recovered. Which, in turn, means that if you import the user information into Craft, the members still would all have to reset their passwords.

If that's okay, then you would be looking at a custom plugin that uses the Users Service.


404 when viewing assets I'm having some trouble getting started with Craft.

I'm attempting to upload some image assets for the first time.

I've set up an asset source. I've tried using both a relative and an absolute path to the file. I am certain that the absolute path name is correct  because I simply copied from the pwd command on my server. Also, when I look in the directory, I see the uploaded images.

I've also supplied a url for the source. (I've actually tried a few different ones.)

Every time I've made a change, I've gone into settings and run Update Asset Indexes just to be sure everything was up to date.

However, when I try to view the images, I get a 404. I've tried typing the URL into the address bar, as well as clicking on "View asset" on the assets page.

I did see this similar question, but I'm not running an nginx server. I'm running Apache.

I would love any insight on what I could be doing wrong. If you need any additional information, I'll be more than happy to edit it in.

Edit: For clarity, I'm trying to set up my file directory and my url to have different structures, which I believe is possible. For example, I want my images to be in public_html/media/images, but I want the url for images to be http://mysite.com/images. Doing that seems to be what causes the problem.

I'll use myself as an example, so if something isn't right we'll know who to blame.

First thing I do is set up an environment variable in my craft/config/general.php file like this:

...
'.dev' => array(
    'devMode' => true,
    'siteUrl' => 'http://mysite.dev/',
    'environmentVariables' => array(
        'basePath' => $_SERVER['DOCUMENT_ROOT'] . '/',
        'baseUrl' => 'http://mysite.dev/',
    )
)
...

Then, when I am creating assets sources, I'll create a general "Images" source:

Name: Images
Handle: images
File System Path: {basePath}media/images/
URL: /media/images/

Note that I am using my environment variable in the file system path.

{basePath}

You can call that whatever you want, it just has to match.

So if you were to view the source of my site, an image that was uploaded would have the path of:

http://www.mysite.com/media/images/my-image.jpg

Hope this helps!


How to validate a form request Is there anything with craft like Laravel's Form Requests?

I am writing a plugin with a custom entry type. Right now, I am doing the store/edit pages and I do not want to reinvent the wheel ;)

Is there any way in craft/yii to easily validate the submitted values from a post request? Or what is the best practice in this case for craft?

Yii 2 (which is what Craft 3 is built upon) has similar looking form/model validation:

https://www.yiiframework.com/doc/guide/2.0/en/input-validation

https://www.yiiframework.com/doc/guide/2.0/en/tutorial-core-validators

You can also look at how Craft does it in its own models and controllers.


Relation row insertion in DB (plugin) this is my first question on StackExchange regarding CraftCMS.

Currently im working on a plugin that should insert a relation row (in db) regarding an entry and asset (image).

Is there a simple and easy way to insert a row in the DB with asset id, source id and field id?

Thanks in advance

If I'm understanding you correctly, what you're looking for is the RelationsService's saveRelations() accessed via craft()->relations->saveRelations().

You pass in your $fieldModel, $source ElementModel and an array of $targetIds that you want to created the relations to.


Changing the name of the Craft folder when placed above the webroot? Can you change the name of the Craft folder? I run several sites on a VPS and to place the Craft folder above the webroot, means that it sits in the User Directory, which has multiple domains running and potentially more domains could run Craft CMS and therefor the Craft folder(s) would conflict if they are all placed in the User Directory.

Yes, you can change the name of the craft folder. In the index.php file in the public folder update the path for the craft folder in the $craftPath variable. I use the following naming scheme for my sites:

// Path to your craft/ folder
$craftPath = '../craft-domainname';

So my server directory looks something like this:

/(server-root)
  --craft-domain1
  --craft-domain2
  --craft-domain3
  --public_html
    --domain1
    --domain2
    --domain3

I keep the name craft in my folder structure but you don’t need to. I just do so it groups all the Craft installations together.


How to upload an asset from a front-end form I've found information on how to upload an asset as part of creating an entry. What I am trying to do is upload an asset from the frontend without creating an entry. I have a logged in user, and what I would like them to be able to do is upload an asset to a folder that is unique to that user (folder name = username). Help?

That's not going to be possible to do without a plugin.

The plugin would need to provide its own Controller which does the following:

Grab info about the uploaded file using UploadedFile::getInstanceByName()
Determine the ID of the asset folder you want to upload the file to using AssetsService::findFolder()
Move the file into the folder using AssetsService::insertFileByLocalPath()

Here’s an example:

// Get info about the uploaded file
$file = UploadedFile::getInstanceByName('fileInputName');
$tempFilePath = $file->getTempName();

// Find the target folder
$folder = craft()->assets->findFolder(array(
    'sourceId' => 1,
    'path'     => 'subfolder/path/'
));

// Turn the file into a managed asset within that folder
craft()->assets->insertFileByLocalPath(
    $tempFilePath,
    $file->getName(),
    $folder->id,
    AssetConflictResolution::KeepBoth);


Get image from related entries asset field I have a "single" entry which has a "entries" field. The related entries have a image field of the "Assets" type.

In the template, i want to display the image from each of the related entries. I figured i could do the following

        {% for relatedImage in entry.relatedImages %}
            {% for images in relatedImage %}

            {% endfor %}
        {% endfor %}

Though not only does it not work, but it is probably pretty inefficient too. Whilst I'm here, how do people go about inspecting what you get from your vars? Is there a Twig/Craft equivalent to PHP's var_dump('relatedImage')?!

Any ideas most welcome!

Got a solution that is cleaner than nested for loops.

{% set myRelatedImage = entry.relatedImages.first %}

then I can do

<img src='{{ myRelatedImage.images.first.url }}'>

My use case was slightly different. I have a bunch of sermons entries that are related to a series entry. It's the series entry that has the image attached.

This worked very nicely.


Porting from EE - How to filter by category/segment in one template Sorry if there is an answer out there for this, I've read quite a few posts but have got myself confused. I hope you can point me in the right direction.

I have this code in my EE template:

{exp:switchee variable="{segment_2}" parse="inward"}
{case value="''"}
{exp:channel:entries channel="portfolio" dynamic="no" status="open" disable="pagination|member_data" orderby="date" sort="desc"}

    {cf_portfolio_link}
    {cf_portfolio_image}
    {title}

{/exp:channel:entries}
{/case}
{case default="yes"}
{exp:channel:entries channel="portfolio" dynamic="no" category="{segment_2_category_id}" status="open" disable="pagination|member_data" orderby="date" sort="desc"}

    {cf_portfolio_link}
    {cf_portfolio_image}
    {title}

{/exp:channel:entries}
{/case}
{/exp:switchee}

I'd like to do the same in Craft - use one template and filter my entries by segment(2).

At present I have this code in my Craft template (the first case works, the second returns a 404):

{% switch craft.request.getSegment(2) %}
{% case "" %}

{% for item in craft.entries.section('portfolioImages').order('id desc') %}

    {% for image in item.image %}

    {% endfor %}

{{ item.title }}

{% endfor %}

{% default %}

    filtered entries to go here

{% endswitch %}

The URL for my portfolio page is mysite.com/work or mysite.com/work/ecommerce-websites if it has been filtered.

I do have a category group set up in the system called Portfolio with 3 top level categories only:

ecommerce-websites
promotion-websites
product-catalogue-websites

Not sure where to go from here now.

Let me know if you need further information.

Cheers

/work/ecommerce-websites is giving you a 404 because there is no obvious place to route it. See http://buildwithcraft.com/docs/routing for details on how Craft tries to route each request that comes in.

You have 3 options:

GOOD: Create individual templates for each category

I’m not sure why you would want to do that, but it is an option, so I’m putting it here.

BETTER: Create a dynamic route

You can create a new dynamic route that tells Craft to point URLs that look something like “work/(slug)” to the “work” template, or you might be better off just creating a new “work/_category” template so that you don’t have a single template that is responsible for two entirely different types of pages, which is a little weird. (If there are similarities between the work index and a work category page, you should probably just create a new Work-specific layout template that outputs those things.)

BEST: Make these your primary category URLs

You said you have a category group set up, and the second segment is supposed to match one of them. If this is the primary place that you would expect to find info about these categories on your site, then go into Settings > Categories > [your group] and check the “Categories in this group have their own URLs” checkbox, and fill in the “Category URL Formats” and “Category Template” settings like so:

Then, double-click on each of your categories and make sure their Slugs are what you would expect the 2nd segments to be.

Here I’m expecting you’ve decided to create a “work/_category” template as suggested earlier, but if you really want your work index template to be handling these pages you can change the Category Template setting to just plain “work”.

As a bonus with this third approach, you won’t need to fetch your categories manually from the template; a category variable will already be available to the template, so you can go straight to outputting {{ category.title }} or whatever. (See step 4 on http://buildwithcraft.com/docs/routing).

This third technique also applies to sections/entries by the way. I mention that because based on your posted template code ({{ entry.websiteLink }}) it looks like you’re managing entry URLs manually with a custom field, which is really not necessary in Craft. Check the “Entries in this section have their own URLs” checkbox in your section’s settings and Craft will assign a primary URL to all the entries in your section, based on the URL Format you give it.


Nested objects for geoJSON using Element API I'm trying to create a GeoJSON feed using the Element API plugin but having difficulty creating the nested structure required for the JSON object:

{
  "type": "Feature",
  "geometry": {
    "type": "Point",
    "coordinates": [125.6, 10.1]
  },
  "properties": {
    "name": "Dinagat Islands"
  }
}

I can get a flat json structure using:

...

return [
    "type" => "Feature",
    "geometry" => "",
    "properties" => ""
];

...

My question is, how would I update the above code to create the nested json objects for geometry and properties?

Thanks. G.

I figured this out myself. I needed to use PHP array syntax.

In answer to my own question, the updated code for a nested object would be:

...

return [
    "type" => "Feature",
    "geometry" => array("type" => "Point", "coordinates" => [125.6, 10.1]),
    "properties" => array("name" => "Dinagat Islands")
];

...

Hope this helps someone else as it wasn't immediately apparent to me.


How to use select dropdown with entries/saveEntry for an entry field? How to use select dropdown with entries/saveEntry for an entry field?

I have an entry with a field that is another entry, which I want to update with a form:

<form method="post" accept-charset="UTF-8">
  {{ getCsrfInput() }}
  <input type="hidden" name="action" value="entries/saveEntry">
  <input type="hidden" name="entryId" value="{{ entry.id }}">
  <label>Vendor
    <select name="fields[vendor][]">
      <option>---</option>
      {% for v in craft.entries.section('vendors') %}
        <option value="{{v.id}}">{{v.title}}</option>
      {% endfor %}
    </select>
  </label>
  <input type="submit" value="Submit"/>
</form>

This works fine, except if nothing is selected in the dropdown (<option>---</option>). In that case, the POST value for fields[vendor][] is ---, and I get a SQL foreign key constraint error.

I have also tried <option value="">---</option> and <option value="NULL">---</option> with no better outcome.

I ran into this a while ago and it drove me nuts. Try adding disabled and selected attributes to your initial option in the select. So in your case <option disabled selected>---</option>.


JS login form on different domain and handling the CSRF token Having sorted out the CORS issue and succesfully logging into Craft from a different domain using Javascript, I've now turned CSRF protection back on. I've got a module returning the CSRF token name and value fine. I fetch the CSRF token with a GET request, then use that token in my login form submission. But I cannot get past Craft being unable to verify the data submission. The same code works fine when run from the same domain.
Does anyone have any experience of doing this?
function fetchCSRFToken() {

    var url = 'http://server.localhost/actions/server-module/server/get-csrf';

    function status(response) {
      if (response.status >= 200 && response.status < 300) {
        return Promise.resolve(response)
      } else {
        return Promise.reject(new Error(response.statusText))
      }
    }

    function json(response) {
      return response.json()
    }

    return fetch(url)
        .then(status)
        .then(json)
        .then(function(tokenData) {
            return tokenData;
        }).catch(function(error) {
        });

}

function login(event, tokenData) {

    var rawAction = "http://server.localhost/" + event.target.action.value;
    var action = encodeURIComponent(event.target.action.value);
    var csrfTokenName = encodeURIComponent(tokenData.name);
    var csrfTokenValue = encodeURIComponent(tokenData.value);
    var loginName = encodeURIComponent(event.target.loginName.value);
    var password = encodeURIComponent(event.target.password.value);

    var data = "action="+action+"&"+csrfTokenName+"="+csrfTokenValue+"&loginName="+loginName+"&password="+password;

    var ajax=new XMLHttpRequest();
    ajax.onreadystatechange = function(){
        if(this.readyState == 4 && this.status ==200){
            console.log(this.responseText);
        }

    }

    ajax.open('POST', rawAction, true);
    ajax.setRequestHeader('Accept', 'application/json, text/javascript, */*; q=0.01');
    ajax.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    ajax.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");

    ajax.send(data);

}

document.querySelector('#loginform-js').addEventListener('submit', function(event) {

    event.preventDefault();

    fetchCSRFToken().then(function(token) {
        login(event, token);
    });

});

And how I get the CSRF token from a module controller:
    /**
     * @return Response
     */
    public function actionGetCsrf(): Response
    {
        return $this->asJson([
            'name' => Craft::$app->getConfig()->getGeneral()->csrfTokenName,
            'value' => Craft::$app->getRequest()->getCsrfToken(),
        ]);
    }

EDIT: I suspect the preflight CORS request is invalidating the CSRF token? The preflight is only necessary on the remote server.

I don't have a good answer for this, but my response is too long to to put into a comment so here goes. I've been experiencing the same thing — I can successfully retrieve the CSRF token, but when I try to log in I get the dreaded 400 Bad Request error.
I found this tidbit on a page about Yii CSRF protection:

When you ebable CSRF validation and use form builder to generate a
form(only post), Yii will auto generate a hidden field and put it in
the form, at the same time, Yii will create a cookie with CSRF token.
When you submit the form, Yii will compare two CSRF tokens from post
and cookie.

I know for a fact that I don't have a cross-domain cookie so there's nothing to compare to. I think the missing cookie is the problem.
In any case, searching for Yii CSRF has given me more to work with than sticking to the Craft documentation. Surely someone has figured this out. In the meantime I'm disabling CSRF from whitelisted domains in my Craft config like this: (for development only):
'enableCsrfProtection' => (
  $_SERVER['HTTP_ORIGIN']  != 'http://localhost:3000' &&
  $_SERVER['HTTP_ORIGIN']  != 'https://staging.example.com' &&
  $_SERVER['HTTP_ORIGIN']  != 'https://example.com'
),

Quick update: maybe this thread can be of help.


Activiation URL empty Running into a weird issue with the site build I'm working currently:

We're creating users based on email addresses coming from an event platform API and are sending activation emails to those users (from our plugin,
using craft()->users->sendActivationEmail($user)).

The email gets sent out but the activation {{link}} is missing the host part of the URL. Instead we're seeing links like this: http:/actions/users/setpassword?code=bo2EDjfC7ebsrEpsx5T%7EyJ2Q6TRR0bI6&id=912b5712-89f6-4dbc-9337-dec15b518536.

Add the host in between and the link works perfectly. I've tried setting a {{ siteUrl }} specifically the locale I'm in but that doesn't do the trick either.

When I go to the new user in the back-end and copy the activation URL there, that one is correct.

Any pointers as to what might be causing this? Thanks!

UPDATE

This is the craft/config/general.php we're using:

<?php

if (!defined('PROJECTCODE')) {
    define('PROJECTCODE', strtolower('seapla'));
}

if (!defined('ENV')) {
    switch (strtolower($_SERVER['DOCUMENT_ROOT'])) {
        case '/data/sites/web/'.PROJECTCODE.'/subsites/'.PROJECTCODE.'.live.be/public';
            define('ENV', 'live');
            break;

        case '/data/sites/web/'.PROJECTCODE.'/subsites/'.PROJECTCODE.'.staging.be/public';
            define('ENV', 'staging');
            break;

        default:
            define('ENV', 'local');
            break;
    }
}

$settings = [
    'subscriptionPrice' => 275,
    'subscriptionPeriod' => 'P1Y',
    'invoicePrefix' => 'ECF2017',
    'autoLoginAfterAccountActivation' => true,
    'useEmailAsUsername' => true,
    'setPasswordPath' => '_members/_reset',
    'logoutPath'=> 'e-learning',
    'defaultCpLanguage' => 'en_be',
    'defaultWeekStartDay' => 1,
    'logoutPath' => 'logout',
    'enableCsrfProtection' => true,
    'omitScriptNameInUrls' => true,
    'postCpLoginRedirect' => 'entries',
    'addTrailingSlashesToUrls' => false,
    'defaultSearchTermOptions' => array(
        'subLeft' => true,
        'subRight' => true,
    ),
    'environmentVariables' => [
        'basePath' => getcwd(),
        'baseUrl' => strtolower((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 'https://' : 'http://') . $_SERVER['SERVER_NAME']),
    ],
    'siteUrl' => strtolower((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 'https://' : 'http://') . $_SERVER['SERVER_NAME']),
];

switch (ENV) {
    case 'live':
        $settings['devMode'] = false;
        $settings['cache'] = true;
        break;

    case 'staging':
        $settings['devMode'] = true;
        $settings['cache'] = false;
        break;

    default:
        $settings['devMode'] = true;
        $settings['cache'] = false;
        break;
}

return $settings;

Figured it out by debugging getSiteUrl in UrlHelper.

Setting siteUrl like 'siteUrl' => strtolower((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 'https://' : 'http://') . $_SERVER['SERVER_NAME']) is fine for browser requests, but $_SERVER['SERVER_NAME'] isn't available when running a console command.

The scheme is set correctly and since we have addTrailingSlashesToUrls set to false, the result became http:/.

Fixed for now by hard-coding siteUrl in our general.php for each environment.


How-to display a dropdown field with optgroups? The display of a dropdown without optgroups is defined:

{% set field = craft.app.fields.getFieldByHandle('<FieldHandle>') %}

<select name="fields[<FieldHandle>]">
    {% for option in field.options %}

        {% set selected = entry is defined
            ? entry.<FieldHandle>.value == option.value
            : option.default %}

        <option value="{{ option.value }}"
                {% if selected %}selected{% endif %}>
            {{ option.label }}
        </option>
    {% endfor %}
</select>

The following error occurs:

Key "default" for array with keys "optgroup" does not exist.

This would work for both with or without optgroup (replace aDropdown with your fieldname):

{% set field = craft.app.fields.getFieldByHandle('aDropdown') %}

{# If we have optgroups in this field, set a counter to 0 else return false #}

{% set optgroupCount = field.optgroups ? 0 : false %}
<select name="fields[aDropdown]">
    {% for option in field.options %}

        {% if option.optgroup is not defined %}
            {# This is a regular option #}
            {% set selected = entry is defined ? entry.aDropdown.value == option.value : option.default %}
            <option value="{{ option.value }}" {% if selected %}selected{% endif %}>
                {{ option.label }}
            </option>
        {% else %}
            {# This is an optgroup #}
            {# Check if we should close a group before opening a new one.#}
            {{ optgroupCount > 0 ? '</optgroup>' }}
            <optgroup label="{{ option.optgroup }}">
            {% set optgroupCount = optgroupCount + 1 %}
        {% endif %}

    {% endfor %}
    {# If we had optgroups better close the last one #}
    {{ optgroupCount ? '</optgroup>' }}
</select>


Controller action redirection when called via route I have a route set up in routes.php that calls a controller action using something similar to what is described here: https://straightupcraft.com/articles/how-do-i-setup-a-route-to-point-to-a-controller-action-instead-of-a-template

This works much better for my purposes than POSTing a form to the controller. However, I'm not sure how best to handle redirects. Ideally I would like to redirect back to the page where the user clicked on the link, but calling

$this->redirectToPostedUrl()

doesn't work when using a route like this. The URL just remains the URL as defined in the route.

Is there a different method I can use to make sure users are returned to the page where they were when they clicked the link?

You're mistaken about how redirectToPostedUrl works... That's designed to redirect from a form submission, when the redirect field was supplied:

<input type="hidden" name="redirect" value="page/to/redirect/to">

What you really want is this:

$this->redirect(craft()->request->getUrlReferrer());

The request->getUrlReferrer method will actually retrieve the originating page URL.


How to slightly alter _layout for one specific page? I have a _layout which includes a contact button:
{% include '_contact-button' %}

This creates a small contact button in the bottom right of every page that when clicked expands into a contact form. I would like this to be on every page of the site except the Contact page as it has it's own contact form. Is there a way in the contact template to not include _contact-button while still using _layout? Something like {% dontInclude '_contact-button' %}?

Try putting it inside of a simple block as the default value...

{% block contactButton %}
    {% include '_contact-button' %}
{% endblock %}

Then on your one-off page, override that block with emptiness...

{% block contactButton '' %}

Untested, but that should do the trick!


How I can capture previous and current URL to a hidden form field I need to create a hidden form field and populate the previous and current URL can someone tell me how I can do that in Craft.

In the context of Craft 3,

<input type="hidden" name="referrerUrl" value="{{ craft.app.request.getReferrer()" />

<input type="hidden" name="currentUrl" value="{{ craft.app.request.getAbsoluteUrl() }}" />

You can see other methods off of the web/Request object you can use here: https://docs.craftcms.com/api/v3/craft-web-request.html


Delete CSRF cookie on submit form success I need to delete the CRAFT_CSRF_TOKEN cookie when a form submission reaches certain/success page. I'm using CSRF stripped cookie's value to store entry title like this:

{% set token = craft.request.csrfToken[:10]|replace({'~':'P', '_':'B', '|':'T'})|upper %}

Upon succesful form submission I'd like to erase cookie name CRAFT_CSRF_TOKEN and it's value so on next form load there is a new cookie value set for CRAFT_CSRF_TOKEN name to prevent next entry to be stored/updated in the same entry.

Trying to achieve this I've failed right after accessing to csrfTokenName.

Neither the property "csrfTokenName" nor one of the methods
"csrfTokenName()", "getcsrfTokenName()"/"iscsrfTokenName()" or "__call()"
exist and have public access in class "Craft\HttpRequestVariable"

I guesss this could be accomplished using the cookies plugin or a simple jquery cookies library like js-cookie.

This is how you would go about it with the cookies plugin: set the cookies name without any value:

{{ setCookie( NAME ) }}


Memory Upgrade Issues Problem
Hi all, I have been struggling with issuing the command ./craft gc. It shows the following
Delete all trashed items? (yes|no) [no]:yes
Running garbage collection ... PHP Fatal Error 'yii\base\ErrorException' with message 'Allowed memory size of 134217728 bytes exhausted (tried to allocate 16384 bytes)'

the allowed memory size equates to 128MB. I attempted to increase the limit but it still showed the 128M Allowed memory size.
What I've Done

I have set 'phpMaxMemoryLimit' => '1024M' in config/general.php
I have set memory_limit = 1024M in the php.ini
I executed the command php --ini |grep "Loaded Configuration File" which showed the correct path
I made a webroot/phpfile with <?php phpinfo(); which showed both the correct path, and correct memory_limit
I checked admin/utilities/php-info which showed the correct memory_limit

Information

PHP version   7.3.3
OS version    Darwin 19.2.0
Craft edition & version   Craft Pro 3.3.19
Mamp PRO version 5.3

Sounds like you don't have the correct PHP loading in your CLI. You should try using MAMP’s PHP Executable in your Terminal.


Get and display a product's variant fields in twig I'm working on a product template that can display products of any type.

Various product types have varying numbers of variant fields each with their own options as other products. (All of my variant fields pull in other product types.)

I want to display each variant field's options as a separate dropdown on the product page.

Can I dynamically fetch the product's variant fields and field options in my product template? I would need, for a given product, to be able to get:

Its product type's variant fields to loop through
Each field's:

Options (and I'd want the option of starting the option list with a "None" option)
Or product type source(s), so that I could display those in an option list directly.

It looks like I'm trying to use variants the way options can be used. I'm going to go with options.


How to add a tags-field to an entry form? I use the following entry form (front-end): https://craftcms.com/docs/templating/entry-form

How can I add a tags-field to this entry form?

You would need to add inputs to the form based on your Tags field handle, with values set to the tag IDs that should be selected.

Here’s a very simple example – it creates a big checkbox list of all the existing tags:

    {% for tag in craft.tags.group('myTagsGroup').limit(null) %}

            <input type="checkbox" name="fields[myTagsField][]" value="{{ tag.id }}">
            {{ tag.name }}

    {% endfor %}

Note that it is not possible to create new tags directly from a Tags field. If you want users to also be able to create new tags from your form, that will require a little Javascript.

+ New tag

Make sure to set the correct groupId in that data object. You can find your tag group’s ID by looking at the URL when editing the group’s settings within Craft’s CP.


Is it possible to return data/models from controller to template via setRouteVariables? I'm trying to write a plugin that lives in the admin interface, that reads external data (a cinema program), parses it, and creates entries based on this (movie info and screening times).

While doing so I build a log of the additions/updates made, that I want to return to the template (the plugin page from where I trigger the update) and display the changes listed in a table. But I have trouble reading anything out with craft.request.getPost() from the template.

The log, basically an array of custom models (log items), seems to be fine while still in the controller. I try to pass this array via craft()->urlManager->setRouteVariables(), but at the template, it seems the only variables it finds are the action and redirect parameters from the original form.

The code in the controller looks like this:

$log = craft()->updateProgram_program->update();
craft()->urlManager->setRouteVariables(array(
   'log' => $log
));

And then I try to read the log variable in my template like this:

{% set log = craft.request.getPost('log') %}

Whatever I do, it seems to always be NULL. I've also tried to set a simple text string as the value, in case it's not possible to post an array like this, but it's still NULL when it comes to the template. It seems the log parameter is simply not found in the POST request at all.

Is there anything obvious I'm doing wrong?

I've scratched my head all day over this, so any tips are extremely welcome!

I believe you are overwriting the log variable you are sending back to the template when you set log equal to the response of getPost.

From what I can see of your code, when you return variables to your template via setRouteVariables, you should be providing the variables you define in that array to your template, without having to take a second step and retrieve them.  So, when your controller returns:

craft()->urlManager->setRouteVariables(array(
   'log' => $log
));

You should then be able to access that variable in your template if it exists:

{% if log is defined %}
    {{ dump(log) }}
{% endif %}

setRouteVariables adds your variables to Twig's context, which you can see in your template by dumping _context:

{{ dump(_context) }}

Or, a handy way to just see the variables available in the context and not the full models is using the keys filter:

{{ dump(_context|keys) }}

In your case, I believe when your page reloads, your log variable is available, but then you set it to null when you try to retrieve it.

Your current code:

{# Sets log to null, because no post variable exists named `log` #}
{% set log = craft.request.getPost('log') %}

{% if log is defined %}
    {{ dump(log) }} {# outputs null #}
{% endif %}

Try outputting the log variable before setting your getPost value:

{# Outputs log if it exists in Twig's context #}
{% if log is defined %}
    {{ dump(log) }} {# will probably output your value #}
{% endif %}

{# Delete this. It just overwrites your existing log variable #}
{% set log = craft.request.getPost('log') %}


Getting unknown property: craft\feedme\events\FieldEvent::fieldValue Getting a strange error when trying to check if a field is null when importing via FeedMe

Getting unknown property: craft\feedme\events\FieldEvent::fieldValue

use yii\base\Event;
use craft\feedme\events\FieldEvent;
use craft\feedme\events\ElementEvent;
use craft\helpers\ElementHelper;
use craft\elements\Entry;

Event::on(Fields::class, Fields::EVENT_AFTER_PARSE_FIELD, function(FieldEvent $event) {
    switch($event->feed['name']){
    case 'offers':
    if ($event->fieldHandle === 'merchants' && $event->fieldValue == null) {
    $event->isValid=false;
    }
    break;
}
});

It should be $event->parsedValue - see here - https://github.com/craftcms/feed-me/blob/develop/src/services/Fields.php#L225


How to display all fields for an entry within an entry field type? I've got a portfolio site I'm building, and on each project's page I'm wanting to show a list of people who worked that project. I created a channel section called "work" with an entry field type called "team". I then created another channel called teamMembers with a plain-text field for their name, another plaintext field for a link to their website, an assets field for their profile picture, and a categories field which would indicate their role in the project. When I'm adding a project as an entry in "work" i have an entries field that allows me to select team members from the teamMembers channel.

For the life of me I can't figure out how to display a list of team members (with each team member's name, link and photo) who worked on a project.

Here's my progress so far: http://dziey3.com/work/polaris

Team

            {% set team = entry.team %}
            {% for asset in entry.teamMembersPhoto.find() %}

            {% endfor %}
            {% for field in team %}

{{ field.title }}

            {% endfor %}

Thanks in advance

It seems on your website that you get the team listed, but not the photos. I think the problem might be that you are accessing the teamMembersPhotoof the entry, not the team.

You can try changing it to
{% for asset in team.teamMembersPhoto.find() %}


Images Broken In Redactor I have an issue that I really do not expect. When using the image function in the Redactor wysiwyg editor, images come up broken. In the editor, and in the rendered entry. All that is missing is a / in the img tag and they work. So redactor is rendering,

and but what it needs is the beginning /

Have I configured something else wrong?

I was adding a slash in from after grabbing image urls in my template code,

/{{ image }}

Did not think about how it might break redactor.


Image quality get low in Craft 3 after applying image transform As of now I am using Craft's image transform to render images according to the size.  If this still appears low quality even Image Transform setting with qulity "Maximum".

If the dimensions of the image are being displayed is larger than the transform dimensions it will show pixelation in the image. Just double up the dimensions of the transform image to see if this fixes it.