Getting error "Your session has ended. Enter your password to log back in." every 30 seconds or so This is happening for all users and only on production environment.

"Your session has ended. Enter your password to log back in."

Entering your password does not allow you to actually see the admin panel again.

Things we have tried:

Deleting the contents of craft/storage/runtime
Removing all rows from craft_sessions in db
Setting 'overridePhpSessionLocation' => false
Setting 'requireMatchingUserAgentForSession' => false
Setting 'userSessionDuration' => false
Setting craft/app/, craft/storage and craft/config as CHMOD 774
Changing craft/ folders to be owned by www-data
Setting session.auto_start = 0

Our environment is PHP 7 with Ubuntu 16.04 running Apache 2.4.18

Something to consider is we run with an Akamai CDN cache that is set to ignore our entire /admin directory, but my suspicion is that something elsewhere is getting cached. Thoughts about that? Is there another directory we should be ignoring?

Also as a point of info, our /craft folder is above the docroot so not publicly accessible and therefore unlikely to be cached.

Finally, what's very strange is if I remove the modal containing the error message from the DOM in Chrome Inspect, I am able to still navigate the panel fine, without having to re-authenticate. Error also happens in both Chrome and Firefox.

Thanks for the troubleshooting help. It appears as though the issue was the cache and how Craft handles sessions.

For those who use a cache/CDN and are having issues with control panel session timeout:

Even after ignoring /admin on our cache, the cached pages on the public-facing portion of the site were conflicting somehow with how Craft was handling the sessions in the admin panel.

Our solution was to create a cookie we called isAuth that was created on login and destroyed on logout. We did this by creating a plugin and using userSession.onLogin and userSession.onLogout.

Then we set our Akamai cache to no-cache, no-store if isAuth cookie is present. This fixed all timeout issues.


How to update the lineItemStatus of an order on the front end with twig? I'm building a simplified interface that is only going to be used by employees preparing the orders. They are in a usergroup that has the right permissions to update orders.
I'm building this because updating an 'order status' or 'line item status' from the controlpanel is too finicky to do from a smartphone or tablet.
I've found how to update an order status here and got that working nicely.
{% set order = craft.orders.id('123').one() %}
{% do order.setAttributes({'orderStatusId': 4}, false) %}
{% do craft.app.getElements().saveElement(order) %}

What I don't know how to do is how to update the lineItemStatus.
I'll probably have to fetch the order first then the lineItem id and then update the lineItemStatus attribute, but I have no idea how to even start.
Any help putting me in the right direction is greatly appreciated!
*I also know this would be better to do with a module or plugin, but alas, I don't write php.

You can use the same technique to set the line item data like this:
{% set order = craft.orders.id(123).one() %}

{% for lineItem in order.lineItems %}
    {% do lineItem.setAttributes({lineItemStatusId: 2}, false) %}
{% endfor %}

{% do order.setAttributes({
    orderStatusId: 4,
    lineItems: order.lineItems
}, false) %}

{% do craft.app.getElements().saveElement(order) %}

^ That would set all line items in an order to the same status... I imagine you have some kind of interface where you can either update a single line item at a time or mark several at once and press a submit button, so in that scenario you'll probably want to add some conditionals inside the loop to check that the line item id you're on matches say, the line item id passed in through the URL or through POST data or whatever so that just the right one(s) get updated


How can I get field's value of entry in other site locale in my element-api endpoint? I'd like to get a field value in 3 differents locales in the same element-api endpoint but I can't make a request similar to this one :  craft.entries.siteId($siteId).id($entryId).one() in twig.

<?php

use Craft;
use craft\elements\Entry;

return [
  'endpoints' => [
    'exhibitions.json' => function() {
      return [
        'elementType' => Entry::class,
        'criteria' => [
          'section' => 'exhibitions',
          // 'locale' => ['francais','english', 'deutsch']
        ],
        'transformer' => function(Entry $entry) {

          // -- Description --
          $description_fr = ($entry->summary) ? $entry->summary : ($entry->body) ? $entry->body : '';
          // $entry_en = $craft->entries->siteId(2).id($entry->id).one();
          // $description_en = ($entry_en->summary) ? $entry_en->summary : ($entry_en->body) ? $entry_en->body : '';
          // $entry_de = $craft->entries->siteId(3).id($entry->id).one();
          // $description_de = ($entry_de->summary) ? $entry_de->summary : ($entry_de->body) ? $entry_de->body : '';

          // -- Tags --
          $tags = '['.$entry->exhibitionsType->label.']';
          foreach ($entry->exhibitionsCats as $key => $cat) {
            $tags .= ',['.$cat['title'].']';
          }

          return [
            'type' => [
              array('target_id' => 'event')
            ],
            'title' => [
              array('value' => $entry->title)
            ],
            'field_subtitle' => [
              array('value' => $entry->subtitle)
            ],
            'field_description_fr' => [
              array('value' => $description_fr)
            ],
            // 'field_description_en' => [
            //   array('value' => $description_en)
            // ],
            // 'field_description_de' => [
            //   array('value' => $description_de)
            // ],
            'pictures' => [
              'url' => $entry->banner->one()->url,
              'copy' => $entry->banner->one()->legend,
              'alt' => $entry->banner->one()->legend
            ],
            'field_event_type' => [
              array('value' => '3') // Long or permanent event (3)
            ],
            'field_date' => [
              array(
                'value '=> $entry->fromDate->format('Y-m-dTH:i:s'),
                'end_value '=> $entry->toDate->format('Y-m-dTH:i:s'),
                'rrule '=> null,
              )
            ],
            'field_state' => [
              array('value' => 'scheduled')
            ],
            'field_type' => [
              array('target_id' => 6) // Audience - Pour tout public (6)
            ],
            'field_categories' => [
              array('target_id' => 24347) // Exhibitions (24347)
            ],
            'field_tags_rest' => [
              array('value' => $tags)
            ],
            'field_location' => [
              array('target_id' => 5179)
            ],
            'field_websites' => [
              array(
                'uri' => $entry->url,
                'title' => $entry->title)
            ],
            'field_email_address' => [
              array('value' => getenv('EIL_EMAIL'),)
            ],
          ];
        },
      ];
    }
  ]
];

Okay I found a way to do it if it can help someone:

$description_fr = ($entry->summary) ? $entry->summary : ($entry->body) ? $entry->body : '';
$entry_en = Entry::find()->id($entry->id)->siteId(2)->one();
$description_en = ($entry_en['summary']) ? $entry_en['summary'] : ($entry_en['body']) ? $entry_en['body'] : '';
$entry_de = Entry::find()->id($entry->id)->siteId(3)->one();
$description_de = ($entry_de['summary']) ? $entry_de['summary'] : ($entry_de['body']) ? $entry_de['body'] : '';


Correct way to getOrderByNumber() from my Plugin in Commerce 2 I am migrating my plugin to Craft 3 / Commerce 2.

What is the best way to call another plugins method like craft()->commerce_orders->getOrderByNumber($number) from my plugins service?

All of Craft’s core services are available via the Craft::$app->getServiceName()->callServiceMethod() signature.

For example, the Elements service would be Craft::$app->getElements()->saveElement()

In the case of other plugins, most will make their Singleton “instance” available as a property on (or method of) their primary plugin class:

use craft/commerce/Plugin as Commerce;
// Maybe a class declaration, and inside your own method…
Commerce::getInstance()->getOrders()->getOrderByNumber('abc123...');


How to show nothing when you leave an input field empty in the entries instead of showing an error? I made a content page (Channel) where the client can add a bunch of content. There will be multiple pages (1 page for every case) with the same layout. Sometimes they don't want to fill in every input field or asset. When they leave a field blank, I get an error.

Is it possible to just not show the parts they didn't fill in?
For example: When I put the website in 'production' they show the broken IMG instead of nothing.

Make sure to add an if statement to check if the value exist or not with the length filter for example.

{% if entry.videoPhoto50 | length %}
   <img src="{{ entry.videoPhoto50  .....
   ....
{% endif %}

So that your code is only executed if entry.videoPhoto50 has a value.


craft_searchindex is MyISAM all others InnoDB Looking at my database today notice this one table is MyISAM and also seems huge relative to all other tables with 147,835 rows.  Is that normal?  Shouldn't all tables be InnoDB?  What would cause one to be MyISAM?

The searchindex table has to be MyISAM because up until MySQL 5.6.4, MyISAM was the only engine that supported full text search indexing.

Craft currently supports back to MySQL 5.1.

It is normal for that table to be large because it's keeping a record of every searchable thing on your web site.


Getting a new cart after adding the product in decoupled frontend I'm using the headless Craft together with decoupled frontend on Nuxt.js.
I have to implement Craft Commerce 3 cart logic on the frontend, for that purpose I'm using graphQl/axios requests.
However each time I call http://example.com?action=commerce/cart/update-cart&note=from+ajax with cart payload it returns me a new cart with added product (doesn't update the current cart, but returns a new cart each time).
Is there something I'm missing in my payload/headers to keep the same cart?

UPD: after some hours of research I found the solution in this topic:
CORS preflight check failing for AJAX login form on different domain
Also I had to pass the orderNumber parameter with the value of cart number in payload.
However I have a different issue now. First I call ?action=commerce/cart/load-cart&note=from+ajax&number={number} to load my stored card into the session. Then I call action=commerce/cart/get-cart&note=from+ajax to get the content of the cart I loaded in step one, but it returns me a new empty cart. I suppose there is something to deal with the CraftSessionId in headers, am I right?


Create an alternate Stripe Payment Method Instead of taking payment via the Omnipay/Stripe Payment Method, what I'm trying to do is just create a new Customer and Credit Card on Stripe during Checkout, no payment taken at all at this stage.

Looking through the Stripe code it looks as though that functionality already exists. On the Stripe Gateway, this looks like it should do what I want.

public function createCard(array $parameters = array())
{
    return $this->createRequest('\Omnipay\Stripe\Message\CreateCardRequest', $parameters);
}

What I'm struggling with is how/where to call this and finish up the Order by turning the Cart into an Order.

The Checkout / Payment page submits to the following Controller:

Commerce_PaymentsController->actionPay()

I could just duplicate the functionality in here swapping out what I don't need, but this feels really hacky/wrong!

Has anyone any suggestions for a more sensible approach?

A no one has come forward and told me it's a bad idea, I've ploughed on and done the following:

Created my own Controller action in my plugin to bypass the payment side of things altogether. I didn't use Omnipay to create my Customer on Stripe in the end. I went with using Stripes own API directly as documented here.

To complete the Order (as-in convert a Cart into a full-blown Order, it was as simple as calling the following Commerce method:
craft()->commerce_orders->completeOrder($cart);


How does the Craft CMS built-in web server works? I just found this while using ./craft help in the Craft CMS command line utilities:

- serve                                      Runs the PHP built-in web server.
    serve/index (default)                    Runs PHP built-in web server.

How to use this built-in web server?
How can I edit these web server
settings?
Can i use multiple of these web server at once?

At this time of writing, I didn't find any documentation about that.

I'm using the latest version of Craft CMS (Craft Pro 3.3.17) under Mac OS (10.14.6).

This just launches PHP's built in web server, documentation for it can be found here: https://www.php.net/manual/en/features.commandline.webserver.php

You can use php -s localhost:8000 instead

You can see available settings by running php -s

Yes you can run multiple versions on different ports

Hope this helps!


Is there a way a plugin can watch for live preview updates? I'm working on a site that involves taking a URL and then getting information about that URL using an API. The URL is entered into a field in a Matrix block, and then another field in the same Matrix block is populated automatically on save. This is working, but only when the article is saved. I'd also like it to work in live preview mode. The event I'm using on save is entries.saveEntry, but I've also tried using entryRevisions.onSaveDraft, hoping that drafts were saved with live preview changes, but that didn't work.

Question:
Is there some event I can listen for that lets me know when the live preview is about to refresh? Can this be done with JavaScript in the admin instead? If so, is there documentation that describes how to do this?

You will probably have to use javascript. Something like this would work.

$('.lp-iframe').on('load', function(event) {
  console.log(event);
});

edit

Try this to bind the lp-iframe after it gets added to the page.

$('.livepreviewbtn').on('click', bindIframe);

function bindIframe() {
  $('.livepreviewbtn').off('click', bindIframe);
  $('.lp-iframe').on('load', function(event) {
    console.log(event);
  });
}


Any way to force delete a locale? I've been able to customize the locale feature for use in a multi-site project, by creating custom locals in /craft/framework/i18n/data. So now each locale has the site name, instead of a language code like "en_au". For example:

veerlofts' => 'Veer Lofts',

instead of:

'ab' => 'Abkhazian',

The problem is, now I can't delete any of the locales (custom or otherwise) in /admin/settings/locales. It gives me this console error in locales.js:

Uncaught TypeError: Cannot read property 'name' of undefined

These older (whether standard out of the box or custom) locales are still defined in /craft/framework/i18n/data.

Another strange thing, if it helps troubleshoot, is that during the first round of trying to customize the locales, the longer custom names were getting truncated to 12 characters, all lowercase.  Those are the ones I'm trying to delete, so the CMS users won't get confused.See attached screen:

You're going to have to remove them directly from the database's craft_locales table.

You're using "locales" in a way we originally didn't design them for, which is why they're getting truncated at 12 characters.

If you're going to do this, you'll need to keep them at 12 characters or less for them to work.


Sprout SEO 3 Image Override Not Working So I have what seems like a simple problem but can't quite find a solution. On my entry template I'm trying to override the image fields as we're using the imager plugin for transforms. However, it doesn't seem to be working at all. No matter what I put inside the craft.sproutSeo.meta do loop, nothing happens. Even if I hardcode a value in there. It seems simple, but is there something I'm missing here? My code is below:

{% set cardEntryImage = craft.imager.transformImage(entry.blogHeaderImage.first(), { width: 1920, ratio: 16/9 }) %}
{% do craft.sproutSeo.meta({
    ogImage: siteUrl ~ cardEntryImage.getUrl(),
    ogImageSecure: siteUrl ~ cardEntryImage.getUrl(),
    ogImageHeight: cardEntryImage.getHeight(),
    ogImageWidth: cardEntryImage.getWidth(),
    ogImageType: cardEntryImage.getMimeType(),
    twitterImage: siteUrl ~ cardEntryImage.getUrl()
}) %}

Could you please let us know where do you output the {% sproutseo 'optimize' %}tag?

The {% do craft.sproutSeo.meta({ tag need to be called before the optimize tag. I'll give you a basic example of how you can do this:

Let's say that you have a _layout where you have the html head tag:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
<head>
    {% block head %}
        {% sproutseo 'optimize' %}
        ...
        ...
    {% endblock %}
    ...
</head>

In your section/_entry (extends your layout) When you need to override something with the do craft.sproutSeo.meta you may need to call it before the {% sproutseo 'optimize' %} so you can do something like:

{% extends "_layout" %}
{% set title = entry.title ~ " - Blog" %}

{% block head %}

    {% set cardEntryImage = craft.imager.transformImage(entry.blogHeaderImage.first(), { width: 1920, ratio: 16/9 }) %}
    {% do craft.sproutSeo.meta({
        ogImage: siteUrl ~ cardEntryImage.getUrl(),
        ogImageSecure: siteUrl ~ cardEntryImage.getUrl(),
        ogImageHeight: cardEntryImage.getHeight(),
        ogImageWidth: cardEntryImage.getWidth(),
        ogImageType: cardEntryImage.getMimeType(),
        twitterImage: siteUrl ~ cardEntryImage.getUrl()
    }) %}
    {{ parent() }}

    ...
    ...
{% endblock %}

Best,

-Andre L


How can I access the file extension of an asset? Migrated from a Slack #help channel question

Jason Mayo [09:53 16/6/15]

Is there anyway to output what file type an assets file is? E.g. if its a Jpeg, SVG or Gif etc.

Yes, you can access a number of properties on assets. You can get the "file group" (whether it's a document, image, video etc) using:

{{ asset[0].kind }}

More specifically, you can access the file extension using:

{{ asset[0].extension }}

Full list in the documentation at: http://buildwithcraft.com/docs/templating/assetfilemodel


Showing a generic image when no image is chosen I'm trying to do this:

{% for image in entry.illustration %}
    {% if image | length %}

    {% else %}

No image.

    {% endif %}
{% endfor %}

Without any luck. What would be a good way of telling craft to do something else if entry.illustration does not have an image defined?

You may want to try this:

{% for image in entry.illustration %}
  {% if image %}

  {% else %}

No image.

  {% endif %}
{% endfor %}

(Assuming the altText field is an entry field.) :)


Caching Issue "unserialize(): Error at offset 0 of 24 bytes" I have never gotten this before when using Craft cms this is the first.

When trying to load my site (locally), I am getting this message

unserialize(): Error at offset 0 of 24 bytes

I have attached some screenshots of what I am getting in more detail

What am I suppose to do to fix this?

Sounds like something just got corrupted when saving to craft/storage/runtime/cache and now PHP/Craft is having a problem reading the corrupted data from cache.

No idea how it happened, but clearing craft/storage/runtime/cache should resolve the issue for now.


Making multiple pages different with the same template Lets say I have four different pages I set up on a channel to have four different directories. ie ... hello/1, hello/2, hello/3, hello/4. But they are all using the same template.

What could an engineer adjust in craft to be different between the four pages vs. not be able to adjust if they can't touch the html template or CSS?

You could try creating a different entry type for your "hello" section.

For example, I am building a site for a restaurant. The "food" section is a structure. Each entree is the same template, each "category" uses the same section, but a different entry type. That way the admin only has to click "new entry", then choose either "entree" or "category" as the entry type.

Each category gives me the titles, "sandwiches" "burgers" etc, then my entree type is the actual food item.

Depending on what they pick, input fields will be different, however the markup on the page remains the same.


User specific entries (relations) Does anyone know how I can show a specific entry to a user (frontend)? My user field is called "gebruiker".

{# Get current member e.g URL /members/1/ #}
{% set currentMember = craft.users.id(craft.request.segment(2)).first() %}

{# Get current members test entries #}
{% set currentMemberTest = craft.entries.section('test').relatedTo({
    targetElement: currentMember,
    field: 'gebruiker',
}) %}

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

{{ entry.title }}

{% endfor %}

Thanks

Instead of looping through currentMemberTest, you're currently setting up a fresh criteria model in your for loop.

Use your nicely set currentMemberTest criteria!

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


Translating the option labels of Dropdown, Checkboxes or Multi-select fields Is it possible to have the labels for any of these fields be translatable in templates? I don't mean make the whole field translatable - the same option values would be shared between locales, I would just like the output the label in the correct language.

Use the translate (or t) filter:

{{label|t}}

See how to translate static text in templates


Can you increase the max size of Rich Text fields? I'm unable to save an entry, and I'm getting an error saying that a Rich Text field is too long.

If I disable the entry, it saves fine, but when it's enabled, it doesn't save.

Can I increase the max size of a Rich Text field?

Under your Rich Text field's setting, there is a "Column Type" option that's set to text by default, which will hold about 64k worth of data.  You can change it to mediumtext, which will store about 16M worth of data.


How to allow browsers to cache Craft's admin static files? I notice that the Craft admin pages append random query parameters to their static files, i.e. jquery-2.2.1.min.js?x=AKVKl03So:

This prevents those static files being cached in browsers, which can make the admin views unreliable in less-than-optimal network conditions.

I see the logic to make this happen is in Craft's app/helpers/UrlHelper.php

Is there a sane way to deactivate that behavior, and allow browsers to cache Craft's static files?

I don't think it's a great idea to disable this cache busting; they put it in there for a reason.  However, if you really need/want to do it, instead of modifying Craft, I'd just configure Apache/Nginx to discard the query string for paths that match /admin/resources/

https://wiki.apache.org/httpd/RewriteQueryString


Duplicate fields on a form Is there a way to repeat fields in the Craft Formbuilder (FreeForm)?
I’m working on a form on which I want to be able to have multiple names/addresses.
Rather than add a new field every time (name 1, name 2, etc.), is there a way to simply copy fields?

Not with Freeform - the fields can only be used once in each form, similar to how fields are used in native Craft elements.
I believe Formie allows you to re-use fields.


3D viewer for Craft CMS I really like grabcad's 3D viewer feature where the user can rotate, zoom, explode the 3d model.

I am wondering about adding similar feature to showcase my 3d models on my website and use asset field for project entry to load store file address on the html and have the js framework that is capable to rendering interactive primitive 3D model to hook up the file to the engine to display 3d model.

My question for folks out there, is there js framework similiar to grabcad's viewer feature?

I know a lot of 3D programs are going to use different file formats. And the viewers tend to vary quite a bit. What are you using?  If you can export to obj format, three.js seems popular.

There's also services that do the heavy lifting of embedding as well. (Kind of like Vimeo for models). Just did a little bit of searching, SketchFab seems interesting and they also offer a free plan. They accept a bunch of file formats plus an API which you could tap in Craft.

They also do oEmbeds so you could use something like Embed Assets to hook into it.


How to query/filter by the value of a lightswitch In my news entries, I have a lightswitch field with the handle 'pinned'. I'm trying to query my news section for both pinned and unpinned news entries (true or false essentially), but I can't get consistent results with any of the following:

{% set pinnedNews = craft.entries().section('news').pinned('1').all() %}
{% set unpinnedNews = craft.entries().section('news').pinned('0').all() %}

{% set pinnedNews = craft.entries().section('news').pinned('true').all() %}
{% set unpinnedNews = craft.entries().section('news').pinned('false').all() %}

{% set pinnedNews = craft.entries().section('news').pinned('1').all() %}
{% set unpinnedNews = craft.entries().section('news').pinned('not 1').all() %}

{% set pinnedNews = craft.entries().section('news').search('pinned:1').all() %} THIS WORKS
{% set unpinnedNews = craft.entries().section('news').search('pinned:0').all() %} DOES NOT WORK
{% set unpinnedNews = craft.entries().section('news').search('pinned:not 1').all() %} DOES NOT WORK

Is there a proper to get the boolean values in Craft 3?

true/false are booleans, not strings, so you shouldn't surround them in quotes:

{% set pinnedNews = craft.entries().section('news').pinned(true).all() %}
{% set unpinnedNews = craft.entries().section('news').pinned(false).all() %}


Bypass Varnish cache if user is logged in Is it possible to bypass the Varnish cache when the user is logged in? I've tried using the "CraftSessionId" cookie, but it seems that it is also set for non logged in users.

So the answer is to test the cookie for a name with username in it, and pass if it exists. You could also check for an exactly 32 digit alphanumeric cookie name I guess.

if (
 req.http.Cookie ~ "username" # Craft sessions have the word username in them
)
{
    return (pass);
}`


How do I display the index of the asset in assets loop? Looking to do something like this:

{% for image in block.images %}
    <img src="{{ image.url }}" data-index="{{ image.index }}">
{% endfor %}

This seems like it should be easy and I feel like I've done it before, however I can't seem to figure it out. Thanks

This will do it:

{% for key, image in block.images %}
    {{ key }} - <img src="{{ image.url }}" data-index="{{ key }}">
{% endfor %}

Keep in mind that's a 0 based array, so the first image will output 0, the 2nd 1, etc.


Can I use translated properties for URL formats Here's my scenario.

I have a structure section: "events". Within that I have three entry types: "events", "exhibitions", "specials".

I would like the events to follow the following URL structure:

{type}/{slug}

So far no problem, since the entry type handles are defined in English. But when it comes to the Norwegian page, I want to use the Norwegian translation for each type: "arrangement", "utstilinger", "spesielle".

So I added in the translations to my static translation file, and tried:

{type|translate}/{slug}

But obviously, since I'm here, I didn't have any luck. Can anyone think of a way to achieve the desired result, without resorting to adding a custom field to each entry type that would need to be filled in for every entry to use in place of {type}?

This turned out to be easier than expected. It's not documented in the filters section of the docs, but the t() filter can take other parameters after the  tokenised variables you might want to replace in the string. Paraphrased from the source code of the globally available t() function:

source: Defines which message source application component to use. Defaults to null, meaning use 'coreMessages' for messages belonging to the 'yii' category and using 'messages' for messages belonging to Craft.
language: The target language. If set to null (default), craft()->getLanguage() will be used.
category: The message category. Please use only word letters. Note, category 'craft' is reserved for Craft and 'yii' is reserved for the Yii framework.

So, the solution was as simple as:

{type|t(null, null, 'nb')}/{slug} for URL format for Norwegian and

{type|t(null, null, 'en')}/{slug} for English.


How to create clean URLs for category strings? This code for linking to a category page:

href="/products/?category={{ category.slug }}"

Generates this URL:  www.website.com/products/?category=category-name

Can someone please tell me how to code links in menus (etc) that will produce URLs without the ?category= string being included in the URL.  So that the URL would become: www.website.com/products/category-name

Many thanks for your help - it is greatly appreciated!

First thing you'll need to do is set up a route that ensures anything for /products/category-name gets routed to the correct template. You can do this from the control panel or via craft/config/routes.php

If you do this in your routes.php file you'd need something like this:

return array(
    'products/(.*?)' => 'products/index',
);

Which is telling Craft that for any url that contains products/any-characters it should use the products/index template.

Then, on that template, grab the segment that is the category slug

{% set catSegment = craft.request.segment(2) %}

You'll then need to get the category that has that slug

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

You then have a category model you can work with and can use a craft entries tag with a category criteria using

{% set products = craft.entries.relatedTo(category).find() %}

Loop through products to output your products.


Changing Image transforms for different media queries Is it possible to set different image transforms for different media queries?
I have a grid layout containing 1 large image and four smaller images on large screens. I have created two image transforms; one called gridSmall and another called gridLarge.
When the screen size is made smaller, all the grid items are arranged in rows of two and ideally I would want them the same size. So therefore I would need the to change the transform of the gridLarge to gridSmall to match the other four images. Is this possible to do without a third party plugin?

This is absolutely possible using plain old HTML, and media queries within a <picture> tag.
Within the tag you set your base image <img> to the url of the smallest size, and a <source> with a media query, like this:
<picture>
  <source
    srcset="{{ image.url('gridLarge')"
    media="(min-width: 1000px)"
  />
  <img
    src="{{ image.url('gridSmall') }}"
    alt="Image of a thing"
  />
</picture>


How do you replicate the EE {date_heading} tag pair in Craft? I'm wondering how I would replicate the ExpressionEngine date_heading tag pair in Craft?

{date_heading}  {entry_date format="%Y %m %d"}  {/date_heading}

  The date heading can be used to show a heading at certain intervals.
  The interval can be set to show hourly, daily, weekly, monthly, or
  yearly.

Group:

Take a look at Craft's custom group filter. Your example could look like this:

{% set allEntries = craft.entries.section('blog').find() %}
{% set allEntriesByDay = allEntries | group('postDate') %}

{% for day, entriesInDay in allEntriesByDay %}
    <h1>{{ day }}</h1>

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

.

Conditionals:

You could also save the last entries date and use conditionals:

{% set allEntries = craft.entries.section('blog') %}
{% set last_date = '' %}

{% for entry in allEntries %}
    {% if last_date < entry.date %}
        This entry is the first of a new day
    {% endif %}

    {% set last_date = entry.date %}

    {{ entry.title }}
{% endfor %}


Craft Commerce Product Options that increase price, but do NOT affect stock My client wishes to sell artwork online. They're all one-off pieces and once one is sold, it should not be available to purchase thereafter.
However, the artwork needs to have an option to be framed which would increase the price.
I can't see how this can be achieved with Variants as each variant has their own stock level.

Worked it out!
Putting this in a custom module should do the trick..., obviously changing the price modifier and option name to your needs.
        Event::on(
            LineItems::class,
            LineItems::EVENT_POPULATE_LINE_ITEM,
            function(LineItemEvent $event) {
                // @var LineItem $lineItem
                $lineItem = $event->lineItem;
                // @var bool $isNew
                $isNew = $event->isNew;

                if (isset($lineItem->options['giftWrapped']) && $lineItem->options['giftWrapped'] == 'yes') {
                    $lineItem->price += 20;
                }
            }
        );


Element API unable to get all() of matrix field I'm getting matrix block content from an entry type which works fine for the most part. It's probably clearer to just paste in the code:

Current element api code:

$relationsData = [];
if($entry->relatedContent){
    $index = -1;
    foreach ($entry->relatedContent->all() as $block) {
        switch ($block->type->handle) {
            case 'relateContent':
                $index++;
                $relatedFeaturedEntries =  $block->featured->first();
                $relatedSubEntries =  $block->related->first();
                $relationsData[$index] = [
                    'title' => $relatedFeaturedEntries->title,
                    'url' => $relatedFeaturedEntries->url
                ];
                $relationsData[$index]['subItems'] = [];
                $relationsData[$index]['subItems'][] = [
                    'title' => $relatedSubEntries->title,
                    'url' => $relatedSubEntries->url
                ];
            break;
        }
    }
}

Which outputs:

      "relations": [
        {
          "title": "Testing workflow",
          "url": "http://localhost/blah",
          "subItems": [
            {
              "title": "Help & Guidance",
              "url": "http://localhost/help-guidance"
            }
          ]
        },
        {
          "title": "Taking part in the blah",
          "url": "http://localhost/blah",
          "subItems": [
            {
              "title": "blah timeline",
              "url": "http://localhost/blah"
            }
          ]
        },
        {
          "title": "Testing workflow",
          "url": "http://localhost/blah",
          "subItems": [
            {
              "title": "Completing on paper",
              "url": "http://localhost/blah"
            }
          ]
        }
      ],

There should be more subItems in each subItems array but I am only getting the first because I'm fetching them using $relatedSubEntries =  $block->related->first(); But nothing else works and just errors i.e. all() or removing first()

Figured it out in the end. As an array is being returned I just needed a for loop to get inside it.

Solution...

                    if($entry->relatedContent){
                        $index = -1;
                        foreach ($entry->relatedContent->all() as $block) {
                            switch ($block->type->handle) {
                                case 'relateContent':
                                    $index++;
                                    $relatedFeaturedEntries =  $block->featured->first();
                                    $relationsData[$index] = [
                                        'title' => $relatedFeaturedEntries->title,
                                        'url' => $relatedFeaturedEntries->url
                                    ];

                                    $relationsData[$index]['subItems'] = [];
                                    $relatedSubEntries =  $block->related->all();
                                    foreach ($relatedSubEntries as $relatedSubEntry) {
                                        $relationsData[$index]['subItems'][] = [
                                            'title' => $relatedSubEntry->title,
                                            'url' => $relatedSubEntry->url
                                        ];
                                    }
                                break;
                            }
                        }
                    }


Email subscriptions system I'm looking for a way to have email subscribers database within Craft without using third-party solutions such as MailChimp.

I'm going to let users enter their emails to subscribe to site categories / channels and then send custom notifications with Postmaster plugin. Pre-defined subscriptions lists will not work for me.

I also don't have membership system.

So I wonder if there's any way to have subscribers database within Craft? Some plugin that people could use to submit their email and area of interest to subscribe and also to unsubscribe?

Sounds quite do-able. I will first admit I don't know how postmaster works at all, so I could be way off in my suggestion. Regardless, you're looking at two plugins working together; a contact form & postmaster.

I would start with the contact form plugin, but modify it a bit so that it captures the users's information. Depending on your needs, I would either have a checkbox so the user could select which section they wanted notifications for, or have a hidden field that is pre-populated with the current section - then just pass that through.

If you want to have a visual representation of these records, you'll either want to look at creating entries for them, or just capture them within the plugin. I have an example of both to help get you rolling. DM me on the slack channel and I can send you my examples.

Here is where I'm not sure how to help. Once you have the information, somehow you'll need to tell postmaster where those records are, loop through and send an email. I'm guessing at this point creating entires that represent subscribers would be easier for postmaster to understand?


How to restrict uploads to currently edited site I've tried

/{{currentSite.handle}}/

but this uses current site handle, not the site I'm currently editing. Is there a way to dynamically set folder to currently edited site?

Oli Bon from Craft Support suggested to use {site.handle} when you define your field (not the volume), which have worked perfectly fine.


How does a plugin make use of Craft's storage? I am building a plugin that needs to cache generated images into a directory in Craft, presumably the craft/storage directory. I took a glance in the docs, but couldn't find much in the form of how to use storage. When building similar functionality in EE I used the their cache directory, so looking for something similar with Craft.

So how does one cache generated files in local directory so they can be used later to prevent the overhead of constantly having to generate the image?

craft/storage/ is used for all sorts of things, so there’s no single API for storing things in there. Mostly you would just be working with PHP’s standard IO functions like file_put_contents(). There are some handy functions in Craft’s IOHelper class too.

You can get the path to the storage folder via PathService::getStoragePath():

$storagePath = craft()->path->getStoragePath();

IOHelper::ensureFolderExists() is a handy function for creating a subfolder for your plugin within craft/storage:

$myStoragePath = $storagePath.'myplugin/';
IOHelper::ensureFolderExists($myStoragePath);


Visitor array has empty values with Smart Map plugin (using MaxMind) I'm receiving an array with empty values when trying to get visitor info using the Smart Map plugin and its Visitor Geolocation feature. I'm using MaxMind's free trial ($5 worth of queries) since FreeGeoIp.net is not recommended and I've double checked the plugin settings and cleared all caches. Looking at the MaxMind account there are no queries logged and my map/debug output has empty location values via PHP (screenshot). Working locally on a .dev domain, running Craft 3 RC and tried FreeGeoIp.net as well but to no avail.
Twig:
{% set visitor = craft.smartMap.visitor %}
{% if visitor %}
  <pre>{{ dump(visitor) }}</pre>
{% endif %}

Output:
 array(8) {
  ["ip"]=>
  bool(false)
  ["city"]=>
  bool(false)
  ["state"]=>
  bool(false)
  ["zipcode"]=>
  bool(false)
  ["country"]=>
  bool(false)
  ["latitude"]=>
  bool(false)
  ["longitude"]=>
  bool(false)
  ["coords"]=>
  bool(false)
}

Was using the MaxMind free trial and I didn't have the Web Service set correctly in the Smart Map plugin settings. It needed to be set to GeoIP2 City.


Multiple localhost config settings Me and my coworker work on the same Craft project.

We work locally with MAMP but access the database online, which works fine.

For the assets I'd like to define separate localhost basepaths, since we don't have the same folder structure.

Is there a way to make this work or do I need to work with IP's instead of localhost?

I'd also be open to set the assets relative instead of absolute to make this work.

Here's a multi environment config guide that I think will accomplish all you need.

It allows for environment specific DB connection parameters, but can also set filepaths, that why you can keep your assets path relative in regards to the path set in the environment.

It's an extension to the multi-environment setup as discussed here.

If you have any questions after reading that, feel free to ask.


When to use "if" or "without"? When is it advisable or prudent to use without rather than a conditional statement to exclude something, eg a set of entries, based on one parameter?

For example, say I have real towns and fictional Towns that are listed on a related Regional page. These Towns are sorted real/fictional by a toggle field -- 0 for real, 1 for fictional.

The fictional towns are used elsewhere and should not be listed on any Regional page. In this case, should I be using if (see below) or without?

Here is how I am doing it right now in my Regional template:

{% if town.townFictional == 0 %}
    <li>{{town.link}}</li>
{% endif %}

This is working fine, but I came across this question where using without was suggested.

Is without preferred in my case, and if so how do I use it? Here is my towns variable:

{% set towns = craft.entries.section('towns').relatedTo(counties) %}

For your example, you should exclude the fictional towns in the initial query itself rather than filtering them out afterwards:

{% set towns = craft.entries.section('towns').townFictional('not 1').relatedTo(counties) %}

So that no towns with the Fictional Lightswitch on will be returned from the database at all.

You would use the |without filter, if you already had an array of items and you wanted to filter some of them out while looping over them. This works best with arrays of simple primitives, such as an array of entry IDs, rather than whole objects.

You would be more likely to use an {% if %} tag if you still wanted to fetch the entry, but wanted to adjust some part of your output based on a condition. So for example if you had an array of entries from different sections, and they might not all have URLs, you might decide to output a link or just the title:

{% for entry in entries %}
    {% if entry.getUrl() %}

{{ entry.title }}

    {% else %}

{{ entry.title }}

    {% endif %}
{% endfor %}


Where to put where() for a query looking for a lightswitch field Struggling with syntax here. I'm trying to query entries in the "resources" section, ordered by postDate desc, limit 1 and that also has the lightswitch "featured" as true. Here is what I have.

        {% set featuredEntry = craft.entries({
            section:            'resources',
            orderBy:            'postDate desc',
            limit:              1,
            where:              {'featured': 1},

        }) %}

Also to note I'm on craft 3.

You can just query for the field value directly How to use Element Queries

{% set featuredEntry = craft.entries({
    section:  ['resources'],
    orderBy:  {postDate: SORT_DESC},
    limit:    1,
    featured: 1,
}).all() %}


Does anyone have a working example of frontend form with multiple file upload, drag & drop etc? I'm trying to create a frontend entry form for a logged in user, with a field to upload multiple assets to that entry.
I've tried using the Jquery FileUpload plugin, but can't seem to get that working.
The situation:

The entry type contains an Asset Field, called photos. This field creates a new folder based on the entry's ID;
Users have to be able to select multiple images, with a nice process-bar showing while uploading;
I've tried uploading directly to actions/assets/uploadFile, but I get a permission error;

Does anyone have something similar working with Craft?

OK, figured it out (or at least it works, so correct me if a better way is available):
This method assumes logged in frontend users, not sure if it's possible for guests, have not tested that. Might give permission errors.
Let's say, we have a section message with id 2, containing an asset field called photos. This is the field in which we want to save all frontend uploaded images.
In your form template, do everything exactly as this doc page says. Beware of the fact that you're own fields input names should start with 'fields[myFieldHandle]', and default fields such as title and author should just have their handle as input name.
Also, make sure your form has enctype="multipart/form-data" in its tag. What you have now, should look like this:
<form action="" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="action" value="entries/saveEntry" />
    <input type="hidden" name="sectionId" value="2" />
    <input type="hidden" name="enabled" value="1" />

    <input type="file" name="assets-upload" multiple />

    <input type="submit" value="Make it work!" />
</form>

You'll notice that the file input field has 'assets-upload' as its name. You can either do this, or make your uploading mechanism change the field name to 'assets-upload' for you, because Craft assumes this name in the controller class you're about to use.
For my form, I used the excellent Jquery File Upload plugin, which starts to do its work once files are selected in the file input field. I'm sure any other plugin could do the same. Make sure the plugin uploads the files to Craft's assets/uploadFile controller for them to be processed. The only thing this controller needs, is a folderId (the id of the asset folder the assets should be copied to). So, this is what the upload plugin needs:
$('#assets-upload').fileupload({
    url: '{{ url(actions/assets/uploadFile) }}',
    dataType: 'json',
    formData: [{ name: 'folderId', value: yourfolderId}],
});

By now, you should be able to have your plugin send one or more assets to Craft's controller. Use firebug or Chrome's devTools to see what is returned. If everything worked as it should, a json-string should be returned containing the fileId(s) of the uploaded file(s).
The only thing left to do then, is creating hidden input fields to tell Craft which assets to relate to this entry. What JavaScript should append to the form, is one or more instances of:
<input type="hidden" name="fields[photos][]" value="yourFileId" />

Example, using the 'done' callback function in JQuery File upload:
...
done: function (e, data) {
    if(data.result.success) {
        var fileId = data.result.fileId;
        $(this).after('<input type="hidden" name="fields[photos][]" value="' + fileId + '" />');
    }
},
...

Submit your form, and see if it works. It should. If not, use the errors Craft returns to solve your problems (quite possibly permission-related).
Final note: My asset field is set to create a different file folder for each entry. In this case, I created a temporary folder and used its ID in the frontend form (because the folder is only created once the entry is saved). Craft will copy the assets to the right place and clean out this temp folder on saving the entry.


Remove entry enable/disable for user Is there a way to disable the general entry enable/disable toggle button for some users and let them have only the localised enable/disable button.
Because I had the problem that a user disabled an entry with the general button and he disabled the entry for all locales. So I want to make it easier for them and remove that general button that affects others.

One way to do it would be to use the Control Panel CSS plugin and hide the button with CSS. But I guess that would hide it for all users, including admins.
Maybe you could write a little plugin for it that checks who logs into the CP and hide it if it's a certain user(group).


Is it possible to import the content of a rich text field into matrix using FeedMe without parsing reference tags to entries/assets? Currently I have content that I’m trying to migrate from a single rich text field into a rich text field living in a Matrix content builder. Migrating most of the content is fine, but I would like to know if it’s possible to migrate the reference tags so that I keep the established relationships. I’m concerned with those entries that are rendered on export/import as  and not

After speaking with the always helpful Andrew Welch of https://nystudio107.com, I realize now that the answer to this is entry.myRichText.getRawContent() to output the exact information needed.


Solspace freeform webhook Just wanted to know if there's an easy way to hook Solspace Freeform submission to external API?

I got a form built using Solspace freefrom Pro, and I'd like to post each submission of the form to an external API. Whats the easiest way to go about this using Craft?

There is an entire section here that discusses API integrations, including the ones that come with Freeform.  http://docs.solspace.com/craft/freeform/v2/


What's the template command to print available tokens? I'm trying to dump a list of available template tokens, and their contents. There's a command that's available in dev mode, but I haven't found it's documentation.

Stick {{ dump(_context) }} in a template file to print out all the available values.

{{ dump(_context|keys) }} Outputs the keys of the array without going through it recursively.


How to iterate over matrix field from a plugin I'm writing a plugin where I have the id of an entry, that entry has a matrix field, and I want to iterate over the blocks of the matrix field. In php. How do I do that? Pointers to good documentation for how to do this would be appreciated too.

So, first you want to get the entry model using your entry id. In the EntriesService there is a method called getEntryById which you can use like so:

$entry = craft()->entries->getEntryById(123);

This will return you an EntryModel which has on it all your fields. So, if you matrix field handle is called matrixFieldHandle then you would access the field contents like so:

$matrixBlocks = $entry->matrixFieldHandle;

A matrix field will return you an array of MatrixBlockModels from which you can get at everything else you need e.g.:

foreach ($matrixBlocks as $block){
  echo $block->id;
  echo $block->fieldHandle;
}

Note that to play with block types you will need to look at the MatrixService and getBlockTypeById() to do things like filter out different blocks based on their block types.


Changing asset of entry's assetfield via entries.onBeforeSaveEntry I'm trying to add an asset to an entry's assetfield when the entry is saved by using the onBeforeSaveEntry service provided by Craft.

craft()->on('entries.onBeforeSaveEntry', function(Event $event) use ($fileIds)
  {
      $entry = $event->params['entry'];
      if ($entry->section['handle'] == "bildupload" && $event->params["isNewEntry"]){
        $entry->getContent()->useruploads = $fileIds;
      }
  });

Contents of the $fileIds-array are created like so:

$copyrightedImage = craft()->assets->insertFileByLocalPath(
      $tempPath,
      $originalFile,
      $myAssetFolderId,
      AssetConflictResolution::KeepBoth
);

if ($copyrightedImage->isSuccess()){
      $fileIds[] = $copyrightedImage->getDataItem('fileId');
}

This works pretty well for fields such as a formatted text field or the title, but I cant figure out how to change the asset inside an asset field.
The assetfield of the entries in the section bildupload goes by the handle useruploads. How would I go about fetching the assetId, the full Url to the photo or whatever is used here and add the desired photo into the assetfield as an additional used asset?

Thanks for any help or hints.

Edit: I tried following what Brandon described here, but to no avail.
There are no errors thrown, however the assetfield of the entry remains completely empty and does not have any image assigned to it. I'm using closures to use the array $fileIds in the functions shown below.

After taking a look again, it turned out to simply be an issue with the scope of the array and a therefore empty array as a result. Works as expected now.


Error when calling an image transform from matrix field I'm trying to call an image via an image transform from a matrix field.

So when I do this:

{% if block.type == "standardImage" %}
  {% set image = block.imageFile.first() %}
  {% if image %}

  {% endif %}
{% endif %}

I get this:

So you can see the width, height and title are all being called successfully, but the image is broken on the web page.

And when I skip the transform and just use {{ image.url() }} the image is called successfully with

Finally when I add this to the config file

'generateTransformsBeforePageLoad' => true,

I get a PHP error

Image “district.png” cannot be found.

I suspect then that the transformed image is unable to be created, but I don't know how to progress this idea, or if I am on the right track at all.

I seem to have worked it out - by specifying

'imageDriver' => 'gd'

in the config. I first tried to specify 'imageDriver' => 'imagick', but I was getting path error messages so I'm guessing it is not installed on the PHP installation I am using.

More info at
Errors with Craft 2.3, Imagine and Imagick


Path to plugin class from a Twig_Node In my custom Twig tag I am trying to reference a class in the Twig_Node compile method, however I receive an error every time stating it can't find it.  What would the path be to a custom plugin class for the Twig_Node?

  Fatal error: Class 'PluginCustomClass' not found in /Volumes/Grid/Devbox/www/event.craft.dev/craft/app/vendor/twig/twig/lib/Twig/Environment.php(403) : eval()'d code on line 431

public function compile(\Twig_Compiler $compiler)
    {
        $compiler
            ->addDebugInfo($this)
            ->subcompile($this->getNode('pluginTarget'))
            ->raw(', ')
            ->subcompile($this->getNode('elementsTarget'))
            ->raw(') = new \PluginCustomClass(')
            ->subcompile($this->getNode('criteria'))
            ->raw(");\n");
    }

Assuming PluginCustomClass is a class inside of a Craft plugin, then the issue is probably that you need to reference it in the Craft namespace.  Something like this should work:

->raw(') = new \Craft\PluginCustomClass(')

Depending on what type of class that is (Service, Variable, Helper, standalone, etc.), Craft might not have auto-loaded it, so you might need to manually require it as well.


Image Transform as a Field I was just checking out the AP insights case study:
I came across the LiveView Editor screenshot. I see an inline Image Transform Crop field. What is the method to add this crop field ?

It's probably just a drop down that sets the crop position setting in the image transform parameter string.

See this: https://craftcms.com/docs/image-transforms#defining-transforms-in-your-templates


How do entry elements render a default string but also return an object at the same time? So this is more of a PHP question than a Craft question, but the only example I can offer is one I've seen in Craft.
{{ craft.entries.id(4).one() }}
Returns a simple string like: "About Page"
{{ dump(craft.entries.id(4).one()) }}
Returns the entire element object.
From a PHP perspective, how does this work? Or where can I find out more about this practice?
It's a tricky thing to look up online and tracing through Craft's codebase hasn't offered much insight for a novice like me.

It's the __toString() magic method:

The __toString() method allows a class to decide how it will react
when it is treated like a string.

https://www.php.net/manual/en/language.oop5.magic.php#object.tostring


The requested URL was not found on this server I've cloned an existing Craft site into MAMP Pro, set up my database in sequel pro and am able to access the site's homepage when I go to the URL I set up in MAMPS hosts. But whenever I click on a link, or try to access /admin, I get the following

  Not Found
  The requested URL /(page name) was not found on this server.

I'm sure it's something simple, probably something I'm missing when I set up the site locally, but I'm at a loss.

Try going to yoursite.com/index.php/(pagename). If that works, check out this article on how to remove it: https://craftcms.com/support/remove-index.php


How save data from form in headless Craft via Vue.js I have front-end form on Vue.js and Craft CMS for the backend. I need form. And I want to save data from the form in Craft CMS. How to save data from user frontend to backend on Craft CMS?

You would not use the headless API to submit content in into Craft, as neither the GraphQL or Element APIs support writing.

The frontend entry form functionality is fairly well documented. You would just need your frontend to build out a post request including the correct action, CSRF token, and whatever fields are needed. The action endpoint will automatically return a JSON response if it is posted to by an AJAX request.


Ajax - Create tag with custom ID programatically I'm trying to create an jQuery/Ajax script to import data from a Wordpress API service and want to import the WP tags into my database.

Everything works as expected when I loop through the data and send it to /actions/tags/createTag but I'd like to keep the original tag IDs in order to be able to import the posts later and keep the relationship with their tags (Craft automatically assigns a length+1 ID to new tags).

Any way I can do this?

You'll need to create a new table/record to store the data

class IdRecord extends BaseRecord
{
    /**
     * Returns the name of the database table the model is associated with (sans table prefix). By convention,
     * tables created by plugins should be prefixed with the plugin name and an underscore.
     *
     * @return string
     */
    public function getTableName()
    {
        return 'ids';
    }

    /**
     * Returns an array of attributes which map back to columns in the database table.
     *
     * @access protected
     * @return array
     */
    protected function defineAttributes()
    {
        return array(
            'oldId'   => AttributeType::Number,
            'newId' => AttributeType::Number
        );
    }
}

Create a new Controller and store with the record

public function actionCreateTag()
{
    $this->requireLogin();
    $this->requireAjaxRequest();

    $tag = new TagModel();
    $tag->groupId = craft()->request->getRequiredPost('groupId');
    $tag->getContent()->title = trim(craft()->request->getRequiredPost('title'));
    $oldId = craft()->request->getRequiredPost('oldId');

    if (craft()->tags->saveTag($tag))
    {

        $tagMap = new IdRecord();
        $tagMap->oldId = $oldId;
        $tagMap->newId =  $tag->id;
        $tagMap->save();
        $this->returnJson(array(
            'success' => true,
            'id'      => $tag->id
        ));
    }
    else
    {
        $this->returnJson(array(
            'success' => false
        ));
    }
}

And when you are saving your entries you'll do

$entry = new EntryModel();
// ... set your content
$oldId = 'number of your old WP tag id';
$tag = IdRecord::model()->find('oldId = :oldId',[
    'oldId' => $oldId
]);
$entry->getContent()->setAttribute('yourTagFieldHandle', $tag->newId);

You can use pluginfactory.io to create your boilerplate.

Edit

Another approach. If you receive the title of the tags as an array like ['tag1', 'tag2', 'tag3'] would be something like

$ids = [];
foreach($tagTitles as $tagTitle){
    $criteria = craft()->elements->getCriteria(ElementType::Tag);
    $criteria->title = 'your Tag Title';
    $tag = $criteria->first();
    if($tag){
        $ids[] = $tag->id;
    }
}
$entry->getContent()->setAttribute('yourFieldHandle', $ids);


Gatekeeper/Knock Knock Pluging not working I feel like there must be something i've missed but i've followed the ReadMes for both of these plugins and they don't seem to work on my website. Does anyone have any experience with them?

I'm using Craft 3 and used the plugin store to install them. I have tried them one at a time so that they don't interfere with each other. I've also made sure the site environment is set to production.

Gatekeeper:
https://github.com/tomdiggle/craft-gatekeeper/blob/v1/README.md

Knock Knock
https://github.com/verbb/knock-knock

Thanks

I can't speak for Gatekeeper, but I'm a big fan of Knock Knock.

Were you logged out at the time? If you are logged in, it will bypass the security screen.


How to use Position Select in Matrix blocks? How does one use position selects to float an element in Craft CMS template? Say I want to allow an author to center or float a quote block to the right or left using a position select. How would I do this in the template?

You would typically just pop out a CSS class based on their selection.

So:

Just pop the value out into your markup, and then write the CSS to produce whatever effect you need


Selling products with a digital variant using Craft Commerce Is it possible to sell products using Craft Commerce, where the product may have digital AND non-digital variants?

For example, a greeting card, might be available as a printed card but also as a digital download.

I know there is a Digital Products plugin - however, this seems to require that the product is either digital OR not (it can't be both):

  Digital products are similar to Commerce’s core products, except that
  they don’t have variants

You could definitely use standard products/variants to sell something that is digitally delivered. The Digital Products plugin just provides a nicer way to verify the ownership of a purchase, but you can see if someone has purchased a particular variant with something like this:

{% set orders = craft.commerce.orders.user(currentUser).hasPurchasables(product.defaultVariant).find() %}
{% if orders|length %}
 You already purchased this item in  Order #{{ orders[0].shortNumber }}
{% endif %}


Sprout SEO 3 with Craft Tags ENVIRONMENT: Craft 2, Sprout SEO 3.4.2, Bob Olde Hampsink's "Tag Manager" plugin.

The site has a bunch of articles organized by category and tags, and I've got a template for showing articles by tag (ex: https://www.therapyinphiladelphia.com/tips/tag/employment/).

In Sprout SEO I've "Enabled Meta Details fields" and attached them to Craft's TAGS using the Tag Manager plugin. This allows me to insert custom metadata for each TAG just like I would on a normal Craft entry.

So in theory the {% sproutseo 'optimize' %} template tag on my "articles by tag" template should pick up the custom values entered into the Sprout SEO meta details fields for the tag... just like it would for a normal entry.

However it's not picking up anything, it just reverts to the Globals set under Sprout SEO's settings.

To debug I've done a couple of things:

Under Sprout SEO > Settings > Advanced > Enabled custom metadata variable (giving it the name metadata), and
turned on Craft's dev mode and echoed {{ dump(metadata) }} into the template.

The output of {{ dump(metadata) }} shows the Globals set under Sprout SEO's settings and not the custom metadata entered into the Tag Manager for the selected tag.

I've also tried using the {% do craft.sproutSeo.meta() %} function to manually override the automatic output of the {% sproutseo 'optimize' %} template tag.

{#
 # ARTICLES BY TAG TEMPLATE
 #}

{% sproutseo 'optimize' %}

    {% do craft.sproutSeo.meta({
      section: 'Self Help Tips',
      title: tag.title,
      description: metadata.metaDescription|striptags|slice(0, 150),
      canonical: craft.request.url,
      ogTitle: tag.title,
      ogType: 'article',
      ogUrl: craft.request.url,
      ogImage: metaImage.url(),
      ogImageWidth: metaImage.width,
      ogImageHeight: metaImage.height,
      ogImageType: metaImage.mimeType,
      ogSiteName: siteName,
      ogDescription: metadata.description,
      twitterCard: 'summary',
      twitterSite: '@twitteruser',
      twitterCreator: '@twitteruser',
      twitterTitle: tag.title,
      twitterDescription: meta.search.description,
      twitterUrl: craft.request.url,
      twitterImage: metaImage.url()
    }) %}

This works if I enter hardcoded strings in, but the metadata variable in the template doesn't pick up the custom metadata entered for the tag.

Is this a bug? Is the Sprout SEO plugin only set up to work with ENTRIES, and not TAGS?

For any Elements that do not have URLs, like Tags or Users, you'll need to tell Sprout SEO what metadata to use.

Also, be sure that the do craft.sproutSeo.meta tag comes before the {% sproutseo 'optimize' %} tag. The do tag prepares the metadata for the optimize tag to process:

{% do craft.sproutSeo.meta({
  section: 'Self Help Tips',
  title: tag.title,
  description: metadata.metaDescription|striptags|slice(0, 150),
  canonical: craft.request.url,
  ogTitle: tag.title,
  ogType: 'article',
  ogUrl: craft.request.url,
  ogImage: metaImage.url(),
  ogImageWidth: metaImage.width,
  ogImageHeight: metaImage.height,
  ogImageType: metaImage.mimeType,
  ogSiteName: siteName,
  ogDescription: metadata.description,
  twitterCard: 'summary',
  twitterSite: '@twitteruser',
  twitterCreator: '@twitteruser',
  twitterTitle: tag.title,
  twitterDescription: meta.search.description,
  twitterUrl: craft.request.url,
  twitterImage: metaImage.url()
}) %}

{% sproutseo 'optimize' %}

We do have on our list to simplify this scenario and allow you to add an Element Metadata field to the field layout and just pass the elementId.

{% do craft.sproutSeo.meta({
      elementId: 123
}) %}

{% sproutseo 'optimize' %}


Multi-site setup in Craft3 Hi guys are the any more detailed tutorials on how to setup a multi site on Craft3 BETA? I created two sites now, a Danish and English through the admin (Settings → Sites). The domain is the same but the Danish version will have the path http://localhost:8888/dk whereas the English version will be everything that does not have the first path of /dk.

I have set in the general.php the following:

return [
    '*' => [
        'omitScriptNameInUrls' => true,
        'usePathInfo' => true,
        'generateTransformsBeforePageLoad' => true
    ],
   'SITEHANDLE_NAME_ENGLISH' => [
       'siteUrl' => 'http://localhost:8888/
   ],
   'SITEHANDLE_NAME_DANISH’ => [
       'siteUrl' => 'http://localhost:8888/dk'
   ],
    'defaultWeekStartDay' => 1,
    'enableCsrfProtection' => true,
    'omitScriptNameInUrls' => 'auto',
    'cpTrigger' => 'admin',
    'devMode' => false,
];

In the Danish folder /dk, I created a new index.php, and the site correctly direct to this file from the URL, BUT, it does not change the site to the the Danish site, even though I have defined my index.php with the new php constant:

<?php
// Project root path
$root = dirname('../');
define('CRAFT_SITE', "SITEHANDLE_NAME_DANISH");
// Composer autoloader
require_once '../craft_folder/vendor/autoload.php';

// dotenv?
if (file_exists("../craft_folder/.env")) {
    $dotenv = new Dotenv\Dotenv("../craft_folder/");
    $dotenv->load();
}

// Craft
define('CRAFT_BASE_PATH', "../craft_folder/");

$app = require '../craft_folder/vendor/craftcms/cms/bootstrap/web.php';

$app->run();

How do I tell Craft to load the Danish site from the index.php? Right now it will only load the primary site not matter what I try.

Thanks!

You can also check out the free video on it here: Using Craft CMS 3 Multi-site

Multi-site has changed as of Craft 3 RC11. It now requires much less config outside of the control panel. See the official docs on Sites in Craft 3.


Showing A Flash Message On Admin Entries Listing (Craft 3) I've written a plugin that imports a CSV and creates entries from that for a client. I'm wanting to redirect them to the entries listing page after (i.e. /admin/entries/tvListings) and show a flash message saying "X TV listings imported.".

So this is a 2 parter:

How do you set flash data in Craft 3.
Is there a default flash key that'll show as soon as I land on the entries listing page?

Thanks.

To show a message

Craft::$app->getSession()->setNotice($message);

To show an error

Craft::$app->session->setError($message);

There is no "default" key that is always shown or something like that. You just use the function and set a message -> the next time the user visits any page the message is shown.


Craft Admin assets do not load over https (Apache & Cloudflare) staging.website.com loads perfectly over https. However, https admin pages immediately break because the assets are trying to load over http. If I navigate to the https asset directly, it loads fine. It would seem that Craft is failing to recognize the https request and kick over to the https url.

Server Setup:

Cloudflare DNS / SSL
Arcustech VPS with Ubuntu & Apache

How I am enforcing HTTPS currently:

Cloudflare Page Rule (Always Use HTTPS)
Craft config: general.php > environmentVariables (siteUrl, baseCpUrl, etc.)

I do not have any https redirects going in my .htaccess - just the standard craft index.php logic. Adding https rules in the .htaccess will cause infinite loop redirects.

The solution I came to was creating an Origin Certificate on Cloudflare, installing on it on my VPS, and setting the SSL setting to Full Strict. Now admin assets are loading perfectly over https. No .htaccess or Patrol plugin required.

If someone knows more about why this worked and the previous approach didn't I would love to hear your thoughts. Thanks @MattStein for clueing me towards this approach.


Current assets don't display in Add an Asset modal for matrix field; using {owner.slug} in path For two channels that restricts uploads to subdirectory/{owner.slug}, when I want to add an image in an existing entry, the Add an Asset modal window doesn't list the existing images (this is a matrix field that supports multiple images). All other cases where the restricted directory isn't a dynamic asset folder work fine. I've updated Asset Indexes and Cleared Caches, but still no luck. Any idea what's up? Thanks.

It's because of how Craft resolves dynamic paths (paths with {variables}) in them. For freshly created Matrix blocks haven't been saved yet and therefore don't have an {owner} yet.

If a dynamic path cannot be resolved, then Craft will point it to a temporary folder that is unique per user per field, but, as soon as you save the Entry and the Matrix block has an {owner}, it will resolve to where it should and all the Assets from the temporary folder that were selected will be move to the resolved folder.

Any Assets that have not been selected will remain in the temporary folder. This also holds true for unsaved Entries if you're using {slug}, for example.


Craft CMS . Service unavailable I am trying to install Craft CMS on Ubuntu 14.04 running NGINX, I get this error log, any suggestions on how to fix this?

2017/08/26 16:18:08 [error] [exception.Craft\HttpException.503] exception 'Craft\HttpException' in /usr/share/nginx/craft/app/etc/web/WebApp.php:800
Stack trace:
#0 /usr/share/nginx/craft/app/etc/web/WebApp.php(203): Craft\WebApp->_processInstallRequest()
#1 /usr/share/nginx/craft/app/framework/base/CApplication.php(185): Craft\WebApp->processRequest()
#2 /usr/share/nginx/craft/app/index.php(62): CApplication->run()
#3 /usr/share/nginx/html/index.php(19): require_once('/usr/share/ngin...')
#4 {main}
REQUEST_URI=/

Thanks

The 503 error that is triggered from that log entry happens when Craft files are in place on the server, but it haven't been installed yet and someone loads the front-end of the website.

Assuming you've set everything else up correct, you just need to complete step #5 in the install docs: https://craftcms.com/docs/installing#step-5-run-the-installer


Allow Script Text in Rich Text I'm trying to configure a rich text field to allow script tags for a demo section on the page.

I added the following settings and linked this to the field

    {
  buttons: ['html','bold','italic','unorderedlist','orderedlist','link','image'],
  plugins: ['fullscreen'],
  toolbarFixedBox: true,
  replaceDivs: false,
  paragraphize: false,
  replaceDivs: false,
  deniedTags: [],
  removeComments: false,
  cleanSpaces: false,
  cleanOnPaste: false,
  removeDataAttr: false
}

However, The script tag is still always removed on save. Is there some other setting i am missing?

Script tags should be put in plain text field types (if they need to be editable by the client at all, otherwise put them in the templates).


CraftCMS > UserSessionService should be compatible with CWebUser I've migrated my Craft project from CentOS/PHP5 to Ubuntu/PHP7 ---  since then I'm seeing this message in /craft/storage/runtime/logs/phperrors.log

[14-Jun-2017 14:40:49 UTC] PHP Warning:  Declaration of Craft\UserSessionService::login($username, $password, $rememberMe = false) should be compatible with CWebUser::login($identity, $duration = 0) in /home/hidden/craft/app/services/UserSessionService.php on line 17
[14-Jun-2017 14:40:49 UTC] PHP Warning:  Declaration of Craft\UserSessionService::afterLogin() should be compatible with CWebUser::afterLogin($fromCookie) in /home/hidden/craft/app/services/UserSessionService.php on line 17
[14-Jun-2017 15:50:53 UTC] PHP Warning:  Declaration of Craft\UserSessionService::login($username, $password, $rememberMe = false) should be compatible with CWebUser::login($identity, $duration = 0) in /home/hidden/craft/app/services/UserSessionService.php on line 17
[14-Jun-2017 15:50:53 UTC] PHP Warning:  Declaration of Craft\UserSessionService::afterLogin() should be compatible with CWebUser::afterLogin($fromCookie) in /home/hidden/craft/app/services/UserSessionService.php on line 17
[14-Jun-2017 16:03:04 UTC] PHP Warning:  Declaration of Craft\UserSessionService::login($username, $password, $rememberMe = false) should be compatible with CWebUser::login($identity, $duration = 0) in /home/hidden/craft/app/services/UserSessionService.php on line 17
[14-Jun-2017 16:03:04 UTC] PHP Warning:  Declaration of Craft\UserSessionService::afterLogin() should be compatible with CWebUser::afterLogin($fromCookie) in /home/hidden/craft/app/services/UserSessionService.php on line 17

Any Help?

It's a known issue you can safely ignore on Craft 2, that's been resolved for Craft 3.

PHP 7.0 (or maybe it was 7.1) changed the way that particular error was reported from E_STRICT (which Craft 2 is suppressing) to E_WARNING, which Craft 2 isn't suppressing, so now it pops up on latter versions of PHP.


Create folder in asset volume via GraphQL Is it possible to create a subfolder within an asset volume via GraphQL? If yes, can you point me in the right direction?
I just found mutations for file uploading, but nothing for folder creation.
Thanks!

Currently, there’s no direct way of doing this. You can pass an existing folder ID but you can’t create folders on the fly.
However, you can create folders via an asset field (with dynamic path) attached to an entry type so there is an option that could work if you really need this done.
Create a section/entry type that has two fields, an Asset field with a dynamic path set to {folderPath} and a plain text one called folderPath.
It would then happen in three steps:

Mutate the Asset and get its ID back
Mutate an entry in your new entry type where you set the Asset field to your (just uploaded) asset ID and set folderPath to whatever path you need, save and get its id back. This would create a folder and move your asset to it.
Delete the entry you’ve just created via a mutation using its id.

I know it’s not straight forward but if you really need to make it work, this would do the trick.


`onBeforeSaveUser` - Access existing user data I'm trying to run a quick check to see if any of my user's data has changed before saving them. However, I'm running into a situation where I can only access the new data.

I can't tell if this is a bug, or simply a misunderstanding of how it works...

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

    // Only do this for existing users
    if(!$event->params['isNewUser'])
    {

        // Get ID of user about to be saved
        $userId = $event->params['user']->id;

        // Look up existing user data
        $existing = craft()->users->getUserById($userId);

        // Why does this contain the NEW data?
        Craft::dd($existing->myField);

    }

});

There may be a reasonable explanation as to why the pre-existing user data is not available. If that is the case, then how can I access the pre-existing data for this user?

Not totally sure, but I believe this may be because the UsersService actually caches UserModels fetched by getUserById() locally in a private class variable.

Instead of using getUserById(), try pulling the user with an ElementCriteriaModel:

$existing = craft()->elements->getCriteria(ElementType::User, array(
    'id' => $userId,
))->first();


Prevent adding users with same email addresses I am adding new users inside of the Craft controller as part of the frontend user import script.
This is the code:
$user = new User();
$user->pending = true;
$user->username = $email;
$user->firstName = $firstName;
$user->lastName = $lastName;
$user->email = $email;
$user->passwordResetRequired = false;
$user->validate(null, false);
Craft::$app->getElements()->saveElement($user, false);

The problem is that if I try to import two users with the same email addresses they just get imported and that's obviously something I don't want to happen. How can I prevent that and silently skip the users with existing email addresses.
I could check the user's existence by querying it in the database but I would like to avoid any unnecessary db queries because there will be thousands of users imported at the same time. That validation line looks promising but I'm not finding any useful instructions in the docs.

You're passing false as the second parameter of your saveElement call... that parameter means you're skipping the built-in validation which should catch this error for you. If you get rid of that you should then receive a warning in the logs when processing existing users, but it shouldn't halt execution of the script.


Checking which version of Craft CMS a site is using I've been asked to look at Craft CMS site where my would-be client has been ghosted by his previous developer. I have no handover information and only FTP and phpmyadmin access presently.

Looking via the FTP it appears that both Craft 3 and Craft 2 versions are installed in the vendors directory.

How can I most easily check which the actual site is being used? From the license key or database perhaps?

Looking via the FTP it appears that both Craft 3 and Craft 2 versions are installed in the vendors directory.

Craft 2 didn't use Composer, so wouldn't have a root vendor directory, so you're likely running some version of Craft 3.

Like Oli mentioned, if you can connect to the database, you can check the version column of the info table to see what version of Craft the site using.

If you can't access Craft's control panel, but can access the database, you can use this to gain control panel access: https://craftcms.stackexchange.com/a/13966/57


Sort CP Entries by Category I know it's possible, using modifyEntrySortableAttributes, to sort the CP entries table by a custom field, when that field is a number, string, date/time, or bool. Would it be possible to sort a CP table by category? If not, is there another hook, or some other way I could implement this functionality?

Sorting by number, string, date/time, bool:
In Craft 2.5, how can you sort the entry index page by a custom field?

This is probably not the answer you are looking for but it works. You can change the Craft.BaseElementIndexand the updateElements function. All you have to do is to change the destination path to a custom controller

Craft.BaseElementIndex.prototype.updateElements = function()
{
    // Ignore if we're not fully initialized yet
    if (!this.initialized)
    {
        return;
    }

    this.setIndexBusy();

    var params = this.getViewParams();

    Craft.postActionRequest('yourPluginHandle/controllerName/getElements', params, $.proxy(function(response, textStatus)
    {
        this.setIndexAvailable();

        if (textStatus == 'success')
        {
            this._updateView(params, response);
        }
        else
        {
            Craft.cp.displayError(Craft.t('An unknown error occurred.'));
        }

    }, this));
},

Then you can create a custom controller that extends the ElementIndexController and can use it's function that calls the private function _getElementResponseData. All the elements that should be displayed are received in

$responseData['html'] = $this->_elementType->getIndexHtml(
    $this->_criteria,
    $disabledElementIds,
    $this->_viewState, <-- this is the important variable
    $this->_sourceKey,
    $this->_context,
    $includeContainer,
    $showCheckboxes
);

The sort order is defined here

if ($sortableAttributes)
{
    $order = (!empty($viewState['order']) && isset($sortableAttributes[$viewState['order']])) ? $viewState['order'] : ArrayHelper::getFirstKey($sortableAttributes);
    $sort  = (!empty($viewState['sort']) && in_array($viewState['sort'], array('asc', 'desc'))) ? $viewState['sort'] : 'asc';

    $criteria->order = preg_replace('/^(.*?)(?:\s+(?:asc|desc))?(,.*)?$/i', "$1 {$sort}$2", $order);
}

As you can easily see it checks if the $viewState['order'] is empty or not. This variable is defined in your controller so all you have to do is to check if your javascript returns a order variable, get the field by handle and check if the field handle is instance of BaseRelationField. If so, you'll unset the variable in the $viewState and change the $criteria by yourself.

Unfortunately the query is executed in BaseElementType.php so you have to implement a way to sort by eager loading elements (which I doubt is possible by default) or you can create a custom element type just for this case and overwrite the entire getIndexHtml() function.

It might sound like a lot of work and effort but honestly it can be done in 5-10 minutes... I've done the same once within no time. It's 99% copy paste. Maybe someone  has a better answer but since there is no real event or hook I'm not sure if there is a real clean way to do this. Of course this is only for Craft 2. In Craft 3 it's much easier since there are more events and hooks and you can replace classes more easy.

Another approach would be to overwrite the entire BaseElementIndex class with Yii or this. But I never did that so I can't give much advice


Date value different in CP and database Have a site registering users.
The user record in the CP says they registered at 11:39 June 12.

The database 'dateCreated' says 10:39.

The site settings timezone are UTC+1 BST.

PHP config date.timezone is Europe/London (actual location)
and Default timezone is UTC.

If I turn off UTC +1 in Craft timezone settings to UTC then front end user record matches database.

What I can't figure out for sure is what time did they really register? :)

Craft stores all dates in UTC to the database, no matter what timezone you configure in settings.

When (user) models are populated, e.g. for use in the CP, DateTime objects are created from these values and the objects’ timezones are set to the one you configured.

If you want to output a user’s dateCreated attribute in a date format that includes the timezone you can easily do that in a template using the date Twig filter. This will return the date in ISO 8601 format using your configured default timezone.

{{ user.dateCreated|date('c') }}

You can also output the date formatted for a diffenent timezone.

{{ user.dateCreated|date('c', 'Europe/Paris') }}


How to get all entries posted within a specific year? I am trying to get all entries posted from 2018 and only 2018. All the other methods I've seen are for from a specific date or between two dates. Is there a simple way to get all posts from 2018 without having to specify get all entries between 1 January 2018 and 31 December 2018?

The markup below is where I have got to, but this is getting all entries from 2018 onwards. But when I change the >= parameter to == it appears to break it.

{% set event = craft.entries.section('events').startDate('>=' ~ formYear).one() %}

This should do what you're looking for:

{% set event = craft.entries({
    section: 'events',
    startDate: 'and, >= ' ~ formYear ~ ', < ' ~ (formYear + 1)
}).one() %}


Image not found with some transforms in english locale I'm working on a page that has 2 different locales. The German locale is perfectly fine but in the english locale some assets that use the transforms seem to not be working at all. Funny thing is this is not working on staging or local environment. The images that don't seem to tranform appear to have the locale in the transform url e.g. /en/ but right next to these images there are other images using the same transform that seem to work. This appears to be random but always the same images are affected never other images when reloading for example. I've tried reindexing the images, deleting the cache, emptying the indexes in the database and adding the convertFilenamesToAscii setting to true in the general config.

If someone else happens to have the issue, here is what solved it for me: https://github.com/craftcms/cms/issues/1853#issuecomment-582353821


Is there any plugin for Blog in Craft 3? I want to create a Blog website in craft cms. I would like to know, is there any plugin for Blog which we can use in Craft similar kind of WordPress?

Nope. Craft works very differently to WordPress. You won't need a plugin for this, but will need to learn Craft. This looks like it might be helpful: https://www.youtube.com/watch?v=lfDZ6v23KcE


Set Up A Global Dashboard For A Specific User Group Is there a way to set the Dashboard up globally for a specific user group and lock it so that it can't be edited?

The dashboard widgets are currently set on a per user basis. Brandon has said on the Google+ community that a site-wide and/or user group solution is planned but doesn't have en ETA.

https://plus.google.com/106689452282751248337/posts/CvZZa5DDGwb

https://plus.google.com/103717873128586100650/posts/gW9buKqF4LA


Editing specific fields from a POSTed form in a plugin I'm struggling to figure out how to do what I need to do, and I think it's more a lack of PHP skill than Craft/Commerce per-se.

I have a plugin that receives POSTed data such as this:

<input name="items[1][qty]" value="6" type="hidden">
<input name="items[1][note]" value="" type="hidden">
<input name="items[1][purchasableId]" value="164" type="hidden">
<input name="items[1][options][endDate]" value="2026-11-03" type="hidden">
<input name="items[1][options][friday]" value="2" type="hidden">
<input name="items[1][options][monday]" value="2" type="hidden">
<input name="items[1][options][startDate]" value="2016-11-05" type="hidden">
<input name="items[1][options][wednesday]" value="2" type="hidden">
<input name="items[1][options][uniqueCode]" value="1553135711" type="hidden">

<input name="items[2][qty]" value="6" type="hidden">
<input name="items[2][note]" value="" type="hidden">
<input name="items[2][purchasableId]" value="193" type="hidden">
<input name="items[2][options][endDate]" value="2026-11-03" type="hidden">
<input name="items[2][options][friday]" value="2" type="hidden">
<input name="items[2][options][monday]" value="2" type="hidden">
<input name="items[2][options][startDate]" value="2016-11-05" type="hidden">
<input name="items[2][options][wednesday]" value="2" type="hidden">
<input name="items[2][options][uniqueCode]" value="736114426" type="hidden">

I need to amend any and all inputs that represent a startDate (e.g., <input name="items[1][options][startDate]" value="2016-11-05" type="hidden"> ). Then hand over to the controller that's going to process the data.

In detail: this is a Commerce related thing using MultiAdd. I need to adjust those startDate values prior to handing off to MultiAdd to do it's thing. The pertinent bit of my plugin looks like this:

public function actionReorder() {
    ... a bunch of stuff relating to the cart ...

    // loop through all the inputs for line items and amend any startDate
        $items = craft()->request->getPost('items');

        ... magic happens here ? ...

    // ok now pass it all over to the multiAdd controller...
        craft()->runController('multiAdd/multiAdd');
}

You will want to use PHP's foreach to loop over each of the items (using $i here to keep track of the index). Then if the current item has a start date, do whatever it is you need to edit it inside the loop. Once you've finished iterating over each item, you will need to set that back to $_POST['items'], so that the MultiAdd plugin can pick up your modified array as usual, using craft()->request->getPost('items').

public function actionReorder() {
    // ... a bunch of stuff relating to the cart ...

    // loop through all the inputs for line items and amend any startDate
    $items = craft()->request->getPost('items');

    foreach ($items as $i => $item)
    {
        if (isset($item['options']['startDate']))
        {
            $items[$i]['options']['startDate'] = '???';
        }
    }

    // re-set back to $_POST
    $_POST['items'] = $items;

    // ok now pass it all over to the multiAdd controller...
    craft()->runController('multiAdd/multiAdd');
}


image transform on reference tag Can someone tell me how to do an image transform on a reference tag? I've tried

{% set images %}

{% endset %}

{{ images|parseRefs|raw }}

But this just gives back the source urls and not the crops.

Regards

I believe a Reference Tag can not perform an image transform because it doesn't return an ElementCriteriaModel object.

I worked around this by using the craft asset id parameter:

    {% set assetSearch  = craft.assets.id(12651) %}

    {{assetSearch.first().getUrl('transform')}}


Loop by column from a table How can I loop from col2 to col4 ? Or loop by column heading handle?
Remplace {{ row.col2 }}

  {% for row in block.tableHandle %}

{{ row.col2 }}

  {% endfor %}

Is this what you're after?

{% for row in block.tableHandle %}

    {% for columnHandle, columnValue in row %}
        {# If not col1 #}
        {% if loop.index != 1 %}

Do whatever you want with: {{ columnValue }}

        {% endif %}
    {% endfor %}

{% endfor %}


Craft CLI ./craft - can I tell it to use a specific php version when running composer via the CLI? With the Craft CLI, is there a way to set which php version to use?
The context here is that the server runs PHP 5.4 for another project, but PHP 7.3 is installed at /usr/bin/php73 and is setup in Apache to use that version for this specific site.
With normal composer install I just specify the path to that version like so:
/usr/bin/php73 /usr/bin/composer update
but I want to be able to run updates via the Craft CLI. The CLI tool then uses the composer version on the server. Is there a way to specify what version of php to use when running commands via the CLI?

This is something I completely overlooked, but the Craft CLI is just a PHP wrapper that's executable on the CLI. So this will work:
/usr/bin/php73 craft help
or
/usr/bin/php73 craft update all
Will run the CLI with the PHP binary of your choice.


Missing entries in admin panel My Craft admin panel is running fine locally but when I login remotely my entries aren't there. Do I need to change something in the config file?

Are you accessing the same databases? You need to make sure that the local database has been uploaded to the remote server. Then all your entries should show up.

You can back up your local database by going to /admin/settings on your local machine. Then you'll need to upload that database to the remote server.

You can also learn more about setting up a multi-environment config in the Craft documentation.


Pulling in Structure entries as radio button options in Sprout Forms I have a form created with Sprout Forms with a custom template to override the HTML. This form needs to pull in plan type information from a structure section that already exists.

I added the structure entries to the form in the template, but they currently aren't hooked up to form so when I hit submit. How can I hook this up so that when a user selects a plan type it will register with Sprout Forms?

I could try and create these fields in the form builder, but the way it's set up it's easier for us and the client to pull the information from the existing entries.

Sprout Forms v2.3.0 adds front-end field support for Entries, Categories, and Tags Relations fields.

By default, the fields will display a multi-select field on the front-end. If the limit is set to 1, they will display a dropdown field.

The fields are designed to work for simple use cases. If you have hundreds or thousands of entries, you may need to consider a custom front-end field type for your scenario.


How do I access the checkbox field column value as a PHP array? I have a checkbox field for dining cuisine types and I see that the checked options are stored as a JSON-encoded array in the content table. If I have an element that uses this field, is there a way I can just get that JSON-encoded value as an array in PHP? Any time I try to get the value of the field, I'm getting the entire MultiOptionsFieldData object which isn't desired in this case. I just want that array of checked values that's stored in the corresponding content table column.

I don't want to write any loops. I just want access to that actual column value from my element in PHP.

I don't want to write any additional queries to get that column value either. Surely, there must be a way to get the actual field value for checkbox fields. Right?

MultiOptionsFieldData extends PHP's ArrayObject class.

You could get the values from it by casting it to an array like so:

$results = (array)$mofd;

That would give you an array of OptionData classes.  If you really didn't want to loop through them, you could do something like:

$func = static function($ofd) {
    return $ofd->value;
};

$results = array_map($func, (array)$mofd);


Structure question (entry in entry?) Let's say I have an auction website:

'Ads' would be a section -> channel
The ads in it would be entries in the channel

Let's say guest users can make an offer on the action/ad. I would like to save all the offers in the entry, so I could read them out front-end.

What would be the best way to save these entries? I'm having difficulty understanding this structure-wise.

Craft has a pretty extensive relationship system, which is what you'd probably want to take advantage of here.

You could make another channel called "Offers" and each offer would be an entry in that section.

Then you could create an entries field called "Ad" and save it in your "Offers" section's field layout and have its source set to "Ad".

Then, when saving an offer, you'd select the ad(s) in the ad field the offer belongs.

You'd be able to query those relationships from the template side like so: https://craftcms.com/docs/entries-fields#examples


Working with Structure & Multiple Pagetypes I have a site that's mostly 'static' content pages, with a few dynamic & more complicated pages mixed in.  To make editing & setting up the navigation easy, I started by creating a Structure that holds all the entries in my Pages section.  Let's say that structure looks something like this -

About

People
History

Products

Product A
Product B

It's more complicated, but just a longer version of that.  This structure is used to generate my navigation for the site, and everything is working as expected.

Now, all my content pages are in place and I need to add the 1-offs.  The first is a contact page, which is going to live @ /about/contact.  I'd like to place it within the structure because otherwise my navigation becomes a lot more complicated.

The problem is, it draws from a different template than my normal content pages, and a structure can only pull from a single template regardless of what sections are listed in it.  Ok, I thought, I could put the entry into that structure and then use a route to direct that page to the template I want to use.  That doesn't work, however, because page URI's are processed before routes.

So, the question is - what am I missing about doing this?  Is there a better way to set up what I'm doing?

Assuming that those pages are working off of different entry types, you should check out this great help article...

  How can I give each Entry Type its own template?

Basically, you let a parent template decide which child template to load, based on the current entry type.