Custom HTML in Rich Text Fields I've noticed the HTML option above Rich Text Fields for entries is now gone in Craft 2.5, regardless of being configured as Default, Simple, or Standard.

Is this a feature that has been removed from Craft in v2.5+? I currently have a ton of content that relies on custom HTML outside of what's available in the format bar, so this would be pretty devastating.

Am I overlooking where this option is now?

If your Redactor config included an "html" value in the "buttons" array, you can remove that, and add a "source" value to the "plugins" array instead.

https://craftcms.com/help/redactor-ii-configs


How are people adding public comments to their Craft sites? It's not been asked as a broad question here yet, but we've all wondered: how does one go adding comments to a Craft site, such as those you'd find on a blog?

I've either used or been aware of...

Tacking Disqus (JavaScript) comments onto pages.
Integrating Google+ comments.
Using a dedicated Craft Section for comments and relating each to a post, collecting submissions with Guest Entries.

Are there others out there? Would an expert comment engineer care to answer authoritatively?

What you describe above is essentially your options. If you use built in sections for comments, you can probably make them more secure from spam by using Dukt's OAuth plugin to require a log in from a more reputable site.

Other third-party options include:

Intense Debate (from the makers of WordPress)
LiveFyre Comments
Facebook Comments


Mcrypt is required on Ubuntu 14.04 I am using Craft on Ubuntu 12.04 servers without problems, but when trying to run it on Ubuntu 14.04 (trusty) I always get the message

  Mcrypt is required.

I installed it, however, via...

apt-get install apache2 php5 mysql-server php5 php5-cli php5-common php5-curl php5-gd php5-mcrypt php5-mysql

...and restarted the web server afterwards. Any hints? Maybe this is a bug with the way craft checks for mcrypt?

I had to run sudo php5enmod mcrypt to enable the module.

It seems this has changed between 12.04 and 14.04—in 12.04 it was enabled automatically.


Add new section in Craft 3 Migrations I have been trying to get my head wrapped around Migrations in Craft 3 and find myself struggling with added a new section.

I have managed to add a new volume, but not a section. Here’s where I have got to so far…

<?php

namespace craft\contentmigrations;

use Craft;
use craft\db\Migration;

/**
 * m180428_195138_test migration.
 */
class m180428_195138_test extends Migration
{
    /**
     * @inheritdoc
     */
    public function safeUp()
    {

      if (is_null(Craft::$app->volumes->getVolumeByHandle("newvolume"))) {
        $volume = new \craft\volumes\Local([
          "name" => "New volume",
          "handle" => "newvolume",
          "hasUrls" => true,
          "url" => "@web/images/newvolume",
          "path" => "@webroot/images/newvolume"
        ]);

        Craft::$app->volumes->saveVolume($volume);
      }

      if (is_null(Craft::$app->sections->getSectionByHandle("awesomeNews"))) {
        $section = new \craft\models\Section([
          'name' => 'Awesome News',
          'handle' => 'awesomeNews',
          'type' => 'Channel',
          'siteSettings' => [
              new \craft\models\Section_SiteSettings([
                  'siteId' => Craft::$app->sites->getPrimarySite()->id,
                  'enabledByDefault' => true,
                  'hasUrls' => true,
                  'uriFormat' => 'foo/{slug}',
                  'template' => 'foo/_entry',
              ]),
          ]
        ], true);

        Craft::$app->sections->saveSection($section);

      }

    }

    /**
     * @inheritdoc
     */
    public function safeDown()
    {

      $newvolume = Craft::$app->volumes->getVolumeByHandle("newvolume");
      if (!is_null($newvolume)) {
        Craft::$app->volumes->deleteVolumeById($newvolume->id);
      }

      $awesomeNews = Craft::$app->sections->getSectionByHandle("awesomeNews");
      if (!is_null($awesomeNews)) {
        Craft::$app->volumes->deleteSectionById($awesomeNews->id);
      }

    }
}

The migration states it has been successful, however, I only see the new volume, not the section. I have tried to execute this with only the block relating to the section.

Does anyone know if it is possible to create a new section with Migrations? If it is, any idea what may be wrong with the above?

As documentation for Migrations is pretty slim, here is the working code:

<?php

namespace craft\contentmigrations;

use Craft;
use craft\db\Migration;

/**
 * m180428_195138_test migration.
 */
class m180428_195138_test extends Migration
{
    /**
     * @inheritdoc
     */
    public function safeUp()
    {

      if (is_null(Craft::$app->volumes->getVolumeByHandle("newvolume"))) {
        $volume = new \craft\volumes\Local([
          "name" => "New volume",
          "handle" => "newvolume",
          "hasUrls" => true,
          "url" => "@web/images/newvolume",
          "path" => "@webroot/images/newvolume"
        ]);

        $success = Craft::$app->volumes->saveVolume($volume);

      }

      if (is_null(Craft::$app->sections->getSectionByHandle("awesomeNews"))) {
        $section = new \craft\models\Section([
          "name" => "Awesome News",
          "handle" => "awesomeNews",
          "type" => \craft\models\Section::TYPE_CHANNEL,
          "siteSettings" => [
              new \craft\models\Section_SiteSettings([
                  "siteId" => Craft::$app->sites->getPrimarySite()->id,
                  "enabledByDefault" => true,
                  "hasUrls" => true,
                  "uriFormat" => "foo/{slug}",
                  "template" => "foo/_entry",
              ]),
          ]
        ]);

        $success = Craft::$app->sections->saveSection($section);

        $errors = $section->getErrors();
        foreach ($errors as $error) {
          echo $error[0];
        }

      }

      return $success;

    }

    /**
     * @inheritdoc
     */
    public function safeDown()
    {

      $newvolume = Craft::$app->volumes->getVolumeByHandle("newvolume");
      if (!is_null($newvolume)) {
        $success = Craft::$app->volumes->deleteVolumeById($newvolume->id);
      }

      $awesomeNews = Craft::$app->sections->getSectionByHandle("awesomeNews");
      if (!is_null($awesomeNews)) {
        $success = Craft::$app->sections->deleteSectionById($awesomeNews->id);
      }

      return $success;

    }

}

This includes the error checking when creating the new section and the save functions are assigned to a variable which are returned at the end.


Navigation structure and uri problems I am using structure type entries for navigation with three fields for navigation that uses either:
-customlink field (plain text) or
-category
entry
as the source for links.

I have product categories setup like in this post: How do I add a subcategory to the URL slug for a channel entry?

This gives me the display of products I want from each category. My nav output template for category navigation looks like this:

            {% if entry.menulink|length %}

            {{ entry.title }}

            {% elseif entry.customMenuUrl %}

            {{ entry.title }}

            {% elseif entry.productCategoryLink|length %}

            {{ entry.title }}

            {% endif %}

My category links work to display my nice list of products.
My products section is set like: https://www.dropbox.com/s/o4ia62jo7i8yo38/Screenshot%202016-03-04%2017.29.35.png?dl=0
with the section entry urls set to render an entry in the template 'flowers/_entry.html''

SO thats the setup for navigation and templates.

Two problems are occurring which I cannot resolve yet.

The entry links in my category template produce nothing. When clicking on an entry from the category  I get my base and site templates but the output at 'flowers/_entry.html' is never rendered. I cant work out where craft thinks the entry template for the category should be.

2 . My navigation links are inheriting the current url
So if on the page 'mysite.com/category1' and i click on 'category1' in my navigation the url becomes ''mysite.com/category1/category1'

Have been round the houses for 2 days on 1 above. I don't mind a learning curve but I am in circles and not ascending the curve :)

OP solved it with using the correct block names.


Relating to Solspace Calendar Events I'm using Solspace Calendar for events, I also have a standard channel for reviews. What I need is the ability to connect the review with the event.

Solspace offers "Calendar Events" custom type field to do that, however, when I use it and attach an event to it this code:

{% set reviews = craft.entries.section('reviews').relatedTo(event) %}
{% if reviews|length %}
   {% for review in reviews %}

{{review.title}}

{{review.description|nl2br}}

   {% endfor %}
{% else %}

There are no reviews yet

{% endif %}

isn't working, and I have the same code working for a standard entry. How do I use relatedTo on custom fields?

This works on a different page with entry present

{% set reviews = craft.entries.section('reviews').relatedTo(entry) %}

This doens't work when event present

{% set reviews = craft.entries.section('reviews').relatedTo(event) %}

I've made sure that:

the event is fetched, and I'm successfully accessing it via code above
there are indeed reviews with this event attached

You can use them the same way like you are used to everywhere else. All relation fields extend the same BaseRelationField so their logic is totally equal.

You can either pass an element, an element id or an ElementQuery/ElementCriteriaModel but not a string to the function. If you want to fetch all related elements of an event you'll need to fetch the event first


Does Craft Commerce support Worldpay refunds? If anyone else is using Worldpay with Craft Commerce (am starting to feel like I'm one of a very small number), do you have order refund functionality? As in, the Refund button that exists on the order page with the control panel.

The answer looks to be "Not if you're using the Legacy gateway" that all my clients seem to be using.


SEO Title Tags Not Showing We’re having a big issue with SEO data. Any link preview does not pull the entry title but the global site title. For example, on this blog post, all link previews (Google, Twitter, Facebook, LinkedIn, etc) show just Bridge Partners as the title and not the page title of Darby Greenwell Joins Bridge Partners To Lead Analytics Practice. I have searched high and low for solutions to this problem. Can anyone help point me in the right direction? Thank you!

www.bridgepartnersconsulting.com

It would be helpful if you post your code instead of a link, as the metadata available on the linked page may change.

A few considerations:

Make sure your page is outputting metadata for each of the services you mention. It looks like you are outputting some basic and Open Graph metadata, but you don't appear to have any Twitter Card metadata. I've added a list of common meta tags that should help address most social sharing scenarios below.
Most of the services you have document which tags matter to them and some even have debugger tools that can help you troubleshoot.

Open Graph Protocol
Facebook Debugger
Twitter Card Spec
Twitter Card validator
LinkedIn Sharing uses the same Open Graph tags as Facebook

Make sure you consider caching. Sometimes, when you test your shared content the services you share it on will cache it. If you then update your content you may not see the updated version of your content in a link you have already shared until you break that cache.
Structured Data is also becoming an important type of metadata to add to your pages: https://developers.google.com/search/docs/guides/intro-structured-data
This stuff gets complicated to maintain directly in your templates very quickly. Several Craft plugins are available to help manage that complexity. Sprout SEO and SEOmatic are two SEO plugins that are well supported and try to address the majority of SEO best practices that you need to worry about.

Common Meta Tags for Search and Social Sharing

<!-- Search -->
<title></title>
<meta name="description" content="" />
<meta name="keywords" content="" />
<meta name="robots" content="" />
<link rel='canonical' href='' />

<!-- Open Graph -->
<meta property='og:type' content='' />
<meta property='og:url' content='' />
<meta property='og:site_name' content='' />
<meta property='og:title' content='' />
<meta property='og:description' content='' />
<meta property='og:image' content='' />
<meta property='og:image:width' content='' />
<meta property='og:image:height' content='' />
<meta property='og:image:type' content='' />
<meta property='og:author' content='' />
<meta property='og:publisher' content='' />

<!-- Twitter Card -->
<meta property='twitter:card' content='' />
<meta property='twitter:url' content='' />
<meta property='twitter:site' content='' />
<meta property='twitter:creator' content='' />
<meta property='twitter:title' content='' />
<meta property='twitter:description' content='' />
<meta property='twitter:image' content='' />


Issue with validator getNameReplacementInFolder I have issue with the following code:

public function getNameReplacementInFolder(string $originalFilename, int $folderId): string
{
    $folder = $this->getFolderById($folderId);

    if (!$folder) {
        throw new InvalidArgumentException('Invalid folder ID: '.$folderId);
    }

    $volume = $folder->getVolume();
    $fileList = $volume->getFileList((string)$folder->path, false);

The problem if I am using an external filesystem the getFileList is a very heavy API call for the external filesystem. It would be much easier to check the filename in the Asset database, than to check it on the filesystem.

Is there any way to avoid this call? Also if the flysystem driver is poorly written it could stuck in case of huge files or folders.

I badly need solution for disable this call - we can take care the indivudual file nameing, or to tweak it or change it for the database call

Thank you for your help

Not the "best" solution but if you really want to "disable" it you are free to overwrite the class via Dependency Injection and Service Locators.

You can overwrite the service with your custom one that extends Crafts service and "remove" the function

Craft::$container->set('craft\services\Assets', [
    'class' => 'prefix\namespace\services\MyCustomAwesomeAssetService'
]);

Since this function is only really needed in the AssetLocationValidator you can as well replace it with your custom validation


Why does Craft set no-cache headers for all requests? Craft seems to be setting headers to tell the browser not to cache anything it serves, which seems bad.

Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0

Why it do dat?

Craft doesn't explicitly set any caching headers in the response, but you can control exactly how you want your caching headers to behave from your templates with the {% header %} tag.

For example:

{# Tell the browser to cache this page for 30 days #}
{% set expiry = now|date_modify('+30 days') %}

{% header "Cache-Control: max-age=" ~ expiry.timestamp %}
{% header "Pragma: cache" %}
{% header "Expires: " ~ expiry|date('D, d M Y H:i:s', 'GMT') ~ " GMT" %}

By default PHP has the session_cache_limiter() method set to nocache, which is probably what you're seeing.


Issue with twig loop.first loop.last contained in nested for statement I'm trying to pull out selected categories in a front-end user profile. The cats have 2 levels and need to be pulled out into a nested list with only the selected options. I've tried different ways of doing this but nothing seems to work by using one for loop. So have nested the second level cats in a second for loop. This will work but the loop.first and loop.last variables are using the parent for loop and not the nested one? Or is there a better/easier way of doing this?

{% for challenge in user.challenges.level(1).options %}

        {{ challenge.title }}
        {% for child in user.challenges.level(2).options %}
            {% if child and child.getParent().id == challenge.id %}
                {% if loop.first %}
{% endif %}

{{ child.title }}

                {% if loop.last %}
{% endif %}
            {% endif %}
        {% endfor %}

{% endfor %}

You should be able to access the outer loop.index etc using the loop.parent context. The Twig docs here should give you what you need.

EDIT: You might be getting strange results because the inner loop contains an if so depending on your conditions you might loop over the first item thus making your inner loop.first not work as expected. You can combine for with an if which might get you a bit closer, like this:

{% for thing in things if thing.isAvailable == true %}
{{-- Your inner stuff --}}
{% endfor %}

More info here.


Plugin - Possible path problem in MAMP - Could not find the task component type I have a Craft plugin that works fine on a live site and on Macs. I have recently installed MAMP (Windows) on my development machine and now, when I try to run one of the plugins commands by using GIT to CD to the Yiic console ... /c/mamp/htdocs/websitename/craft/app/etc/console ... and run the command ... php yiic pluginname commandname ... I get the error message ... Encountered an error running task 700 (plugin_task): Could not find the task component type.

I am pretty sure that the problem is that the task file is not being found, but I think I have the upper/lower case elements correct:

\pluginname\consolecommands\PluginnameCommand.php

<?php
namespace Craft;

class PluginnameCommand extends BaseCommand
{
  public function actionUpdate($testError = false)
  {
      $task = craft()->tasks->createTask('pluginname_event', 'Updating data', [
            'testError' => $testError,
      ]);
      craft()->tasks->runTask($task);
  }
}

\pluginname\tasks\Pluginname_EventTask.php

<?php
namespace Craft;

class Pluginname_EventTask extends BaseTask
{
}

Have I the cases wrong, or am I missing something in setup?

Note that this is a followup to ... Running console (yiic) under MAMP (Windows) ... which was a path problem solved by modifying the yiic file.

My guess is it's a case sensitivity issue between your plugin class names and the names of those files on the file system.

If you're on an NTFS filesystem on Windows, it is case sensitive.  I recommend generating boilerplate plugin code from something like https://pluginfactory.io/ (they even have a tasks checkbox) to help avoid issues like this.


Customize Admin Sidebar Menu Items? Looking for a way to show Channel entries directly on the sidebar for content editors. So if someone has access to:

DEFAULT STRUCTURE of Sidebar Menu

Entries ->

CHANNELS ->

News

News Item 1
News Item 2
News Item 3

PREFERRED STRUCTURE of Sidebar Menu

News

News Item 1
News Item 2

In other words, Content Editors don't need to see "Entries" and then "CHANNELS" to get to their section they update. When someone has permissions for a specific Section or Channel, it should be neatly accessible on the left side.

In Craft, what is the correct approach to make this happen?

Craft does not offer this functionality natively. Luckily there's a few plugins out there that will help your users navigate around a bit easier:

In the CP Nav
https://github.com/engram-design/CPNav (This should accomplish your need)
https://github.com/picdorsey/craft-sidebarenhancer

In the Entries index
https://github.com/james1238/EntryTypeSources
https://github.com/engram-design/ExpandedSingles


Batch entries by year? I have a press release index page that loops through all the press releases. I want to organize them by year. So everything in 2018 will have a header that says 2018 press releases and then all the press releases for 2018 and so on.

Should I do a conditional that checks the date, or is there something like the | batch but for date? Open to ideas.

You can use the group filter

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

{% set allEntriesByYear = allEntries|group('postDate.year') %}

{% for year, entriesInYear in allEntriesByYear %}

{{ year }}

        {% for entry in entriesInYear %}

{{ entry.title }}

        {% endfor %}

{% endfor %}


Import / Aggregation DB - with 50 Million Records - Best Practice? I'm working on my second Craft project ever. (First was an ultra-simple site just to learn the basics.)

With this new project I need to accomplish 2 things...

(1) - Private - Import/aggregate mass data from external sources based on my specific search parameters (think YouTube, CNN, BBC, Instagram, Reddit, Imgur, Pinterest, etc).  Then slice, dice, curate, categorize, headline, and editorialize that data to create content-rich, topical feeds.

(2) - Public - Present those content-rich feeds as dense Topical Resources for my website visitors.

Craft is a brilliant solution for building a robust (and lightning fast) Public front end.

But based on how Craft operates underneath the hood... What's the Best Practice for managing the Private raw data behind the scenes?

Is it smarter to have ONE Craft Install with one DB - and separate tables for the imported (but not yet published) data?

OR

Is it wiser to do TWO entirely separate Craft Installs - one for the Private back-end work (importing, compiling, editing, building newly curated feeds) - and another to grab and serve the Public (post-curation) results?

I'm not sure why you would do two different servers.

Your front end can be cached with Blitz / NGINX which will take a load off the server and admin.

How often are you aggregating the data?

I've just imported 10k records from a source and I would recommend writing your own module to handle the imports as commands. From there you could set up a cron which would run at a scheduled interval. These commands wouldn't run via the web server so you wouldn't be restricted to memory / timeout limits.


Stock Levels for Commerce 2 I am putting together a proposal for an eCommerce site - one of the (obvious) requirements is inventory management. I do not see anything specific in the Commerce 2 docs. Basically, want to enter stock levels for each product and then have that number change as orders are placed. Is that possible or does it require  a plug-in?

Thanks!

Commerce (as at V2) has basic stock handling that will do exactly what you mention - for each product you can set a stock level (alternatively, you can set it to unlimited stock if you wish).  When orders are completed stock is debited by the amount sold (note stock is not debited when items are added to carts - which is good, because it means you don't have to deal with not being able to sell things that are locked up in stale carts).

Commerce will not let you sell out of stock items, and there are template tests you can use to display the stock state in any way you choose (be careful with caching in this area!).

Note that the stock handling is fairly simplistic - e.g. I am pretty sure that there is no automatic return handling (so if you e.g. cancel/refund an order, it won't automatically add the stock back).

If you need stock handling beyond this then you would need to look at building a plugin specific for you needs (or one that integrates a sophisticated inventory handling system).


Image does not be shown Good mornig

I am having a problem with my bannerImage.
First off i show you how i did it and what the problem is.

In the first picture you can see, how i get the image.
This method works fine for 3 other pages on this website.¨
My field setup is correct, because in other templates it works fine.

The only thing i can now think off is that there's something wrong with the name of the template.

Thanks for your help.

EDIT
I fixed this problem like this.

This might be a silly question, but is your .pic-banner class for this template styled correctly, ie. given a height etc?

Since you're setting it is a background-image it won't "expand" the element to the aspects of the image as it normally would using a img-element.


Missing matrix fields This is a head scratcher. We have a site we are about to launch that was ready to go when suddenly at some point in the day yesterday a bunch of Matrix fields within a group went missing. Just gone. Of course this broke the site and our templates started erroring out. Our first instinct was that they were manually deleted but the client is saying that they didn't touch the fields area. We also talked to the web host / Arcustech and they said that everything looked fine on their end. We had to restore the database which was a bummer.

So my question is, could this have been due to a recent bug? Is there a way we can see what fields get deleted via the logs? It's really bothering us that we can't pinpoint exactly what happened here.

I should mention we were on 2.2.2592 when this happened. Thanks for any help.

Nothing in Craft will automatically delete Matrix fields, and there haven’t been any DB migrations that would have deleted an entire Matrix field. (There was a recent migration that deleted some orphaned Matrix block rows in the DB, but that would only have affected the data, not the fields themselves, and wouldn’t have made any noticeable change in the Control Panel.) Someone must have gone in and deleted the field, or changed its name/field type.

If it happened recently enough, there might still be some evidence of it in your logs. We can take a look - just send in a ticket from your Dashboard and they will be included automatically.


SEOmatic not merging fields from a related entry I have a pretty specific set up: posts get created via rss feeds and images are not attached to the specific posts, so instead in the entry template I use an image from a related entry. When I try to use the related entry's image as the SEO image and merge it with SEOmatic, it does not merge.

Has anyone ever tried doing this with SEOmatic? This is the code I'm using:

{% if craft.entries.section('episode') %}
   {% set relatedPodcastImage = craft.entries.section('podcastChannel').relatedTo(entry).albumCoverPicture.first().getUrl('large') %}
      {% set seomaticMeta = seomaticMeta | merge(
            { og:
                  {
                  title: entry.title,
          description: entry.podcastDescription,
                  image: relatedPodcastImage
                  }
            },
        { twitter:
                  {
                  title: entry.title,
                  description: entry.podcastDescription,
                  image: relatedPodcastImage
                  }
            }
      ) %}
{% endif %}

Make sure you're not doing this inside of a {% block %} or you will run into Twig Processing Order / Scoping issues.

There are some good examples of doing that here: Dynamic Twig SEO Meta


Get entries that are enabled and disabled for the site A Craft (3.4 Pro) website has setup two sites, one for each language. There are entries in a section that are enabled and others that are disabled for each language.
I want to get a list of all the entries, regardless of whether they are enabled or not.
I know there is a enabledForSite parameter but this can be set to either true or false but not both.
For example the query below returns only enabled entries.
{% set items = craft.entries({
  section: 'works',
  enabledForSite: true,
  status: [
    'live', 'pending', 'disabled', 'expired'
  ]
}).all() %}

How can I get a list that contains both enabled and disabled entries?

With the help of Oli from Craft, it turns out the solution is simpler than I thought:
{% set items = craft
    .entries()
    .section('works')
    .anyStatus()
    .all()
%}

This returns all entries, enabled and disabled.


Propagate entries manually between sites I have a client that wants to setup a multilingual site, but for the purpose of this site they only want certain entries to be translated.
If I setup sites that use a section which is configured to NOT propagate entries across sites, then I haven't found a way to link entries manually for entries that I DO want to propagate. Is this not possible? One could of course just create the entries manually, but then I loose the linking between them to provide a language switcher though. Also, I can't really re-save an entry on another site easily.
Is the preferred approach to do propagate and keep them unpublished? I feel that that makes it unwieldy very quickly...

i think one solution is new propagation method 'Let each entry choose which sites it should be saved to', introduced in Craft 3.5.
see this issue for more information.


Equivalent of Records in Craft 3? Trying to convert a plugin from Craft 2 to Craft 3, not sure what's the Records equivalent in Craft 3.
How do I get this to work in C3?
class SearchRelationshipRecord extends BaseRecord
{
    public function tableName()
    {
        return 'some_name';
    }

    protected function setAttributes()
    {
        return [
            'aaa' => AttributeType::Number,
            'bbb' => AttributeType::Number,
            'ccc' => AttributeType::String
        ];
    }

    public function defineIndexes()
    {
        return [
            ['columns' => ['aaa']],
            ['columns' => ['bbb']],
            ['columns' => ['aaa', 'ccc']],
            ['columns' => ['bbb', 'ccc']],
        ];
    }
}

/**
 * Class SearchRelationship record
 *
 * @property int $id
 * @property int $aaa
 * @property int $bbb
 * @property string $ccc
*/
class SearchRelationship extends ActiveRecord
{
    /**
     * @inheritdoc
     * @return string
     */
    public static function tableName(): string
    {
        return '{{%somename}}';
    }
}

All you really need to define is the table name.  Yii 2 uses reflection on the database table to generate the column/object property names at runtime (replacing the old setAttributes method).
Worth reading: https://www.yiiframework.com/doc/guide/2.0/en/db-active-record
Indexes should be initially defined in your plugin's install migration (replacing defineIndexes).


Supertable or Neo for nested Matrices and compatibility with Craft 4 I typically avoid using Supertable or Neo because I don't want the extra dependency going forward. However I'm in a project where I needed nested matrices.

I know that in C4 nested matrices will be possible and that there is likely to be a migration script for that (according to what I remember from dotall2019). That being the case which plugin is recommended Supertable or Neo?

Will they both have a migration path to Native?

In reply. In a tweet from Brandon... Neo will get a direct upgrade path to matrix.
https://twitter.com/brandonkelly/status/1114144432243265536?s=19

That being said. I used supertable more recently.


Publishing entry returns Internal Server Error (1030 Got error 139) Trying to publish changes in one of 3 locales of an entry gives error:

Internal Server Error
CDbCommand failed to execute the SQL statement: SQLSTATE[HY000]: General error: 1030 Got error 139 from storage engine

It is basically a row size problem.
The entry has many fields and there are 3 locales. It is possible to save a draft of the changes made.
What i tried:
On staging server I have solved the problem with changing the database config

innodb_file_per_table=1
innodb_file_format = Barracuda

and then changing row format of some tables (entries, content and fields) to compressed.
This is not possible on live production server since host does not allow it. And also it probably is not the best solution.
I also tried to change the table engine to MyISAM but this gave error:

SQL Error [1217] [23000]: Cannot delete or update a parent row: a foreign key constraint fails

I hope there is a simple solution to all this.
Thank you for your help, I am a bit green in all this, my background is in design.

I also tried to change the table engine to MyISAM

That won't work because Craft relies on foreign key constraints that InnoDB provides and MyISAM doesn't support.

There might be some server config/changes you can do to address the issue, but because you're bumping into MySQL/InnoDB limitations, I'd try to address this from an information architecture point of view.

i.e. You've likely got a lot of fields that are probably ending up as text data types in MySQL.  Can you change those to fields that use varchar instead?  Can you logically break up the fields so they make sense inside of a Matrix field?  Matrix fields get their content stored in their own table outside of the main craft_content table, which is where you're likely running into that error.


Plugin Routes: Asterisk Token effect from CP Routes I'd like to use the asterisk token functionality that is available in the CP in my plugin. This way I can have an infinite amount of 'pages' under certain routes. In the CP, it looks like myroute/*

Is it possible for me to get the same functionality in my plugin routes?

Routes have been working amazing for me via the standard:

public function registerSiteRoutes()
{
    return array(
    'myroute' => array('action' => 'myPlugin/myAction')
  );
}

Though when I try the asterisk trick, it doesn't work:

public function registerSiteRoutes()
{
    return array(
    'myroute/*' => array('action' => 'myPlugin/myAction')
  );
}

Does anyone know if this is possible and/or the way to accomplish this?

Thanks!

You can't have tokens in your plugin routes, but you can easily add a segment variable that recreates the asterisk token's functionality with some regex. According to the the official docs on routing, the asterisk represents

  (...) any string of characters, except for a forward slash (/)

Here's what the defintion for a route with a "asterisk-like" segment could look like:

public function registerSiteRoutes()
{
    return array(
        'myroute/(?P<asteriskToken>[-\w]+)' => array('action' => 'myPlugin/myAction')
    );
}

Note that the string "asteriskToken" will be the variable name for this route segment's value when it is passed to your controller. It could be named anything.

The above route will match any URIs such as

/myroute/whatever (asterisk token will be "whatever")
/myroute/123 (asterisk token will be "123")
/myroute//foobar (asterisk token will be "foobar")

Coming to your controller, here's how you could look up the asterisk token variable's value:

public function actionMyAction( array $variables = array() )
{
   $asteriskToken = $variables[ 'asteriskToken' ];
}

Be aware that any calls to /myroute (i.e. without the second segment) will now 404. If this is unwanted – or if you want to define a default value for your asterisk variable – you can make the asterisk token segment optional. This is done by wrapping the segment variable in parentheses and appending a question mark at the end (kudos to @carlcs for this trick, originally given as an answer to my question here:

'myroute(/(?P<asteriskToken>[-\w]+))?' => array('action' => 'myPlugin/myAction')

With the latter regex, your route will now also match the following:

/myroute (asterisk token will be undefined)

...and in your controller, here's how you could define a default value for the asterisk token variable:

$asteriskToken = isset( $variables[ 'asteriskToken' ] ) ? $variables[ 'asteriskToken' ] : 'myDefaultAsteriskValue';


Is there a way to apply project.yaml changes on deployment? Love the new new project config functionality, but if there are changes that need to be synchronised the site essentially goes down until the changes are applied manually.

I wondered if anyone had a simple way to programmatically apply the changes automatically when the site is deployed, via a webhook?

You can create a script to use the craft executable to sync your project config file

./craft project-config/sync


Images not showing after Craft 2 to 3 migration Hi upon migrating my site from Craft 2 to 3 I'm getting errors like this:

Twig Runtime Error – Twig_Error_Runtime
Variable "largeImage" does not exist.

"largeImage" refers to an image transform, this error happens with all image transforms where I've used an assets field to place a picture.

Also whenever I have embedded a picture inside an editor, this doesn't show either and the URL that is written out is:

 src="@baseUrl/images/image.png"

Clearly, something has gone wrong for @baseUrl to appear there. I've checked my base URL settings and it is set to "http://localhost:8888".

I don't know what else to try so any help would be much appreciated. Thanks.

I did manage to fix this problem with some support, however I now have a few other problems as a cause of this and I think it is best to try and start a fresh post on it. I had to change the baseUrl which fixed the error but now have broken images across the website and duplicate folders in my assets. Argghh.


Error when trying to test Craft Pro on .dev I have a fresh Craft install set up locally at mysite.craft.dev. I would like to start building out the features offered by the pro license, but when I click the "Show me" link in the footer, I get "An unknown error occurred."

I am seeing this error in craft.log:
015/04/03 17:13:55 [error] [php] Cannot modify header information - headers already sent (/Users/aaron/Sites/mysite/craft/app/framework/web/CHttpRequest.php:1392)

In potentially related news, tasks do not seem to be behaving correctly.

Anyone ever experience this before? Any help is appreciated :)

I found a solution! I had my local environment setup with homebrew following this article's instructions. After looking at the php error logs, I uncommented always_populate_raw_post_data = -1 in the php.ini file found in /usr/local/etc/php/5.6.

I then restarted the brew services with brew services restart php56 (install brew services by tapping gapple/services with brew tap gapple/services) and restarted apache with apachectl restart.

That did the trick!


Imager Transforms, Cacheing and S3 Got Imager running great on my S3 hosted images. However it's cacheing transforms locally on my server. I'd like to save some disc space and have the transforms on S3 too, but struggling to get my config right. I've created a couple of folders on S3 (imagertransforms) and added the following to my imager config:

'imagerSystemPath' => 'imager/',
'imagerUrl' => 'https://myaddress.s3.amazonaws.com/_imagertransforms/',

Doesn't seem to be working though and not sure how best to debug. Am I missing something?

Imager will always create and store the transformed images locally in your imagerSystemPath, even if you choose to upload and serve them from an external storage. The files in that folder acts as the cache, so that Imager knows if a transform has been created or not.

Alternatively, Imager either would have to; 1) make a request for each transformed image to see if it existed in the external storage, or 2) have some other method of keeping track of what transforms has been made (DB, DB-like file, or something). Option 1) adds an insane amount of overhead, whereas 2) adds quite a bit of complexity and possibly some overhead (like Craft's built-in transforms, which requires DB queries). So I opted for speed and simplicity, and sacrificed disk space. :)


Problems Securing Database Connection Over SSL I used to connect to my database over SSL by directly modifying the createDbConnection method in Craft's AppBehavior.php:

$dbConnection = new DbConnection();

$dbConnection->connectionString = $this->_processConnectionString();
$dbConnection->emulatePrepare   = true;
$dbConnection->username         = craft()->config->get('user', ConfigFile::Db);
$dbConnection->password         = craft()->config->get('password', ConfigFile::Db);
$dbConnection->charset          = craft()->config->get('charset', ConfigFile::Db);
$dbConnection->tablePrefix      = $dbConnection->getNormalizedTablePrefix();
$dbConnection->driverMap        = array('mysql' => 'Craft\MysqlSchema');

// additional attributes to connect over SSL
if (getenv('DB_SSL_ENABLED') == 'true')
{
    $dbConnection->attributes   = array(
        PDO::MYSQL_ATTR_SSL_CIPHER => 'DHE-RSA-AES256-SHA:AES128-SHA',
        PDO::MYSQL_ATTR_SSL_CA     => CRAFT_CONFIG_PATH . 'rds-combined-ca-bundle.pem',
    );
}

$dbConnection->init();

But as of a new Craft release there is a native Craft way to do this by setting a new "attributes" key in the database config file. Unfortunately, Craft won't make a connection when I connect using this new method. I get the dreaded Craft can’t connect to the database with the credentials in craft/config/db.php error. My revised db.php looks like this:

$url = parse_url(getenv("DATABASE_URL"));

define(SERVER, $url["host"]);
define(USER, $url["user"]);
define(PASSWORD, $url["pass"]);
define(DATABASE, substr($url["path"], 1));

return array(
    'server' => SERVER,
    'user' => USER,
    'password' => PASSWORD,
    'database' => DATABASE,
    'tablePrefix' => 'craft',
    'attributes' => array(
        PDO::MYSQL_ATTR_SSL_CIPHER => 'DHE-RSA-AES256-SHA:AES128-SHA',
        PDO::MYSQL_ATTR_SSL_CA     => CRAFT_CONFIG_PATH . 'rds-combined-ca-bundle.pem',
     )
);

Not sure what could be going wrong here. Are there additional attributes that need to be set when doing this the Yii way?

Silly mistake. I forgot to update AppBehaviors.php to the newest release after moving the attributes logic to db.php:

$dbConnection = new DbConnection();

$dbConnection->connectionString = $this->_processConnectionString();
$dbConnection->emulatePrepare   = true;
$dbConnection->username         = craft()->config->get('user', ConfigFile::Db);
$dbConnection->password         = craft()->config->get('password', ConfigFile::Db);
$dbConnection->charset          = craft()->config->get('charset', ConfigFile::Db);
$dbConnection->tablePrefix      = $dbConnection->getNormalizedTablePrefix();
$dbConnection->driverMap        = array('mysql' => 'Craft\MysqlSchema');

// Support for Yii's $initSQLs
if ($initSQLs = craft()->config->get('initSQLs', ConfigFile::Db))
{
    $dbConnection->initSQLs = $initSQLs;
}
// See if we have any extra PDO attributes passed in.
if ($attributes = craft()->config->get('attributes', ConfigFile::Db))
{
    $dbConnection->attributes = $attributes;
}

$dbConnection->init();

After adding the new lines of code, I was able to connect :)


Is it possible to import orders into Craft Commerce? We have to migrate a CSV dump from a Drupal commerce shop to Craft Commerce.

It is important to import ‘Order Email’ / ‘Username’, ‘Order Date’, ‘Ordered Items’ (Name or ID), ‘Item Price’.
Address etc. are not relevant. An Order Reference could be generated automatically from us.

If these are not enough fields for a Craft Commerce order: Which mandatory fields does an order require in Commerce?

Anyone know if there is a way to do this? We would of course love to do it with the FeedMe plugin, but that does not seem to be applicable to Craft Commerce orders.

Sprout Import supports importing Craft Commerce Orders on Craft 3.

I can't speak to which fields are required off of the top of my head but importing to custom fields, variants, and even custom fields like Matrix on Variant Layouts is possible. Any required fields you don't include will throw an error and tell you they are needed.

An example of the Orders import format is available in the Element Importer docs.

Sprout Import uses a specific JSON format to perform imports so you will need to convert your CSV export into the appropriate JSON format to import if you choose to go this route.


Commerce PDF error: Image not found or type unknown In the order template, this error shows up in the generated PDFs when adding standard JPG images.  We're running Commerce 1.2.x on PHP70.

It could be related to this dompdf issue, but how do we fix it in Craft Commerce?

Try setting:

'pdfAllowRemoteImages' => true,

in your commerce.php config file.


Image Transform Quality settings This is a simple question but I haven't been able to find the answer. Does the Image Transform Quality setting "Auto" mean that no compression will be applied to the transform?

It should probably be more accurately renamed to Default instead of Auto, but if that is selected, then it will use the defaultImageQuality config setting value.


How to access HTML input values from Twig and vice versa I am new to Craft and Twig in general. I have encountered the following problems and struggling to find a solution for hours.

I want to access the value of "foo" input field inside the twig delimiters to set the "json" variable.
I want to change the "clicked" boolean, whenever the submit button is clicked.

The myFunc is a function that I am using from a custom plugin so it is not relative.
I have commented what I've last tried and does not work for me.

I am using Craft 3, if that helps.

{% block body %}
    {% set clicked = false %}

    <form name="search" action="{% set clicked = true %}">
        Foo
        <input name="foo" type="text"/>
        <input type="submit" value="Get Json"/>
        {#    <a href="{{ set clicked = true }}"#}
    </form>

    {% if clicked %}
        {% set json = jsonator_myFunc(search.foo.vars.value) %}
    {% endif %}

{% endblock %}

EDIT/SOLUTION:

A few more days into Craft CMS and chill and I realize how silly my question is.

Thank you for the replies. The solution which I was looking for is:

craft.request.getParam('foo')

You can do it without JavaScript (if you don't mind the page refreshing) by accessing the request variable:

https://docs.craftcms.com/api/v3/craft-web-twig-variables-request.html#public-methods

{{ craft.app.request.getParam('foo') }} {# Should be the value of the input named 'foo' #}


How to prevent access to asset folder (and redirect to other page)? I have an asset source with url "/guides/".
When I put a file to this folder, a file gets an url:
domain.com/guides/myfile.pdf

If I go to "domain.com/guides", it shows me the file directory.
I prevent access to this by creating .htaccess file and now I see a Forbidden page (You don't have permission to access /guides/ on this server).

I have a Guides entry page: domain.com/guides/my-guides-main-page
Is it possible to make a redirection like this:
domain.com/guides -> domain.com/guides/my-guides-main-page

It would be much safer and easier to work with if you put all assets folders into domain.com/assets/ as it can cause such conflicts.


Craft 2: Serve language / locale i18n according to user agent As the official documentation does not give any hints on this:

I am wondering how to serve the correct localization of my website according to the user’s language preference and/or browser/OS language with Craft.

From other platforms/plugins I know that this is done through user agent detection, e.g. if the browser/OS is English you’ll get the EN, if it’s Spanish you’ll get the ES version of the content, etc.

The project I am working on has DE as the primary locale and the language switcher shall only appear subtly within the footer. Non-German visitors should automatically get the EN version without having to interact with any interface element.

How can I implement this?

You could accomplish this before your PHP is executed as redirects listening for the accept_language header (both are untested from my part):

APACHE

RewriteEngine on
RewriteCond %{HTTP:Accept-Language} (de) [NC]
RewriteRule .* http://example.com/de/ [R,L]

NGINX

map $http_accept_language $lang {
  default en;
  ~de de;
}

location ~* "/" {
  return 302 https://example.com/$lang;
}


Craft newbie : can anyone recommend a simple image slider? I have just started working with Craft and I'm learning as I go, by porting over an existing site to it. It's mostly going well.

However, I stumbled when I tried integrating an imageslider on the Homepage. It's a slider called Flexslider, and I've been unsuccessful in integrating it as a series of entries for each slide. When the browser tries to render the page it stops at the "data-bg" tag...

Here is my code :

{{ entry.slideTitle }}

{{ entry.slideSubtitle }}

        ...

I'm open to replacing Flexslider with a more Craft-friendly slider, if anyone can point me in the right direction?

Many thanks!
Ric

There's quite a lot missing from your code / question. I'll make some assumptions.

Your slider is on a the Home page of your site (not a single entry page/template)
Your have a Section in Craft called "News"
Your slides consist of custom fields within News, called: 'news cover image', 'title' and 'sub title'
You have an Image Transform configured in Craft called "News Slide"

Your code could then, look like this:

    {# Find the most recent 3 entries in the News Section #}
    {% set newsEntries = craft.entries.section('news').limit(3) %}

    {% for entry in newsEntries %}

        {% set image = entry.newsCoverImage.first() %}
        {% if image %}

{{ entry.title }}

{{ entry.subTitle }}

        {% endif %}

    {% endfor %}

The first Set tag finds the most recent 3 News entries (More info here...)

The For loop contains the slides and will loop x3 times.

The Set-image tag grabs the first asset (image) assigned to the "news cover image" custom field.

Let us know how you get on...


Archive page - only show posts from certain month Using this handy thing (http://buildwithcraft.com/help/entry-archive) to create an archive page, but not quite doing what I need it to do.

Set up as a route to call /year/month, replacing year with current year if not provided and replacing month with most recent month that has posts in it if not provided.

This version will print out all posts from a single year:

{% set entriesInYear = craft.entries.section('pressReleases').limit(null).after(year).before(year+1) %}

{% for entry in entriesInYear %}

{{ entry.title }}

{% endfor %}

And this version will print out the entire year into groups based on month:

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

{{ month }}

        {% for entry in entries %}

{{ entry.getLink() }}

        {% endfor %}

{% endfor %}

But what I need is to only get the posts from the month in the url and am not sure how to get there... basically an entriesInMonth variable as opposed to an entriesInYear.

There's probably a cleaner way to go about this, but something like this should work:

{# These are probably coming from the querystring, but I'll hard code them here #}
{% set year = 2015 %}
{% set month = 'July' %}

{% set entriesInYear = craft.entries.section('news').limit(null).after(year).before(year+1) %}
{% set groupedEntries =  entriesInYear | group("postDate|date('F')") %}

{{ month }}

    {% for entry in groupedEntries[month] %}

{{ entry.getLink() }}

    {% endfor %}

You'll probably want to add error checking and validation in case no entries exist for the month or the month/year is invalid, etc.


Give included twig component unique ID When I include specific Twig template component multiple times, how can I give it a unique ID (or class)?

Components are not inside for loop, so I cannot use loop.index. I also don't wont to pass unique variable myself when I include it. And using random Twig function doesn't ensure that the result is unique.

Let's also assume that each component doesn't have unique Craft element assigned to it, like entry - in such case, I could just use this entry ID.

You can create a unique ID function in PHP and pass it to Twig

{% set uniqueId = uniqueId() %}

And your PHP part

class Extension extends \Twig_Extension implements \Twig_Extension_GlobalsInterface
{
    public $uniqueIds;

    public function getFunctions(): array
    {
        return [
             new Twig_SimpleFunction('uniqueId', [$this, 'getUniqueId'])
        ];
    }

    /**
     * getUniqueId
     *
     * @return string
     */
    public function getUniqueId(): string
    {
        // generate a random string
        $id = StringHelper::randomString('12');

        // check if it's already set
        while (\in_array($id, $this->uniqueIds, true)){
            // if so, use another one
            $id = StringHelper::randomString('12');
        }
        // set it as "used"
        $this->uniqueIds[] = $id;

        return $id;
    }
}


yii\web\ServerErrorHttpException Craft 3 install I'm new with Craft CMS and receive this error when I try to install it

-------------------ERROR-----------------------------
An Error occurred while handling another error:
yii\web\ServerErrorHttpException: The info table is missing its row in C:\xampp\htdocs\craft\vendor\craftcms\cms\src\base\ApplicationTrait.php:512

The info table is missing its row...

The craft_info table in the database should only ever have one row in it.  In a fresh Craft installation, then installer should populate the row with the relevant information.

If you're getting that error message, then that table is missing its one row, which would indicate that some other error happened during installation.

If it's a Craft generated error, then that underlying message would be in your craft/storage/logs files.  If it's a web server generated error, that error would be in your web server's error logs.


Using a field multiple times in a single template we have a problem over and over again and I wonder if we're missing something.
Using bootstrap we have a matrix field, let's call it Grid, that has blocks like "full column" "half column" etc. It's extremely usable across all pages.

Now the issue is we can have only one such matrix per template. And a standard page looks like this:

[some title]
[some grid] <- Grid
[some hero image]
[again some grid] <- Grid
[some other stuff]
[even more grid at the end!] <- Grid

The only solution is to create yet another Grid field that uses the same twig code for rendering only to use it again on the same side.

The solution would be a way to put a field in an entry type but with ability to manually set the handle. So we could put the same field (Grid) and refer to them using topGrid, middleGrid and bottomGrid.

Is there any way to solve this problem?

thanks!
Jan

The only solution is to create yet another Grid field that uses the same twig code for rendering only to use it again on the same side.

Do you need to enforce that structure or is it a "soft" restriction (meaning things won't go south if the blocks get turned around)?

If it were me, I would treat Matrix more or less like a site builder.  [some hero image] and [other stuff] could also be blocks in that matrix, alongside full column and half column, you just need the appropriate code to "close up" the grid when necessary.

You would have different blocks (like Grid, Hero Unit, Ad space, etc.) and then when building the page, just insert them in the appropriate spots.

That's the canonical use of Matrix of course. If you need full control over how things are presented you don't necessarily have to build out the page in the order the blocks appear in. If you name various blocks you could filter by block type and then spit out only the blocks that would appear in that area. For example, even if there is only one hero unit, you can specify it should only appear once and then spit out the hero where it needs to go (say at the top).

If you're doing this for a client, it might be helpful to number the blocks so they put the blocks in the intended order to avoid surprises but with matrix it's pretty open ended which might be less likely what you're looking for.

Ideally we should be able to have some "default" blocks and lock 'em in place so they can't be moved or disabled... maybe in a future version of Craft.


Default Upload Location needs matrix field and entry info... How? I have a towns entry with a matrix field: townAlbums.

This matrix field has just one block type: photoAlbum.

This one block type has two basic text fields (the important one being albumName and one asset field for uploading images to the gallery: albumPhotos.

I want the Default Upload Location for this matrix subfield albumPhotos to be dynamic, taking both the parent entry slug (slug of the town entry) and the name of the album: albumName. I'm not sure how to accomplish this.

Desired url:

http://sitename.com/uploads/towns/town-slug/album-name/filename.jpg

What should I be entering for my Default Upload Location?

Thanks!

If your desired URL is:

http://sitename.com/uploads/towns/town-slug/album-name/filename.jpg

The the "Upload Location" for the setup you described would be something like:

towns/{owner.slug}/{albumName}/

I'm assuming towns is just hard-coded since you're referencing town-slug in the next segment.


Entry saving in task fails due to required assets/matrix fields being read as blank, even through they are not I have a task that is used to collate relationship data for a specific entry and save it as JSON to a text field in that entry. Everything is working fine, except for the saving of the entry which fails because the required Matrix / Assets fields in the entry are being read as blank. I've checked to make sure that the entries have all required fields completed, but the errors still persist.

The entry saving code in the task:

$entry->getContent()->setAttribute('latLngs', json_encode($latLngs));

craft()->entries->saveEntry($entry);

The errors being returned:

[_errors:CModel:private] => Array
(
    [gallery] => Array
    (
        [0] => Gallery cannot be blank.
    )
    [standardContent] => Array
    (
        [0] => Standard Content cannot be blank.
    )
)

Where gallery is an Assets field, and standardContent is a Matrix field. All other required fields seem to be working fine with no errors.

Is this to do with the way I'm saving the entries, or something else?

Thanks!

This is due to the way Craft manages custom fields at the moment (but has been “fixed” for Craft 3). Whenever you save an element, you need to make sure all of the field values are in the same format they would be if they had come from an Edit Entry form submission. Here’s another post that describes what that looks like: How to save a matrix content of a new entry in my plugin?


Craft 3 language switcher Does anybody successfully implemented a language switch run Craft 3? Trying the Craft 2 variant slightly adjusted but still running into issues: Invalid site handle: nl

{% set otherLocales = craft.app.i18n.siteLocaleIds|without(craft.locale) %}
{% for locale in otherLocales %}
   {% set localeEntry = craft.entries.id(entry.id).locale(locale).one() %}
    {#  set localeCategory = craft.categories.group('worksCat').locale(locale).first #}
    {% if localeEntry.locale is defined and localeEntry.locale == locale %}

            <img src="/{{ craft.app.i18n.getLocaleById(locale) }}.svg"  {{ craft.app.i18n.getLocaleById(locale).nativeName }}

    {% else %}

             {{ craft.app.i18n.getLocaleById(locale).nativeName }}

    {% endif %}
{% endfor %}

The concept of localization has changed in Craft 3, there are not only locales anymore - now you have different sites and site groups.

Example without multisite - only different locals

You can get all available sites for an entry with

{% set supportedSites = entry.getSupportedSites %}

This will return you an array of all supported sites for the entry.

{% for siteForEntry in entry.getSupportedSites %}
    {# get the site #}
    {% set site = craft.app.getSites.getSiteById(siteForEntry.siteId) %}
    {# check if it's the current site #}
    {% if site.id == entry.siteId %}
        active site = {{ site.id }} {{ site.language }}
    {% else %}
        {# if it's not the current site, get the entry for this site #}
        {% set entryForOtherSite = craft.entries.id(entry.id).site(site).one() %}
        link to site with id {{ entryForOtherSite.siteId }} {{ site.language }} - {{ entryForOtherSite.title }}
    {% endif %}
{% endfor %}

When you take a look at your /admin/utilities/deprecation-errors you'll see many records because all your locale functions will do this

public function locale(string $value)
{
    Craft::$app->getDeprecator()->log('ElementQuery::locale()', 'The “locale” element query param has been deprecated. Use “site” or “siteId” instead.');
    $this->site($value);

    return $this;
}

They tell you: "This function is deprecated, use "site" instead"

Example with multisite - different sites and locales

If you are going to have multiple different sites with multiple locales you can manage each site in one group and insert all the locales for these sites in each group.

- Site group A
    - language A (siteId 1)
    - Language B (siteId 2)
- Site group B
    - Language A (siteId 3)
    - Language C (siteId 4)

For Example if the user is in site group A you want to show only language A and language B but not Language C even if the entry exists in all sites.
So you can grab the group of the current site and loop through all sites of the group.

{% set currentSite = craft.app.sites.currentSite %}
{% for siteInGroup in currentSite.getGroup.getSites() %}
    {% if siteInGroup.id == entry.siteId %}
        active site = {{ siteInGroup.id }}{{ siteInGroup.language }}
    {% else %}
        {% set entryForOtherSite = craft.entries.id(entry.id).site(siteInGroup).one() %}
        link to site {{ entryForOtherSite.siteId }} {{ siteInGroup.language }} - {{ entryForOtherSite.title }}
    {% endif %}
{% endfor %}


Is there an easy way to download the assets directory to a local install? I'm trying to speed up the process of synchronizing my production site down to my local install. Currently, it is: Back up database, wipe local database, import database backup. It's not perfect, but it is pretty fast.

But synchronizing the assets down is still a pain. Is there a process or plugin that makes it easy/easier to synchronize assets (uploaded photos, etc.) between installs?

I use rsync with grunt. There is a grunt rsync task, which is just a wrapper for raw rsync. If all I used grunt for was the rsync I don't think it would be worth it, but I use it to compile my sass, and to reload my browser (grunt-contrib-sass, grunt-contrib-watch) among other things.


How do I select a default in the Position Select field? Just getting around to adding advanced layout features to our site, when I say advanced I just mean floated images left & right. The problem I seem to have though is that left is always the default position.

There is a way around it if I disable left & right and use drop-left & drop-right but I think it would be more usable if we were able to set a default.

As there's no settings option to define a default, there's two things you can do:

Copy / fork the field type and add the option or simply hack it to your needs.
Contact P&T and make a feature request for setting field type defaults for Position select (and others).


Possible FeedMePro Anomaly When Trying to Update Table I am running into an anomaly when trying to use FeedMe to update existing fields.  My data source is a CSV file.  I have a unique ID.

I used FMP to create the entries.  Now, I want to update a table in each entry with annual sales data.

FMP is set to update existing elements.  My unique ID (Line ID) exists in both the entries to be updated and the source CSV file.

I have aligned the source CSV file fields to the target entry table fields.  The data preview looks good, with the value for each year correctly aligned.

I also reduced the # of fields being updated to just the table fields and unique ID.

FMP runs the feed with no errors.  But, the output value for each year in the table is no longer correctly aligned with the assigned year in FMP setup.  I thought at first it was a templating error on my part, but the values are misaligned in the CP entries.

Help.

I believe this has been fixed in the latest version of Feed Me (3.0.2.1 at time of writing). Do feel free to comment if not, or get in touch via the Feed Me support channels


Trying to output contents of array I'm trying to find a way of using php's print_r to output the entries that were pulled from the entries in the database. I'm pretty much brand new to Craft cms coming from Laravel, so a common thing I've done in the past with querying the database is seeing what I got back by outputting my array using either print_r or laravel's dd($array) during testing for a sanity check. I can't seem to find an easy way of doing this in Craft. This is what I've tried so far:

{% set listItems = craft.entries().section('todoList').all() %}

{{ listItems }}

The {{ listItems }} of course gives the array to string conversion error when rendering the page, so I tried doing:

{{ listItems | join }}

but that only outputs the title of the entry. Thank you in advance for any help!

It looks like using {{ dump(listItems) }} gave me enough to work with. I forgot to mention I had tried this before. It didn't work the last time, but I suspect I gave it an incompatible data type.


Bulk selecting Members and then including them in an email to another specific Member in a different member group I'm wondering if the following is possible within CraftCMS and suggestions for making it happen?

We have two Member groups (Customers and Contractors). When a Customer makes an enquiry they complete a series of pre-set questions.  These pre-set questions are used to filter individuals from the Contractors group.

On submission the Customer receives a notification email with a link.  Admin also receives a notification with the same link.

The link takes the customer to a page which displays:

Customers own submitted information and responses to the pre-set
questions.
Same page also displays a list of matched Members from the
Contractors group who fulfil the criteria which is matched using the
pre-set questions fields.

Customer can then decide which contractor they wish to work with.

Customer clicks "Hire" and an email is sent to the selected Contractor.  Email contains the Customers contact details.

Any help/advice is very much appreciated.

Martin

This is definitely possible. While certain features can be done with a custom module, my answer will focus on using Sprout Email as that plugin makes it easier to give your users more control in the email management workflow.

Sprout Email comes with several Notification Events. For example, when your customer submits their inquiry form you could configure a Notification Email to watch the 'When an Entry is saved' event and trigger an email to your customer or an admin or both. You can configure more than one email to the same event. In this example I'm assuming your form is a front-end Entry Element. However, if you're using Sprout Forms, Sprout Forms comes with a 'When a form entry is saved' event and Sprout Email has a Custom Notification Event API so it's possible to add support for other scenarios as well.

By default, the Notification Events are fairly simple. But if you need to be more specific than 'When an entry is saved' from a particular section you could further limit the scope of when the event is triggered using the Send Rule setting to, say, check if the author of the entry is in one of the particular groups you want to send to.

While there are simple default templates to get you up and running quickly, the Notification Emails sent are completely customizable via Email Templates and you can include personalized data in your email from the data available to the event you are triggering.

This means you can include whatever link you need in your email and whatever info you want to share that was submitted from the form such as the person's name in a 'Dear So and So' part of the message or all of the submitted responses so they can have them on record as well.

The link you include in the email could be constructed dynamically and include an ID or some other reference in it so that when the user clicks, you can look for that ID, validate the user, and pull in the submitted information or other info onto the results page. All of that will happen outside of Sprout Email and directly in Craft just as any other page. The only thing provided by the email integration for these features is the ability to construct the link in the email with the appropriate info so that you have what you need to do what you want to do.

In the case where the customer clicks "Hire" there may be a couple of events to consider. For one example, let's say when the customer hit's hire you trigger a re-save Entry event where you update the submitted Form and mark a lightswitch field to true. Again, you've triggered a Save Entry event and you can use the 'When an Entry is saved' Notification Event to trigger an email. In this case, you may want to limit the Notification to be triggered only when the Send Rule validates and finds that your 'hired' lightswitch setting is set to true.

To mention one other feature, you can also enable Sent Email tracking in Sprout Email. If you do, Sprout will record each email that was sent and capture who it was sent to, the HTML of the email that was sent, and some other metadata. If a user ever reports they did not receive a message you can check the Sent Email history and you have the option to review or resend Sent Emails.


Is it possible to compress image transforms? I'm using image transforms to create 1x versions of hdpi 2x images but one area I get slammed on web page performance is loading these images. Is it possible to compress them and if so, how?

All common image file formats are compressed, even lossless formats like RAW, TIFF or PNG use compression!

To reduce file size of you images you should choose a lossy format (avoid TIFF Baseline or BMP), and accept some degree of information loss to reduce the file size. You usually set this quality to file size ratio in percentages (for the web). Craft's default quality ratio applied on transforms, defaultImageQuality, is set to 75%, but you can always set it to your needs from the Control Panel or in your templates.

There's a nice chart on Wikimedia, illustrating the relative quality of quality settings for JPG formats.

Additionally I'd recommend you to have a look at this other question about transformation performance with image libraries supported by Craft.


Some (but not all) controller action routes return 404 on staging server I've created a module for a project that has several actions, all of which are called through AJAX. Each is a post request that sends over any required params plus the CSRF token using the method described here: https://craftcms.com/guides/enabling-csrf-protection#updating-your-javascript

On localhost, everything works correctly. On the staging server, some work correctly but others return a 404 error. Specifically, the response gives "Template not found: actions/module-name/location/geocode-inputs".

web.log doesn't look to be throwing any errors, and I'm not sure where else to look. Any ideas on what might be going wrong?

I figured this one out, it was bad error handling on my part.

If the service you're calling returns NULL, this will appear in the network tab as a 404.


Set asset uploader from frontend entry form Now that Craft keeps track of which user uploaded an asset, I'm wondering if it's possible to set this information when an asset is uploaded via a frontend entry form. I have a form that includes an asset field and I would like the assets that are created to be "owned" by the current user. Can this be done via a hidden input, or would I need to hook into an asset event?

I ended up using an event to accomplish this:
use yii\base\Event;
use craft\elements\Asset;
use craft\events\AssetEvent;

Event::on(Asset::class, Asset::EVENT_BEFORE_HANDLE_FILE, function (AssetEvent $event) {
    $asset = $event->sender;
    // This does not work because it doesn't set the `uploaderId` property on the asset
    // $asset->setUploader(Craft::$app->getUser()->getIdentity()); // Doesn't work, bug?

    // So I just set the `uploaderId` directly
    if (is_null($asset->uploaderId)) {
        $asset->uploaderId = Craft::$app->getUser()->getId();
    }
});


How do i get sites by group handle/name? How can I get sites by their group handle/name within twig templates?
Documentation only mentions querying sites by group id - getSitesByGroupId.

I would rather suggest you to do that in PHP but the Twig way would be the following

{% set allSites = craft.app.getSites().getAllSites() %}
{% set sitesWithGroup = [] %}
{% for site in allSites %}
    {% if site.getGroup().name == 'my group name' %}
        {% set sitesWithGroup = sitesWithGroup|merge([site]) %}
    {% endif %}
{% endfor %}


Grouping by Category with Multiple Keys I've started off with this solution:
http://craftcookbook.net/recipes/330

{% set testsByAllergenGroup = {} %}
{% set entries = craft.entries.section('tests').order('title asc') %}
{% set groups  = craft.categories.group('allergenGroup') %}

{% for group in groups %}
  {% set entries = entries.relatedTo(group) %}
  {% if entries|length %}
    {% set testsByAllergenGroup = testsByAllergenGroup|merge({
      (group.title): entries
    }) %}
  {% endif %}
{% endfor %}

    {% if groups|length %}

Allergy Groups:

            {% for group in groups %}

{{ group.title }}

            {% endfor %}

      {% for groupTitle, groupTests in testsByAllergenGroup %}

          {{ groupTitle }}

          {% for entry in groupTests %}

{{ entry.title }}

View Details

Add to Cart ($40)

          {% endfor %}

          BACK TO TOP

      {% endfor %}

    {% endif %}

I'm hoping to output the group title and slug, but this code will only allow for one variable to be set in the merge set:

{% set testsByAllergenGroup = testsByAllergenGroup|merge({
  (group.title): entries
 }) %}

I'm hoping to do something like this:

{% for group, groupTests in testsByAllergenGroup %}

    {{ group.id }}

Can you guys help me out? Thanks!

p.s. this is my first major Craft CMS project so Twig is new to me ;)

Try adding square brackets around your object:

{% set testsByAllergenGroup = testsByAllergenGroup|merge([{ (group.title): entries }]) %}

Update:

First thing I'd change is to set the object keys to something unique (slug or id works better than title).

To feed the object with all properties you need (so you don't need to do further DB queries later), do the following.

The values of your object can be objects too, this allows you to assign more data to each individual key.
You could define a custom key for each property you need for your output (i.e. 'groupId': group.id) or
pass the whole category model (see example code below), which allows you to access all of its properties in the output loop.
With the entries you need to make sure to assign an array of entry models and not an ElementCriteriaModel! So make sure to
add the find() method to your craft.entries call.

{% for group in groups %}
    {% set entries = entries.relatedTo(group).find() %}
    {% set testsByAllergenGroup = testsByAllergenGroup|merge([{
        (group.slug): {
            'group': group,
            'entries': entries
        }
    }]) %}
{% endfor %}

{% for key, value in testsByAllergenGroup %}
    {{ value.group.id }}: {{ value.group.title }}
    {% for entry in value.entries %}
        {{ entry.title }}
    {% endfor %}
{% endfor %}


How to create a new Tag group and save it? I'm new to the Craft CMS framework and have a question about tags. How can I create a new tag group?
You can create a tag list by hand via the admin panel > settings > Tag Groups > New Tag Group.
This is a way I can't use for plug-in development. So far as I know, I have to use the following code:
    $tagGroup = new TagGroup();
    $tagGroup->name = 'GroupName';
    $tagGroup->handle = 'GroupHandle';

You were on the right track. To save things in Craft, you need to use the according service. In your case you need the tags service:
$tagGroup = new TagGroup();
$tagGroup->name = 'GroupName';
$tagGroup->handle = 'GroupHandle';
$isTagGroupSaved = Craft::$app->getTags()->saveTagGroup($tagGroup);

if(!$isTagGroupSaved) {
    // Inspect validation errors if saving the tag group failed
    var_dump($tagGroup->getErrors());
}


Localization - linking to other pages goes to 404 I have a localized site set up where the language switcher and translations are working fine. However when I link to internal pages it goes to a 404.

general.php has this:

 //local only
 'etf-craft.dev' => array(
    'devMode' => true,
    'siteUrl' => array(
       'en' => 'http://etf-craft.dev/en/',
       'fr' => 'http://etf-craft.dev/fr/'
   ),
   'environmentVariables' => array(
        'environment' => 'local',
        'basePath' => 'D:\sites\etf-craft\public_html',
        'baseUrl'  => 'http://etf-craft.dev',
    )
),

site structure is like this:

craft
public
public/en/
public/fr/

index.php in /fr/ and /en/ directories contains the following where french says /fr/ instead of /en/:

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

// Tell Craft to serve the English content
define('CRAFT_LOCALE', 'en');

One link I've created that 404s on me is:

    {{ "News" | t}}

What I expect is that it takes me to http://etf-craft.dev/en/news and the news page shows up. However I end up going to a 404.

However if I manually remove the /en/ from the address bar the news template shows up correctly.

not working - http://etf-craft.dev/en/news
working - http://etf-craft.dev/news

What am I doing wrong?

First off, make sure you have .htaccess files in both the en and fr folders and this per the localization guide.

Secondly, you're missing a comma in the siteUrl array:

'siteUrl' => array(
    'en' => 'http://etf-craft.dev/en/',
    'fr' => 'http://etf-craft.dev/fr/' <--------add comma here-----
),


Display categories not related to an entry I'm trying to output a list of categories that are not related to a particular entry (in order to show a list of services other than the service related to the current entry).

I have this code which lists the category that is related to the current entry:

  {% set categories = craft.categories.group('services').relatedTo(entry).all() %}
  {% nav category in categories %}

{{ category.title }}

  {% endnav %}

Is there a way of turning this on its head, so that the other, non-related categories are displayed? Something like a notRelatedTo(entry) parameter?

You can grab all ids and exclude them from your query

{% set excludeIds = craft.categories.group('services').relatedTo(entry).ids() %}
{% for category in craft.categories.where(['!=', 'elements.id', excludeIds]).all() %}

If your relation field is in your entry you can do

{% set categories = craft
    .categories
    .section('services')
    .where(['!=', 'elements.id', entry.category.ids()])
    .all()
%}


variable inside for loop is empty outside the loop I need to set a bunch of variables to feed my html head metas. Most of the time the page is directly related to an entry but i also have pages for each user with a route that look like 'equipe/user.username':

{% if craft.request.getSegment(1) == 'equipe' and craft.request.getSegment(2) is defined %}
    {% set user = craft.users.username(craft.request.segment(2)).first()%}
    {% set title = user.username %}
    {% set description = user.description %}
    {% set resume = user.resume %}
    {% set url = siteUrl~'equipe/'~user.username %}
    {% for asset in user.imageHeader %}
        {% set imageUrl = asset.getUrl('header') %}
        {{ imageUrl }}
    {% endfor %}
{% else %}
    {% set title = entry.title %}
    {% set description = entry.description %}
    {% set resume = entry.resume %}
    {% set url = entry.url %}
    {% for asset in entry.imageHeader %}
        {% set imageUrl = asset.getUrl('header') %}
        {{ imageUrl }}
    {% endfor %}
{% endif %}
{{ imageUrl }}

Everything works fine except for the imageUrl variable. it behave like a local variable. I can retrieve the value just after it is set, but not outside of the for loop... any idea why ?

I found the solution to the issue... indeed it behave like a local variable ! if i want to use it outside of the for loop it seems that i have to set it before with something like:

{% set imageUrl = '' %}


How do I find live and pending entries when using an array? I have this in my listings template, but the 'pending' parameter does not seem to work.

{% set urlCat = craft.request.getSegment(3) %}
{% set category = craft.categories.slug( urlCat ) %}
{% set allEntries =  craft.entries.status('live, pending').section('sectionName').relatedTo(category).find() %}

This seems to only return 'live' entries even though I do have 'pending' specified.  I've tried this several ways and cannot seem to make it work.

The strange thing is that this seems to work fine on my single entry page where I have:

{% set entry = craft.entries.section('sectionName').slug(selected).status("live, pending").first() %}

Any ideas?  Thanks :)

You can get all entries regardless of status with .status(null):

{% set allEntries =  craft.entries.section('sectionName').relatedTo(category).status(null).find() %}


Logged in after email validation Is it possible to login automatic the user right after he validate his email address

I believe you're looking for the aptly named autoLoginAfterAccountActivation config setting.


How can I create a loop to cycle thru each category and the the entries within each category? So, I have a loop that populates all the entries related to a given category. See below.  I have multiple categories.  Right now, I use the same code for each category -  swapping only the name of the category out (e.g, category1, category2 ...).  How can I build a loop that avoids this?

My current template is as follows. I did not include the repetition for each category.

        {% set category = craft.entries.seciont('posts') %}

Aircraft

            {% for entry in category.relatedTo(craft.categories.slug('category1')) %}

                         {{ entry.title }} k

            {% endfor %}

First you loop through the categories then use the category to loop through all the entries related to that category.

{% for category in craft.categories.group('categoryGroup') %}
  {% for post in craft.entries.section('posts').relatedTo(category) %}
    {# your markup #}
  {% endfor %}
{% endfor %}


Craft 2.6 incorrect string value SQL error for 4 byte UTF-8 characters when saving entries On a Craft site that uses the Dukt Twitter plugin I have started seeing SQL errors when saving certain entries that use Twitter data:

CDbCommand failed to execute the SQL statement: SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xF0\x9F\x93\xB8co...' for column 'keywords' at row 1. The SQL statement executed was: INSERT INTO `craft_searchindex` (`elementId`, `attribute`, `fieldId`, `locale`, `keywords`) VALUES (:elementId, :attribute, :fieldId, :locale, :keywords) ON DUPLICATE KEY UPDATE `keywords` = :keywords. Bound with :elementId='10', :attribute='field', :fieldId='111', :locale='en_gb', :keywords=' lots of keywords here... '

Within the keywords field is an emoji character that actually shows up when Twig throws the error. I've been researching the issue and it appears to be related to the collation of the DB tables and 4 byte UTF-8 characters, currently all the DB tables are utf8_unicode_ci, potentially changing this to something like utf8mb4 should work in theory.

However, what doesn't make sense is the same collation is being used on our staging environment and the error does not occur when saving and its the exact same data. Initially I thought this was due to the schema of the database being different, but I tried recreating my local DB with the same schema matching our staging and re-importing the tables, but the error still happens.

So I'm slightly confused as what the key difference is with our staging environment compared to local dev. Looking at our hosting provider, it seems the MySQL version if 5.6, where as on my local dev its 5.7.22, so this is a key area potentially.

But it does raise the overall question as what is the best course of action for emoji support on Craft 2, should all the tables be changed to utf8mb4?

So it looks like our Craft site had an older version of the Dukt Twitter plugin installed. In a newer version it looks like the Twitter keywords have been handled better with:

return StringHelper::encodeMb4($keywords);

Which is similar to the same work done in the Craft core files for emojis.

https://github.com/craftcms/cms/issues/1627

Updating the plugin seems to have solved the issue saving on my local development environment, so not a direct answer, but a better solution than messing around with the the DB schema/collation.


Outputting structured product attributes in JSON-LD code with SEOMatic My products have a lot of attributes that I would like to serve to Google AMP via JSON-LD. The attributes vary between product types.
How should I do this?
I see there is a file under nystudio107\craft-seomatic\src\seomatic-config\productmeta\JsonLdContainer.php, and I am guessing I should put that file in my own config and modify it a bit, but I am not sure how to approach this.
Edit: Then of course there is the question: What are you really trying to do?
I am under the impression that I can tell Google what the different attributes on my product are, and that Google can use this when generating rich previews of search results. I understand that Google has a list of Supported Structured Data, and from that it doesn't seem you can or should add additional non-supported attributes to the JSON-LD output...
Then again, I see there are a lot of attributes that are in fact supported. Like Brand. How do I add Brand to my JSON-LD? I guess all attributes from Schema.org are supported?

Andrew will likely come along and give a better answer, but you can definitely extend the outputted JSON-LD in SEOMatic.  No need to copy any of the schema things over, I think.
Here's an example from a good while ago of adding brand, mpn, sku to the mainEntityOfPage i.e. your Product.

{% if not craft.app.request.isAjax and 'debug' not in craft.app.request.segment(1) %}

    {# Set the brand ... #}
    {% set mainEntity = seomatic.jsonLd.get('mainEntityOfPage') %}
    {% set brand = product.brand.one() ??? null %}

    {% if brand|length %}
        {% set productBrand = seomatic.jsonLd.create({
            'type': 'Brand',
            'name': brand.title,
            'url': brand.homepageUrl,
        }, false) %}
    {# If someone has left off the brand, let's just say it belongs to us... #}
    {% else %}
        {% set productBrand = seomatic.jsonLd.create({
            'type': 'Brand',
            'name': 'Store Brand',
            'url': 'https://yourstore.com',
        }, false) %}
    {% endif %}

    {% do mainEntity.brand(productBrand) %}
    {# We use the title here as the actual offers below have the real MPN/SKU #}
    {% do mainEntity.mpn(product.title) %}
    {% do mainEntity.sku(product.title) %}

{% endif %}

Here's an example dealing with offers, for the actual variants of that product (assuming these are variant products):

    {# We show out of stock offers even for discontinued products at the moment #}
    {% set offers = [] %}
    {% for variant in variations %}

            {% set offers = offers|merge([seomatic.jsonLd.create({
                'type': 'Offer',
                'name': variant.description,
                'description': variant.description,
                'url': product.url,
                'availability' : (variant.available and object.available and (variant.hasUnlimitedStock or variant.stock > 0)) ? 'http://schema.org/InStock' : 'http://schema.org/OutOfStock',
                'itemCondition' : 'https://schema.org/NewCondition',
                'mpn' : variant.mpn ??? "",
                'price' : variant.salePrice|number_format(2, '.', ''),
                'priceCurrency' : 'AUD',
                'priceValidUntil' : now | date_modify('+1 year') | atom,
                'offeredBy' : {"@id" : "https://yourstore.com/#identity"},
                'seller' : {"@id" : "https://yourstore.com/#identity"},
                'sku': variant.sku,
                'image' : (one(object.masterImage)|length) ?   { "@type": "ImageObject", "url" : "https://yourstore.com" ~ craft.imager.transformImage( one(object.masterImage), 'large' ).getUrl() } : "",
                'category' : (one(object.categories)|length) ? one(object.categories).title : "",
            }, false)]) %}

    {% endfor %}

    {% do mainEntity.offers(offers) %}

SEOmatic is really very well documented, you'd want to review (well, the whole Using SEOMatic section really!) - but more specifically:
https://nystudio107.com/docs/seomatic/Using.html#seomatic-variables
and
https://nystudio107.com/docs/seomatic/Using.html#json-ld-meta-object-functions-seomatic-jsonld


How can I pre-populate my billing/shipping information within Commerce? When a user registers on my site, I am asking for their first, last, email and address.

I would like to be able to pass the data I already have along to commerce. So when I get to the /address screen, as much of that form is already pre-populated.

I see this:

{% set modelName = modelName is defined ? modelName : 'address' %}
{% set model = address is defined ? address : null %}

So I (think) the ideal solution is to set the model to the user model. I will never allow guest checkout on this site, yet I want to keep as much flexibility as possible (not delete a bunch of stuff). So I gave this a shot:

{% if currentUser %}
    {% set modelName = modelName is defined ? modelName : 'user' %}
    {% set model = user is defined ? user : null %}
{% else %}
    {% set modelName = modelName is defined ? modelName : 'address' %}
    {% set model = address is defined ? address : null %}
{% endif %}

And I get this error:

Craft\UserModel and its behaviors do not have a method or closure named "businessName".

Which makes perfect sense - that's not in the user model.

I could go into the form filed and just set the values like this:

<input type="text" id="{{ modelName }}-firstName" class="form-control"
                   name="{{ modelName }}[firstName]"
                   value="{{ currentUser.firstName }}">

But is that going to lead to disaster? Thank you for any suggestions!

What I gathered from the documentation, you could try this:

{% set customer = craft.commerce.getCustomer() %}

then

{{ customer.address.businessName }}

or it might be

{{ customer.addresses.businessName }}

https://craftcommerce.com/docs/customer-model


Image Transforms - Image not processed until second page refresh I'm new to Craft, and am not sure whether I've got something weird happening or if what I'm experiencing is expected behavior.

I notice that when I add new entries containing image assets that get transformed (using a control panel transform in this case), that the images don't get transformed until the (template) page is loaded a second time. Therefore, each new page contains empty images and alt-text on its first load. Once I refresh the page, the images appear as expected.

Is this expected behavior? Right now this requires me to visit the page of every entry I create, in order to 'seed' it for use.

Not a deal breaker, but I'm just curious whether there's something I'm doing wrong on my end.

In your config file, set generateTransformsBeforePageLoad to true:

general.php:

return array(
    //other configs
    'generateTransformsBeforePageLoad' => true
);

This will trigger craft to generate and save transforms ahead of loading the page, as explained in the documentation here, this is will also work if you're using a plugin to provide the images.


How do I talk to Smart Map in JavaScript? Well, I know for a fact I am doing this incorrectly & it's going to be painfully obvious. I can see why (I think) but to be honest I just don’t “get it”.
I’m trying to style a Google map using Smart Map & JavaScript, but keep getting the JS error:
Uncaught ReferenceError: smartMap is not defined(…)

This is what my template looks like:
{# Google Map of location. #}
{% set options = {
    height: 500,
    width: '100%',
    zoom: 15,
    markerOptions: {
    },
    infoWindowOptions: {
        maxWidth: 200
    }
} %}

    <div id="mapCanvas">
        {{ craft.smartMap.map(product.address, options) }}
    </div>

    <script src="/assets/js/app.min.js"></script>
</body>

Within app.min.js I am doing this:
if ($('#mapCanvas').length) {
    var styles = [{
        "featureType": "all",
        "elementType": "geometry",
        "stylers": [{"visibility": "simplified"}, {"hue": "#ff7700"}]
    },

    ...

    smartMap.map['smartmap-mapcanvas-1'].setOptions({styles: styles});
}

I've been reading this post which literally has the answer to my problem I believe. I just don't understand how to tell the system where/what smartMap is.
Thank you for any suggestions!
EDIT
Here is what the rendered page looks like:
<script src="/assets/js/app.min.js"></script>
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js"></script>
<script type="text/javascript" src="http://mysite.dev/cpresources/smartmap/js/smartmap.js?d=1449217510"></script>

EDIT 2
Just for future reference in case someone else comes across this thread. It ended up being the way I was initializing my js file.
// This executes before we're ready
(function () {
    'use strict';
    ...

})();

// This works
$(function () {
   ...
});

I'd recommend loading your JS file after the smartmap.js file has been loaded. The smartMap JS object needs to exist before your code gets run.

Try loading your JS using the includeJsFile tag... I believe that should place it in the correct position.

{% includeJsFile "/assets/js/app.min.js" %}

If that doesn't work, then you may need to wrap your code in something that would prevent it from running until the page is fully loaded...

$(function () {
    // Your code goes here
});

^ That example uses jQuery. The same can be achieved without jQuery, if you're not using it.


Smart Map with multiple different markers based on a matrix field I'm having some trouble setting different markers using the smart map plugin and was hoping someone might be able to point me in a direction I might not see.
The different locations are are set through a matrix field with two different block types; one that should return a blue marker and one that should return a green. I've been following the docs at: https://plugins.doublesecretagency.com/smart-map/different-icons-for-different-marker-types/ but have still been getting a javascript error preventing it to be rendered.
The javascript error is "uncaught TypeError: Cannot read property 'setOptions' of undefined. I'm sure this is because the markerId variable isn't getting the address from the matrix field.
Any help or insight would be greatly appreciated, thanks!
 {% set locations = entry.filmMap %}
{% set mapOptions = {
    height: 580,
    zoom: 10,
    draggable: true,
    markerInfo: '_includes/mapInfoBubble',
    markerOptions: {
    icon: 'http://maps.google.com/mapfiles/ms/icons/green-dot.png'
  }
} %}

{{ craft.smartMap.map(locations, mapOptions) }}

{# Loop through location entries #}
{% for item in locations %}

  {% switch item.type %}
    {% case 'filmSites' %}
      {% set icon = '/assets/src/images/blue-marker.png' %}
    {% case 'castingCalls' %}
      {% set icon = '/assets/src/images/green-marker.png' %}
    {% default %}
      {% set icon = 'http://maps.google.com/mapfiles/ms/icons/green-dot.png' %}
  {% endswitch %}

  {% set address = item.address %}

  {# JS: Change marker icon #}
  {% includejs %}

    var markerId = 'smartmap-mapcanvas-1.{{ entry.id }}.address';
    smartMap.marker[markerId].setOptions({'icon': '{{ icon }}'});

  {% endincludejs %}

{% endfor %}

I believe the problem is in this line of code:

var markerId = 'smartmap-mapcanvas-1.{{ entry.id }}.address';

Because you're generating markers from matrix blocks, you'll need to use the block ID instead of the entry ID. In your case, that may looks something like this:

var markerId = 'smartmap-mapcanvas-1.{{ item.id }}.address';


ImageOptomize and SEOmatic - Is Image Variant Required for Social and SEO images? Do ImageOptomize and SEOmatic work together - or to be more specific do I need an image variant for the social and SEO images defined in SEOmatic?

I have been importing content into a News entry.
I am defining my image variations using imageOptimize on the News Volume.
I have a "meta image" asset field which is being used to serve the SEO and Social Media images to SEOmatic's SEO settings for the entry.

Before installing and using imageOptimize the meta image previews were working fine with SEOmatic in the entry editor. Now they are not getting picked up... do I need to define an image variant that matches the SEO and Meta image sizes?

Also... SEOmatic is such a time saver, I estimate I have saved at least two weeks dev time with this plugin. Thank you Andrew!

I've used SEOmatic and ImageOptimize together before and never had those issues. SEOmatic should care less about the presence of the ImageOptimize field on the asset and you definitely don't need to specify custom ImageOptimize variants for your SEO/social purposes. SEOmatic grabs the raw image (like you would grab the asset url in the templates) and does its own transforms to get that image ready for social/SEO use.

My guess is something is incorrectly setup in the Content SEO settings for whatever section the entry you're currently editing exists in. If you still can't figure it out, I'd be curious to see screenshots of those settings...

Also, fwiw, Andrew does provide a very handy SEO Settings field that might be worth considering as a replacement to the setup you've got going on currently. As he mentions in the plugin README:

  Modern SEO works best if it actually reflects what is on the page, visible to the user, so pulling from your page's content will work well in most cases.

So what I've done (and would recommend, though it would mean you would lose your client-friendly field descriptions) is to pull the SEO/social data out of the content of the page and then add the SEO Settings field to that last tab just in case you need to overwrite stuff. For example, rather than adding the asset used as the masthead image and the asset used for SEO/social separately, use the same field for both. Makes it simpler on the client and on you! And then, if and when you do need a different image for the social/SEO metadata, you can use the SEO Settings field.