How to Organize a Courses Site I am trying to create a site that offers courses.  Each course will be broken up into sections with each sections containing a number of lessons.  Viewers will then be able to progress through the course one lesson at a time - at their own pace (like Lynda.com).

  Note: the sections are merely there for organizational purposes - they don't actually house any content.  All the actual content is
  limited to the Course page and the individual Lessons.

I am trying to figure out the best way to organize this. This is my current thinking (but I'm not sure this is the best way to do it).

Section & Entry Types

I have created a Structure Section called Courses with two Entry Types:

Course
Lesson

I have then set up a matrix field for the Course entry type with two field types:

Section Name:  Plain Text field type for the name of the section
Section Lessons: Entries field type set to Courses (for the list of lessons  in each section)

The idea being that on the course page I could quickly and easily create a number of sections and then add the relevant lessons to each section.  I can then set up the template to progress through each section and it's lessons in order.

With that said, I had two other ideas.

Set up three entry types - Course, Section & Lesson

I would then have the Course be the parents of the various Sections and the Sections be the parents of the various Lessons.

This also seems fairly easy to do (the only problem is creating an entry for each section given that the Sections don't actually house any content).

Set up categories for each course

I could then assign each lesson to a category (I would then have to figure out how to order the content).

Any suggestions as to which is the best way to proceed?

Thanks.

Short answer: I'd lean towards a structure section. Matrix is a close second.

Long answer:
When I'm faced with this an information architecture decision, I look at a couple things:

How "reusable" is the solution? (is content only stored in one place?)
Is it easy for the content author?

What's great about Craft is it generally makes both relatively easy.  What you don't want is to duplicate content in more than one section because it creates multiple sources of truth.

I typically reach for Matrix fields when I need to mix/match content on a single page.
Entries/Structures are better when you need to build content that could potentially be brought in from any area of the site.
Categories are usually "global" in scope. They also wouldn't be the right choice here. You'd end up creating too many of them and you'd eventually want to create a category set for each course to keep everything straight.

Matrix

Let's look at the workflow for doing it the Matrix way. If you want to create a new lesson, you need to define it in two places: the Lesson entry itself and the Section/divider entry (and then tell Craft which section the Lesson entry goes).

It's also going to be harder to see from the CP how many lessons are in the section.

I find Matrix fields tougher to template as well. If you use Matrix for navigation, you're going to have to iterate over all of them to see which one you're currently on. Because you're relating the entry, you're also going to have to do a "reverse" lookup.

Structures

That said, Structures bring their own set of problems and solutions. I like structures because you can easily move them up and down in the hierarchy. If a content author messed up and put a lesson in the wrong section, it's an easy drag/drop.

I also find templating a bit easier too. Want to get your current section you're in? Just get its parent:

{% set courseSection = entry.parent %}

Then you can spit out its children:

{% nav %}

 {{ entry.title }}

{% endnav %}

URLs

When you create a parent/child relationship in a structure section, the parent is going to create a new URL as well. That might not be ideal if you have thin content in the divider like you mentioned.

So your URL might look like this:

Course / Section / Lesson
 url.com/craft-cms/twig/intro-to-twig

If you use a Matrix field:

Course / Lesson
 url.com/craft-cms/intro-to-twig

That "thin" content is going to live at twig for example. I don't necessarily see that as  bad thing but keep that in mind.

Although you might not use the section/divider for much content now, you may end up needing it in the future. Every slug in that course has to be unique now as well because you're not dividing it up. You wouldn't be able to do this with a matrix field:

Course / Section / Lesson
 url.com/craft-cms/twig/intro
 url.com/craft-cms/twig/filters

If you use a Matrix field, it would have to be something like:

Course / Lesson
 url.com/craft-cms/intro-to-twig
 url.com/craft-cms/twig-filters

That's a little harder to keep consistent from a content authoring perspective as well.

I see it as a "table of contents" for the section. In a traditional book, it might be an introduction to what you're about to learn in each section. Otherwise you'd need to create another lesson called "Introduction" for example.

So to sum it up, a structure with 3 entry types is what I'd use followed by Matrix.  I don't think could go wrong with either solution though.


How to make PNGs crisp using Imager + Optipng and Craft 3? I've installed Imager in a Craft 3 site and everything looks fine except my PNGs are fuzzy. I've set 'pngCompressionLevel' => 0, because I'm using Optipng and the docs say to do this. The PNGs have transparency. Here's a screenshot of the two (left is the normal asset, right is the asset after sent through Imager).

My template code mostly looks like this (a lot of it is originally refactored in a reusable macro):

{%- set logos = entry.partners.all() -%}
{% for logo in logos -%}
   {%- set sizes = craft.imager.transformImage(logo, [{ width: 150 }], {
      format: 'png',
      mode: 'crop',
      allowUpscale: false,
      interlace: true,
      pngCompressionLevel: 0
   }) -%}

{%- endfor %}

The HTML it produces is below. I'm only using one resize width for these logos since they are small, but my macro is setup to accommodate other images with larger srcsets.

I've tried taking out the different config settings like mode, allowUpscale, and interlace but they have no effect.

Any help would be appreciated!

Unfortunately, resizing images always tends to make them a little bit blurry, especially if the size that it's resized from isn't very big. But, here's a few things you can try:

Make sure you're using the Imagick image driver in Craft, that gives you alot more options to play with ('imageDriver' => 'imagick' in your general config).
Try playing around with the resizeFilter config setting. This is the algorithm used to resize the image. Some are good for photos, some are good for illustrations. Some give the resized image a "softer" look, some a "harder" one.
Make sure smartResizeEnabled is set to false (it's the default), as this does a lot of up and down scaling to create a file that has a smaller filesize.
Consider running the sharpen or unsharpmask effects on the transform. It might give undesired results if the image is too blurry, or the sharpen is too heavy, but it could be useful to just add a little bit more sharpness in the end.
AFAIK, optipng shouldn't be doing anything to the image that would impact the visual quality of it. But, just to eliminate that, make sure you try without any post optimization tools also.
Also, make sure that the image is actually displayed in the size that you've intended it to be (150px), and that you don't have any CSS rules on it that would result in it being treated as an GPU accelerated layer (transforms, etc). That blurs things like crazy. But, you can easily test if that's the case by opening the transformed image in a separate browser/application.

Hope this helps.


Rendering templates from plugin controller Right now I'm trying to accomplish routing users through a controller action before rendering the plugin's CP template...

[Plugin]Plugin.php

// ...
public function registerCpRoutes()
  {
    return [
      'plugin/controller' => ['action' => 'plugin/controller/action']
    ];
  }
// ...

The idea here is that I want to perform validation checks in the controller before I serve up the view.

I'm running into two issues when it comes to rendering the template from the controller:

The template path is set to the core template directory (which makes plugin templates inaccessible)
If I reset the template path to, say, the plugin's directory then I can no-longer extend core layouts (like _layouts/cp) within my template.

My solution was to then just fetch the plugin's template as a string and then render it using the renderString method so that way I can use the template without modifying any path variables...

[Plugin]Controller.php

// ...
protected function renderPluginTemplate($template, $variables = array())
  {
    $oldPath = craft()->path->getTemplatesPath();
    $newPath = craft()->path->getPluginsPath() . 'plugin/templates';

    craft()->path->setTemplatesPath($newPath);

    if(!$templatePath = craft()->templates->findTemplate($template)) {
      throw new Exception(Craft::t('Could not find template with path: ' . $template));
    } else {
      $templateContent = file_get_contents($templatePath);
    }

    craft()->path->setTemplatesPath($oldPath);

    echo craft()->templates->renderString($templateContent, $variables);
  }
// ...

This works for the most part. Now the layout isn't pulling in the right Javascript dependencies – no JS gets fired – so the panel content is hidden and the dropdown menus don't work.

There must be a better way to do this. I'd be super grateful if anyone could provide any insight.

Jon

Figured it out!

I went ahead and took at look at how Craft's renderTemplate method works which cleared it up for me. A few things...

Craft caches CSS/JS resources inside of getHeadHtml() and getFootHtml() which are automatically injected into every template rendered through renderTemplate. Injecting these into my template fixed the JS problem.
I forgot to set both the Content-Type and charset headers. Not necessary in my case but it's something that's good to add anyway.
To keep things consistent with the way Craft does things I outputted everything into a buffer and terminated the request.

Here's the working concept of my renderPluginTemplate method; I borrowed lots from Craft's renderTemplate function within the BaseController:

protected function renderPluginTemplate($template, $variables = array())
  {

    // Grab the new template's content
    // ---------------------------------------------------------------------

    $oldPath = craft()->path->getTemplatesPath();
    $newPath = craft()->path->getPluginsPath() . 'plugin/templates';

    // Set template path to the plugin directory (temporarily)
    craft()->path->setTemplatesPath($newPath);

    // Attempt to fetch the template content/extension.
    if(!$templatePath = craft()->templates->findTemplate($template)) {
      throw new Exception(Craft::t('Could not find template with path: ' . $template));
    } else {
      $templateContent   = file_get_contents($templatePath);
      $templateExtension = IOHelper::getExtension($templatePath, 'html');
    }

    // Reset the template path
    craft()->path->setTemplatesPath($oldPath);

    // Set up the headers and render the template
    // ---------------------------------------------------------------------

    if($output = craft()->templates->renderString($templateContent, $variables)) {
      // Set the MIME type for the request based on the matched template's file extension (unless the
      // Content-Type header was already set, perhaps by the template via the {% header %} tag)
      if (!HeaderHelper::isHeaderSet('Content-Type')) {
        HeaderHelper::setContentTypeByExtension($templateExtension);
      }

      // Set the charset header
      HeaderHelper::setHeader(array('charset' => 'utf-8'));

      // Are we serving HTML or XHTML?
      if(in_array(HeaderHelper::getMimeType(), array('text/html', 'application/xhtml+xml'))) {
        // Are there any header/footer nodes in the queue?
        $headHtml = craft()->templates->getHeadHtml();
        $footHtml = craft()->templates->getFootHtml();

        if($headHtml) {
          if(($endHeadPos = mb_stripos($output, '')) !== false) {
            $output = mb_substr($output, 0, $endHeadPos).$headHtml.mb_substr($output, $endHeadPos);
          } else {
            $output .= $headHtml;
          }
        }
        if($footHtml) {
          if(($endBodyPos = mb_stripos($output, '')) !== false) {
            $output = mb_substr($output, 0, $endBodyPos).$footHtml.mb_substr($output, $endBodyPos);
          } else {
            $output .= $footHtml;
          }
        }
      }

      // Output it into a buffer, in case TasksService wants to close the connection prematurely
      ob_start();
      echo $output;

      // End the request
      craft()->end();
    }
  }


Freeform with project.yaml? On my development instance, I added a freeform form. Now I would like to deploy that form to the staging, or later, live site.

When committing my changes, I noticed that nothing was added to project.yaml. So I guess the changes are just saved in the DB and will not be synced at git-based deploy.

Is that by design? Can I enable useProjectConfigFile somewhere?

If not: how do I export the form definitions and deploy them to another instance? By MySQL?

Project config is designed to sync the architecture of your site, not the content, so structural changes can be made without affecting the content. Forms are seen as content, like entries, so this would be the expected behaviour.
The suggested workflow would be to create the form on the production site, then pull to local environment to do any front-end work, then push those changes to production.
The nystudio107 craft scripts are pretty useful for syncing databases and assets if needed.


Localized ElementTypes in a plugin My question is re: localization of ElementTypes in a plugin.  I have the records all working fine in multiple locales.

The part that I'm not "getting" is I think there should be one Element in craft_elements and then for each localization, there should be one record in craft_elements_i18n yes?  And then for each localization, there should be a separate record in my craft_seomatic_meta table for each localized version yes?

This is where in my controller it saves the ElementType: https://github.com/khalwat/seomatic/blob/master/controllers/SeomaticController.php#L173

And here is the function is calls in my service to save the element & record: https://github.com/khalwat/seomatic/blob/master/services/SeomaticService.php#L683

When I call $result = craft()->elements->getElementById($metaId, 'Seomatic_Meta', $locale); how does it "know" which record to look up to load the returned Seomatic_MetaElementType with data?

I'm clearly missing something basic regarding how this should all work

The part that I'm not "getting" is I think there should be one Element in craft_elements and then for each localization, there should be one record in craft_elements_i18n yes?

Yes.

  And then for each localization, there should be a separate record in my craft_seomatic_meta table for each localized version yes?

Only if the values in that table need to be stored on a per-locale basis, which to my knowledge has never been the case until now with SEOmatic.

  When I call $result = craft()->elements->getElementById($metaId, 'Seomatic_Meta', $locale); how does it "know" which record to look up to load the returned Seomatic_MetaElementType with data?

Any time you run an element query (which getElementById() does), the element type’s modifyElementsQuery() method will be called, which gives the element type a chance to make changes to the query. In yours, you have the following code:

$query
    ->addSelect('seomatic_meta.*')
    ->join('seomatic_meta seomatic_meta', 'seomatic_meta.elementid = elements.id')
    ->andWhere(DbHelper::parseParam('seomatic_meta.locale', $criteria->locale, $query->params));

That condition you’re adding to the query on the seomatic_meta.locale column is what is ensuring that the correct localized row in your seomatic_meta table will be included in the result.

That’s just for selecting elements though. I might be missing something, but looking at your SeomaticService::saveMeta() method, it doesn’t look like you’re ever ensuring that all of the localized rows are actually getting saved. If you take a look through ElementsService::saveElement(), you will see that one of the things it does is loop through the locales returned by $element->getLocales() and make sure that there’s an ElementLocaleRecord (elements_i18n row) for the element in each of those locales. If you want to store rows for each locale in your own craft_seomatic_meta table, it’s the plugin’s responsibility to do that, not Craft’s.


Is it possible to allow a user choose tags in admin panel using checkboxes? The system I'm building requires a flexible taxonomy, where users should be able to add new taxonomy stuff to entries really easy and freely as soon as the need arises. So tags seem to work best for this situation.

However, there's a usability issue I'm concerned about. And that's a lot of typing, potential typos, and general "closeness" of what's already available to users (existing tags already added by users)

What I would ideally like is a tag field, which would still allow standard entry, but which also has a checkbox list of all existing tags as well - so users could just quick check tags they want to add to an entry - without typing anything - and add any extra tags manually only when these are needed.

Would something like that be possible to implement in Craft?

(The system will be an internal one, so there's no worry about too many users adding too many tags. Eventually, every single required tag will be created at some point, and users will be able to just choose from checkboxes - that's the ideal vision of how things would work on the data entry side)

thanks!

Any reason why you'd choose tags over categories?

Categories seem to be more of what you're describing:

  Eventually, every single required tag will be created at some point.

And since Craft 2.5, authors can easily create categories right in the Entry screen as well as pick the category they want if it's already created. No manual typing required if it already exists.

Tags are usually looser approximations of the content and are considered by content strategists to be more of a "folksonomy".

If you wanted to push forward with checkboxes as tags, you could probably create a custom field that spits out all the tags as checkboxes, along with a way to add new ones.


DeleteStaleTemplateCaches taking forever I have a website with a few thousand entries. At the bottom of the entry template, we show 4 random news posts from the last 4 weeks.

Now, when someone adds a new entry, the DeleteStaleTemplateCaches task starts running. This causes cpu and memory peaks on our server that go to 100%. This task also takes about 30 minutes to complete, meaning that our cached homepage only shows the new article after 30 minutes.

Any ideas why it takes so long, solutions on how to fix this? (Apart from caching the 4 entries on the bottom of the page, and caching the homepage, we didn't do anything weird.)

This is a side-effect of Craft's amazing automagical cache system. :) Check out my answer on this question for an explanation of what happens.

Regarding your question of how to fix this, part of the solution is probably what I wrote in the answer, to make sure that you don't create more caches than you need, by caching globally and using the request path as key.

Other ways to counter this problem is to use the ColdCache and CacheFlag plugins. They serve different purposes, and isn't right for all caches, but they have one thing in common, they doesn't save anything to the templatecachecriteria table, which determines the length of the delete stale template caches task. I usually end up with a combination of all three on projects that have a lot of content.

ColdCache is good to use in the cases where you primarily are caching a single entry, and you can get away with breaking the cache when the entry is saved. By using the modified date of the entry as part of your cache key, Craft will create a new cache every time you save the entry (don't worry, the old caches will be deleted when they expire, and doesn't affect performance in any way).

CacheFlag is good to use when you know what sections, globals, categories or... whatever, you're caching. For instance, if you have a news section, and are caching a list of news entries, you could add a flag to the section in CacheFlags settings, wrap the list in the CacheFlag tags and add the flag. Whenever an entry in that section gets saved, all caches with that flag gets deleted and refreshed the next time the list is shown.

Both of these approaches sacrifices something in terms of cache breaking - and it takes some thinking through to get right - but performance wise you gain a lot.


Database backup fails I'm building my Craft site locally, but need to make it live. When I go into Utilities -> Database Backup and try to create a backup, I get the error "There was a problem backing up your database. Please check the Craft logs."
I checked the log and see this:
  Could not create backup: The shell command "mysqldump --defaults-extra-file="C:\wamp64\www\craft\storage\runtime\temp\my.cnf" --add-drop-table --comments --create-options --dump-date --no-autocommit --routines --default-character-set=utf8 --set-charset --triggers --single-transaction --no-data --result-file="C:\wamp64\www\craft\storage\backups/build-your-firm_200624_180437_9nnsavzxmh_v3.4.24.sql" stw && mysqldump --defaults-extra-file="C:\wamp64\www\craft\storage\runtime\temp\my.cnf" --add-drop-table --comments --create-options --dump-date --no-autocommit --routines --default-character-set=utf8 --set-charset --triggers --no-create-info --ignore-table=stw.stw_assetindexdata --ignore-table=stw.stw_assettransformindex --ignore-table=stw.stw_sessions --ignore-table=stw.stw_templatecaches --ignore-table=stw.stw_templatecachequeries --ignore-table=stw.stw_templatecacheelements --ignore-table=stw.stw_cache --ignore-table=stw.stw_templatecachecriteria stw >> "C:\wamp64\www\craft\storage\backups/build-your-firm_200624_180437_9nnsavzxmh_v3.4.24.sql"" failed with exit code 1. in C:\wamp64\www\craft\vendor\craftcms\cms\src\controllers\UtilitiesController.php:340

I don't really know how to resolve that. Can I get around this by making a database backup in PhpMyAdmin?Is there any difference?
Thanks in advance.

The database backup from Craft is slightly different to the SQL export in phpMyAdmin. Craft’s export (presumably) assumes you’re going to want to import that data into an existing site, whereas phpMyAdmin’s default (presumably) assumes you’ll want to import it into an empty database.
However you can do exactly as you suggest — export from phpMyAdmin locally, create a new Craft installation on your live server, use phpMyAdmin on the live server to delete the new database’s contents, then import the original data with phpMyAdmin.
I did this a few months ago (long story); it worked fine, nothing has exploded so far.


CDbException warning 1265 after updating matrix field A testimonial matrix field has existed in our system for a couple of months. I've just deleted a block that's no longer needed, and am now receiving a SQL warning related to another one of the blocks. The warning occurs when I set the Max Length to anything lower than 145. Here's the warning text:

CDbCommand failed to execute the SQL statement: SQLSTATE[01000]: Warning: 1265 Data truncated for column 'field_testimonial_quotation' at row 1. The SQL statement executed was: ALTER TABLE `craft_matrixcontent_testimonialmatrix` CHANGE `field_testimonial_quotation` `field_testimonial_quotation` VARCHAR(110) NULL

I've checked all of the Entries that use this matrix block, and none of them are close to the Max Length limit.

The column field_testimonial_quotation in your craft_matrixcontent_testimonialmatrix table has data in it that is longer than 145 characters long.

Since it looks like your MySQL box is running in strict mode, MySQL is warning you that data has been/will be truncated by changing the max length to something below that.


Merge Entries but only after X amount of entries I'm trying to get entries from two sections and merge them together which is pretty straight forward using the merge filter.

For example, my sections are:

News
Promoted News

But, my main issue is I only want Entry 1 from Promoted News to appear after 2 entries in News and so on (In a 2 entry increment)

I don't want it like this:

News - Entry 1
Promoted News - Entry 1
News - Entry 2
Promoted News - Entry 2
News - Entry 3
Promoted News - Entry 3
News - Entry 4
Promoted News - Entry 4
News - Entry 5
Promoted News - Entry 5

But like this:

News - Entry 1
News - Entry 2
Promoted News - Entry 1
News - Entry 3
News - Entry 4
Promoted News - Entry 2
News - Entry 5
News - Entry 6
Promoted News - Entry 3

I thought about doing it using a conditional and incrementing a variable, but I don't think this would work with pagination so I need to merge them in to one array.

Is it possible to do this? My heads mashed thinking about doing this...

Thanks!

Seems like a rather specific edge case, so I'd be surprised if there's something built in (nothing comes to mind). However, you could write a custom twig filter fairly easily to do this.


Development – deployment environment I am new to Craft 3 and never set up a local environment with composer, bitbucket and gulp. So I dived into all these things to get my hands on Craft 3. At the moment I am using a shared hosting without a ssh access so I have to deploy my site by using FTP Upload. Is it correct that I just need to upload the entire Craft folder with all its subcategories (/vendors, /config, /modules etc. etc.) after development to the production server and then just to adapt the .env file?

I am a little bit curious about this, since it is recommended not to upload some of the sensitive folders with access to a repo. I know that this due to the fact that nobody should see your logins public. This does not apply for the production server? If I point my subdomain to the /web folder with its index.php on the production server everything should be fine? Just want to be sure.

So the way I'd recommend doing it is that you use .gitignore to exclude your /vendor directory from the repo; a good starter .gitignore file can be found here: https://github.com/nystudio107/craft-scripts/blob/master/example.gitignore

Then you'll work on it in local dev, update Craft/plugins in local dev, and on deploy to production have it do composer install to update your /vendor dir to match what is is your composer.lock file.

The article Setting up a New Craft CMS 3 Project covers this in the DEPLOYING CRAFT CMS section.

You also might want to get a workflow set up for syncing the database and assets as per the Database & Asset Syncing Between Environments in Craft CMS article.


Plugins: Is there any events and/or calendar plugin in the making? I'm in desperate need of a plugin that lets:

Users create calendar events or (even better) lets you import those from Outlook or GCal.
Visitors participate in an event and (after submitting a form) get a calendar request through e-mail

Does anyone know of any plugin(s) in the making, or should I start building my own?

Until the Craft plugin store becomes an "official things", the best, most curated list of plugins available for Craft is over on Straight Up Craft

The closest thing I can find on there to what you're looking for is the "Recurring Dates" plugin.


Storing data for page in twig I'm using craft-stripecheckout to accept payments on my site, but want to email the user with the custom fields after they have been redirected.

Easiest way to describe this is below:

Page 1 - User is asked for payment amount and other custom inputs such as age.

Page 2 - Confirmation of details is shown, and Stripe payment button appears.

Page 3 - User is redirected here via the plugin after payment is completed. this is when the email is sent with custom fields, such as age

What is the best way to store all of the POST data, and use it again on the confirmation page?

I'm not exactly sure how this plugin works, but in general the best way to do this is to rely on Webhooks.  You can listen for charge.succeeded events and send an email when those occur.  If you're not a programmer, you can always use something like Zapier or IFTTT to do this too.

:)  Hope that helps!


Overriding native CP template (without hacking the core) Is it possible to create a plugin that overrides a control panel template, and still be able to update Craft normally?

What I'd like to achieve:

I have a custom field with information on every asset in the assets panel. I want to see this custom field when I upload / select an asset in an entry.

Template I want to customize:

Unless I'm mistaken, it looks like you don't actually need to override that whole template. It sounds like you really just want to add a column (or multiple columns) to the assets index view.

The modal that you're showing is using the same logic as the main assets index view. So it's simply a matter of adding your own custom columns to that, and then selecting those columns to be included.

The defineAdditionalAssetTableAttributes hook allows you to create new columns for your assets index. You'll still need to select those columns via the UI in the control panel (which is super easy).

You'll probably also need to use the getAssetTableAttributeHtml hook, which allows you to customize how your column's data is displayed.

Using both of these hooks together will allow you to add whatever additional columns you'd like to the asset index view. And once you've selected your new custom columns, the exact same columns will appear in the modal view (like in your screenshot).


Possibility to change where Image Transform folders are stored? When using Inline Transforms in a template and also when the image transform is set in the Image Transforms section of the control panel then say my images folder is located at :

/images

And say I create an Image Transform called Square 100 [square100] (in either way mentioned above), the folder with the transformed images get saved to :

/images/_square100

Is there any way to prevent this because I'd like to be able to upload images to a certain folder but then have the URL not shown in any way so people can't find the original files. At the moment you can tell that they are in a folder called images and all you'd need to do to access them is to delete the /_square100 part from the URL.

I tried taking a look at the config variables but couldn't see anything pertaining to this sort of thing or perhaps I'm missing it somewhere?

Many thanks,

Mark

Currently the answer is no.  Those paths are hard set in the code.

Sounds like something for the feedback site, though.  Be sure and share your use case.


Check for value in supertable Is it possible to check for a value in a supertable field during the for loop:

{% for item in craft.products.supertable.lightswitch(1).all() %}
  {# stuff #}
{% endfor %}

This returns

  Impossible to invoke a method ("lightswitch") on a null variable.

So I guess the content of the supertable field is not available yet?
Because if I write:

{% for item in craft.products.all() %}
  {% if item.supertable.lightswitch == 1 %}
    {# stuff #}
  {% endif %}
{% endfor %}

This works nicely. Is this not a part of the element criteria model?

The Super Table field value is a query, so the .all() needs to be called on the field itself (not on lightswitch). But looping over queries is in itself deprecated in Craft, so you should set it to a variable first, and then loop over that.

In any case, the .all() will return all rows of your Super Table field, each of which contains your lightswitch field (even if there is only one row).

If you know there is only one row, perhaps something like this would work, but I haven't tested it:

{% if craft.products.supertable.one().lightswitch == 1 %}

I would anyways recommend performing the query first, then use the result to loop or get your field.


How do I get just the first entry with a 'for' loop? I have this this code -

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

{{ entry.title }}

{{ entry.postDate.format('F d, Y') }}

                {{ entry.body }}

            READ FULL STORY...

{% endfor %}

I thought the .first() would pick up just the first news story, however it is returning the same container several times.

I then want to return all other entries elsewhere, so what should I include in my code below to do this -

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

{{ entry.title }}{{ entry.postDate.format('F d, Y') }}

        {% endfor %}

As you'll only ever be working with one entry I wouldn't bother with the for loop for the first part of your question. Just set a variable with your featured news article. Something like this (not tested though):

{% set featuredArticle = craft.entries.section('news').first() %}

{{ featuredArticle.title }}

{{ featuredArticle.postDate.format('F d, Y') }}

        {{ featuredArticle.body }}

    READ FULL STORY...

EDIT: Then for the second part of your question this other answer tells you how to exclude an Entry:

How can I exclude the current entry when I've structured my syntax like this?

So from the other article, you'd do:

{% set entries = craft.entries({
  section: 'news'
}).id('not ' ~ featuredArticle.id) %}


Only fetch structure entries that are first level or sub level that don't have a parent I have a Structure with my entries in. How can I hide the parent entries that contain children? I still want to show the parents children.

For example I want all the below entries bar "About" and "Services"

- Home
- About
    - Sub
    - Sub
    - Sub
- Stuff
- Services
    - Sub
    - Sub
    - Sub
- Things

So, this is my code right now

{# Set parameters for prev/next elements list #}
{% set params = craft.entries.section('pages') %}

{# Get the prev/next elements #}
{% set prevEntry = entry.getPrev(params) %}
{% set nextEntry = entry.getNext(params) %}

Do I need to modify the params to remove the entries that are parents?

You can use the hasDescendants() method to filter out any parent entry with children. You have to use an ElementCriteriaModel with .getPrev() and .getNext().

{% set entries = craft.entries.section( 'pages' ) %}
{% set entryIds = [] %}

{% for entry in entries %}
  {% if not entry.hasDescendants() %}
    {% set entryIds = entryIds|merge( [entry.id] ) %}
  {% endif %}
{% endfor %}

{% set criteria = craft.entries.id( entryIds ) %}

{% set prevEntry = entry.getPrev( criteria ) %}
{% set nextEntry = entry.getNext( criteria ) %}

You will also need to add logic to get the first and last entry is next or previous is null.


cp login over https gives error I've set up a site with SSL, and finally got everything to load over https as well in the CP. But now I'm getting an error when trying to log in. When I look at the logs it says that the username cannot be blank. Which is weird, since I filled it out.

I'm also seeing the insecure symbol on the login button. But not sure why it's there.

This could be a couple things:

Server config
.htaccess file
SSL Certificate

But it sounds to me like the insecure login button means those assets are not being served over SSL. How'd you confirm the site is served over https?

Craft's control panel resources are not actually in the document root so what's happening is Craft's controller (index.php) is handling those would-be 404 requests and spitting out the cp resource in question from the backend via php.

Server Config

If you can access a static file over https in the document root (say something like https://yoursite.com/images/sitelogo.png or your main CSS file) and your browser is showing the padlock and not an error, that means your virtual host is setup correctly.

That's the first thing I'd rule out. If you're not getting your browser's padlock on a simple request like that, your SSL setup needs tweaking, probably a bad virtual host config. For good measure, most certs allow www- and non www so check www.yoursite.com as well. (It's easy to forget to put in a ServerAlias in the VirtualHost block to handle both hostnames and then try to access the site and wonder what's going on, I've done it!)

.htaccess

Another source of trouble could be if you have some additional rewrite rules in your .htaccess file. A common one is to rewrite from www.sitename.com to sitename.com or vice versa for example—that could actually be redirecting to the insecure resource instead of over SSL, depending on your rewrite rules. So Craft wouldn't actually be serving your site over SSL because your rules would always say to rewrite the request to an insecure resource.

SSL Certificate

Browsers can do weird things if you your SSL cert is not installed correctly.  I like Symantec's SSL checker for this sort of thing. If you're using domain based validation, like the regular comodo or geotrust certs, some of them require additional "chained" or intermediate certificates to work correctly. Besides checking your server config and certificate, that checker will also make sure the chain of trust is in the right "order".


Single not loading correctly with additional segments I've got a single set up to point to /calendar on my site. the single has only one field, SEOmatic so I can add meta title, description etc.. the rest of he page is loaded with content from the photoblog channel.

The issue is that I've got things organized by months and if there are no month segments in the url I redirect to the current year and month so that for example today the site would redirect to /calendar/2016/08 and when it does this the meta tags are getting pulled from the homepage single and I don't know why.

I also have a template route set like this

If I remove the redirect code for the year/month the meta tags come through correctly, but if it's there no luck.

How can I fix this.

simplified template code here:

{% if craft.request.segment(2) == "" %}
  {% redirect "/calendar/" ~ now.year ~ "/" ~ now|date("m") %}
{% endif %}

{#
  // take month digit and convert to date format so we can output
  // the full month name below next to the year
  // if this isn't done will only output 08 or 09 for august or september etc...
#}
{% set viewMonth = '00-' ~ month ~ '-01' %}

{% set entryAfterDate = year ~ '-' ~ month %}
{% set entryBeforeDate = year ~ '-' ~ (month + 1) %}

          {% set entries = craft.entries.section('photoblog').limit(null).after(entryAfterDate).before(entryBeforeDate) %}

          {% for entry in entries | reverse %}

            more code here

          {% endfor %}

{% endblock %}

If I understand your question correctly you might be better off using SEOmatic's Template Meta feature.

Using the Template Meta you're be able to set the meta info on a per template basis. So in this case you'd create a one to use for your calendar.html template.


Error handling in Craft So I'm used to JS where I can console.log() most errors to assess the best way to debug what's going on.
In Craft, as many of the sites I am working on are live and in production and I struggle (horribly) to find solutions to issues! Also because the site is live I cannot enable dev mode....
Is there a way to console log errors? (from looking at posts here I do not think there is, but I must ask directly).
If there is not, maybe someone could explain how they would handle this situation (Which I am currently in so this is not hypothetical).
I'm using SS twitter feed to populate a page with twitter tweets.
I would like to see what data is available to me, to use (or not use if some posts are different - and have to write conditions for).
In JS I would console log this i.e.
var tweets = getTweetsFunction
console.log(tweets)

this would display an array of objects and from there I could find out what fields are available.
But in Twig, posting
{% for tweet in craft.ssTwitterFeed.displayPost( '4' ) %}
  {{tweet}}
{& endfor &}

just gives me the "Server error" message.
Side note here, I have enabled the craft dev tool bar

And can see that it has a log section, can you log twig variables to this section to review them?
I understand that this might be a really basic question but it's driving me mad that every wrong turn ends in Server Error.
Thanks for any help,
W

As of craft 3.2 dump and die is enabled even for sites that are running without dev mode - dump and die is the solution to this issue.

The usual method for debugging a Craft site is to pull down a copy of the production database content, import it into your local development database and run a local copy of the site's code on your computer. You can run the site using Craft's Nitro development environment, or use other local development environment frameworks like Valet or MAMP.
Once you have this local development site running, you can make changes to the templates to help debug issues or view the properties of objects, just by modifying the Twig templates. The Twig dump function is useful for viewing the contents of an object to see which properties you have available:
{% for tweet in craft.ssTwitterFeed.displayPost( '4' ) %}
    {{ dump(tweet) }}
{% endfor %}

If you're running the site with devMode enabled, the dd tag (Dump-and-die) is also helpful. This will dump out the variable and nothing else, i.e. your page won't render but instead you will get a formatted dump of the variable you're inspecting:
{% dd(craft.ssTwitterFeed.displayPost('4')) %}


Pantheon hosting alternative for Craft CMS I'm coming from a WordPress background and use Pantheon for all my client websites. I love the service they provide, especially easy migrations and multi-environments (Multi-dev feature branches, Dev, Test, Live) they provide out of the box. It helps a small company off load all the dev ops work.

We also love Craft CMS, and would like to start using it more, but are struggling to find a host that provides the same/similar amount of features and support.

I've checked out Recommended hosting company for a Craft site? but none of the recommendations include features that I'm looking for.

Here are the main features I'm looking for:

Dev, Test, & Live
- Run a continuous integration workflow out of the box. Every site you create includes a Dev, Test, and Live environment connected by version control. Each has its own database, file system connection, and URL.

Cloud development environments
- Multidev allows you to fork your entire stack (code and content), work independently, then merge changes back into the master. Each branch is an entire development environment with the same configuration as the live site. Spin up cloud environments for feature branching, per-dev sandboxes, QA environments, and more. Multidev makes it easy to manage your development workflow and keep your team’s work in sync.

From what I understand it is possible to host a Craft site on Pantheon but they will not offer the same level of support that you would get using WordPress or Drupal. This is what I've been told by Pantheon technical support, at least.

The workflow you're looking for could be mostly set up on Heroku using review apps, however, to my knowledge they don't have the same workflow where new branches can be created with cloned content from whichever environment or branch you'd like.

I think that this would be possible by running postdeploy script from app.json, which fires once when the review app is created. You could write a script that pulls production content and clones an S3 bucket into a new one, giving you a Pantheon-esque workflow.

If you're going to go down this route you might want the AWS CLI Buildpack, the ability to use environment variables in Craft (see Matt Stauffer's site for this) and you'll probably want to use Jaws for MySQL since, in my experience, it's much faster than ClearDB.

I'm in the same boat as you, coming from a WP heavy background and very reliant on Pantheon, so currently looking into a similar set up myself. Hope this provides some direction.

It would be amazing if Pantheon just offered Craft support out of the box.


Using Image Transform as another custom field I've created a section with a thumbnail image and also a dropdown to allow the user to select the transformation to apply to that image.

I've pre-created all the asset transformations ready and this is the code I have :

{% set imageTransform = storyEntry.storyThumbnailTransform %}
{% set thumbnailImage = storyEntry.storyThumbnail.first() %}
<img src="{{thumbnailImage.url(imageTransform) }}" alt="" class="post__preview-img post__preview-img--grid">

However, it doesn't appear to be rendering the image. If I output storyEntry.storyThumbnailTransform to the page, it displays the value of the image transform as expected.

What am I doing wrong? Or is there another way to accomplish this?

The imageTransform value is actually an object, representing the entire dropdown field.

Update the first line to this...

{% set imageTransform = storyEntry.storyThumbnailTransform.value %}

This will ensure that the selected value is passed on, instead of the full object.

(The reason that you see the proper value when you output it directly is because the object's __toString method is automatically being called internally.)


Output play lists in Videos by Dukt Is it possible to output whole playlists in the videos plugin by Dukt?
I have looked through the docs, but cannot see any examples or mention of this. But in the back-end system there are playlists.

The plugin is only showing the playlists in the CP, in the Videos explorer, to help you pick a video to be used in a video field. It is not currently possible to list playlists and their videos from the templates, but it’s on our list of things to explore for Videos 2.0.


Templating basics: extend, include or use? I'm making first steps with Twig in Craft. Ok, it's a Twig question. But maybe you can give me the best practice for Craft?

I'm used to create templates Top-Down, like having a master.html template that includes footer.html, header.html, content.html etc.

Now Twig and with this Craft suggests I'd rather extend / inherit parent templates.

It looks like the easy way to start if I simply use {% include "pages/partials/_head.html" %} – but will this later on, when I start working on the content, somehow prohibit accessing the unique features of extend?

So: Should I grasp the logic of extend first or doesn't it matter?

My setup regarding includes for templates is as follows:

I'll have a 'site' structure that looks at /pages/_entry.twig for it's template. But I'd have a range of entry types within this structure, for example:

Homepage
Contact
News
Standard content

Then my /pages/_entry.twig template looks like this:

{% extends "_layout/base.twig" %}

{% block content %}
    {% include 'pages/' ~ entry.type %}
{% endblock %}

So the extending of my base template is sorted for all of them in one place (less repeated code ) and it just includes a file based on the entry type like so:

/pages
  -- _entry.twig
  -- contact.twig
  -- homepage.twig
  -- news.twig
  -- standardContent.twig

And the entry type matches the file name so each entry type has it's own template automagically.


Get file errors after upload Hi I have a plugin which is basically a form. This form has upload file field which I added in the backend side in Assets fields so I have something like this:

                <fieldset>

                        Upload File
                        <input type="file" name="fields[myAssetNameHandle]">

                </fieldset>

I send the form to the server with ajax like this:

    var formData = new FormData($form[0]);
    $.ajax({
        type: 'POST',
        dataType: 'json',
        url: '{{ actionUrl("myplugin/sendApplication") }}',
        data: formData,
        processData: false,
        contentType: false,
    ......

On the myPluginController I have validation

    $model = new myModel();
    $model->test_var = craft()->request->getPost('test_var');

    if ( $model->validate() ) {

    }else{

    }

Evrithing works fine except that I did some restriction to upload files on that asset field for example only documents so when I upload an image I do not have any errors. So how can I get the errors for that field and if there are no erorrs how can I get the name so After validation to add the file into the db? Thank you in advance and sorry for my English if is not so good.

You can get the errors from the model by using $model->getErrors().  That will return an array of errors indexed by the attribute name.

Since you submitted over AJAX, you'll want to use $this->returnErrorJson() to return them and have your JavaScript parse the errors out to display them to the user.


Batch saving a custom field to multiple users via controller I have to build a custom plugin for an internal user management system/data export that needs to be able to get triggered from the CP.

I basically have to sort a big amount of users (1500+) in a specific plugin tab in the Control Panel. The sorting is done via Vue/JS. When I am done sorting the users I need to be able to trigger and save a field (a string I will enter in the CP Tab) for all of those users in the same order as it was sorted in the CP.

For now, I have simply sent an array of User Ids to my plugin controller via post request:

public function actionSubmitRef()
{
    $request = \Craft::$app->getRequest();

    $userIds = $request->getParam( 'userIds' );
    $refNumber = $request->getParam( 'refNumber' );

    $response = [
        'userIds' => $userIds,
        'refNumber' => $refNumber,
    ];

    WFWPlugin::getInstance()->saveNewReferenceNumber( $userIds, $refNumber );

    return $this->asJson( $response );
}

The controller passes the array of Ids and the string to save to a function that saves the string to each user:

public function saveNewReferenceNumber( $userIds, $refNumber )
{
    $i = 0;

    foreach ( $userIds as $userId ) {
        $i ++;
        $user         = Craft::$app->users->getUserById( $userId );
        $tableValue   = $user->getFieldValue( 'aktionsRefNumber' );
        $tableValue[] = [
            'col0' => $refNumber . '-' . $i,
        ];

        $user->setFieldValue( 'aktionsRefNumber', $tableValue );
        $success = Craft::$app->getElements()->saveElement( $user );

        if ( ! $success ) {
            Craft::error( 'Couldn’t save the entry "' . $user . '"', __METHOD__ );
        }
    }
}

The problem is that with this huge amount of save requests, PHP either times out or it simply can't be processed. I end up with having a max of 40 saved uses with the right value in the field.

How could i solve the issue? I have recently asked the question in the discord dev channel and using a console command has been suggested, but since the users need to be sorted in the CP, the string has to manually be entered and then triggered via a button, I couldn't get it to work.

Another approach was to push each save request into a yii2 job queue but that didn't help either...

Thanks for the help, much appreciated!

For such large amounts of operations it's best to use a Job. You should only make sure to batch your results and don't fetch every user separately.

use Craft;
use craft\base\Element;
use craft\db\QueryAbortedException;
use craft\elements\User;
use craft\helpers\App;
use craft\queue\BaseJob;
use yii\base\Exception;

class ResaveUsers extends BaseJob
{
    // Properties
    // =========================================================================

    /**
     * @var int[] The user Ids
     */
    public $userIds;

    /**
     * @var string the reference number
     */
    public $refNumber;

    // Public Methods
    // =========================================================================

    /**
     * execute
     *
     * @param \craft\queue\QueueInterface|\yii\queue\Queue $queue
     *
     * @throws \Throwable
     * @throws \craft\errors\ElementNotFoundException
     * @throws \yii\base\Exception
     *
     * @author Robin Schambach
     * @since  07.05.2019
     */
    public function execute($queue)
    {
        $query = User::find()->id($this->userIds);

        $totalElements = $query->count();
        $currentElement = 0;

        $elements = \Craft::$app->getElements();

        try {
            $i = 0;
            foreach ($query->each() as $user) {
                $i ++;
                $this->setProgress($queue, $currentElement++ / $totalElements);

                $tableValue   = $user->getFieldValue( 'aktionsRefNumber' );
                $tableValue[] = [
                    'col0' => $this->refNumber . '-' . $i,
                ];
                $user->setFieldValue( 'aktionsRefNumber', $tableValue );

                /** @var Element $element */
                $user->setScenario(Element::SCENARIO_ESSENTIALS);
                if (!$elements->saveElement($user)) {
                    throw new Exception('Couldn’t save element ' . $user->id . ' (' . get_class($user) . ') due to validation errors.');
                }
            }
        } catch (QueryAbortedException $e) {
            // Fail silently
        }
    }

    // Protected Methods
    // =========================================================================

    /**
     * @inheritdoc
     */
    protected function defaultDescription(): string
    {
        return Craft::t('app', 'Resaving {class} elements', [
            'class' => App::humanizeClass(User::class)
        ]);
    }
}

You can start your job with

Craft::$app->getQueue()->push(new ResaveUsers([
     'userIds' => [1,2,4,5,6],
     'refNumber' => 'foobar'
]));


Experience with Craft's native rss/atom support? I'm trying to use the native support for rss and atom as described in the documentation, but it misses some info.

https://craftcms.com/docs/templating/atom-feed
https://craftcms.com/docs/templating/rss-feed

Did anyone got this to work? I'm not even sure how to name my template or what the url is going to be.

I tried the following template names:
template.twig.atom
template.atom.twig
template.atom

I tried requests with atom in the header and .atom postfix. Both without any success.

Yeah, so I have a rss.twig file in the root of my template directory.

{% header "Content-Type: application/rss+xml" %}
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">

{% set rss = craft.entries.section('article').limit(10).type('article') %}

<channel>
  <title>My Site Name</title>
  <link>{{ siteUrl }}</link>
  <description>My site description</description>
  <language>en-au</language>
  <atom:link href="{{ url() }}" rel="self" type="application/rss+xml" />

  {% for item in rss %}
  <item>
    <title><![CDATA[{{ item.title|raw }}]]></title>
    <link>{{ item.url() }}</link>
    <description><![CDATA[
    {% for block in item.body %}

  {% if block.type == "text" %}

    {{ block.text }}

  {% elseif block.type == "footnote" %}

    {% include 'blocks/_footnote' %}

  {% elseif block.type == "pullQuote" %}

    {% include 'blocks/_pullquote' %}

  {% elseif block.type == "heading" %}

    {% include 'blocks/_heading' %}

  {% elseif block.type == "image" %}

    {% include 'blocks/_image' %}

  {% elseif block.type == "audio" %}

    {% include 'blocks/_audio' %}

  {% elseif block.type == "video" %}

    {% include 'blocks/_video' %}

  {% endif %}

{% endfor %}]]></description>
    <pubDate>{{ item.postDate.rfc2822() }}</pubDate>
    <guid>{{ item.url() }}</guid>
  </item>
  {% endfor %}
</channel>

</rss>

If I access, http://myurl.com/rss - I get my lovely feed.


Front End Entry Form - File/asset field not saving when ajax submitted I have a front end entry form which submits and saves fine when not using ajax.
But when i do submit via ajax the text fields etc save fine but the file/assets field will not.
I have stripped it right back for testing but still not saving the file on ajax submit.
I have even made the logged in user a full admin for testing purposes.
My Form:
<form method="post" id="applicationForm" class="sform2" accept-charset="UTF-8" enctype="multipart/form-data">
    {{ csrfInput() }}
    {{ actionInput('entries/save-entry') }}
    {{ hiddenInput('sectionId', '3') }}
    {{ hiddenInput('enabled', '1') }}
    {{ hiddenInput('entryId', '159') }}

    <label for="nameAccountIsHeldIn" class="col-12 col-form-label">Name account is held in</label>

    <input type="text" name="fields[nameAccountIsHeldIn]" class="form-control" id="nameAccountIsHeldIn" value="">

    <input type="file" name="fields[accounts][]" class="form-control" id="accounts" multiple>
    <button type="submit" class="btn btn-primary">Submit</button>

</form>

js:
$('.sform2').submit(function(ev) {
    ev.preventDefault();

    startAlerts();
    var data = $(this).serialize();
    var url = $(this).attr("action");

    console.log($(this));
    console.log(data);

    $.ajax({
        type: 'POST',
        url: url,
        data: $(this).serialize() ,
        dataType : 'json', // changing data type to json
        success: function (response) { // here I'm adding data as a parameter which stores the response
            console.log(response); // instead of alert I'm changing this to console.log which logs all the response in console.
        }
    });

});

Finally found the answer after much time spent on it.
The $(this).serialize() loses the file input - and can't submit.
Updated ajax submit to
$.ajax({
    type: 'POST',
    url: url,
    data: new FormData(this) ,
    dataType : 'json', // changing data type to json
    processData: false,
    contentType: false,
    success: function (response) { // here I'm adding data as a parameter which stores the response
        console.log(response); // instead of alert I'm changing this to console.log which logs all the response in console.
    }
});


What's the largest number of elements Craft can handle well? We are in talks with a client about developing a database that currently has about ~7000 items in it, each with at least one photo so thats likely almost 20,000 with ambitions to grow it to be at least twice that size.

Should I be concerned about scaling a Craft to that size?
What's the largest craft database any of you are running?
Has anyone had any issues with large number of elements slowing down the system to unusable levels?

We have a site with (as of right now) 77,613 elements. 9,954 of which are entries.

We found that we had to be careful about using Craft's {% cache %} functionality because clearing the element cache criteria took a long time. Instead we use a Varnish cache and it all works fine.

There are times when it's not as fast as it should be, particular templates that pull in a lot of data from different places struggle if there's a bit of traffic to it at any one time - but Varnish resolves that. There's probably lots in those templates that we could be doing to make them more efficient too, it's just not been a high priority because it works okay.]

Just make sure your hosting is reasonably beefy. Depending on your traffic mysqld might get called upon a lot and that can be a resource hog. I recommend using something like DigitalOcean where you can simply increase the VPS specs if things are struggling and tweaking Craft settings or templates isn't helping.

And with Craft 3's performance boosts coming this year, I think you'll be fine.

Hope that helps!


Commerce: what is the purpose of a line item's snapshot? Having nearly completed my first real Commerce project, I managed to utilize most of the features offered in Commerce 3. However, I never quite figured out what the use of a line item's snapshot is for. What is it and when would you need to use it? There isn't anything about it in Commerce's docs.

The snapshot is there so that the key details of an order are forever more available on the order record.
Imagine living with Commerce for a long time - you will of course most likely add, change and/or remove products (or variations) as time goes by.
You might simply disable ones you remove, or you might delete them.  If Commerce did not have line item snapshots, old orders would refer only to these now deleted things - thus, for example, when presenting an order history view to your customers, the details would not be available and this would (at least) mean some order details could no longer be displayed accurately.  And at worst, it might well cause serious errors with your templates/page rendering, if you're relying on those details being there.
Another example - prices change over time.  The order snapshot shows the price at the time of the sale, not the price now - which might be substantially different.
It might even be the case that store operators are altering products actually while a customer has them in their cart and is busy making an order.
Thus the snapshot mechanism is an elegant, if perhaps poorly documented, solution to these issues.
Thus - and you're right, this should probably have its own explanation in the docs - the best practise with Commerce is to always use the snapshot details by preference once something is a line item - i.e. when dealing with carts (incomplete orders) at any point, or orders - always use the snapshot data.
Of course the snapshot doesn't have everything in it (like images etc) - so for prettier templates, you often end up with some conditional logic referring to the actual product / variant - but you must check if it is still available first, before using any data from it, and have a fall-back if it is no longer available.


dev- branch plugin forks being prompted for update I'm currently using a fork of a plugin for my site, and using a "dev-[branch-name]" version specification in the composer "require" block, with a "vcs" repository definition for the fork location on github - basically looks like:
"repositories": [
  {
    "type": "vcs",
    "url": "https://github.com/[forked-account/plugin-name]"
  }
],
"require": {
  "[original-account/plugin-name]": "dev-branch-name"
  ...
}
...

This worked fine for several months, but I'm suddenly now seeing a prompt to update to the latest version of the plugin on the author's "master" branch when running Craft update.  Has something changed with the requirements for the composer file version declarations for Craft to respect the "dev-" branch version as the preferred plugin version?

I experience the same with https://github.com/Saboteur777/craft-support forked from https://github.com/jasonmccallister/craft-support (which is a fork of https://github.com/lukeyouell/craft-support).
Using composer update will not change "tracks" to the original plugin, so you are safe to update, the notification is a minor annoyance, though.


How can I add a dynamic "active" CSS class to the navigation on any given page? Just wondering how people approach setting a class of current in their navigation. Is there anything in Craft or Twig where you can set a conditional to check if a page is the current page. Or do you just need to set classes/ids on the body tag based on the segment?

Any ideas appreciated, Gareth

Tip: To keep it short and reusable I would recommend that you wrap your preferred "check-method" in a Twig macro, I like Anna's version the most:

_macros.html:

{% macro is_active(segment) %}{% if craft.request.firstSegment == segment %}active{% endif %}{% endmacro %}

layout.html:

{% import "_macros.html" as macros %}

News
Blog


What does defaultTokenDuration affect besides hidden entries' share links? Per this answer, configuring defaultTokenDuration is the way to change the lifespan of hidden entries' share links from the default 24 hours. The v2 docs describes this as affecting "system tokens" but no further explanation of system tokens is provided. The v3 docs refers simply to "tokens."

[edit: I believe one other thing this controls is the lifespan of password reset tokens.]

I'd like to increase the lifespan of draft entries' share links, but wonder what other consequences I should take into account before changing defaultTokenDuration. What all does it affect?

Currently (as of Craft 3.0), it will affect entry and category share links.  Some additional things might be using it in the upcoming 3.1 and plugins are free to use it for whatever they want.

For example, in Commerce 2, it is used for creating product preview share links.


Feed Me Cron Job failing on 123-reg hosting I'm trying to set up a cron job to run the feed me direct feed url in 123-reg hosting. The command they are saying to use is:
/usr/local/bin/php /home/username/public_html/index.php?p=actions/feed-me/feeds/run-task&direct=1&feedId=1&passkey=xxxxxxx

However I'm getting an error:
Could not open input file: /home/username/public_html/index.php?p=actions/feed-me/feeds/run-task
The feed action runs fine when used in a url. So is there something not right with the cron? Looking at the error message that is sent through it seems to be stripping anything after the first & ?

Ok after a bit of digging. It turns out I was able to run this with wget. But had to comment out the &'s as these were being read as commands in cron. Also worth noting you would need to do the same with %'s as well.
So the final solution is:
wget -q -O - https://domain/index.php?p=actions/feed-me/feeds/run-task\&direct=1\&feedId=1\&passkey=xxxxxxxxxx >/dev/null 2>&1

Hope this helps anyone else with a similar issue.


How can I force a download of entry data to an excel file? The website I'm building enables users to book places on events. This is simply a form which creates an entry in a channel containing 2 fields: "related user" and "related event". In the control panel I've written a simple plugin which displays all the entries in that channel exactly the same as the control panel normally would do, but now I can display any fields I want instead of just title and post date.

My client wants to be able to export the entry data from the control panel into Excel (xls or csv). What's the simplest way to do this? I read somewhere about changing http headers to force a download of a file, so can I just force a browser download of a dynamically generated page containing a table of all that entry data?

When I say "force a download" I mean I probably just need a button that says "Export", but it should download the file instead of opening it in the browser.

Craft's HttpRequestService has a sendFile method (available via craft()->request->sendFile()).

The 3rd parameter is an optional $options array that accepts key => value pairs.  One of those is 'forceDownload' => true and when that is passed in, Craft will set the proper HTTP headers to force the given file to be sent to the browser as a download.

You could do this from inside an action in one of your plugin's controllers.  Something like:

public function actionDownloadFile()
{
    // Grab your file content from wherever you have it stored. Here, it's just hard coded into a string.
    $contents = 'row1column1,row2column2'.PHP_EOL.'row2column1,row2column2'.PHP_EOL;

    // Call sendFile, giving it the name of the file to send, the contents and tell it to force a download to the browser.
    craft()->request->sendFile('filename.csv', $contents, array('forceDownload' => true));
}


How to stop a Slider We've got a HeroSlider on our website, and I no longer wish for the slider to slide (if that makes sense?).

Currently the homepage is 3 slides, however when I remove the 2 slides I don't want, the 1st slide still tries to slide, and in doing so disappears.

I need it to be static.

As far as I can see the code for the slider is:

        var $heading    = $('.heroslider-text h2');
        var $para       = $('.heroslider-text p');
        var $btn        = $('.heroslider-text .btn');

        // Define animation sequence for hero elements.
        if($para.length){
            this.seq = [
                { elements: $heading, properties: { opacity: [1, 0], translateY:[0, 50] }, options: { duration: 250 } },
                { elements: $para, properties: { opacity: [1, 0], translateY:[0, 50] }, options: { delay:60, duration: 250, sequenceQueue: false } },
                { elements: $btn, properties: { opacity: [1, 0], translateY:[0, 50] }, options: { delay:60,  duration: 250, sequenceQueue: false } }
            ];
        } else {
            this.seq = [
                { elements: $heading, properties: { opacity: [1, 0], translateY:[0, 50] }, options: { duration: 250 } },
                { elements: $btn, properties: { opacity: [1, 0], translateY:[0, 50] }, options: { delay:60,  duration: 250, sequenceQueue: false } }
            ];
        }

    };

    this.runSequence = function(){
        if($('.heroslider-text').hasClass('animated')){
            $.Velocity.RunSequence(this.seq);
        }
    };
};

Thank you very much.

Maybe use a smarter slider? I frequently use Slick, which will only initialise when the number of items is > 1.

In addition, within my template code I would only include the markup required only for the slider if the number of slides is > 1, as I like to keep my markup clean. Something like:

  {% if entry.hero|length > 1 %}
{% endif %}
    // Hero / Slider markup goes here…
  {% if entry.hero|length > 1 %}
{% endif %}


Removing a matrix row via front end entry form Read some similar posts on here but they don't quite solve my problem. I've gt an entry form with a matrix field in it, and I’m trying to make it editable via front end entry form. Specifically I'd like to be able to remove rows – either delete them, or disable them.

So my form has a ‘Remove’ button (Remove) on each row. Clicking the button should remove or disable the matrix row, save and reload the entry/page. Javascript isn’t my forte but here’s what I’ve got so far:

document.addEventListener('DOMContentLoaded', function () {
    function getAll(selector) {
        return Array.prototype.slice.call(document.querySelectorAll(selector), 0);
    }
    var $removeBtn = getAll( '.remove' );
    if ($removeBtn.length > 0) {
        $removeBtn.forEach( function ( $e ) {
            $e.addEventListener('click', function () {
                var target = $e.dataset.target;
                document.getElementById( target ).value = null;
                $( '#failures' ).submit();
            });
        });
    }
});

On my template I’ve got:

<input type="hidden" name="fields[{{ assessment.assessmentActionPlan }}][{{ block.id }}][type]" id="type-{{ block.id }}" value="failure">
<input type="hidden" name="fields[{{ assessment.assessmentActionPlan }}][{{ block.id }}][enabled]" id="enabled-{{ block.id }}" value="1">

My script is correctly setting the enabled field value to null and submitting the form (#failures), but the matrix field on the entry remains unchanged. Where am I going wrong? Thanks for any help.

In the end I went with a slightly different approach, allowing users to remove multiple rows before submitting the form. Nod to this excellent article: https://caffeinecreations.ca/blog/editing-a-front-end-form-with-matrix/


List only Orders containing specific Products Each Product has a Merchant field which is standard Craft User. What I'd like to do is list out all Orders which contain one or more Products relating to the currentUser. I was hoping I'd be able to use Relations to accomplish this, so something like this:

{% set products = craft.commerce.products({
  'relatedTo': currentUser
}) %}

{% set orders = craft.commerce.orders.relatedTo({
  'sourceElement': products,
  'field': 'lineItems.purchasable.product'
}).find %}

The first query works fine and returns only the Products relating to the currentUser, but when I try to use it as the basis for the second query, that's where it collapses in a big heap! Am I in the right ballpark, or isn't this possible in the way I'm trying?

Any help gratefully received.

This is now possible as of Craft Commerce 1.1.1211 using the new hasPurchasables criteria attribute:

https://craftcommerce.com/docs/craft-commerce-orders#haspurchasables


Error reporting Freeform submission jumps to top of page despite auto form anchor I'm using Freeform 1.7.2 and since version 1.6.2 a form anchor is automatically added:

  Added form anchor to be automatically generated so inline error returns can focus down to form, if it's lower down on page.

Yet, the submission still jumps to the top of the page if there is an error. I asked a similar question before, but this was before the name anchor was added. Shouldn't this now work by itself?

Here's my super simple code:

{{ craft.freeform.form("formName", {
   instructionsBelowField: true,
   useRequiredAttribute: true,
}).render() }}

We've recently discovered that this feature is not always reliable unfortunately. However, we're working on addressing this and coming up with a better solution in the coming weeks. Sorry for any inconvenience.


log out being shared with bootstrap.php I have an external php app that sits in a subdirectory in the public folder on the same server (and domain) as craft. I am trying to use bootstrap.php to check the logged in status of the current user. Is this possible?

It is currently working for me by checking that the user is logged in (it does return false while not logged in) - but after the user logs out of craft the bootstrap.php continues to return true that the user is logged in.

$craft = require '../../craft/app/bootstrap.php';
if ($craft->userSession->isAdmin() && $craft->userSession->isLoggedIn() ){
 // this returns after a log in, but continues to be true after a log out. It does not return true initially before using both craft and this script.
}

Hopefully that makes sense, any ideas?

I also could not get the onLogout or onBeforeLogout to execute. I see it is in the class reference, but not listed in the event documentation:

public function init()
{

    craft()->on('usersession.onLogout', function(Event $event) {
        echo "THIS DOES NOT EXECUTE";
        die();
    });

    parent::init();
}

Is it possible the log out event is not triggering?

I just tested this and it works as you'd expect it to work for me locally:

<?php

$craft = require '/path/to/craft/app/bootstrap.php';

if ($craft->userSession->isAdmin())
{
    echo 'I am an admin.';
}
else
{
    echo 'I am not an admin.';
}

if ($craft->userSession->isLoggedIn())
{
    echo 'I am logged in.';
}
else
{
    echo 'I am not logged in.';
}


Ordering relatedTo entries There are a few tickets touching on this, but the solutions proposed aren't working and I'd like to share the use case:

I have a Table of Contents page that is outputting a set of entries based on an Entries field, in the order they appear in that field. When you click on an entry on that page, it loads on its own page.

At the bottom of the individual entry page, I have Prev/Next URLs, using:

{% set data = craft.entries.section('works').relatedTo(issue.contents).limit(null) %}
{% set prevEntry = entry.getPrev(data) %}
{% set nextEntry = entry.getNext(data) %}

The prev & next entries there, though, are based on a sort in the 'works' section, not the entries field.

I've tried this, per the documentation:

{% set entries = craft.entries(
    {
        relatedTo: { sourceElement: issue, field: "contents" },
        order:     "sortOrder",
        limit:     null
    }
) %}

That gives me the following error. How can I sort .relatedTo entries based on the source field's order?

Integrity constraint violation: 1052 Column 'sortOrder' in order clause is ambiguous. The SQL statement executed was: SELECT `elements`.`id`, `entries`.`sectionId`, `entries`.`typeId`, `entries`.`authorId`, `entries`.`postDate`, `entries`.`expiryDate`
FROM `craft_elements` `elements`
JOIN `craft_elements_i18n` `elements_i18n` ON elements_i18n.elementId = elements.id
JOIN `craft_content` `content` ON content.elementId = elements.id
LEFT JOIN `craft_relations` `sources1` ON (sources1.targetId = elements.id)
LEFT JOIN `craft_matrixblocks` `target_matrixblocks1` ON target_matrixblocks1.id = sources1.sourceId
JOIN `craft_entries` `entries` ON entries.id = elements.id
JOIN `craft_sections` `sections` ON sections.id = entries.sectionId
LEFT JOIN `craft_structures` `structures` ON structures.id = sections.structureId
LEFT JOIN `craft_structureelements` `structureelements` ON (structureelements.structureId = structures.id) AND (structureelements.elementId = entries.id)
WHERE (((((elements_i18n.locale = :locale) AND (content.locale = :locale)) AND (elements.archived = 0)) AND ((elements.enabled = 1) AND (elements_i18n.enabled = 1) AND (entries.postDate <= '2016-05-17 14:08:35') AND ((entries.expiryDate is null) OR (entries.expiryDate > '2016-05-17 14:08:35')))) AND (elements_i18n.enabled = 1)) AND ((target_matrixblocks1.ownerId=:target_matrixblocks1ownerId1) AND (target_matrixblocks1.fieldId = 15))
GROUP BY `elements`.`id`
ORDER BY `sortOrder`. Bound with :locale='en_us', :target_matrixblocks1ownerId1='6'

First you’ll need to get the Table Of Contents entry that holds the Entries field (the source entry). I’m going to assume that is in a Single section with the handle toc.

{% set toc = craft.entries.section('toc').first() %}

Once you have that, you can just pass its Entries field value into getPrev() and getNext():

{% set prevEntry = entry.getPrev(toc.myEntriesField) %}
{% set nextEntry = entry.getNext(toc.myEntriesField) %}


Craft install failed with error php7 not found, but server has php 7 installed I'm trying to install a backup from production site which is running craft 3.0.26 to a UAT site. While installing, faced an error regarding PHP versions. Since both the sites are in the same server, where server shows php71 as the version, but while trying to install craft on UAT site using ssh, its showing error since PHP is running on 5.6.0.

Please help need regarding this.

It sounds like your server environments are different. It is possible to run different version of PHP on different parts of a server, so it really depends on your setup, but that is surely what is going on here. Without more details about your server I don't think it will be possible to give a more detailed answer. Good luck!


GUI Crop image field - Plugin request I'm just wondering here if something like this is possible. On a website I'm working on for a photographer, he's in need of carefully selecting focal points on his images.

I'm aware of the focal point plugin, but that is connected to the assets file itself. And not the entry. So basically what I'm asking is

Is it possible to:

Upload the full source image to assets
On an entry, select this
image
Have a separate field with a GUI control of the cropping of
selected image from point 2.

Save the entry. And Craft takes those parameters and generates the new image and puts it in the destination folder. So the new cropped image is not in Assets at all.

The reason for this need is because the photographer wants full control of the focal points of each image.

TLDR:
Is it possible to a use something similar to this gui control on a field where an image has been selected, instead of having it directly on the assets file?

Have you seen this solution: http://craftcookbook.net/recipes/120?

Vote here for better image cropping in Craft: http://feedback.craftcms.com/forums/285221-feature-requests/suggestions/7302748-intelligent-cropping-for-flexible-images


Rich Text Field is returning an empty object over api of plugin json_expand Is anybody using the json_expand plugin for API functionality?
For the entry type Rich Text Field its just returning an empty object.

This is my json_expand endpoint:

{% header "Content-Type: application/json" %}
{% set utensils = craft.entries.section('utensils').find('') %}
{{ utensils | json_expand | raw  }}

It's returning everything except that Rich Text field which just returns this:

"utensil_textbox": {}

I just came across this problem and solved it by editing the JsonExpandService.php file (located in craft/plugins/jsonexpand/services/) in two places.

Change line 101 from this:

$relatedArray[$subHandle] = $subValue;

To this:

if($subField['type'] == "RichText") {
    // Rich Text field values need to be converted to a string
    $relatedArray[$subHandle] = (string)$subValue;
} else {
    $relatedArray[$subHandle] = $subValue;
}

And change line 115 from this:

$entryData[$handle] = $value;

To this:

if($field['type'] == "RichText") {
    $entryData[$handle] = (string)$value;
} else {
    $entryData[$handle] = $value;
}

This fixed Rich Text fields coming through as empty objects for me.

This plugin hasn't been updated in 3 years, so Craft probably changed something about how Rich Text fields are outputted and the plugin never adjusted. Just a guess.


What's the difference between 'user', 'currentUser', and 'account'? I notice in the template examples that user, account and currentUser are all being used, but not seeing clear documentation on these. Can someone perhaps explain the difference?

Example User Registration Form uses {{ account.username }}

Example User Profile Form uses {{ user.username }}

and there is a Global Variable called {{ currentUser.username }}

I assume that user is perhaps just an alias to currentUser (unless explicitly defined otherwise)? And that account is something that is used exclusively for user/saveUser?

The reason I ask is that I'm creating edit profile pages, and want to make sure they are secure. Seems like just using user is enough, as that appears to always be populated correctly with the currentUser data; and if not logged-in it redirects to the log-in page.

Thanks.

Update:
As of Craft 3.x, the deprecated user variable no longer works. Make sure to use the proper currentUser variable instead!

Original:
user and currentUser are exactly the same. They contain the UserModel of the currently logged in user.
Why are they exactly the same? Originally, user was the preset value for the current user. However, there were many cases of people manually setting a value for user (often in the context of a for loop through a group of users), and therefore overwriting the preset value. So P&T introduced currentUser as an alias which was much less likely to be overwritten.
account will only exist on the User Registration Form. Its value is automatically set when the form is submitted. account represents the values entered during the attempted registration (whether the registration was successful or not).
For the sake of your Edit Profile pages, you'll want to use currentUser.


Detect currently selected source of custom elements I have a split-style + New Element button for my custom element type. Thanks to this previous thread, the right-side dropdown menu is working perfectly!

My question now is, how do I get the + New Element side of it working?

I keep studying the entries templates, to see how it's done over there. But I've noticed that when you navigate between entry sources, the page URL actually changes. When navigating between my custom element sources, the page URL does not change.

How can I help the + New Element button detect what source is currently being viewed?

You can see how this is working by opening craft/app/resources/js/craft.js and searching for the Craft.EntryIndex class definition.

Craft.EntryIndex is an extension of Craft.BaseElementIndex, and is used to govern all Entry indexes in Craft (including Entry selection modals). We pull that off with this line of code, which you’ll find immediately after the class definition:

Craft.registerElementIndexClass('Entry', Craft.EntryIndex);

The logic governing the “New Entry” button is a little complicated, and it relies on an initial version of the button HTML already being available on the page (thanks to the craft/app/templates/entries/_edit.html template), but all the magic happens within its onSelectSource() method, including updating the URL.


Replace placeholder string in text field with HTML generated by Asset query I have a Matrix block with a text field and an Assets field. The text field has a Markdown filter applied to it.

I'd like the content owner to be able to enter a placeholder reference to one of the images uploaded to the sibling Assets field.

For example, when the template processes…

This is a **paragraph**.

%%img2%%

This is some more text.

…then %%img2%% (or some such syntax that won't conflict with Markdown) gets replaced with the HTML generated for the second image by the relevant Assets query running in the template.

I've done things like this before with MXjumper and ExpressionEngine but am pretty new to Craft and not sure how to go about it.

I figure I need to:

Set a dynamically named variable (because I don't know in advance how many images are in the image field)
Use replace on the text field, but the replace statement should incorporate dynamically named search strings and the replacements would be the variables named at step 1 not strings.

Really not sure how to execute either of these 2 steps in Twig.

Would something like the following work for step1?

{% for img in sectionImages %}
    {% set n %}{{ loop.index }}{% endset %}
    {% set img ~ n %}

        {% if img.caption|length %}

            <span{{ img.caption }}

        {% endif %}

    {% endset %}
{% endfor %}

And what then for step 2…

{{ block.sectionText|markdown|replace('%%img' ~ n ~ '%%': img ~ n) }}

My step 1 code feels like it's close but I suspect it's not right. And in any case I feel sure my step 2 code is further off from what's needed.

I think maybe I need to be storing img as key|value pairs in an array and working with that somehow.

Any pointers much appreciated.

This is partially side stepping your question but, it could be a solid option just the same:

You might consider checking out Selvin's Doxter Markdown plugin. It has support for Entries, Assets, Users, Tags, Globals and Categories.

This all via reference codes which can be copied and pasted into the Markdown as needed.


expiryDate in craft_templatecaches I've found this in the documenation:

  Dates and times are both formatted for the user’s preferred locale.
  They are displayed in the site’s timezone, however they get stored in
  UTC like all other dates in Craft.

That's fine.

I use this timezone: UTC+1 (CET) - Europe/Rome

As expected everything is saved in the database with an UTC offset of minus one hour exept the expiryDate in the craft_templatecaches table: the UTC offset is minus two hours.

Here is my code snippet:

{% set expiredNews = craft.entries.section('news').order('expiryDate')|first %}
{% set expiryDate = expiredNews.expiryDate %}

{% cache until expiryDate %}

Example:

expiryDate in entry: 2015-04-01 00:00:00

expiryDate in cache: 2015-03-31 22:00:00

Why is there an offset of two hours and what does that mean for cache invalidation?

The above code example works.

Short and simple answer: daylight saving time (DST)

Standard time: -1 hour in database

Daylight saving time: -2 hours in database


Craft Commerce: Bakery site with multiple bakeries (How to handle product types and variants) Alright, so I am trying to persuade a client to switch to Craft Commerce for their bakery shop.

Thing is, their current setup is kinda messy, and I just cant figure out how to convert it properly to Craft.

Case:
They have Cakes, Cakes comes in a multitude of sizes, with a lot of choices. Different types of cakes have different choices (Fill, jelly, nuts, colors, figures etc.)

All possible combinations of the choices results in a unique ID (EAN) for that cake, that the bakery can use in their system for production.

Thats ok, we can have product types and variants for all these. But here is the hard part: each bakery have their own set of choices, some bakeries dont have the same type of jelly, or the same colors for the toppings.

Each bakery choose what cakes they want to sell, and what kind of configurations they have.

When on their front page, you type inn your ZIP code and we use that to determine the closest bakery, based on that, we show that bakery's cakes, with their configurations.

Since there are about 10 bakeries, having a chocolate cake with custom variants per bakery will get really messy really fast, given how many cakes each bakery has. So I am trying to figure out how to separate each bakery and its product in the CP.

I toyed with the idea of creating one product type per bakery, and just having a generic "cake" model that can be built up however they like, but this seems very hard for both us and the client, they having to create the same options over and over, and us having to "magically" get all kinds of configurations from some kind of matrix field, creating choices based on this in the frontend, and sending those choices by mail when the order is complete.

Is there some kind of "hack" where I can have a separate product (database) tables per user group, or something like that? If bakery X logs on the CP, we show products from this table, if bakery Y, we show products form another table.

The rest of the site is going to be joint, about us, contact, articles etc are all the same across bakeries. So I would like to avoid having 10 licenses, 10 databases and 10 installs to cope with this.

Any other ideas are greatly appreciated, maybe I am looking at this the wrong way, but having 300 cakes, with 18 variants each is going to make it impossible for a specific bakery to maintain their cakes.

Mathias

The way I see it, you have 2 very similar but different problems:

How does each bakery log in and maintain their own inventory?
How does each cake get built up in the admin?

You can pull off the separation of locations by using different permissions. Each Bakery would have their own user login (Store #1, Store #2, etc.) By setting the appropriate permissions, when Bakery #1 logs in, they won't see any other entries/products other than their own. To filter this on the front end, you just ask Craft to filter by the appropriate author. So in other words, Author = Bakery location.

We built a site where we had different, individual teachers logging into the same Craft install. Every teacher could post their own class schedule. We also didn't want them to view or edit each other's classes (but everyone on the front end could see and filter them for example). In your case, it would basically work the same way.

The second problem is much more complex.  I don't think you're that far off from creating a single "cake" product or different cake products (depending on what you're selling), for example, and then creating different options (variants) around those basic types. How you build up those products really depends on how you manage inventory, SKUs, variants, prices, etc. If some of those options don't have prices (eg butter creme frosting doesn't cost more than vanilla), it's just an additional option, that gets to be a bit easier in terms of options. You can just pull those options off with Craft fields.

Another way to pull it off on the admin side would be if the bakeries know how to upload an Excel/CSV file to the site, they could update their availability from that. It would be up to the you, the developer, to figure out what data is available and some sort of function to make it work. That's a pretty common use case for, say, a manufacturer with thousands of SKUs. To change pricing one-by-one in the Craft admin would take hours. But a CSV lets you bump all the prices up or down with just a couple Excel macros, which you can then export out.

FWIW, these are both non-trivial problems to solve. There's probably other ways to do so but Craft gives you some tools to help pull this off.


Using front end lookup for map display I see the docs here about getting the lat/long of an address from a zip code, city, etc. I am having issues getting the map to render from this info. My code:
{% if craft.smartMap.visitor.ip != '' %}
    {% set locations = craft.smartMap.visitor.coords %}
{% else %}
    {% set locations = craft.smartMap.lookupCoords(90210) %}
{% endif %}

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

I get:

Undefined index: fieldId

How do I convert the lat/long result into one of the correct location types?

Let me start with a minor side note... You'll want to change the first line to this:

{% if craft.smartMap.visitor.ip %}

It's better to test against a "falsey" IP address, instead of explicitly testing for an empty string. I believe the IP address would resolve to false if nothing was found. Either way, a general "falsey" check will work as expected here.

It's not currently possible to convert a raw set of coordinates into a more complex object.

That being said, you could fairly easily do it using the built-in smartMap JavaScript object...

{# Get visitor's coordinates #}
{% if craft.smartMap.visitor.ip %}
    {% set coords = craft.smartMap.visitor.coords %}
    {% set jsCoords = 'smartMap.coords(' ~ coords[0] ~ ', ' ~ coords[1] ~ ')' %}
{% else %}
    {% set coords = craft.smartMap.lookupCoords(90210) %}
    {% set jsCoords = 'smartMap.coords(' ~ coords['lat'] ~ ', ' ~ coords['lng'] ~ ')' %}
{% endif %}

{# Blank map #}
{{ craft.smartMap.map([], options) }}

{# Add visitor marker #}
{% js %}
    smartMap.createMarker('visitor-marker', {
        position: {{ jsCoords }},
        map: smartMap.map['smartmap-mapcanvas-1'],
    });
{% endjs %}

UPDATE: I fixed a bug in v3.0.5 which makes this even easier.


apply transform to image uploaded into Redactor? Is it possible to allow the selection of an image transform on an image that's been uploaded into a Redactor field?

Sure, from the Redactor "Insert Image" modal:


Possible memory leak - GeneratePendingTransforms/ImageMagick Wondering if anyone else has had issues with memory and a large amount of image transforms.

I seems like perhaps memory is not being freed up between transforms. When GeneratePendingTransforms is running, that process skyrockets my CPU and memory, and just keeps climbing until it is done.

Possibly related: https://stackoverflow.com/questions/9993085/php-imagick-memory-leak/12835966#12835966

I had this same issue with an image-heavy site hosted on WebFaction w/ PHP5.6, using latest Craft 2.6.x version.

I added the fix Brad mentions + another config line:

// From http://stackoverflow.com/a/12835966
// Pixel cache max size
$this->setResourceLimit(\Imagick::RESOURCETYPE_MEMORY, 256);
// Maximum amount of memory map to allocate for the pixel cache
$this->setResourceLimit(\Imagick::RESOURCETYPE_MAP, 256);

in craft/app/vendor/pixelandtonic/imagine/lib/Imagine/Imagick/Imagick.php at line 33, at top of smartResize() function.

This was before adding the 'generateTransformsBeforePageLoad' => true, line to our config, I haven't tested removing this setting after adding that to our config.

When still in heavy development, we'd clear image asset caches and the transform queue would grow like crazy, and PHP processes would grow past 1.5gb until our host killed all of our processes. I haven't seen this issue since adding those Imagick settings.


Shipping in Craft Commerce Is it possible to apply a shipping cost to the cart before a customer enters their shipping address?

The site I am working on has a fixed shipping rate of £3.50 for UK orders under £22. If the order value is over £22 then the shipping is free.

Anyone based in and shipping to, Europe has a set rate based on weight of the order.

Is it possible to set the initial base shipping cost to the cart screen before checkout and then change the shipping cost and method when the customer adds a shipping address during checkout?

What is the best approach for setting these shipping rates in the Control Panel, and how to apply these in the cart?

The short answer is no, it is not possible.  The much longer answer I will add to your other question:

Setting Shipping Country and Method for the Cart screen


Querying channel entries hits memory limit We have a channel that has about 700 entries but is paginated with a limit of 30 entries. Our client is looking to add a button so users can print out all entries. One of our proposed solutions was to redirect to a stripped down page (no header, footer, etc.) with all of the filtered entries that automatically engages the browser's print method. The problem is if no filters have been applied, Craft can't handle 700 entries (I've tested a bit and 130 seems to be the limit).

How should one go about this? Is upping our memory limit (currently 128M) the only way around this? Would it be better to generate a JSON object on channel entry save that we could then load in the print page's template?

Any suggestions would be appreciated!

EDIT

Here is some additional information. The page is basically just a list of companies. There is a field for the company's name, address, contact name, telephone, email, website, type (category), country (category), and also SEOmatic (which we obviously don't need to display). I haven't actually looked at the tables, though.

The error I am getting:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 79 bytes) in /Library/WebServer/Documents/site/craft/app/fieldtypes/PlainTextFieldType.php on line 59

EDIT 2

Channel: Companies

Field Layout:

Meta: SEOMatic (don't need to output)
Company Name: Plain Text
Company Address: Plain Text
Company Contact Name: Plain Text
Company Email: Plain Text
Company Telephone: Plain Text
Company Website: Plain Text
Company Type: Category (there can be MULTIPLE types, doesn't have any fields associated with it)
Company Country: Category (there can only be ONE type, doesn't have any fields associated with it)

Categories:

Company Types
Company Countries

Assuming you're referring to Craft 2, the EntryModels that get returned to a template do have a significant memory overhead attached to them you're probably running into.  Doing the math, even bumping your php.ini memory_limit up to 256M is only going to get your around 260 results coming back with your given fields/configuration.

It's one of the big things we first improved in the upcoming Craft 3.

In the meantime, you've got a couple of options:

Paginate the results so you can do them in smaller batches.
AJAX/lazy load the results over multiple requests in smaller batches.
Write a plugin (https://craftcms.com/docs/plugins) that bypasses Craft's Element/Model loading and queries the database directly and returns only the data you explicitly need back to the template, without all of the model overheard.