How to list out entry types in a section

Take a look at the sections documentation: https://craftcms.com/docs/templating/craft.sections

The following code lists all entrytypes of all sections.

{% set sections = craft.sections.getAllSections() %}

{% for section in sections %}

{{ section.name }}

    {% set entryTypes = section.getEntryTypes() %}

        {% for entryType in entryTypes %}

{{ entryType.name }}

        {% endfor %}

{% endfor %}

If you like only to show used entry types:

Loop trough all entries
Collect all entry types in a array
Now, you can loop trough the entry types array


The Craft Commerce example template's include a file called meter.html to display the progress bar.

At the top of template there is an array of steps that is used to calculate the percentage as the user progresses through the checkout process.

In order to get your progress bar to show the correct percentage you will need to change the url's for each step to match your site's structure.

Something along the following lines will likely be what you need:

{% set steps = [
  {
    label: "Start Order",
    url: 'shop/test/checkout'
  },
  {
    label: "Address",
    url: 'shop/test/checkout/addresses'
  },
  {
    label: "Shipping",
    url: 'shop/test/checkout/shipping'
  },
  {
    label: "Payment",
    url: 'shop/test/checkout/payment'
  }
] %}

This will then make the following true for the current step and the width will be calculated.

{% if craft.request.requestUri|slice(1) == step.url %}
  {% set width = ((key + 1) * 100 / steps|length) - 20 %}
  {% set class = "sel" %}
  {% set currentStep = key %}
{% endif %}


In whatever Section you're getting that error in, you've got an Assets field inside of Matrix (or possibly SuperTable) and that Assets field has “Restrict uploads to a single folder” set and you've got a dynamic subfolder path setup for it.

In that dynamic path, you're using {slug} when you should be using {owner.slug}.

From the docs:

  Note that if you are creating the Assets field within a Matrix field, the source element is going to be the actual Matrix block, not the element that the Matrix field is being created on. So if your Matrix field is attached to an entry, and you want to output the entry ID in your dynamic subfolder path, you would type {owner.id} not just {id}.


Trigger Info window in Smart Map using external navigation

When conducting a proximity search, it's common practice to display a list of nearest locations, alongside a map displaying markers of nearest locations.
You may want each marker's info bubble to open when clicking on the text link.
You'll need a JavaScript function to handle opening the info windows.
function openInfoWindow(mapId, fieldHandle, entryId) {

    // Prep to open info window
    var markerName = mapId + '.' + entryId + '.' + fieldHandle;
    var map        = smartMap.map[mapId];
    var marker     = smartMap.marker[markerName];
    var infoWindow = smartMap.infoWindow[markerName];

    // Close all open info windows
    for (var i in smartMap.infoWindow) {
        smartMap.infoWindow[i].close();
    }

    // Open new info window
    infoWindow.open(map, marker);

    // Zoom to marker
    var zoomLevel = 6;
    smartMap.zoomOnMarker(mapId, markerName, zoomLevel);

}

When you loop through your entries to generate the results list, you can attach an onclick event which calls your function.
{% for entry in allEntries %}

{{ entry.title }}

{{ entry.myAddressField.distance }} miles away

{% endfor %}

For more information, check out the documentation for manipulating the map in JavaScript...


Craft 3 on new MAMP Pro 5 installation: "iconv(): Unknown error (22)" problem in /vendor/twig/twig/src/Extension/CoreExtension.php

Per my earlier comment, the convert_encoding filter is causing this, I think only in newer versions of Twig than what my live site running Craft 2 uses.

I guess that probably somewhere in my site content, one of our content managers somehow inserted a character that convert_encoding is choking on. Rather than figure out where that is, and know that the site would blow up again the next time they did it, I've replaced bodyText|striptags|convert_encoding('UTF-8', 'HTML-ENTITIES')|slice(0, 200)|default('Read more') with
bodyText|striptags|slice(0, 200)|default('Read more')|raw, and while I have not tested this thoroughly to know that it works as intended in all cases, it's at least not blowing up an index listing of 100 articles because (I suspect) one entry has some weird character in it any longer.


Headings Not Shown When Adding Custom Source

So I have my headings displaying now but this is more of a flawed workaround than an answer.

Basically when the ElementIndexesService->getSources() function finds element index settings it then works through the sources ordering them and applying headings based on the settings.

As my sources are custom ones added by a plugin they don't exist in the settings. Because of this they are shuffled to the end of the list and the headings are removed.

My fix is to add them to the settings in the database. This can be done using...

$elementIndexesService = new ElementIndexesService();
$settings = $elementIndexesService->getSettings(ElementType::Entry);
// and
$elementIndexesService->setSettings(ElementType::Entry, $settings);

$settings consists of two sub arrays containing the sources and their order. By adding my custom sources to these everything appears in the entries index as planned.

The flaws are that I now need to maintain this whenever the entries that effect the sources are created or deleted. Also the index settings modal overwrites the settings in the database so again I have to maintain it if they are changed.


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


Solved: Unable to get composer running to install CraftCMS

Yes, after lots of trying I finally found the solution!! It was ESET causing the problem

Today, after re-installing PHP7 from scratch (so not using wamp and its contents anymore to make sure it's not wamp setup causing these problems) and reinstalling composer again I found that even that didn't work.

So I figured it really should be in some anti-virus or other blocking tool. And I only use ESET Internet Security.

But I tried disabling both ESET firewall as well as ESET anti-virus several times before and it didn't solve the mystery of the composer connectionproblems.
So I took a closer look at ESET advanced settings more deeply now and it seems that eventhough I thought I turned everything in ESETs scans and blocks completely off (and that's exactly what ESET displays!), there happens to be a SSL-scan that wasn't turned off by that so still actively preventing composer to work.

I would say scanning SSL communication by ESET shouldn't cause any problems anyhow, just some milliseconds delay or whatever, but it obviously was completely blocking composer from reaching packagist through ssl. Turning off the SSL scan made composer reach packagist with https immediately, so finally this solves the mystery.

For people coming here with the same problem with composer and SSL and use ESET too, if you set up php and composer correctly then you should try this on ESET to solve the problem:

Enter ESET advanced setup (via rightclick menu on ESET icon)
Open up 'Web and email', and then the 'SSL/TLS' tab
Click the 'edit'-link after 'List of SSL/TLS filtered applications' (a dialog opens)
Check if the php.exe composer is using is in the list and if it does: make sure the scan action is set to 'ignore'. That prevents ESET from scanning the traffic via SSL from php.exe. Perhaps you could also add some certificate to the 'List of known certificates' here, but I solved it this way instead.
If php.exe is not in the list you should get a dialog window when running
a composer command like 'composer diagnose' that needs ssl with packagist and ESET shows a dialog box for the new connection: set it to IGNORE. Scan will result in composer throwing warnings and having no connection with packagist.
If php.exe is not in the list and you don't get the ESET dialog window for the new connection when running 'composer diagnose' either you probably don't have the 'SSL/TLS protocol filtering mode' in ESET (under 'web and email'/SSL/TLS tab in advanced settings) set to interactive mode. Set it to interactive mode than.
If none of the above worked you could also choose to fully turn off all SSL/TLS protocol filtering in ESET by just switching it off in 'web and email' --> SSL/TLS --> Enable SSL/TLS protocol filtering. Then ESET isn't scanning any SSL anymore.

Hopefully this helps more people having the same issue.

Thisone really caused me headages for last weeks because it hold me back from switching to craft 3. So I'm really excited I finally got an answer to this now!! Finally it's time to move to the more important stuff!


Emails not being sent when transaction complete

The error is not telling you that the email address is missing, I think, but rather that the email itself to send is missing.

Have you assigned an actual email to send for that particular status?

Commerce->Settings->Order Statuses - check the column 'Has Emails' has a value of 1 or more in it.

(To actually assign one, create it first in the email section, and then in this section click on the order status and in the bottom field 'Status Emails' you'll then be able to choose your created email).

Based on the error and the code generating it (in Commerce_OrderStatusesService.php) - I would say you've set up a status but not actually assigned the email you've made to it.


Having an issue with assets, while i am upload the image from the admin

That error message means your basePath is incorrect and Craft can't find the directory you're referring to.

From your settings, it looks like Craft would try to upload images to /public_html/src/assets/images/. If that's correct, try using / or nothing instead of your current basePath. And make sure the folder exists on the server.


Because logoSlider.image is an array of images (even if there's only one image in the array) you need an additional 'for' loop to catch all of the images (not just the first or last). Try something like this:

{% for logoSlider in entry.logoSlider %}
   {% if logoSlider.type == 'logo' %}
     {% for image in logoSlider.image %}

     {% endfor %}
   {% endif %}
 {% endfor %}


Model public method throws CMapIterator warning

User error. It's a naming collision with the getAttributes method within my model and the CModel class.


How can I get image locations in a list of entries using the Element API plugin?

This should work for the images and you can easily adapt to do your categories & kachelgroesse if needed (not tested)...

'api/looks/list' => [
    'elementType' => 'Entry',
    'criteria' => ['section' => 'looks'],
    'transformer' => function(EntryModel $entry) {
        $images = [];
        foreach ($entry->featuredImage as $image) {
        $images[] = $image->url;
        }
        return [
        'title' => $entry->title,
        'id' => $entry->id,
        'url' => $entry->url,
        'jsonUrl' => UrlHelper::getUrl("looks/{$entry->id}.json"),
        'kachelgroesse' => $entry->kachelgroesse,
        'category' => $entry->category,
        'image' => $images
        ];
    },
],


Before you run your transform, you can check the width of the asset file and adjust your transform as needed.

{% set thumb = {
    mode: 'scale',
    width: 1000,
    quality: 70,
} %}

{% if asset.width < 1000 %}

    {% set thumb = {
        mode: 'scale',
        width: asset.width,
        quality: 70,
    } %}

{% endif %}


How to create a Matrix Relation field / relate Matrix Blocks to other Elements

The BaseRelationField is able to relate all elements - even Matrix Blocks but it's a little bit tricky because in order to display everything properly you need to define sources but Matrix Blocks have no sources.

At first we need to make sure our Matrix Blocks have a valid source, otherwise this Javascript check messes all up

var $sources = this._getSourcesInList(this.getSourceContainer());

// No source, no party.
if ($sources.length === 0) {
    return false;
}

And nothing works So we need the following

Event::on(
    MatrixBlock::class,
    MatrixBlock::EVENT_REGISTER_SOURCES,
    function(RegisterElementSourcesEvent $event) {
        if (empty($event->sources)) {
            $event->sources[] = [
                'key'         => 'MySource',
                'label'       => 'All Matrixes',
                'defaultSort' => 'elements.id',
                'data'        => [
                    'handle' => 'matrix'
                ],
                'criteria'    => [
                    'typeId' => 21,
                    'fieldId' => 70 // <-- this is the matrix field of Entry A otherwise the values won't be populated
                ]
            ];
        }
    }
);

In order to display an identifier we need to set the title attribute to the block, otherwise all we see is an id.

Event::on(
    MatrixBlockQuery::class,
    MatrixBlockQuery::EVENT_AFTER_POPULATE_ELEMENT,
    function(PopulateElementEvent $event){
        $element = $event->element;
        if($element->getType()->handle === 'person'){ //<-- make it is the correct matrix block
            try{
                $element->title = $element->getFieldValue('firstName') . ' ' . $element->getFieldValue('lastName');
            }catch(Exception $exception){
                // whatever you need
            }
        }
    }
);

Since Matrix Blocks usually have no table attributes we need to define them as well

Event::on(
    MatrixBlock::class,
    MatrixBlock::EVENT_REGISTER_TABLE_ATTRIBUTES,
    function($event) {
        $event->tableAttributes['id'] = ['label' => 'ID'];
        $event->tableAttributes['email'] = ['label' => 'Email'];
    }
);

After that you can use the normal BaseRelationField and extend it like you are used to for custom element types


Entry URIs incorrect when using entriesService->saveEntry()

Ok, so the answer was quite simple: I was using the PHP DateTime object instead of Crafts DateTime.

Removed the \ on this line:

$date = new \DateTime($article['article_start'], new \DateTimeZone('Europe/Oslo'));

and everything worked perfectly.


So it turns out you can modify an existing property like this:

$event->params['entry']->getContent()->existingProperty = 'new value';

What I ended up doing was using a hidden field and then updating the value of that from the sproutForms.onBeforeSaveEntry event:

craft()->on('sproutForms.onBeforeSaveEntry', function(Event $event) {
    $entry = $event->params['entry'];
    $entry->getContent()->subscribeStatus = 'success';
});

Since that property can be set depending on what the response is from the cURL post, it's possible to deliver success/error messages to users on the thank you page and prevent the subscribe from silently failing in the background.


Multiple sections, limiting the structure by depth

or would I have to pull all entries separately into an array?

This one.

100% untested, but something like this should work:

{% set ids = [] %}

{% set ids = ids|merge(craft.entries.section('events,opinionPieces,whitepapers').ids()) %}

{% set ids = ids|merge(craft.entries.section('checklists').level(1).ids()) %}

{% set entries = craft.entries.id(ids).find() %}


Import database backup when using docker

Partial solution - I removed all backups except the most recent from the backups folder.

It seems that changing the site name prevented the site from finding the correct sql file or adding new backups to .ignore.

If you want to change the name then be sure to remove other backups from the site directory.


Check the site for missing file links / warn user before removing used files

is there a way to check the site for missing file links, including those in redactor?

I can't think of a way to do this outside of writing a custom plugin/PHP script that loaded everywhere an Asset field might exist on an install, grabbed its contents and verified them against the file system.

Additionally, it would have to load any Rich Text field you have setup with Asset sources, use some regex to match any Assets reference tags it might contain and do a similar file system verification to check for the existence of the images.

  Also is there any strategy for preventing clients from removing used assets?

Take away their "Remove Files" permission from the Asset source under their user/user group permissions.


It's not possible to have different defaults per locale with the Table field type. Also keep in mind that the content from the first locale you edit is copied over to all other locales on the first save.

But how about using numbers for the months in the table and to show the full month names in your templates get them from craft.i18n.getLocaleData:

{% for row in myTableField %}
    <li>
        {{ craft.i18n.getLocaleData().getMonthName(row.col1) }}:
        {{ row.col2 }}
    </li>
{% endfor %}

Another way would be to use the date filter:

{{ ('2015-' ~ row.col1 ~ '-1')|date('F') }}


Adding file uploads to commerce product line items?

You will not be able to upload an asset into a line item at Commerce 1 or 2.

You only 2 options are

1) Upload the asset to an order custom field(s). Submit a new question with your code if this is not working for you.

2) Upload the asset anywhere else, (including optionally the order), and then put the URL of the asset into the line items options data. See https://docs.craftcms.com/commerce/v2/adding-to-and-updating-the-cart.html#line-item-options-and-notes


Checking if a matrix field with entries has more than one entry

I believe the code below should work. This code assumes you are on a single entry page or within a loop and your entry is available to you with the entry variable. You may need to adjust the block.type name and block.employees entries field name to match your proper handles. I've added comments inline to clarify each step:

{# Loop through your Matrix Field #}
{% for block in entry.contactMatrix %}

    {# Check to see which type of block you have.  You only want to check for the employees entry field if you are within the contact block #}
    {% if block.type == 'contact' %}

        {# See if your employees entries field has more than 1 entry #}
        {% if block.employees|length > 1 %}

          {# Output HTML for blocks with multiple employees #}

        {% else %}

          {# Output HTML for blocks with zero or one employee #}

        {% endif %}

    {% endif %}

{% endfor %}


How to get query or param from URL and then use in Links?

Use craft.request.getQueryStringWithoutPath() like so:

products/category?{{craft.request.getQueryStringWithoutPath()}}

  Returns the query string, except for the p= param (which was probably added by your .htaccess redirect).

More complicated logic to avoid the ? when the query string is empty (one of several ways to do this):

{# queryString will include '?' if we have one, otherwise '' #}
{% set queryString = (craft.request.getQueryStringWithoutPath() ? '?'~craft.request.getQueryStringWithoutPath()) %}
products/category{{queryString}}


As @mmikkel pointed out, as of Craft 2.4.2697, Craft is PHP 7 compatible.


Dashboard icons missing with flexible SSL

This is a bit of a stab in the dark, but have you tried forcing SSL for all CP requests?

http://buildwithcraft.com/help/force-ssl

Ultimately your .htaccess would look something like this:

<IfModule mod_rewrite.c>
 RewriteEngine On

 # Force SSL for CP requests
 RewriteCond %{HTTP_HOST} example\.com [NC]
 RewriteCond %{REQUEST_URI} ^/admin/ [NC]
 RewriteCond %{HTTPS} !=on
 RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [NC,R=301,L]
</IfModule>


Webhooks: Filter Entry by type (or Section)

You can register additional filters.
See the documentation - https://github.com/craftcms/webhooks#filtering-events
The example shows you how to add a filter based on the entry's type as you need.


with a get request from /index.php?p=admin/actions/users/session-info&dontExtendSession=1 I can get my CSRF Code + the User ID. Great.


Douglas's answer is correct... Also, if you'd simply like to try Craft Pro before purchasing it, you can do so while running Craft in your local environment.

  https://craftcms.com/support/try-craft-client-pro

UPDATE:

It's now possible to try Craft Pro from any non-public domain:

  https://pixelandtonic.com/blog/test-craft-client-pro-from-any-non-public-domain


How to check if a field exists on a section

I think you're running in to a caching issues here or you're not testing with devMode turned on perhaps.

I've just tested here and if I remove a field and reload an entry in devMode I immediately get an exception e.g.:

Craft\Commerce_ProductModel and its behaviors do not have a method or closure named "unimformityMeasurement".

Actually, even with devMode off I get a 500 server error with the same information, so I am thinking that you're very likely hitting a cached result that is preventing you from  seeing these errors.

(In my experience you are correct the data is still in the database though).


Yes, your code looks fine.

It's possible that the second and third entries just don't have content in the body_testimonial field.

(Unrelated — I recommend using testimonial as your loop variable, since it represents a single Testimonial entry. This is a good practice in general: Variables that represent a list should have a plural name, and variables that represent a single object should have a singular name.)


Getting errors back to a template whilst in an event

Rather than ending the request in your plugin, you should probably set $event->performAction = false, add your errors to the charge model and return control to Charge to add it's own error message and return to the calling template template.

So your code should look more like this:

craft()->on('charge.onBeforeCharge', function(Event $event){
    $newUser = new UserModel;

    $newUser->firstName = craft()->request->getPost('firstName');
    $newUser->lastName  = craft()->request->getPost('lastName');
    $newUser->username  = craft()->request->getPost('username');
    $newUser->email     = craft()->request->getPost('email');
    $newUser->password  = craft()->request->getPost('password');

    if ($newUser->validate()) {
        // create user
    } else {
        MyPlugin::log('User supplied details were invalid, attempting to redirect with errors.', LogLevel::Error);

        // Add our error message to the charge object
        $chargeModel = $event->params['charge'];
        $chargeModel->addError('myErrors', 'Invalid user details supplied');

        // Stop the payment from proceeding
        $event->performAction = false;
    }
}

In your template you should be able to access the errors by calling charge->getErrors().

If you supply a parameter to the getErrors() function you will only get those errors back. So if, as above, we add a custom key to the error, we can query for that in the template like this:

{% set myErrors = charge.getErrors('myErrors') %}
{% if myErrors | length %}
    {# Oops! Something went wrong, let's handle that… #}
{% endif %}


Wrap a quote in differently styled quotes depending on locale?

You could do this by adding the locale ID as a class to the body tag and then use a technique like described in this nice CSS-Tricks to add the quotes depending on that body class.

https://css-tricks.com/almanac/properties/q/quotes/

If you want them to be in the HTML you could write a quick Twig macro that adds the quotes depending on the locale ID.

{% macro wrapInQuotes(string) %}
    {%- set quotes = {
        'en': ['“', '”'],
        'de': ['„', '“'],
        'fr': ['« ', ' »'],
    } %}

    {{- quotes[craft.locale][0] }}
    {{- string }}
    {{- quotes[craft.locale][1] -}}
{% endmacro %}

{% import _self as macros %}
{{ macros.wrapInQuotes(entry.quote) }}


I've managed to get it working with great help from Brad Bell and Oli.
The following code changes feedme slugs on Import.
use craft\feedme\events\ElementEvent;
use craft\helpers\ElementHelper;
use craft\elements\Entry;

Adding the following Event with the namespaces above works nicely.
        Event::on(
          Process::class,
          Process::EVENT_STEP_BEFORE_ELEMENT_SAVE,
          function(craft\feedme\events\FeedProcessEvent $event) {
            switch($event->feed['name']){
                case 'merchants':
                    $element = $event->element;
                    $element->slug = ElementHelper::createSlug($element->title.' '.'Whatever you'd like appended!');
                    break;
            }
        });


If the email address is not yours, follow these instructions...

If the email address is yours, then your local system probably isn't sending out email. Follow these instructions to manually set the password.


How to use a dynamically defined field handle in a plugin?

This should do it for you:

$entry->$fieldHandle->last()->uri;


Are there any file-based static cache options for Craft CMS?

Someone has recently developed a standalone static HTML caching plugin for Craft CMS which does similar to what you're after:

HTML Cache plugin for Craft CMS

This Craft plugin will generate static HTML files for your website. No need for Reddis/Varnish setups anymore!

Improves the speed drastically: 300-1500MS to 2-50MS (depending on
server setup) if ubercache is enabled from the settings page
Busts the cache automatically when an entry has been updated
Cache duration time can be set; defaults to 3600 seconds (1 hour)
Active development and support through Craft's Slack

NOTE: This plugin is still in beta, so please test if this plugin works as expected on a development environment before pushing to a production site.


apply transform to image uploaded into Redactor?

Sure, from the Redactor "Insert Image" modal:


When it's only for frontend: you can search for entries from different sections with

set entries = craft.entries.section(['blog', 'about', 'foo']).find()

This returns you all enabled/active entries from all the sections with the handle blog, about or foo.


Craft 3 Redactor Link no longer has target option

Add the linkNewTab config option to the Redactor config you're using:
So, that would become something like:

{
    "buttons": [...],
    "plugins": [...],
    "linkNewTab": true
}


Creating an archive page with full year and month list

{% set groupedEntries = entriesInYear | group("postDate|date('F')") %}

Will give you an associative array where the keys are the months, and the values are the entries for that month.

Now you need to loop over all the months, not just the ones in the groupedEntries.

Make an array of all the months.

{% set allTheMonths = ['January', 'February', 'March', ... 'December'] %}

Make an array of all the months that have entries (twig's keys filter)

{% set monthsWithEntries = groupedEntries | keys %}

Loop over the months (all of them), and output either the number of entries (groupedEntries[month]|length) or 0

{% for month in allTheMonths %}
  {% if month in monthsWithEntries %}

{{ month }}&nbsp;({{ groupedEntries[month]|length }})

  {% else %}

{{ month }}&nbsp;(0)

  {% endif %}
{% endfor %}


I think you need to reference a macro name inside of your _common/_helpers file.

For example:

{{ helpers.input('username') }}

That would output a macro called input:

{% macro input(name, value, type = "text", size = 20) %}
    <input type="{{ type }}" name="{{ name }}" value="{{ value|e }}" size="{{ size }}" />
{% endmacro %}


Is there simpler, less assuming Craft documentation?

Best is to create fresh Craft instalation and experiment, learn basics. I did the same thing when I was assigned to a large drupal project.

Here is a resource list on Craft:

http://craftcookbook.net
http://straightupcraft.com/articles/getting-started-with-craft-cms
http://webdesign.tutsplus.com/courses/building-landing-pages-with-craft-cms
http://craftcms.com/docs/templating/craft.entries
https://craftcms.com/support
http://straightupcraft.com/events/matrix-entry-types-and-advanced-content-layouts

"..and I think it's down to my basic understanding of how Sections, Entries and Fields work"

It's quite simple really :)
You attach fields to section - this defines a "template" for your entry/entries.

Single type section has one entry, Channel & Structure have multiple entries. Also you can create few entry types for Channel & structure (https://straightupcraft.com/articles/how-do-i-output-an-assets-field-inside-a-matrix-field-inside-an-entry-type).

STRUCTURE SECTION EXAMPLE

Create fields

Create section

Create Entry types (Click Edit Entry types)

Drag&Drop fields

Create new Entries

Note: Entry type changes

Create entry template file (see step 2 for file location).
File located under (installation folder)/craft/templates/example/_entry.twig

Result

You can also pull those two entries from any twig file like this (Details):

{% for entry in craft.entries.section('example') %}
    {{entry.title}}

{% endfor %}

OR just first one

{% set firstExample = craft.entries.section('example').first() %}
{{firstExample.title}}

See also this


I finally found a solution of my problem that makes the A&M Nav plugin the perfect choice for me.

The general problem is that amnav offers this function to fetch the activenode id:

{% set activeNodeId = craft.amNav.getActiveNodeIdForLevel('mainmenu',1) %}

This doesn't help because:

Unfortunately the level1 (last parameter) is related to the structure in craft, not in the plugin. In my case the child of a menuitem is not necessarly a child in craft (e.g. a single content).

That means, this function doesn't help me to get the children of a parent that has active children.

This code works to get the active menu item of the first level in the A&M Nav structure:

{# for first level #}
{% set activeNodeId = craft.amNav.getActiveNodeIdForLevel('mainmenu',1) %}

{# for second level #}
{% set nav = craft.amNav.getNavRaw("mainmenu") %}

{% for item in nav %}
    {% if item.hasActiveChild or item.active %}
        {% set activeNodeId = item.id %}
        {% set activeNode = item %}
    {% endif %}
{% endfor %}


Is there a way to upload an asset with a URL?

Firstly, you could manually copy/paste all your images into your Asset Source folders, then hit "Update Asset Indexes" from the settings. What this does is scan the directories for files, and creates them in the database if they don't exist. Once thats done, in your entries, you simply need to enter the filename in the search field (once you click "Add an Asset" on your asset field), and you're done.

For a more automated solution, you could look at Feed Me to update your entries, along with automatically uploading your assets from a provided URL. Your feed could be as simple as:

[{
  title: "Entry Title 1"
  images: [
    "http://my.website/my-image-1.jpg",
    "http://my.website/my-image-2.jpg"
  ]
}, {
  title: "Entry Title 2"
  images: [
    "http://my.website/my-image-3.jpg",
    "http://my.website/my-image-4.jpg"
  ]
}]


Commerce 2 Adding tax to custom adjuster

Having slept on it i thought it could be something to do with the order of the adjusters. Maybe Tax was applying to the price before my custom adjuster. So in the event i did the following:

var_dump($event->types)

This told me that my custom adjuster was going to the bottom of this array. To resolve this i used the php function array_unshift to push it to the front of the array

array_unshift($event->types,MyAdjuster::class);

This now gave me the following array:

array(4) {
      [0]=>
      string(18) "modules\MyAdjuster"
      [1]=>
      string(33) "craft\commerce\adjusters\Shipping"
      [2]=>
      string(33) "craft\commerce\adjusters\Discount"
      [3]=>
      string(28) "craft\commerce\adjusters\Tax"
    }

As you can see the adjuster is at the front of the array and now the tax applies to the fee as required.


Creating a new locale on craft 2, entries won't load

Is the /fr/ directory created in your public_html folder?
https://docs.craftcms.com/v2/localization-guide.html#step-5-set-up-the-files

Maybe try making a totally new entry for all 3 locales.


Search only by Field instead of entire content

Give this a go:

{% set searchTerm = craft.request.getParam('q') %}
{% set query = craft.entries({
        search: 'title:*' ~ searchTerm ~ '*',
        limit: 5,
        locale: craft.locale,
        order: 'score'
    }) %}

You can leave out the * on both sides if you only want to search for full word matches. Also, this might help you take it further: https://craftcms.com/docs/searching


How can I update a custom Order field in a plugin controller?

Turns out I really overthought this one! It's exactly the same as you would usually do it in Craft.

$this->cart->getContent()->setAttributes(array(
    'orderShippingOptions' => $myValue
));

craft()->commerce_orders->saveOrder($this->cart);

The bit I was missing was craft()->commerce_orders->saveOrder($this->cart);


Specify which template/layout to use based on URI segment

I'm not completely sure about what you're asking, but you might want to look in to craft.request:
 https://craftcms.com/docs/templating/craft.request

In your structure template, you can check your URL segments, and use twig include to load the desired template, based on those segments.

Another related feature is dynamic routing:
https://craftcms.com/docs/routing#dynamic-routes

You could use this to route a URL to a different template.


Images not saving to images folder in web directory

The solution I found was to start the path with an uppercase C and colon :

C:/xampp/htdocs/craftCMS/craftetest/web/images/drinks


At the time of this writing, the ideal solution isn't possible. But, as jpea suggested, creating a plugin was dead easy, so here it is:

Low Blocks

...which lets me use syntax like this:

{% set block = craft.lowBlocks.id(craft.request.segment(2)) %}
{% set entry = block.owner %}


Craft 3 auto-creates sub-folders in assets. How can I prevent this?

My guess would be your Asset Indexes are out of sync.

If you go to Settings->Utilities in the Control Panel, there is one that says "Update Asset Indexes".  Click it, let it run and you might be prompted to resolve some out-of-sync indexes.  Once you do that, it should work normally.


Max character limit on WYSIWYG text editor plugin?

It works for me, just changing the config file:
{
  "buttons": ["html", "bold", "italic"],
  "plugins": ["fullscreen", "**limiter**", "counter"],
  "linkNewTab": true,
  "toolbarFixed": true,
  **"limiter": 235**
}


execute Yii2 console command from Yii2 extension with Craft

ok, found out how this works:

it's not sufficient to composer-require the extension
it needs to be activated. for bizley/migration this is done via controllerMap in e.g. app.php (see documentation)
you can now create migrations for existing tables, but they are saved to Craft's vendor director (vendor/craftcms/cms/src/migrations/)
since this is not the right place, I manually created a migration via Craft's console command, copied the code from vendor/craftcms/cms/src/migrations/, removed the automatically created migration and pasted it into the manually created one.


How do I add commas to an output that returns a list of names?

You can use loop variables

{% set i = country|length %} // number of total items
{% set indexLast = i - 2 %}  // index of the last comma
{% for name in country %}
    {% if loop.last and i > 1 %} and {% endif %}{{ name.title }}{%if i > 2 and loop.index0 < indexLast  %},{% endif %}
{% endfor %}

Explanation:

if there is more than one item and it is the last iteration: add an and at the beginning
if there are more than 2 items (otherwise it's only one and) and the current loop index is smaller than count - 2 ( it should display nothing in the last iteration and only an and before the last)-> display a comma ,


Replace placeholder string in text field with HTML generated by Asset query

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.


How to Auto-Generate a Craft Commerce Product Title

You can generate the Variant titles automatically, but not for top level Product Types:


A browser will give that error by default when you try make an AJAX call from domain A to domain B.

In your particular case, it looks like you're loading the control panel from mydomain.com, but the live preview request (which comes from how you defined your Site URL under Settings->General) has www.mydomain.com in it.

Note the www.  A browser will treat that as an entirely separate domain.

If that's how you want it, great.  You need to modify your public .htaccess file (the one that sits next to Craft's public index.php file to allow the other domain via Access-Control-Allow-Origin.

Likely it's just a mistake though and you should correct the Site URL setting or access the control panel from the other domain.

It's also worth forcing one or the other (www redirect to non, or non redirect to www) via .htaccess for consistency and because search engines will treat them as one site.


Error when submitting Date Field from the front-end: cannot be blank

The input tag presented in the comments above does not appear to use the correct input tag format for the date field. To submit a date field on the front-end, your input fields need to be setup with the following name structure and value format:

<input type="text" size="10" name="fields[fieldHandle][date]" value="10/15/2012">
<input type="text" size="10" name="fields[fieldHandle][time]" value="6:12 PM">

Using your example field handle of child1DateOfBirth this would be:

<input type="text" size="10" name="fields[child1DateOfBirth][date]" value="10/15/2012">
<input type="text" size="10" name="fields[child1DateOfBirth][time]" value="6:12 PM">

To submit any field on the front-end of Craft requires that you use the right format for the input field you are submitting.  Assuming the field submits just fine from within Craft, one way to track down the format you need on the front-end is to use your browser's developer tools and look at the input tags for the respective field in the Craft control panel.

The Craft CMS Field Guide on Straight Up Craft is another resource that gives examples of all the different native Craft fields and examples of input fields for the front-end.

If things currently aren't working, consider trying to hard code these values and confirm that this works at all.  You'll then need to figure out how to get the respective datepicker you are using to format the selected data into the proper input format as described above.

I don't believe this is an issue with any specific form plugin being used.  In the case you wanted to use a dynamic date field with your form (instead of manually creating your form as you describe above), you could extend Sprout Forms and add support for a custom front-end field.


You have to set the criteria model's limit parameter to null and disable pagination.

'criteria' => [
    'group' => 'fullMembership',
    'limit' => null,
],
'paginate' => false,


Probably what you're seeing the the generic webserver 404 error page... which means there's something wrong with your server config, as its not sending 404's to Craft to handle.


You're asking a loaded question. When you mention memory, how exactly are you measuring that?

Site performance can depend on a few factors, including the hosting provider, the hardware, what Craft fields you're using, etc. Craft tends to hit the database a lot so if your connection to MySQL isn't good—say on a mediocre shared hosting provider—that's going to slow you down.  Using a lot of Matrix fields can really slow you do or if you're trying to fetch a lot of entries at once.

The best answer I can give without specifics—and the biggest win—is to do some caching with Craft's  {% cache %} tags.  Using the cache will cause Craft to look in its already generated output instead of multiple trips to the db.   Anything that has a  {% for %} loop block is likely going to generate a lot of db queries and is a good candidate for caching (like a navigation menu).

If you're already using caching, make sure you're doing it efficiently. Craft stores the output of the cache tag so you need to put the tags around things that actually output something—you can't cache variables.

For example:

{% cache %}
    {% set whateverEntries = craft.entries.section('whatever') %}
{% endcache %}

{% for theEntry in whateverEntries %}
...

... won't cache anything.  But this would:

{% cache %}
    {% set whateverEntries = craft.entries.section('whatever') %}
    {% for theEntry in whateverEntries %}
        <h1>{{theEntry}}</h1>
           {{theEntry.postExcerpt}}
         ...
    {% endfor %}
{% endcache %}


How to import entries from Craft 2 to Craft 3?

The typical way to do this would be to use something like https://plugins.craftcms.com/feed-me, where you could setup a feed of the data you want to export, map it to the proper fields in Craft 3, then import the data from a feed.


Craft throwing an SQL error on Save when Matrix field has a lightswitch


How do you replicate the EE {date_heading} tag pair in Craft?

Group:

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

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

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

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

.

Conditionals:

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

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

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

    {% set last_date = entry.date %}

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


This is not so much a Craft question as a web server question.

The directory structure of Craft is intended for the web server to have the public (or web in Craft 3) directory configured as the document root.

This is a configuration setting you’ll find in your Apache, Nginx or other web server documentation.


Issues with compiled_templates - call to undefined method

It is my bad. Thanks to Brad Bell, I went to check whether the macros were on both the staging and live servers. The macros existed on staging but not on live.


How do I loop through and access all sections of returned entries?

Entries to not have a getAllSections method. You can use the group filter to group your entries by their sections.

{% set entries = craft.entries.section(['inspirationArticles', 'pages', 'pressArticles', 'products']).search(searchQuery).order('score') %}
{% set grouped = entries|group('section') %}

{% for section, entriesInGroup in grouped %}

Section: {{ section }}

        {% for entry in entriesInGroup %}

{{entry}}

        {% endfor %}

{% endfor %}

Here's some documentation to help!


searching assets - using related entry slug

I have not tried this against a working database but based on something very similar this should work:

{% set matchingPhotos = craft.assets.folderId(5).relatedTo({
  targetElement: craft.entries({
    slug : 'example-photographer',
    section : 'photographers'
  }),
  field : assetsPhotographerField
}) %}

In reverse what you are doing is getting all the photographer entries that match that slug that are related to the assets field in that specific folder id...does that make any sense?!

You may need to swap targetElement out for sourceElement - I never know which way round it should be!


Element Actions for Entries being viewed from modifyEntrySources

The checkboxes will only show up if there is at least one available element action for the current source.

Element actions are defined by element types’ getAvailableActions() methods, which will vary their response based on the $source that is passed in.

In EntryElementType’s case, if an unrecognized $source is passed in, then no actions will be returned.

However, EntryElementType::getAvailableActions() does have a hook called addEntryActions, which gives plugins the opportunity to add additional actions to its response.

So on top of using the modifyEntrySources hook, you can also use the addEntryActions hook to provide the actions that your custom source should have.

public function addEntryActions($source)
{
    if ($source == 'myCustomSourceKey')
    {
        $elementType = craft()->elements->getElementType(ElementType::Entry);
        return $elementType->getAvailableActions('section:X');
    }
}

(Replace X with the ID of a section you want to mimic.)


A further requirement came up to change the Italian output (symbol moved to after the price rather than before) so I opted for a simple Twig extension:

/**
 * Wrapper for Craft's NumberFormatter->formatCurrency
 * Changes formats for French and Italian display
 *
 * @param        $value
 * @param string $currency
 *
 * @return string
 */
public function currencyDisplay ($value, $currency = 'GBP')
{
    $value = craft()->numberFormatter->formatCurrency($value, $currency);
    $localeId = craft()->locale->id;

    if ($localeId == 'fr')
    {
        $value = str_replace('£UK', '£', $value); // remove UK
    }
    else if ($localeId == 'it')
    {
        $value = str_replace('£ ', '', $value) . ' £'; // relocate sterling symbol
    }

    return $value;
}


The setting useXSendFile was set to true.  I changed this setting to false and everything works now.  Looks like this guide could help to get things working when this setting is set to true.


How can I have created data (id) returned for a GraphQL mutation?

As noted by yvanavermaet in the comments on the question, this is an issue with Craft. It's been fixed in 3.6.5.
Thanks!


Update:

Looks like changing the 'data' key is a bit more difficult I suspected.  We just released Element API 1.3.0 that exposes the internal $resourceKey necessary to change that value.

In your elementapi.php config file, something like this should work:

UPDATE: This is the final code that I used, and it works perfectly.

return [
    'defaults' => [
        'resourceKey' => 'manifest'
    ],

    'endpoints' => [
        'assets/data/assets.json' => [
            'paginate' => false,
            'elementType' => ElementType::Asset,

            'transformer' => function(AssetFileModel $asset) {
                return [
                    'id' => $asset->title,
                    'src' => $asset->url,
                ];
            },
       ],
    ]
];

The output you're seeing is defined by your craft/config/elementapi.php config file.

You can read about that configuration file and all of the available settings in the Element API documentation at: https://github.com/craftcms/element-api/tree/v1#setup


entry is available without query when templates are set in the CP, is this an acceptable method?

the simple answer is: yes it is an acceptable method!

In single sections or in a single entry of a structure or channel, this is totally fine.

You need the entries query if you want to do something like having a list of all recent blog posts on your homepage. So on your index.twig the "entry" object has got all data for the homepage, like title, url and all fields!

Example index.twig:

<h1>{{entry.title}}</h1> <---(the title of your site)

{% set blogPosts = craft.entries().section('blog') %}
{% for entry in blogPosts.all() %}
  {{ entry.title }} <---- (the title of a blogpost)
{% endfor %}


Force specific language for user activation mail and edit localized email templates

When using a frontend form to create a new user it is actually straight forward, because you can easily send a preferredLanguage attribute with the request that sets the language on creation (see this line in the user controller). However, if you want to use the CP form to create a user, there doesn't seem to be an out of the box solution for your problem. Here is what you could try:
There is a template hook in the user edit template. You could use this to inject an input that sets the preferred language. You could even show that input for new users only. In the simplest case it could look something like this:
<input type="text" name="preferredLanguage" value="de">

You surely would want to have a select or something with the available languages. To inject the markup into that template you would have to create a module or plugin and then follow the docs for template hooks.
PS: If you wonder where the user language is stored, it has an extra table called userpreferences storing stuff like this in JSON format.


what is the correct way to programmatically set checkboxes (MultiOptionsFieldData) in a migration? (solved)

Sleeping on it (and peeking at the db) provided a solution, with even simpler code:
$entries = \craft\elements\Entry::find()
  ->section('sectionProduct')
  ->all();

foreach($entries as $entry) {
  $entry->setFieldValue('distribution', ["1", "2"]);
  Craft::$app->getElements()->saveElement($entry);
}

where "1" and "2" are the values associated to the checkboxes.
If you know the checkbox values, use setFieldValue and pass them as an array:

[] (empty) no checkboxes selected
["single value"]
["multi", "values"]


May have answered on Stack/plugindev:

@sjelfull  was intrigued, so started reading code about this, until the thought occurred: you seem to be asking a front end instance to access a CP template? This shouldn't be allowed unless it was a CP or action request, no?  The setting to TemplateMode can't fail this way, must be in trying to use the template, and that may fall apart at line 904 of TemplateService.php, would think. I don't put it past you to have another clever idea, though :wink: -- Takk for de...


Why does the UserSessionService create a *state* cookie?

craft()->userSesssion->saveCookie() is basically a fancy wrapper for craft()->request->getCookies()->add() that (as you've discovered) does some key and value based hashing to ensure that cookie data hasn't been tampered with between requests.  Which is especially useful if, for example, cookies are used to maintain user session.

If that's not the behavior you're looking for, you can use PHP's setCookie method (like LJ Cookies and the Cookie plugin do) or you can interact with craft()->request->getCookies()->add() directly outside the context of the UserSesssion service.


Re-installing the Sprout Invisible Captcha plugin and including the following line before the closing tag got it working:

{{ craft.sproutInvisibleCaptcha.protect() }}


I'm not clear on what you're asking.

A user's cart is created as soon as they land on any page that has {% set cart = craft.commerce.cart %} in it; whether they are a logged in user or not. Carts are not attached to Users until the order is complete (and only if you were a logged in user). You can have a cart as a guest, add to it, then log in and you'll still have the same cart.

Are you saying that you want someone to fill out a cart, pay for it, complete the order - then be logged out immediately? Why? If they complete an order and then make another order it will already be a different cart.


Based on your example and description, it's a bit hard to tell whether you are dealing with a category template or an entry template, because in your description you say that the category handle is called 'media', but in the example you are grabbing entries in the section called 'media'.

Assuming you are on a category template (i.e. trying to create a category index page for example), then you should be able to just grab the current category from the 'category' variable (provided by craft), entries related to that category using relatedTo(category), and the next and previous categories from category.nextSibling and category.previousSibling (or category.next and category.previous depending on whether your categories are hierarchical). If so, then the following should work (not tested):

{# category template #}

{% set prevCategory = category.prevSibling %}
{% set nextCategory = category.nextSibling %}
{% set entries = craft.entries('mySection').relatedTo(category) %}

{{ category.title }}

    {% for entry in entries %}

{{ entry.title }}

...

    {% endfor %}

{% if prevCategory %}Previous {% endif %}{% if nextCategory %}Next{% endif %}

If you are dealing with an entry template (i.e. an entry detail page), then you may need to clarify the question a bit.


How can I filter selected/related entries by their categories?

Start by looping thru each category. Say, all categories in a category group called "eventsCategories." Then find entries related to each category (if any).

{# loop through each of the categories #}
{% for category in craft.categories.group('eventsCategories') %}

  {# find the exhibitor entries that are related to both the Event entry and category #}
  {% set categoryListings = craft.entries({
    section: 'exhibitors',
    relatedTo: ['and',
      { sourceElement: entry, field: 'myEntriesField' },
      { targetElement: category, field: 'myCategoriesField' }
    ]
  }) %}

  {# Only show this category if there were any related exhibitors #}
  {% if categoryListings|length %}

{{ category.title }}

    {% for listing in categoryListings %}

{{ listing.title}}

    {% endfor %}

  {% endif %}
{% endfor %}


Never too late to answer your own question.

This is easily resolved now as Craft 3 stores user photos as assets, you just need to assign the CDN URL to the public URL field in Assets.

https://docs.craftcms.com/v3/changes-in-craft-3.html#user-photos


How can I query entries based on a Matrix Block Type?

If you weren’t using Element API here, you could do this by adding a condition to the element query:

$query->andWhere(['exists', (new \craft\db\Query())
    ->from(['b' => \craft\db\Table::MATRIXBLOCKS])
    ->innerJoin(\craft\db\Table::MATRIXBLOCKTYPES . ' bt', '[[bt.id]] = [[b.id]]')
    ->where('[[b.ownerId]] = [[elements.id]]')
    ->andWhere(['bt.handle' => 'yourBlockTypeHandle'])
]);

But Element API doesn’t give you direct access to the query. I can think of a couple ways to pull it off, though.

Option 1: Implement a custom element query param.

You could define a new element query behavior class, which wraps that condition into a new hasBlockType param:

<?php

use craft\db\Query;
use craft\db\Table;
use craft\elements\db\ElementQuery;
use craft\events\CancelableEvent;
use yii\base\Behavior;

/**
 * @property ElementQuery $owner
 */
class ElementQueryBehavior extends Behavior
{
    public $hasBlockType;

    public function hasBlockType(string $handle)
    {
        $this->hasBlockType = $handle;
    }

    public function events()
    {
        return [
            ElementQuery::EVENT_BEFORE_PREPARE => [$this, 'prepare'],
        ];
    }

    public function prepare()
    {
        if ($this->hasBlockType) {
            $this->owner->andWhere(['exists', (new Query())
                ->from(['b' => Table::MATRIXBLOCKS])
                ->innerJoin(Table::MATRIXBLOCKTYPES . ' bt', '[[bt.id]] = [[b.id]]')
                ->where('[[b.ownerId]] = [[elements.id]]')
                ->andWhere(['bt.handle' => $this->hasBlockType])
            ]);
        }
    }
}

Then you’d need to register that behavior with new element query instances, from your module’s init() method.

\craft\base\Event::on(
    \craft\elements\db\ElementQuery::class,
    \craft\db\Query::EVENT_DEFINE_BEHAVIORS,
    function(\craft\events\DefineBehaviorsEvent $event) {
        $event->behaviors['my-behavior'] = new ElementQueryBehavior();
    }
);

Finally, from config/element-api.php, add this to your endpoint’s criteria array:

'criteria' => [
    'hasBlockType' => 'yourBlockTypeHandle',
    // ...
],
// ...

The advantage of going this route is that your new hasBlockType query param will be available everywhere, so you can reuse it from any element queries you’re writing in Twig or PHP.

Option 2: Use a custom Fractal resource class.

Element API allows you to define Fractal resource class using the class endpoint param.

Yours could extend the built-in ElementResource class, overriding its getElementQuery() method.

<?php

use craft\db\Query;
use craft\db\Table;
use craft\elementapi\resources\ElementResource;
use craft\elements\db\ElementQueryInterface;

class MyElementResource extends ElementResource
{
    public $hasBlockType;

    protected function getElementQuery(): ElementQueryInterface
    {
        $query = parent::getElementQuery();

        if ($this->hasBlockType) {
            $query->andWhere(['exists', (new Query())
                ->from(['b' => Table::MATRIXBLOCKS])
                ->innerJoin(Table::MATRIXBLOCKTYPES . ' bt', '[[bt.id]] = [[b.id]]')
                ->where('[[b.ownerId]] = [[elements.id]]')
                ->andWhere(['bt.handle' => $this->hasBlockType])
            ]);
        }

        return $query;
    }
}

Then from config/element-api.php, add this to your endpoint config (note that it would not go in criteria):

'class' => MyElementResource::class,
'hasBlockType' => 'yourBlockTypeHandle',
// ...

Option 3: Just use Preparse

If you only care about a single block type, and don’t really need this to be configurable, the simplest route would be to use the Preparse Field plugin, and actually store whether entries have the block type, as part of their entry data.

For example, if the handle of the Matrix block type you care about is text, then you’d create a Preparse field called hasTextBlock, with this template:

{{ element.myMatrixField.type('text').exists() ? '1' }}

Then resave your entries, and add this to your endpoint’s criteria array:

'criteria' => [
    'hasTextBlock' => '1',
    // ...
],
// ...


Image Transform to convert animated GIF to static?

Is this a one-off image or do you need to use the transform for a bunch of GIFs?

There's no way automated way to tap into transforms currently. (Craft 3 is going to be much better in this respect.)

The other hard part is you're probably going to want to specify what frame of the GIF to use. (Fun fact: years before browsers supported animated gifs, they would simply show either the first frame or the last frame.)

If it were me, I'd set the static frame manually using whatever method you want (Photoshop, Imagemagick/gd on the command line, etc.)

Then use a custom field on the asset to relate that static gif back to its animated counterpart.  Unlike in other CMS, this is where Craft really becomes powerful.


Nothing to see here. We had a corrupt index.

Running this command in the DB brought our searches down from 90 seconds to 1 or 2 seconds. I'd still love it to be faster. But we can live with 2 seconds:

optimize table searchindex;


Possible to have a single entry page with multilingual slugs and only one index.html?

What you're asking for is fine. Create a subfolder within your public directory for each locale with it's own index.php and define the new path to craft/ and the locale. For example, within public_html/fr/index.php you might have:

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

// Tell Craft to serve the FRENCH content
define('CRAFT_LOCALE', 'fr');

With the single, you set the slug yourself within the section's settings (one slug for each locale that section is available to).


How can I use    within a redactor/rich-text field?

There are keyboard shortcuts that can accomplish super and subscript.

From the Redactor changelog:

Superscript shortcut now crtl+h (high, super) instead of old ctrl+l
Subscript shortcut now crtl+l (low, sub) instead of old ctrl+h


Is there a way to convert a Craft MySQL database to PostgreSQL?

First, I'm glad you've realized what a mistake you made.
There's not a fool-proof way to do this, other than to do a fresh installation of Craft using PostgreSQL and migrate the content over.
There is a tool called pgloader that purports to be able to convert a MySQL/MariaDB database into PostgreSQL and it gives it the old college try.
My experience is that it works a good 70% of the time depending on things like environmental configurations and the size/complexity of the original database, so here's hoping luck is on your side.
Be sure and check their issues if you run into any errors.
Make backups. YMMV. UAYOR. Test the #@*! out of the resulting database.

What You’ll Need

An existing Craft CMS install that uses MySQL or MariaDB
Running MySQL and PostgreSQL servers, and the DSN for each
pgloader

Steps

Download and install pgloader. If you’re on a Mac, you can use brew install pgloader.

Save and customize a local command file* for pgloader:
LOAD DATABASE
    FROM mysql://root:root@mariadb/craft3
    INTO pgsql://craft3:secret@postgres/craft3
    WITH quote identifiers
CAST type datetime to timestamp
ALTER SCHEMA 'craft3' RENAME TO 'public'

AFTER LOAD DO
    $$ ALTER TABLE craft_searchindex ADD COLUMN keywords_vector tsvector; $$,
    $$ UPDATE craft_searchindex SET keywords_vector = CAST (keywords as tsvector); $$,
    $$ ALTER TABLE craft_searchindex ALTER COLUMN keywords_vector SET NOT NULL; $$
;

This one assumes your MySQL username and password are root, the host is mariadb, and the source database is craft3. The PostgreSQL username and password are craft3 and secret, the host is postgres, and the target PGSQL database is craft3.
Be sure to adjust the  craft_ table prefix to match whatever you’re using on your MySQL database.
If you need to specify a port for either DSN, append a colon and that number to the hostname. (For example, specifying port 3306 for mysql would become mysql://root:root@mariadb:3306/craft3).

Tell pgloader to read the MySQL database into PostgreSQL:
pgloader /path/to/command-file

Example conversion output, which includes useful stats and warnings.

*Why use a command file?
You could run pgloader mysql://root:root@mariadb/craft3 postgresql://craft3:secret@postgres/postgres/craft3, but column names would all be lowercased, some critical type conversions and search index updates would be missing, and using a password in any terminal command is usually a bad idea since it will be visible in that shell’s command history.


Sounds like you probably have a stuck or error'd "Delete Stale Template Cache" task.

You can tell if a task is stuck because there will be a circular progress bar in the upper-right hand corner of the CP that isn't progressing.

If it error'd, it will be red and you'll have the option to re-try it.

Regardless, here's the general troubleshooting steps necessary for both cases: http://buildwithcraft.com/help/stuck-tasks


Tag Localization: how to create a tag without translation fallback version?

OK, so this isn't quite how i expected it to work, but it does so far. I won't post code, because you just need the right process:

Assuming you're creating tags for a dual locale site of English (en) and Spanish (es)

Create a TagModel for first locale (en)
Set attributes and content for first en version
Save it
Load a new instance of a TagModel by loading the tag you just saved by id, but specify the other locale.

$tag_es = craft()->tags->getTagById($tag_en->id, "es")

Assign the es title, content and attributes (regenerate the slug, too!)
Save the es tag with

tags->saveTag($tag_es)

Now, Tag Manager should keep them separated by locale, and you can query them by locale, too.

The bottom line is, you have to create alternate locale versions by essentially cloning the original Tag Model while specifying the new locale string, then reassign the content and just save it. Again, not what I expected.

EDIT: Check your results in the database. Don't believe the Tag Manager — it only shows data from one locale for some reason.


Is it possible to upload a zip file via Assets?

Yes, you can upload zip files from the main Assets table in the control panel as well as from an Assets field type assuming 1) you haven't removed 'zip' from the allowedFileExtensions config setting and 2) you haven't restricted the allowed file types in the field's settings.


(Apache) pages only load when adding index.php?p=

Disabling the omitScriptNameInUrls config option makes it work. Not sure if this is a "solution" though


Or you could just use an existing seeding plugin like A&M Seed. :)

Even if it does do exactly what you're looking for, you can use it as a starting point for your plugin.


How can I create a template macro within my plugin for use within front end templates?

I'm not aware of this being possible. The control panel uses a different template path than the front end. This makes plugin templates generally inaccessible. One possible option is to create a template variable that runs a macro or renders a template on behalf of the user. Something like:

{{ craft.pluginHandle.macro(arguments) }}

You will need to make sure that the template path is set to the Control Panel so that your macro can be found, and that it's set back afterwards. At the start of the function set this:

craft()->path->setTemplatesPath(craft()->path->getCpTemplatesPath())

Then when you are done rendering your macro (preferably to a variable to return later), you set it back:

craft()->path->setTemplatesPath(craft()->path->getSiteTemplatesPath())


Localized Environment Variables Based On siteUrl?

I also set up those two environment variables (totally custom variables, with the one specialty that they are passed to the CP)
for my multilibgual sites.

But I have both basePath and baseUrl combined for all my locales!

'.dev' => array(
    'siteUrl' => array(
        'en' => 'http://local.mysite.dev/',
        'fr' => 'http://local.mysite.dev/fr/',
    ),
    'environmentVariables' => array(
        'basePath' => '/path-to-mysite/public/',
        'baseUrl' => 'http://local.mysite.dev/',
    )
)

I use these variables for two things:

Make assets from local asset sources available to all my locales. I set them absolutely, because relative paths don't
do it in this case, as the path to the assets' folder and the URL is a different one from http://example.com/fr/ as it is from http://example.com/.
Build absolute URLs to static files from my templates, e.g.
<link rel="stylesheet" href="{{ craft.config.environmentVariables.baseUrl }}stylesheets/site.css" />
Both, the url() function and the siteUrl variable don't work in this case, they always return the site's URL including the locale part.

So it's basically just a way to build absolute URLs to Craft assets and files for me.

I'm actually not totally sure how much of this could be solved with root relative paths, but in my case I've also
at least one environment where the path from web root to the craft site is differently to my other environments.

(For testing sites on mobile devices where I can't set virtual domains, I have an environment to access the site via the
local machine's IP address. As there's multiple sites on that machine, they are all in subfolders under web root.)


Ok, I managed to figure it out following directions on this page:
Creating dynamic array and set keys

{% set filmData = { "film" : film.title, "url" : film.url, "starts" : starts, "ends" : ends, "length" : film.length } %}

{% if not attribute(screeningsForTheater, screening.theater.label) is defined %}

    {% set screeningsForTheater = screeningsForTheater | merge({ (screening.theater.label) : [filmData] }) %}

{% else %}

    {% set otherFilms = attribute(screeningsForTheater, screening.theater.label) %}
    {% set otherFilms = otherFilms | merge([filmData]) %}
    {% set screeningsForTheater = screeningsForTheater|merge({ (screening.theater.label) : otherFilms }) %}

{% endif %}

EDIT

However I realized I had to create another level to the array by including the date of the screening. This was the format needed:

screenings = {
  "22.3.2018" : {
    "Theater 1" : {
      "Movie 1" : { ... },
      "Movie 2" : { ... }
    },
    "Theater 2" : {
      "Movie 3" : { ... },
      "Movie 4" : { ... }
    }
  },
  "23.3.2018" : {
    "Theater 1" : {
      "Movie 5" : { ... },
      "Movie 6" : { ... }
    },
    "Theater 2" : {
      "Movie 7" : { ... },
      "Movie 8" : { ... }
    }
  }
}

I spent some time trying to create this kind of array using twig, but couldn't get the merge to work correctly.

I then created a plugin and a templateVariable to do the search and array stuff using PHP, which was a lot more comfortable, and got this working in no time.


Craft 3 - Twig search query for entry with custom EntriesField containing disabled entry

The search parameter only searches the element that is the subject of your element query (i.e., the source entry) - it does not search related entries. For that you need to use the relatedTo parameter. (I'm not sure why you're getting a successful result for the November entry - perhaps the source entry also has the word November in it somewhere?).
Additionally, you'll need to use the anyStatus parameter to fetch expired entries.
So to pull this off, you'll need to conduct the search against the other section and then find related entries, i.e.:
{% set sectionBEntryIds = craft.entries.section('SECTION-B').search(searchParam).anyStatus().orderBy('score').ids() %}

{% set sectionAEntries = craft.entries.section('SECTION-A').relatedTo(sectionBEntryIds).all() %}


Undefined property when using cacheMethod = db

Solved. The client was using something called Samba Share on their server and that didn't work well with permissions. They changed servers and it was solved.


This was a separate issue causing this, the above works fine.


Sending E-Mails via SMTP with email address that contains special characters

After endless try and error I finally got it work. I used the ACE version of the email address e.g.
client@clientwithö.de -> client@xn--clientwith-ncb.de

Although I tried this at the beginning it is working now and I do not know what changed the result. :)


Are there any poll plugins for Craft CMS?

The only public listing of plugins that I'm aware of is on the straightupcraft site — so if nothing is there that meets your requirements then probably not. New plugins are getting added all the time though.

Depending on your requirements, developing a custom solution would probably not be too difficult though. If you want to give it a shot and have questions feel free to ask.


Get all Categories with getGroupById in Element API plugin - Craft 3


Hyperlinks in blog are not showing underlined

Hyperlink styles are defined in you stylesheet (CSS).

Applying the underline text-decoration property like so:

text-decoration: underline;


validationKey on load balanced enviornments

It should be the same for every server in the load balanced environment.

You should also set the appId config setting to a consistent value for every server in the cluster as well.

I've updated the documentation for those config settings to clarify.


Unsure whether to use Sprout Forms or code forms regularly

Sprout Forms offers you a lot of the same functionality as standard Craft Entries. Both Sprout Forms and Entries allow you to create front-end forms that allow users to submit data to the database. Here are a few thoughts on why you would choose one over the other to manage content that requires front-end forms. None of these reasons are absolute, so take them with a grain of salt for your own situation (and happy to modify this list if anybody has feedback in the comments):

Craft Entries

You want your submitted data to be managed alongside your other content on the Entries tab in the Craft Control Panel
Your submitted data has the concept of an "author" and can be related to a user in your database
Your submitted data has any other concepts that are specific to Entries, such as Post Date or Expiry Date
You want to manage the HTML for all of your forms and fields in your templates

Sprout Forms

You want to allow form submissions by anonymous users who are not logged into your website
You don't want all of your form data cluttering up the Entries area where you manage the primary content of your website
You want to create multiple, similar forms with variations on fields (such as creating a new form with slightly different fields to test a landing page)
You just want a backup of a submitted form in the database (the primary workflow will take place via a notification email that gets triggered when a form is submitted)
You want to be able to easily output your form in your templates dynamically (Sprout Forms handles all of the front-end code for you – including error states – with a single line of code). In addition, the base templates it uses to output the form can be customized using Template Overrides to meet your website design requirements.

Can Sprout Forms handle all of your requirements? Yes, however there are a few items worth mentioning as they may involve other Sprout plugins or custom development. I'll go into detail below.

10 unique forms with about 30 fields each

Sprout Forms can handle as many fields as you need. And makes it easy to output them in your templates without having to create all the necessary HTML by hand using the displayForm, displayTab or displayField tags.

One field will be Users Field Type (or another way to choose up to 3 users)

Currently, we support three relations field (Entries, Categories, Tags). Adding support for the Users Relation field would be possible via a custom integration (mostly just copying one of those existing custom fields), or reach out and we may be able to add this to the core plugin. We held off on adding Users at this point as we wanted to get better feedback on how it would be used to know how to implement it best.

Front end forms will allow guests and logged in members to fill out

Any user can fill out a form. If you want to capture information about a logged in user, you can pass the information you want to track to a field in your form. Sprout Fields has two fields that are helpful for this, the Hidden Field and the Invisible Field.

Back end admin will edit submitted entry form and fill out admin only fields which are hidden on front end

Admins can edit the form via the Craft Control Panel. You can hide fields from displaying on the front-end in several ways. The Hidden or Invisible field give you some basic ways to do this, however are more for capturing values that are not visible to the user on the front-end.

Another way is to use Rendering Options which allow you to customize the id or class names of particular fields as they are dynamically output.  You could, for example, add the class name of hidden to the fields you don't want displayed on the front-end and either supress their visibility or remove them from the page with javascript.

A final way would be to create a custom field that behaves exactly how you need it to.

Ideally be able to conditionally display certain fields on the front end based on selections made by the person filling out the form (example: if person selected "Apple" choice in question 2, then show sub choices "gala", "Granny Smith". If person selected "banana" choice in question 2, then don't show any sub choices)

This is going to be your most challenging item with both Craft Entries and Sprout Forms. You will likely have to write some custom javascript to get this behavior to work, and you'll have to keep this code in mind if you ever update your fields or naming conventions as the code on the page will probably only know what you tell it about how you have things setup in your database.

The easiest place to start here will be to see if you can target the default IDs output on your fields and add the behavior you need to them. If you need more customization of the class names for your code, Template Overrides and Rendering Options give you a lot of flexibility in how you structure your code for your needs.

There are probably several other approaches that can be taken here based on your specific use case so it would be best to talk this through with a developer who knows your project requirements well.

Form field content will need to be searchable so info can be displayed on front end template (show user how many forms he submitted, show field content based on date period)

Sprout Forms Form Elements and Sprout Forms Form Entry Elements (the user submissions in Sprout Forms) use Craft's Element Type API and are searchable in the same way that all Craft Elements are searchable.

You would need to be sure you are capturing the right user information in your form entries to perform the searches your require such as the userId. Sprout Forms captures date information about when a submission is created and modified.

Need to be able to create and display different reports on all 10 forms on a front end page (possibly export to csv too)

Sprout Reports is designed to work closely with Sprout Forms for your custom reporting needs. Out of the box, Sprout Forms has one report integration that lets you run a report on all of your submitted entry data. However, we purposefully de-coupled Sprout Forms and Sprout Reports to allow more customization for your reporting.

Sprout Reports enables you to create custom reports that provide different views into your Form data, add additional columns to your reports such as related user data, and customize what options an admin user has to select from when running a report.

Custom reports do require a developer to set them up, but they are very flexible and fairly easy to implement once you have clearly defined what you need. Please reach out to the Sprout Team if you have any questions on how these work or how to set them up.

All reports are exportable via CSV.


Because extraEntries is not an array of elements but an object of type EntryQuery in order to fetch the entries you have to do

{% set extraEntries = craft.entries.section('events').relatedTo(category).orderBy('startDate asc').offset(3).all() %}

It was actually the same in Craft 2 but the class had an iterable and countable interface, so when you do |length it actually does .total() (to execute the command and fetch the number of rows) These automatic mechanisms are removed/deprecated now thus you have to know what kind of object you use

When you take a look at your cp you'll see a bunch of deprecated warnings.

I suggest you to read the docs


Building a DbCommand to compare two columns on Variants

Completely untested, but this should return all variants whose price column's value is less than your custom field's originalPrice value.

$results = craft()->db->createCommand()
    ->select('v.*')
    ->from('commerce_variants v')
    ->join('content c', 'v.id = c.elementId')
    ->where('v.price < c.field_originalPrice")
    ->queryAll();


Sprout Forms: gather data from the page a form is on

You're understanding the purpose of the Hidden and Invisible fields correctly and your desired workflow is possible.

Let's step through each part:

Hidden and Invisible Fields

These fields allow you to capture values on the page that the user doesn't see.  This includes any variable available to the page your form is being submit on. The key thing to note is that by default, all variables may not be available and for some variables, you will have to take an extra step to make them available.

By default, the only dynamic variables available to the Hidden and Invisible fields are variables that are global in scope like {{ craft.request.path }} or something like that.  To make an entry variable available, you will need to use the addFieldVariables tag on your page:

{# This line makes the entry variable available to your
   Hidden and Invisible Field settings. #}
{% do craft.sproutForms.addFieldVariables({ entry: entry }) %}

{# After you use addFieldVariables, you can display your Form as normal #}
{{ craft.sproutForms.displayForm('contact') }}

With the code above in place, you can now use any values that you want from the entry in your Hidden or Invisible Field Settings like {{ entry.title }}, {{ entry.postDate|date('Y-m-d) }}, {{ entry.excerpt }} or even loop through an array of data like Entries or Users, just like you would in your Twig template (as long as your final value can be stored in a PlainText field.

Dynamically access form data with Sprout Email

To send this information in a notification email, you'll first need to setup a new Notification in Sprout Email and select the rule "When a Sprout Forms entry is saved".

When your form is submitted, your Sprout Email template will have your entire SproutForms_Entry object and all of the submitted fields available to it via the object variable.

So, while your entry values were available to your form as:

{{ entry.title }}
{{ entry.postDate|date('Y-m-d) }}
{{ entry.excerpt }}

They will be available dynamically to your email template as:

{{ object.title }}
{{ object.postDate|date('Y-m-d) }}
{{ object.excerpt }}


Go with #1.  It looks like you've already got a Portal_CodeModel created, you just need to populate them from the controller, perform validation (if any), then pass the array of Portal_CodeModel objects to your service.

You'll want to remove the Portal_CodeModel type hint from your service's addCodes signature (or change it to array) since you're passing in an array of objects, instead of a single one.

Here's an example in your controller with any code validation:

$codeModels = array();
$codes = explode("\r\n", craft()->request->getPost('codes'));

$success = craft()->portal_code->addCodes($codes);

And in your service:

public function addCodes($codes)
{

    foreach($codes as $code)
    {
        $existingCode = Portal_CodeRecord::model()->findByAttributes(array(
            'code' => $code,
        ));

        if ($existingCode)
        {
            $existingCode->code_used = 1;
            $existingCode->save();

            {# or whatever else you want to do when the code already exists in the database #}
        }
        else
        {
            $codeRecord = new Portal_CodeRecord();
            $codeRecord->code = $code;
            $codeRecord->code_used = 0;
            $codeRecord->save();
        }
    }

}


What does defaultTokenDuration affect besides hidden entries' share links?

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.


Solspace Freeform query for submission assets returns all site assets

The following template code resolved this issue for me:

{% for field in submission.fieldMetadata %}
     {% if field.type == "file" %}
        {% set assetIds = attribute(submission, field.handle).value %}
        {% if assetIds %}
           {% for assetId in assetIds %}
              {% set asset = craft.assets.id(assetId).one() %}
              {% if asset %}
                 {% if asset.kind == "image" %}

                 {% else %}
                    {{ asset.filename }}
                 {% endif %}
              {% endif %}
           {% endfor %}
        {% endif %}

     {% else %}
        {{ attribute(submission, field.handle) }}
     {% endif %}
{% endfor %}


Is it possible to make links open in a new tab by default?

Merits of doing this aside, I agree that JS is probably the easiest way to go here.

This code adds target="_blank" to all external links.

// Make sure any offsite links (non js/mailtos) open in a new window
// from https://css-tricks.com/snippets/jquery/open-external-links-in-new-window/ - comment at end.
function openAllExternalLinksInANewWindow() {
    $(document).on('mousedown', 'a:not([href*="mailto:"],[href*="javascript"])', function(e) {
        var isInternalLink = new RegExp('/' + window.location.host + '/');
        if (!isInternalLink.test(this.href)) {
            $(this).attr('target', '_blank');
        }
    });
}


Craft equivalent to EE snippets for use in templates?

Craft uses Twig, and Twig uses macros for reusing snippets of code within templates.

In your macro file (for instance, macro/userMacro.html), you can create a macro:

{% macro hairColor(user) %}
    {{ user.hairColor }}
{% endmacro %}

Then, in any other file (or in your main _layout template, for that matter), you can import and use this macro:

{% import "macro/userMacro" as userMacro %}

{% for user in craft.users %}
    {{ userMacro.hairColor }}
{% endfor %}

Place your import-tag at the top of your _layout file, and you will be able to use it in every template that extends it (or is included by it).


Is using craft.config to access siteUrl possible?

Yes, if you set up proper multi environment configs, this isn't very hard. My config/general.php file usually look something like this:

return array(

  '*' => array(
     // some general settings here
  ),

  'mydomain.craft.dev' => array(
    'environment' => 'local',
    'devMode' => true,
    'useCompressedJs' => false,
    'siteUrl' => 'http://mydomain.craft.dev/',

    'environmentVariables' => array(
      'fileSystemPath' => $_SERVER['DOCUMENT_ROOT'] . '/../',
      'publicRootPath'    => 'public/'
    ),
  ),

  // staging and other environments here

  'mydomain.com' => array(
    'environment' => 'prod',
    'devMode' => false,
    'useCompressedJs' => true,
    'siteUrl' => 'http://mydomain.com/',

    'environmentVariables' => array(
      'fileSystemPath' => '/path/to/system/root/',
      'publicRootPath' => 'html/'
    )
  )

);

Then, to only include the GA tracking tag when I'm on the prod server, I include this in my html head:

{% if craft.config.environment=='prod'  %}
  <script>
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-XXXXXXXX-X', 'auto');
    ga('send', 'pageview');
  </script>
{% endif %}

You could of course check siteUrl instead, but I prefer to use something a little more abstract. Just in case the siteUrl changes.


Is there a way to force Craft to notice a new license key?

Clearing the Craft storage/runtime/cache folder will force the license refresh.
Licensing info is stored for 24 hours at a time.
It's also worth double-checking that you definitely have the correct license installed in /config/license.key and specify the correct domain in your Craft ID account.


Is there an option to edit title-parameter for Links in Redactor?

There's currently no out-of-the-box way with Redactor, other than to open the HTML source view and adjust the <a> tag manually to be something like <a href="yourlink" title="yourtitle">.

All Redactor settings regarding links can be found here: http://imperavi.com/redactor/docs/settings/links/


Eager loading of reverse related elements?

Isn't eager loading the wrong idea here, since categories do not have a property anyway, which automatically points to entries assign to this category?

Let's take 2 samples:

Sample #1: behavior like lazy loading (one entry query per category)

{% for category in categories %}
{% set entries = craft.entries...relatedTo(category)
{% endfor %}

Sample #2: behavior like eager loading (one entry query for all categories)

{% set entries = craft.entries...relatedTo(categories)

Now the only trick is to sort the entries in a way that they are easy accessible from each category in the {% for category in categories %} loop.

Or should't Craft automatically cache the loaded categories and therefor make accessing them from the entry fast after having executed the Sample #2 query?

What I mean is that it would not become faster, only more comfortable if this eager loading was possible.

Only ideas...


Is it possible to change one segment of the current url and keep the rest of it the same in a cleaner way?

So!!!! I was getting confused about the various craft properties pertaining to urls, and I thought that even if I grab the path, that it would include the region segment, but surprise! {{ craft.request.path }} grabs the remaining portion of the url, after the region segment! So, I can use code that I've written above and I only need to add:

<!-- language: lang-twig -->

    /{{ craft.request.path }}

Example:

<!-- language: lang-twig -->

    <form action="" name="dropdown">
        <select name="country-select"  id="country-select" class="form-control" onchange="location = this.value;" autocomplete="off">>
            {% set locales = craft.i18n.getSiteLocaleIds() %}
            {% set locale = craft.locale %}
            {% for loc in locales %}
                {# checking if current loop has active locale #}
                {% set isHome = (loc == locale) %}
                {% if isHome %}

                    {% if loc == "en" %}
                        <option value="/{{ loc | replace({'en': 'eu'}) }}/{{ craft.request.path }}" selected>Europe</option>

                    {% else %}
                        {% set subTags = locale|split('_') %}
                        {% set territory = subTags|length > 1 ? craft.i18n.getLocaleData(craft.locale).getTerritory(subTags|last) : '' %}
                            <option value="/{{ loc | replace({'en': ''}) | trim('_') }}/{{ craft.request.path }}" selected>{% if territory %}{{ territory }}{% endif %}</option>

                    {% endif %}

                {% else %}

                    {% if loc == "en" %}
                        <option value="/{{ loc | replace({'en': 'eu'}) }}/{{ craft.request.path }}">EU</option>
                    {% else %}
                        <option value="/{{ loc | replace({'en': ''}) | trim('_') }}/{{ craft.request.path }}">{{ loc | replace({'en': ''}) | trim('_') | upper }} </option>
                    {% endif %}

                {% endif %}

            {% endfor %}
        </select>
    </form>

Yay!! I wanted to share my answer because I've been working on this issue for a few days and couldn't find a solution anywhere. Maybe it will help someone else that runs into this issue when building a multi-country website with Craft. Cheers!


For anyone looking to do this on Craft 3, I used pThumb previously, but I created a plugin specifically to do this for Craft 3 - https://github.com/bymayo/craft-pdf-transform

It takes Asset PDF files and coverts them to JPEG / PNG files automatically when they are uploaded.

Or, do theres a Twig method that lets you convert the PDF to an image if the image already exists in Assets. But this can be a bit labour intensive on the server to do when a template is rendering so is only advised for small files.


How do I view / output the gateway response message?

Best to do this in your business logic plugin really, rather than in templates I'd say.

(You probably don't want to be passing this through to templates generally.  That said, you could easily add a template variable to this approach I guess...)

Here's some example code - and note what you get back will vary greatly depending on the gateway, so make sure you use defensive code like array_key_exists etc.

If you set an http session var, you can then retrieve this using a template variable:

    // Save the Beagle Anti-Fraud Score to the order
    craft()->on('commerce_transactions.onSaveTransaction', function ($event){

            $transaction = $event->params['transaction'];
            $order = $transaction->order;

            // Transactions are saved before responses too....
            if($transaction->response){
                craft()->httpSession->add("gatewayResponse", $transaction->response);
                BusinessLogicPlugin::log($transaction->response);

                //example of saving some of this data to a custom field in the order if you want to hang on to any of it...
                if (array_key_exists("BeagleScore",$transaction->response)){
                    $score = (string) $transaction->response['BeagleScore'];
                    BusinessLogicPlugin::log($score);
                    $order->setContentFromPost(["beagleScore"=>$score]);
                    BusinessLogicPlugin::log(craft()->commerce_orders->saveOrder($order));
                }
            }
     });

Then, to set it up as a template variable, something like this will work:

class YourPluginVariable
{
    public function gatewayResponse() {

        $return = "";
        $gatewayResponse = craft()->httpSession->get("gatewayResponse");

        if($gatewayResponse)
            $return = $gatewayResponse;

        craft()->httpSession->remove("gatewayResponse");

        return $return;
    }
}


Require password from current user on front-end form?

You'd create a Craft plugin with a controller that has an action, say actionSaveForm().

Your controller would look for a password POST variable and if that existed, validate that against the currently logged in user's account to make sure it was a match.  If so, continue onto Craft's saveUser or saveEntry, etc. (whatever you're using the form for, otherwise, return a validation error message.

Roughly like this:

public function actionSaveForm()
{
    $this->requirePostRequest();
    craft()->userSession->requireLogin();

    $password = craft()->request->getRequiredPost('password');
    {# grab anything else you need from POST #}

    $currentUser = craft()->userSession->getUser();

    if (craft()->users->validatePassword($currentUser->password, $password))
    {
        {# saveEntry, saveUser, etc. then redirect #}
    }

    // Invalid Password
    craft()->urlManager->setRouteVariables(array(
        'error' => "Invalid Password"
    ));
}


"An unknown error occurred." appears when I try to log into Craft's admin using browsersync's proxy mode

Forgot about this question!
I've since solved it by using a different approach.

Now I'm injecting the broser-sync script via its config, avoiding injection if the url is '/admin/', and redirecting to :8000 if '/admin/' is visited from :3000

Here's my whole working browser-sync.js config file, for those few other souls searching for something similar:

Note: I'm auto-injecting the webpack dev build with this config as well.

const sync = 3000
const script = 'browser-sync-client.js'

const php = 8000
const webpack = 1337
const adminPath = '/admin/'
const address = require('ip').address()

module.exports = {
    port: sync,
    proxy: {target: `${address}:${php}`},

    files: [
        'source/layout.twig',
        'source/pages/*.twig',
        'source/components/*.twig'
    ],

    ui: false,
    open: false,
    notify: false,
    ghostMode: false,
    socket: {clientPath: ''},

    logLevel: 'info',
    logPrefix: 'Browser-sync',

    watchEvents: ['change', 'add'],

    rewriteRules: [
        {match: /<\/head>/i, fn(request, result, match) {
            return `<script src="http://${address}:${webpack}/build.js"></script>` + match
        }}
    ],

    snippetOptions: {
        ignorePaths: adminPath + '*',
        rule: {
            match: /<\/body>/i,
            fn(snippet, match) {
                return `<script src="http://${address}:${sync}/${script}"></script>` + match
            }
        }
    },

    middleware: [function(request, result, next) {
        if (request.url.startsWith(adminPath)) {
            result.writeHead(301, {Location: `http://${address}:${php}${request.url}`})
            result.end()
        } else {
            next()
        }
    }]
}


If I understand correctly you can check for available variants, then output whatever detail you need for the items. Something like this should get you started:

{# Check there are variants #}
{% if product.variants|length %}

  {# Loop through the variants #}
  {%- for purchasable in product.variants -%}

    {# Check the variant is available #}
    {% if purchasable.stock <= 0 and purchasable.unlimitedStock == false %}

      {{ purchasable.description }}
      {{ purchasable.salePrice|commerceCurrency(cart.currency) }}

    {% endif %}
  {%- endfor -%}

  {% else %}
    {{ "Out of Stock"|t }}
  {% endif %}

{% endif %}

If you want to target only a specific variant you can refer to it directly using either its title (slug) or its variant ID, e.g.:

{% set variants = craft.commerce.variants.id(8376).first() %}

You can find more detail in the docs for the Variant Model and the docs for Craft Commerce Variants.


Image Transforms: Is there a way to detect portrait or landscape?

The best way would be to use the Fit image transform.

Set the transform to 'Fit' and set both your width and height values to 1000px. That way the image will continue to scale until the first longest edge reaches 1000px.


craft.entries isn't going to like a variable in the start or end dates.

i.e. your startDateParam should just be {% set startDateParam = yearParam ~ '-01-01' %}

And then your craft.entries is going to grab everything between the two dates.

If you're trying to grab everything that overlaps the year ends... I suspect you're going to have to do a little bit of funny business...

e.g. start date = a month before the year end, and end date is a month after the end date.

then when you do the loop, have it check both.

If start date is before the end of the year OR the end date is after the beginning of the year.

Then show all the items that meet that criteria. So if there's an event dec 12-13, 2015, the loop picks it up, but your if-check hides it. If it runs dec 30, 2015 to jan 2, 2016, the if-check shows it.

Maybe something like

{% set startDataParam = date_modify('November 1, ' ~ year-1 ~ ' 00:00:00') %}
{% set endDateParam = date_modify('February 28, ' ~ year+1 ~ ' 23:59:59') %}

{% set pastEntries = craft.entries({
 startDate: startDateParam,
 endDate: endDateParam
}).section('events').order('endDate desc') %}

{% for pastEntry in pastEntries %}
{% if pastEntry.startDate => date_modify('January 1,' ~ yearParam ~ ' 00:00:00') or pastEntry.endDate <= date_modify('December 31,' ~ yearParam ~ ' 00:00:00')}
  {{ all your event details here }}
{% endfor %}

That make sense?


Removing headers from blog post "excerpts" (using Hacksaw)

You could use the Twig replace filter with a regular expression, this'll remove the tag and it's content.

{{ entry.body | replace('/<h([1-6])>.*?<\\/h([1-6])>/', '') | raw | hacksaw(chars='300',allow='<p>', append='...') }}

The only limitation is regular expressions aren't fantastic with nested html tags, so your mileage my vary!

You might need to play around with the Regex a bit if you want to just limit it to a few headings, this will strip all h1, h2, h3, h4, h5, h6. You also might not need the | raw filter, it seemed to escape everything after the replace when I quickly tested it.