What are the issues with adding Craft Commerce to an existing Craft CMS site?

You should absolutely use Craft Commerce to store the products, as there is no migration from Entries -> Craft Commerce products.

You don’t need to pay for a Craft Commerce license if you are not utilizing a payment gateway, so there is really no downside to getting things into Commerce in the first place, and plenty of downside to needing it and not having it already in Commerce down the road.


Could this maybe be a unicode issue? Maybe the api plugin is producing \u2019 instead of the unicode to produce a normal '


Using the required field validation in custom element types/plugins?

Custom field validation happens automatically for you when you pass your element into craft()->elements->saveElement(). That function will return true or false, largely depending on whether custom field validation passes.

See EntriesService::saveEntry() for an example.


Query Entry Using multiple custom Fields Element API

getPost() will search the request’s POST data, but you are setting the parameter values as query string params, so you should be using getQuery().

'studentNumber' => craft()->request->getQuery('studentNumber'),
'email' => craft()->request->getQuery('email'),


Matrix loop (nesting?) issue using switch

I'm not entirely clear what your Matrix blocks/fields are setup like, so it's a little hard to tell what's going on here.

But I'm going to take a stab at it.

Your outer loop is looping through all the blocks in the calendarGroup Matrix field.

Then you're using a switch to determine which piece of code to execute based on which one of the two block types each block is.

All that looks ok.

But here is I think where your problem lies:

{% for entries in entry.calendarGroup.type('events') %}

{% endfor %}

This loop is starting fresh and looping over all the Matrix blocks in the calendarGroup Matrix field, except this time it's only getting the blocks of the event block type.

Then, inside that loop you are using the {{ block.fieldName }} variables again. But block is set in your parent loop. And nowhere are you referencing entries from your inner loop.

So there is a mismatch in your logic. I think you can simply do away with the inner loop, it's it's going to out put all of the event blocks inside each event block in the outer loop.  That, to me, seems like the issue.


To set a related category (or any other kind of element) you will want to pass an array of categoryIds (elementIds) — even if, as in this case, there is only one category or element. You can either set the ID as a static value if it's predefined or dynamically look it up based on the title, slug or any other unique element attribute.

$criteria = craft()->elements->getCriteria(ElementType::Category);
$criteria->title = 'Hotel';
$accomodationTypeCategory = craft()->elements->findElements($criteria);

$entry = new EntryModel();
$entry->sectionId = 3;
$entry->typeId = 3;
$entry->authorId = 1;
$entry->enabled = true;
$entry->getContent()->setAttributes(array(
    'title'             => 'Test Entry',
    'body'              => 'Testing',
    'address'           => '101 Silver Avenue',
    'phone'             => '0209900292092',
    'websiteAddress'    => 'www.example.com',
    'towns'             => 'Newy',
    'accommodationType' => array(
        $accomodationTypeCategory[0]->id
    )
);
craft()->entries->saveEntry($entry);


Craft assets indexing wants to remove files that still exist

This has happened to me in a couple scenarios:

When I am working across multiple environments and forgot to sync assets properly. (i.e. I pulled down the database snapshot from production, but not the newer assets that would be referenced in its Assets index).
When one environment uses a case-sensitive file system (e.g. a unix host), and one uses a case-insensitive file system (e.g. OSX). In this case, syncs and Git pulls may fail to differentiate between files with similar names, and both Git and Assets may bugger up.

Those are the first two things I'd double-check.


How can I validate that I am passing an Asset into my custom twig filter?

Actually, you had your code just right imo:

use craft\elements\Asset;

...

if (!$asset instanceof Asset) {
    return false;
}


I would try to add the fonts with the Craft plugins

Control Panel JS
Control Panel CSS


Can structure entries have their own entries?

Update

Following your comment, and if I understand well, you already are using a URL for the categories, but want to create kind of a subpage "information" for them. It is a bit more complicated but it can be achieved. What you can do is create a route, either from the control panel or the config/routes.php file in craft/config. It may be easier to do it from the control panel first. If you go to Settings > Routes and click on "New route" you can enter the following information:

It will create a new URI endpoint for the "information" pages that you want and map them to a _information.html template in the "categories" folder.

You can then create _information.html template and retrieve your category using the following code:

{% set category = craft.categories({ group: 'categoryName', slug: craft.request.segments[1] }) %}

Assuming the handle of your category is categoryName of course.
craft.request.segments is an array containing all parts of your URI, starting from 0. Thus, the second part of the URI, which is the selected category's slug, is stored in craft.request.segments[1].
The variable category will then contain all the fields assigned to the category that you want to display in the information page.

It is possible and quite easy to do in Craft.
You can create a new text field named "External link" for example, and assign it to the category.

To do that, go to Settings > Categories > {Name of your category} and select the "Field layout" tab. You can then assign the "External link" field to the category like you would for a section.

You can now edit your categories and add the external link for each one of them.


Redactor adds  to both image and video embeds, how to style differently

It's probably not the answer you want to hear, but the best way to avoid these kind of problems is to modernise your content model so that videos are stored in their own dedicated section, and then allow authors to create relationships to those video entries via a dedicated 'video' block type in a content matrix. Similar for images really (though it is arguably still important to allow for inline images in Redactor such as for images in the middle of sentences). If you want to prevent Redactor from wrapping images with a figure element you can specify imageFigure: false in your Redactor config json files.
If you can't update your content model easily, then as a last resort you might need to delve into the Retcon plugin to manipulate Redactor's output.


Fetching Unique Categories related to Entries via GraphQL

You can run a categories query and pass it your product id(s) as well as the category group id (though that's not necessary) to fetch all categories related to your products.
The query:
query getRelatedBrands($relatedTo: [QueryArgument] = "", $groupId: [QueryArgument] = "") {
  categories(groupId: $groupId, relatedTo: $relatedTo) {
    id
  }
}

and the variables:
{
  "relatedTo": [13306, 13638],
  "groupId": [1]
}

Which would return:
{
  "data": {
    "categories": [
      {
        "id": "3"
      },
      {
        "id": "234"
      }
    ]
  }
}


How are you trying to use it in the template?

Below is a very basic way of how to display a setting in a front end twig template.

First define your settings with the defineSettings() method (as you already have).

protected function defineSettings()
{
    return array(
        'mySetting' => array(AttributeType::String, 'required' => true)
    );
}

Then create a directory in the root of your plugin folder and call it “templates”. Create a new .html or .twig file in that folder and call it “_settings.html”. Inside of that you could put the following:

{% import "_includes/forms" as forms %}
{{ forms.textField({
        label: "My Setting"|t,
        id: 'mySetting',
        name: 'mySetting',
        instructions: "Input your setting"|t,
        value: settings.mySetting,
        errors: settings.getErrors('mySetting')
    })
}}

After this go back to your primary plugin class and add the getSettingsHtml() method:

public function getSettingsHtml()
{
    return craft()->templates->render(‘pluginHandle/_settings', array(
        'settings' => $this->getSettings()
    ));
}

Now, if you go into admin/settings/plugins you can click on your plugin and there will be an input field there where you can save the setting. If you wanted to get this value you could add a method to your service like this:

public function getMySetting()
{
    $plugin = craft()->plugins->getPlugin(‘pluginHandle');
    $settings = $plugin->getSettings();

    return $settings->mySetting;
}

You could call this anywhere throughout your plugin like this:

craft()->pluginHandle_serviceName->getMySetting();

To do that on the front end in a twig template, just create a method in the variables class. It would look something like this:

public function getMySetting()
{
    return craft()->pluginHandle_serviceName->getMySetting();
}

In your front end twig template you could call it like this;

{{ craft.pluginHandle.getMySetting() }}

I hope any of this clears it up a bit.


As you've found, Commerce carts exist independently of a Craft user's session.

A workaround would be to write a simple plugin that listens to something like the onLogin event and that plugin would check for the commerce_cart cookie and if it exists, nuke it.

That would force a new cart for each new login.


Use default Craft error/exception layout in Plugin

If I'm understanding your question correctly, then you get that behavior by default.

If you:

throw new Exception('Uh oh.');

Then you'll get the same error handling layout and logic that Craft uses.

You can read here for more information on how that works.


Figuring out why my image is not working in the template

You can have more than one Asset in any Assets field, so it always returns to you an array of assets. So you just need:

{{ entry.hoofdafbeelding.first().getUrl('square') }}

...assuming you want the first asset.


Non Integer Quantities in Craft Commerce

Given how much of Commerce internally will be relying on whole number quantities, I think option 2 is the far better plan.

You can't add custom fields to line items currently, and while you might be able to hack something using the options/notes systems, or custom order fields on the order as a whole, I'd think this would get complex to maintain quickly. Best to use your minimum selling measure as the unit and dress it up front end.... that should work well and will be substantially easier to implement and (importantly) maintain.

With stores, even more than websites, long term ease of understanding and maintenance should be a high priority goal.


Element-api - filter Draft entries by the draft author (not original author)

I think i have found the answer after digging in Element docs... looks like this works! in criteria

'draftCreator' => $user->id


Can't find S3 bucket using Craft Pro in trial mode

The bucket you're trying to list is probably in the Frankfurt S3 region. The 3rd party library used in Craft 2.x for Amazon S3 support does not support Signature Version 4 that Frankfurt region requires, so you won't be able to use buckets in that region, as outlined in this answer

Craft 3.0 will not have this limitation, however.


The short answer: No.
However, as this answer states, it will be possible to do this in the future.

Just as a tip, I know it doesn't answer your question: it's an effect you can easily achieve with CSS, by rounding the corners to 50%.


Commerce: Combining unwanted quantity discounts

Not really a good answer as such but at the moment (June 16) there is currently no facility to print the actual price a particular item will sell at after all discounts/sales are applied (unless you calculate it yourself).

This seems to me a bit of an oversight.

I have requested it as a feature, and Luke seemed amenable to the idea but I have no idea on the ETA for it.

To solve the cumulative discount issue - you can either express the discount as a cumulative thing as you mention, or you could write a simple plugin that listens to

https://craftcommerce.com/docs/events-reference#commerce_discounts.onbeforematchlineitem

...and only applies the desired discounts when the desired conditions are met


Ordering of ElementCriteriaModel with varying statuses

Your statuses are incorrect. They would be correct for many elements, but the Entry Element overwrites them to the following:

EntryModel::LIVE
EntryModel::PENDING
EntryModel::EXPIRED
BaseElementModel::DISABLED


I think I'm following and it sounds like the job for a plugin with a custom field type.

In your example, since you want to use a Dropdown field, then your plugin's field type could extend Craft's default Dropdown field type.

When populating the field type's default values (from your pre-defined statements), you could then randomly select which ones are selected on new entries).


How to order or filter entries by their author's custom field?

This requires a bit of extra work on the ElementQuery, but it can be efficiently done in the same query.

We first perform an inner join on the author's content table using the authorId so that the custom field is available to us.

in Twig:

{% set elementQuery = craft.entries()
    .section('sectionHandle')
    .with(['author'])
    .innerJoin('{{%content}} author_content', '[[author_content.elementId]] = [[authorId]]')
    .andWhere({'author_content.field_customFieldHandle': 'X'})
%}

in PHP:

$elementQuery = Entry::find()
    ->section('sectionHandle')
    ->with(['author'])
    ->innerJoin('{{%content}} author_content', '[[author_content.elementId]] = [[authorId]]')
    ->andWhere(['author_content.field_customFieldHandle' => 'X']);

To order by a custom field we use orderBy.

in Twig:

{% set elementQuery = craft.entries()
    .section('sectionHandle')
    .with(['author'])
    .innerJoin('{{%content}} author_content', '[[author_content.elementId]] = [[authorId]]')
    .orderBy('author_content.field_customFieldHandle asc')
%}

in PHP:

$elementQuery = Entry::find()
    ->section('sectionHandle')
    ->with(['author'])
    ->innerJoin('{{%content}} author_content', '[[author_content.elementId]] = [[authorId]]')
    ->orderBy('author_content.field_customFieldHandle asc');

To filter by a custom field we add andWhere.

in Twig:

{% set elementQuery = craft.entries()
    .section('sectionHandle')
    .with(['author'])
    .innerJoin('{{%content}} author_content', '[[author_content.elementId]] = [[authorId]]')
    .andWhere({'author_content.field_customFieldHandle': 'X'})
%}

in PHP:

$elementQuery = Entry::find()
    ->section('sectionHandle')
    ->with(['author'])
    ->innerJoin('{{%content}} author_content', '[[author_content.elementId]] = [[authorId]]')
    ->andWhere(['author_content.field_customFieldHandle' => 'X']);


Loop through both category group and tag group in single loop

Something like this may work for you (untested).

{% set categories = craft.categories.group('myCategoryGroup').find %}
{% set tags = craft.tags.group('myTagGroup').find %}
{% set elements = categories|merge(tags) %}

    {% for element in elements %}

{{ element.title }}

    {% endfor %}

Sorting them alphabetically is a little more difficult. For that you may want to try twig's sort filter or, failing that, the supersort or craft-twig-better-sort plugins.


You could use the children tag:

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

        Products

            {% nav entry in entries %}

                    {{ entry.title }}
                    {% ifchildren %}

                            {% children %}

                    {% endifchildren %}

            {% endnav %}


Output field content for a product in Craft Commerce

Welcome to Craft!

A very basic piece of code for displaying your image would look like this (the if statement first checks if the field actually has an asset or not):

{% if product.productImage|length %}

{% endif %}

This quite simply outputs the image as it has been added in Craft, full size. Of course this isn't ideal as the images could be huge. That's why we have Image Transforms, which allow you define the size of the images.

Here is the above code again, but updated to use a new transform we have created in Craft called 'Test Transform', with a handle of 'testTransform':

{% if product.productImage|length %}

{% endif %}

Hopefully that gets you started. I'd recommend reading through the Craft docs for using and templating asset fields.


my vendor/craftcms/cms folder delete automatically after every update or install

I had a similar issue yesterday.

When running composer install from my linux (Homestead box), via the command line, a stack of weird errors flew by indicating a "problem with the zip file".

Then craft died. All the vendor/craftcms files were created but empty!

Only way round it, for me, was to run the composer install from windows instead.


I copied your markup, setting and name and label manually and it added the disabled property if I used disabled: true

{{ forms.textField({
label: 'Example Label',
name: 'Example Name',
value : 'Example Value',
disabled: true,
required: true
}) }}

Perhaps you could try manually defining the field (as I did) without reading from the variables and confirm that it works.

If that fails, I suggest you enable dev mode and then use twig's dump() function to check that you don't have any errors and that the field is given correct values.

Is there anything in your log file?


Asset thumbs missing in control panel after Assets Source update

Go to Settings > Clear Caches. Should regenerate them all from the new source.


Craft Commerce — Billing / Shipping Address validation / required Fields

It will be possible in the next release (commerce 2-beta.5):

https://github.com/craftcms/commerce/issues/342


Craft CMS with Google Cloud SQL as backend database

Craft currently won't operate properly if you have GTID enabled because GTID enforces that every table involved in a SQL statements in one transaction have to utilize the same storage engine.

While virtually all of Craft's tables use InnoDB as the storage engine, the craft_searchindex table is still on MyISAM, because InnoDB didn't add full-text support until MySQL 5.6 and Craft still supports back to MySQL 5.1.

If you're running MySQL 5.6+ (which you should be because I don't believe GTID was introduced until 5.6), then you can manually change the storage engine of the craft_searchindex table from MyISAM to InnoDB and you shouldn't run into any issues.


How to Make getURL Output Complete URL (rather than root relative)

Craft should actually output absolute URLs when using getUrl. But you need to set siteUrl to make this work, so check if you have it set in Settings → General or with a siteUrl property in your general.php config file.


How to get values into twig template for fields of type Matrix in Craft CMS 2?

You should be able to get your content by using a for loop on your Matrix field:
{% for blocks in kHandle.yourMatrixfieldHandle.all() %}
    {{ block.fieldHandle }}
{% endfor %}

Alternatively, if you only have one block in there, you could use:
{{ kHandle.yourMatrixfieldHandle.first().fieldHandle }}


The trick, as it were, is to define the Matrix field in your form as an array.

First, the Matrix entry field itself:

<input type="hidden" name="fields[traveller][new1][type]" value="travellerDetails">
<input type="hidden" name="fields[traveller][new1][enabled]" value="1">

Then, for each field within the Matrix block:

<input type="text" name="fields[traveller][new1][fields][travellerTitle]" value="">

If you are going to allow for more than one Matrix field in your form, you must increment the block number, e.g. "new1" becomes "new2". You can do that with some JS.


Create Solspace Calendar Event on Commerce onOrderComplete

To listen to Craft Commerce order save event, you must make a new plugin (or use an existing one) and in it's ::init() method, listen to the commerce_orders.onSaveOrder event:

class TestPlugin extends BasePlugin
{
    public function init()
    {
        parent::init();

        craft()->on(
            "commerce_orders.onSaveOrder",
            function (Commerce_OrderModel $order) {
                // Create the event
                $event = new Calendar_EventModel();

                $event->getContent()->title = "New Event Title";
                $event->slug                = "new-event-title";

                // Any custom fields go through the ::getContent() model
                $event->getContent()->body = "This is a custom rich text field";

                // Do whatever you need to do with the order data
                // By using the $order OrderModel
                // For example:
                //
                // $event->getContent()->body = "Order total: " . $order->totalPrice;

                // Mandatory fields
                $event->calendarId = 1;
                $event->authorId   = craft()->getUser()->id;
                $event->startDate  = new DateTime();
                $event->endDate    = new DateTime();

                $event->allDay = true;

                // Save the event using Calendar Events service ::saveEvent() method
                craft()->calendar_events->saveEvent($event);
            }
        );
    }
}


It's 95% an IDE issue.  Craft can take advantage of this because it provides PHP DocBlock property information in WebApp (which is what craft() is a reference to) and IDE's like PhpStorm are smart enough to analyze that and find the classes you're referencing for autocompletion.

It's impossible for Craft to let plugins dynamically add properties to that DocBlock, but I have seen some clever plugins provide their own abstraction around craft() so they can add their own plugin specific DocBlock info that enables autocompletion around services.


How do I show entries that do not have a certain category?

I found this to work, although maybe there’s a better method.

{% set excludedCategory = craft.categories.id('100') %}
{% set excludedEntries = craft.entries.section('blog').status('live').relatedTo(excludedCategory).ids() %}

{% set entryIds = craft.entries.section('blog').status('live').ids() | without(excludedEntries) %}
{% set entries = craft.entries.section('blog').status('live').id(entryIds) %}


How can Craft-generated Content HTML be accessed via an external PHP app?

Your app can load up Craft using its bootstrap.php file:

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

That file returns a Craft\WebApp instance. From it, you can access all of Craft’s services, including the ElementsService which provides APIs for fetching elements and their content.

Read through our Working with Elements guide to get an idea of how those APIs work.

As a quick example, here’s how you’d get the entries in a section with an ID of 1 with a category selected, with an ID of 5:

$criteria = $craft->elements->getCriteria(Craft\ElementType::Entry);
$criteria->sectionId = 1;
$criteria->relatedTo = array('targetElement' => 5);

$entries = $criteria->find();

To get the HTML for an entry, you could either assemble that in PHP based on the entry’s content fields, but it would probably be easier to just write a template for it, and have TemplatesService::render() render it for you:

$html = $craft->templates->render('path/to/templates', array(
    'entries' => $entries
));


How can I check on the value of a template variable?

If you have devMode set to "true" in your config files, you can use "dump" in a twig template like this without any plug in needed:

{{ dump(myArray) }}


How can I use a session consistently in a service and variable?

I suspect you're getting different session IDs because you're creating a new instance of HttpSessionService (which ultimately is a wrapper for PHP's session handling).

What you should be doing is using Craft's existing session off of craft()->httpSession and grab the existing PHP session ID with craft()->httpSession->getSessionID().

No need to call craft()->httpSession->open(), because Craft will automatically start the session as soon as the HttpSessionService gets loaded.


This sounds like a bug. Please submit a issue at http://github.com/craftcms/commerce


How do you save a new Entry to be enabled on 2+ Sites?

I was able to get this working with this:

$findTheNewEntry = Entry::find()
    ->sectionId($sectionId)
    ->id($entry->id)
    ->anyStatus()
    ->siteId($secondSiteId)
    ->one();

$findTheNewEntry->enabledForSite = true;
Craft::$app->elements->saveElement($findTheNewEntry);

When creating a new entry via ->saveElement(), Craft automatically creates entries for all sites that have that section enabled. The issues I was having were because status and enabledForSite are different, and I needed to use ->anyStatus() to retrieve an element that was globally enabled when I created it but not enabled for the second site yet. Once that was retrieved, I could enable that entry for the second site as well.


How do I get extracts in search results?

I think creating your own Twig filter is your best bet.
So, create a filter that takes a string, searches that for another string and returns an extract. It could do this by using some regular expression hocus pocus, I guess.

{{ entry.bodyText | extract('your search term', 3, 3) }}

would be how you'd use it (assuming, for example, that your filter accepts the three arguments searchTerm, wordsBefore and wordsAfter).


Edit: I changed it to your variables, not sure if I set the array brackets 100% correct but the idea should work.

You could set the defaults in the macro as you already did,
then in your template call the macro and pass the options e.g. :

{% set image = block.slide.first() %}
{# macro #}
  {% set imgParam = [
    thumb: { quality: 60, },
    tSM: { mode: 'crop', width: 1536 },
%}

{% macro isotopeItem(imgParam) %}

and merge the passed options in the macro with your macros defaults e.g.:

 {% set defaults = [
    thumb: { mode: 'fit', width: 100, quality: 60, },
    tSM: { mode: 'fit', width: 1536, quality: 80, },
    tMD: { mode: 'fit', width: 340, quality: 80, },
    tXL: { mode: 'fit', width: 1536, quality: 80, }
  ]
%}

{% set imgParam = imgParam ? defaults|merge(imgParam) : defaults %}

so you will only need to pass explicit changes.


How can I display search "excerpts" from multiple sections?

There is no way at present to delegate a field as the search excerpt field in Craft, so it needs to be handled by the search results template. It is possible to use conditionals but this can bloat the template, especially when there are multiple sections and each section outputs different fields in different ways, so I prefer to create dedicated search excerpt templates and include them in the search results template as follows:

{% include ['_search-excerpts/' ~ entry.section.handle, '_search-excerpts/default'] %}

The above code will render the section's dedicated search excerpt template if it exists in a folder called _search-excerpts, otherwise it will render the default search excerpt template which can contain for example:

{{ entry.title }}

The resulting folder structure would then look like this:

_search-excerpts/default.html
_search-excerpts/sectionA.html
_search-excerpts/sectionB.html
_search-excerpts/sectionC.html


You can share a temporary link to an unpublished entry by clicking on the "Share" button, right next to the "Live Preview" button.

Craft 2:

Craft 3:

This creates a link with a token that will expire automatically. The length of time that the token lasts for can be controlled with the defaultTokenDuration config setting.


Issue resolved. Having checked with Yii debug bar i could see that there was no $_post data with the request. It seems axios sends the data as JSON and not usual post data. Switching to vue-resource enabled me to post the data for craft to use, new code:

this.$http.post('', {
    [this.csrfName]: this.csrfToken,
    action: 'commerce/cart/update-cart',
    lineItems: {[id]: {'remove': 1}}
}, {
    emulateJSON: true,
    headers: {
        'X-CSRF-Token': this.csrfToken
    }
})


Split-style button for "New" custom element

Those split-style buttons are just multiple regular buttons (.btn) next to each other, wrapped in a .btngroup div:

  Button One
  Button Two

If you want to make one of your buttons trigger a dropdown menu, give it the class .menubtn, and add your .menu div right after it.

  Button One

Menu Button

Option One

Option Two

As long as this HTML is in the page’s initial HTML, Craft will automatically initialize the menu. If you’re adding it in JavaScript later on, you will need to initialize the menu yourself, by calling the menubtn() jQuery function on it:

$('#mycontainer .menubtn').menubtn();


So, if a category section has "has it's own url's" ticked, then the template defined there will take precedence over the custom route. Custom routes i'm told are a fallback and will not override already set routing.


Setting arbitrary PHP constants in index.php

Hat-tip to Brad for finding this answer.

This can be achieved with something like the following in your index.php:

define('BRADS_FAVORITE_HOBBY', "Drinking");

Thanks to the power to Twig, you can then access this in your templates using:

{{ constant('BRADS_FAVORITE_HOBBY') }}


Just like a lot of things in Craft or in computer science in general, there's multiple ways to do things.
The actionInput function is just a shortcut for outputting a hidden input:
<input type="hidden" name="whatever" value="whatever">

...much like {{ entry.title }} in Twig is really a shortcut in PHP for something like <?php echo twig_escape_filter(...) ?>.
However, the 2 snippets you posted are not necessarily equivalent.
When you put the "action" attribute on a form:
<form method="post" action="whatever">

... a web browser is actually sending a POST request to that location, versus when you leave it off:
<form method="post">

... a browser will POST to the current page.
The difference seems subtle but say your form has errors, you probably don't want to be POSTing to your controller "directly", you want to reload the same page. (And you don't typically don't want someone bookmarking your controller action.)
The older Craft 2.X documentation has a great little bit about this:

When you leave your form’s ‘action’ attribute blank, browsers will default to the current request’s URL. Which is great in the event that your controller needs to reload the previous page without a redirect. A common example of this is when the user’s input didn’t validate, and you want to pass the errors back to your template (ideally tucked away within a model).

Craft/Yii handles the nitty-gritty routing behind the scenes.


Craft gives you a lot of options here. I think you're close. The way I'd set it up:

Boats (section)
Suppliers (section)
Boat Type (category)

Then in your boats section, set up a Supplier relational field, and have it relate back to your suppliers section and also a Boat Type relational field, which relates back to that category group.

In this way, on the front end, you can easily filter by boat type or supplier.

Example: on your supplier pages, you can easily get a list of all the boats made by that supplier, just by querying that section like:

{# assume we're on a supplier page #}

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

{% for theBoat in boatsBySupplier %}

{{theBoat}}

Model: {{theBoat.modelNumber}}

    ...
{% endfor %}

In terms of templating, there won't be a huge difference if you choose a category over an entry, for example, for your suppliers.

I tend to think of brands (suppliers) as content, thus content belongs in an Entry, not in a taxonomy (category). (Down the road you might want to have more than one supplier type, for example.)

But if your data on suppliers is relatively thin, a category would work just as well. Even then, unlike other CMS, Craft allows you to use custom fields on Categories to add more data. So there's no wrong answer there.  In that case, Craft will populate the category variable (and not entry) so just change that and you should be all good.

Not sure what you mean here:

  But does it make more sense to use suppliers as entries [fields] and relate them to products as 'parents'?

If you're asking about setting up a structure, and having the top level parent be the supplier and the boat model be a child, I'd steer clear of that.  A lot of things can go wrong with that model.

In general, I like to keep data structures as "flat" as possible and create depth with Craft's relationships. But if you're asking about using entries fields to relate your suppliers back to your boats, that's exactly what my example above does.


How to improve search performance on front-end?

Have you looked into eager loading the Matrix field if you are on 2.6? This should vastly cut down on the number of queries needed.

The other thought could be to use the Preparse field plugin to push the matrix fields into simple text, and then direct the search query to only look at the title field and preparse fields.


Fields not displaying for some entries in control panel

If you have xDebug installed on your server, you're probably running into this.

If you don't, you're probably running into this.


Why won't the values of an editableTableField show up in my template?

That string that Craft stores is just JSON. When you try to save an array, Craft will automatically JSON-encode it, since MySQL doesn’t have an array-based data type.

To get that string to be automatically decoded back into an array for you, you need to give your field type a defineContentAttribute() method that returns AttributeType::Mixed:

public function defineContentAttribute()
{
    return AttributeType::Mixed;
}

To get the values to actually output, you will need to make sure you’re passing the old value with the correct name. Your csvimport.html template is looping through a variable called rows, which is meant to represent the existing value, but in getInputHtml() you are sending $value to the template as a variable called value.

So if you change this line in your template:

{% for rowId, row in rows %}

to:

{% for rowId, row in value %}

the template will probably start outputting data.

If you’re not actually making any changes to the table HTML, you should probably just include the actual _includes/forms/editableTable.html template, though. Using your own HTML puts you at a little risk, if you also intend to keep using the Craft.EditableTable JavaScript class, since those two are very much tied together. We aren’t concerned about making breaking changes to the way the HTML is supposed to look, as long as we haven’t broken the way the actual editableTable.html template is supposed to be included.

So from csvimport.html, you should just replace your entire <table>...</table> HTML with this:

{% from "_includes/forms" import editableTable %}

{{ editableTable({
    id: id,
    name: name,
    cols: cols,
    rows: value
}) }}

(In this case I’m using the editableTable() macro in _includes/forms.html instead of including the actual _includes/forms/editableTable.html template, mainly because I think using the macro looks nicer.)


First, based on your example code I don't think you actually need to loop on the entries – you could simply group them on the brand name, and then loop on the keys for the grouped array (the keys would be your brand names):

{% set brands = allEntries|group('brand')|keys %}

{% for brand in brands %}
     <option value="{{ brand }}">{{ brand }}</option>
{% endfor %}

So that's a slight optimization, but you'd still be pulling ~18k entries to print ~140 brand names and I'm not sure the above wouldn't still crash your server – so ideally you should probably use a different strategy altogether.

If you're comfortable w/ writing a little PHP, I'd suggest you scaffold a custom plugin – make sure that the Variables component is included, and add something like the below to the variables/YourPluginHandleVariable.php class:

public function getBrands()
{
    $query = craft()->db->createCommand();
    $query->selectDistinct('field_brand');
    $query->from('content');
    return array_filter($query->queryColumn());
}

In your template, you'd use this like so:

{% set brands = craft.yourPluginHandle.getBrands() %}

{% for brand in brands %}
     <option value="{{ brand }}">{{ brand }}</option>
{% endfor %}

Be sure to replace yourPluginHandle and YourPluginHandleVariable with the actual handle for your plugin.

Note that I haven't actually tested the above w/ as many as +18k rows, so even a distinct select query might not be performant enough. Of course, you can always cache the result.


Twig didn’t add arrow function support until v2.10.0, so you need to be on at least Craft 3.1.29 if you want to use them.


Change password on user profile (customer account in Craft Commerce)

Commerce just relies on existing Craft functionality for this and if you look at UsersController->saveUser, you can see that if the existing password is incorrect, then the error will be added to the UserModel's currentPassword property.

So something like this should work:

    {% for error in user.getErrors('currentPassword') %}

{{ error }}

    {% endfor %}


Least CPU intensive way to get number of matching elements?

When you call the |length twig filter you are implicitly treating the element query as an array.
This behaviour was depreciated in Craft 3, and also results in a DB query being sent that is equivalent to .count() (Craft 3) or .total() (Craft 2).

To remain up to date, while still minimising SQL load for your page: either call the relevant command (.count(), .total()):

{% set productCount = craft.products.relatedTo(category).count() %}

Or, if you're going to be doing a full (limit: null) query at some point anyway, do that now and then use the length filter:

{% set products = craft.products.relatedTo(category).limit(null).all() %}
{% set productCount = products|length %}


Creating a web app notification system/center?

I created a simple plugin for you to start. Note that is not a ready-to-use plugin so you'll have to change the things you need. This is just meant to be a starting point for you.
You can use the code and change it how you like it but mostly it is for learning purposes. So please don't expect it to be "finished" since I don't know your needs and your structure. The most important thing: my css/design skills are awful so I did not style anything.. you have to do it on your own

Feel free to say what I could/should change for you.

So here it is Usernotifications

So let's go through it:
My idea was to create a section called usernotifications (you don't have to do it by yourself, it is created onAfterInstall and can be changed later) that has different entry types for different messages and purposes. If you want to change the section handle make sure to change the $criteria->section = 'usernotifications'; in my service. This way you can create messages/notifications how you like and make them really dynamic. Please read this for some ideas and instructions Overview

Craft renders all those entries unless the user dismisses them or if they are too old. Check my service for the logic.

The Controller:has two methods, the first is actionRemoveNotificationto remove a message/notification for a user. So you'll display a dismiss button and as soon as someone clicks it, you create a record in your database with the userId and the entryId, so you know which user removed a notification.

/**
 * Remove a notification for a user
 */
public function actionRemoveNotification(){
    $this->requirePostRequest();
    $this->requireAjaxRequest();

    $response = [
        'success'   => false,
        'message'   => 'could not find entry'
    ];
    if($entryId = craft()->request->getParam('id')){
        $userId = craft()->userSession->getUser()->id;

        $record = UsernotificationsRecord::model()->find('entryId = :entryId AND userId = :userId', array(
            'entryId'   => $entryId,
            'userId'    => $userId
        ));
        if($record){
            // user already removed the message... there must be something wrong or he/ she cheated :P
            // you can actually ignore this... just wanted to show you how to search for entries^^
        }else{
            $record  = new UsernotificationsRecord();
        }

        $record->userId = $userId;
        $record->entryId = $entryId;

        if($record->save()){
            $response['success'] = true;
            $response['message'] = 'notification removed for user';
         }else{
            $response['message'] = 'could not save record';
            $response['errors'] = $record->getErrors();
        }
    }

    $this->returnJson($response);
}

The service:
The service should return all notifications for the current User or nothing at all if the user is not logged in

/**
 * Get all notifications for the current user
 *
 * @return string
 */
public function getAllNotificationsForUser(){
    // check if user is logged in...
    if(!craft()->userSession->getUser()){
        return false;
    }

    // fetch all removed notifications of the user to not fetch them in our query
    $removedNotifications = craft()->db->createCommand()
        ->select('entryId')
        ->from('usernotifications')
        ->where(['userId' => craft()->userSession->getUser()->id])
        ->queryColumn();

    $criteria = craft()->elements->getCriteria(ElementType::Entry);
    $criteria->section = 'usernotifications';
    // user should not be overwhelmed with too many notification when they didn't log in for too long
    // so show only notifications 14 days ago, you can change this length or remove it if you want
    // but make sure to change the value in the task as well.
    // you could also create settings for the plugin where you can store how long
    // then entries should be displayed
    $someDateInThePast = date('U', strtotime("-14 days"));

    $criteria->postDate = "> " . $someDateInThePast;
    // exclude the ids of the removed notifications
    if($removedNotifications){
        $criteria->id = 'and, not ' . implode(', not ', $removedNotifications);
    }

    return $criteria->find();
}

Your Variable
In your variable you'll get the html for those notifications, you can find the templates in templates/entries/entrytypes

public function getAllNotificationsForUser(){
    $html = '';
    $entries = craft()->usernotifications->getAllNotificationsForUser();
    if($entries){
        // I get a deprecated hint here, but the solution stated in craft throws
        // an exception... So I'm using this one
        $oldPath = craft()->path->getTemplatesPath();
        $newPath = craft()->path->getPluginsPath() . 'usernotifications/templates';
        craft()->path->setTemplatesPath($newPath);
        $html = craft()->templates->render('entries/index.twig', array(
            'entries' => $entries
        ));
        craft()->path->setTemplatesPath($oldPath);
    }
    return $html;
}

I guess these are the most important parts, you can check the rest in my git repo and ask/request whatever you like.

You can render the entries with

{% set notifications = craft.usernotifications.getAllNotificationsForUser() %}
{{ notifications|raw }}

Before I forget it: I created a task to remove too old records. You can access it via /admin/actions/usernotifications/removeOldRecords


Your server seems to be missing the shell command mysqldump, contact your IT-Specialist and tell him you need that to be installed you can backup your website.

Or if you plan on installing it yourself, this should do the trick.

Excerpt  from there:

sudo apt-get install mysql-client-5.7

If it's not able to find the package, try entering the statement till the mysql part and then hold tab it should then show you all available versions which you can install.


Can you set the redirect path for system forgot password form?

You can. You have to build some front end forms:

Forgot Password Form (http://buildwithcraft.com/docs/templating/forgot-password-form)
Set Password Form (http://buildwithcraft.com/docs/templating/set-password-form)

Be aware of the config setting, setPasswordPath.

It's also worth noting that a user account with control panel privileges will be redirected to the control panel set password and login no matter what.

Edit:
Also, check out setPasswordSuccessPath for redirecting the user after they've successfully set their new password. Again, this only applies to non admin users that have completed this process using the front end forms you have setup.


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

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

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


Delay Updating element slugs and URIs Job

You can try disabling Craft's queue temporarily by adding 'runQueueAutomatically' => false to general.php, then trigger the feed via the command line.
Without testing this might prevent the 'Updating element slugs and URIs' job, but in any case – doing it this way you should see better performance overall.
p.s. if you add --verbose to the end of the command you can see what it's doing.


Redactor removes article tag from HTML while saving

You can specify custom HTML Purifier configs so that it will allow article tags and the Redactor fields will respect the configs.
See: https://github.com/craftcms/redactor#html-purifier-configs


What SQL query can I run to remove all users assigned to a particular group?

You've done it the correct way.  Assuming all of Craft's foreign keys and cascading deletes are all still in place, removing the user's element ID from the craft_elements table is the way to go and all related data will cascade delete from there.


You'll not be able to use the dot notation here, and instead use the array notation.

Try: {{ node['itunes:summary'] }}


Element-API migration - entries by category

Solved it like this:

//categories
    'api/v1/ship/category/<catId:\d+>.json' => function($catId) {
        return [
            'elementType' => Category::class,
            'criteria'    => ['id'   => $catId],
            'paginate'    => false,
            'transformer' => function(Category $category) {
                $entries = Entry::find()->relatedTo($category)->all();

                $en=[];
                foreach($entries as $entry) {

                    //Final return
                    $en[]= [
                        "type" => "shipItem",
                        'sendtoseafarerhelp' => $entry->sendToSeafarerHelp,
                        'title' => $entry->title,
                        'url' => $entry->url,
                        'categoryTitle' => $entry->shipCategory[0]->title,
                        'categorySlug' => $entry->shipCategory[0]->slug,
                        'categoryUrl' => $entry->shipCategory[0]->uri,
                        'summary' => $entry->shipIntroText,
                        'descripton' => $entry->shipDescription,
                        'pdfs' => $pdfs,
                        'thumbs' => $thumbs,
                        'sponsors' => $sponsors
                    ];
                }

                return [
                    'title'   => $category->title,
                    'entries' => $en
                ];
            }
        ];
    },


Assuming this is in Craft 3, you should be using .orderBy() instead of .order(). Does the following work as expected?

{% set users = craft.users.group('influencer').orderBy('score desc').limit(24) %}

{% paginate users as pageInfo, pageUsers %}

{% for user in pageUsers %}
    {{ user.username }} : {{ user.score }} <br>
{% endfor %}

Here it is in the docs: https://docs.craftcms.com/v3/dev/element-queries/user-queries.html#orderby

Also turn on devMode to be sure that no errors are being suppressed.


Updating Craft Produced Fatal Error.What now?

How big is your database? It could be that Craft is failing to backup your database as part of the update process because it is running out of memory.

Try setting the backupDbOnUpdate config setting to false and running the update again.


If user has no access to email how to give them a temp password?

You can "Copy password reset URL" and give it to them via some other means (IM, etc.).


Experience with Craft's native rss/atom support?

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

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

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

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

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

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

    {{ block.text }}

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

    {% include 'blocks/_footnote' %}

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

    {% include 'blocks/_pullquote' %}

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

    {% include 'blocks/_heading' %}

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

    {% include 'blocks/_image' %}

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

    {% include 'blocks/_audio' %}

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

    {% include 'blocks/_video' %}

  {% endif %}

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

</rss>

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


So, if I understand you correctly, you're trying to use the Model IDs channel as a middle man? If so, I think you would just need two steps:

To get all SSDs from a Memory Entry

{% set modelIDs = craft.entries.section('MODEL ID SECTION HANDLE').relatedTo(entry).ids() %}
{% set ssds     = craft.entries.section('SSDS SECTION HANDLE').relatedTo(modelIDs).all() %}

To get all Memory from an SSD Entry

{% set modelIDs = craft.entries.section('MODEL ID SECTION HANDLE').relatedTo(entry).ids() %}
{% set memory   = craft.entries.section('MEMORY SECTION HANDLE').relatedTo(modelIDs).all() %}


Are there any advantages of updating from PHP 5.4.40 to 5.6?

Short yes! You can find a detailed Benchmark on http://www.lornajane.net/posts/2014/php-5-6-benchmarks. If possible i would try to update from PHP 5.4.40 direct to PHP 7. The performance from PHP 5.4 to PHP 7 is massiv. A change to PHP7 made our Craft installation twice as fast. You can find some further information here -> https://pixelandtonic.com/blog/php-7


The smoothest way to store JSON object to an entry?

It's a little tough to say, since you it seems like you haven't actually architected any of this in the Craft back-end yet. I encourage you to create a field (or fields) which would be a good container for this data.

Once you've established what kind of field you're using, you may find that there is a different answer... but based on your current intent to store a simple JSON object, it sounds like you'd be using a simple plain text field.

Assuming you're using a plain text field, this is actually quite simple to accomplish. Use your JavaScript to set the value of a hidden field, before submitting the form:

<input type="hidden" name="fields[songsJson]" value="" />

More info on saving entry data from a front-end form:

  https://craftcms.com/docs/templating/entry-form


What's the configuration to enable Craft for free CloudFlare and Railgun?

I'm going to answer this one, to share information on how I just did it. One issue will remain, but that will be raised in a separate question.

The first thing is to understand the URL layout which CloudFlare/Railgun will require. You or your hoster will create A records in DNS for all but one of these, each of them pointing to your server IP.

There's an order in which these records should be created, which your hoster will specify, in order to check all is well before aetting the CloudFlare service to be fully active for visitors to your site. So don't just go ahead from this list!

Your main site, which will remain un-accelerated, but is a necessary DNS reference, and fallback if you disconnect CloudFlare. We'll call that domain.com.
The access subdomain, where CloudFlare/Railgun retrieves content from your site in order to accelerate it. This will be cloudflare-source.domain.com, or similar if your hoster differs.
if you're going to need SSL (https) to protect your Craft CP admin, you'll need a non-CloudFlare url to allow this, unless you're using one of the non-free versions of CloudFlare which allow SSL. Let's call this secure.domain.com.
Notice that secure.domain.com on https/SSL can also be what you'd use to shelter e-commerce pages, but be very careful here. Unless you want to be required to go through a process of certifying PCI compliance, you'll want to use an actually self-safe e-commerce solution like Stripe.js, which handles customer and credit card data so that they are never sent to your server. The secure page set up here just adds security against mistakes, and helps build customer confidence by showing visibly that everything is protected by SSL.
Any other subdomains such as a staging server will need to be on the same domain DNS record set, and also controlled by your server's virtual hosting config to arrive at the proper html folders on your site.
Finally, and as mentioned, only after all the CloudFlare arrangements have been verified operating as your hoster show you to do, then a final DNS record will be added, by you or them depending on who's managing DNS. This will be a CNAME record aliasing www.domain.com, and it will point not to your site, but to the CloudFlare URL you'll be given, something like www.domain.com.xyz.cloudflare.net.

Ok. Notice that the CNAME alias is from www.domain.com. Your hoster will give you a set of prefix rules to go in your public Craft directory's .htaccess file, above the handling which calls Craft itself. If you have special rules there to cause automatic switching to SSL for the Craft CP, a small portion of those will need to go before the CloudFlare additions. I'll cover that in another question/answer on automatic SSL itself, updating an earlier post to one of the cookbooks, and as setup has slightly changed.

The result of the DNS and .htaccess additions is that your site will now always redirect visitors to www.domain.com even if they originally linked simply domain.com. As you can see, www.domain.com is aliased by the CNAME record to call CloudFlare rather than your site directly, and that's how the speed-up caching is applied.

Railgun will also operate on this URL once you turn it on from your CloudFlare control panel, the one which will have been set up for you by your hosting provider. You want to let them do that, as it is different and differently connected than one which would result from you signing up to CloudFlare independently, thus enabling your hoster's service.

Then you can see why the extra cloudflare-source DNS access is needed. Your main site will refer to www.domain.com, which comes from CloudFlare. CloudFlare must then get its picture of your site from somewhere else, and cloudflare-source.domain.com is that place.

Now that we have CloudFlare arranged via DNS and .htaccess, what do you need to do in Craft configuration to properly use it? As it turns out, not very much.

You need to refer Craft to the now-required www.domain.com wherever it needs reference to your site, rather than domain.com. In particular, the constant siteUrl needs to be set this way You can do that in the CP General configuration page, and/or as a definition in general.php.

Thus if you are not using languages (Locale on Craft Pro), in general.php you would set:

'siteUrl' => 'http://www.domain.com/',

while if you are using languages you would in general.php set the siteUrl array by the same principle, according to the languages on your site. This example is for English, Russian, and Swedish:

'siteUrl' => array(
    'en' => 'http://www.domain.com/en/',
    'ru' => 'http://www.domain.com/ru/',
    'sv' => 'http://www.domain.com/sv/',
),

Several such arrays can be used individually as ever within a multi-site configuration, covering staging servers and so forth if you use that method. With or without multisite, if you've set your staging server as its own subdomain, then that will automatically bypass CloudFlare/Railgun for staging, which is very likely what you'd prefer.

Lastly, if you are using Craft Pro languages (Locale), you'll need to copy the fully equipped main site .htaccess to each of the language folders on the html site, so that they will respond appropriately. Not an option, and one of those fun ways to go wrong with languages, which when set up properly, are on Craft very easy and practical to work with.

How much improvement do you gain, from setting this up?

It can be quite dramatic.

On initial Pingdom testing and a site of not quite medium complexity, I'm seeing >5x improvement monitored in the US: from 2.5 seconds to 0.3 seconds for full all-images page loads, that important first customer access to your site.

Going overseas, CloudFlare is making practical a European customer's site from a single server base at Arcustech in the US. The same ordinary first-load pages go from 3 seconds to under 0.5 seconds. A difficult page with video players on it goes from around 25 seconds to around 1.7 seconds complete, both of these in Amsterdam from Minneapolis servers. The delay on the slow page is due to the video player background loading of libraries, so the screen view comes up more rapidly, but you can see it would be unusable without CloudFlare.

You can see that the CloudFlare-amplified service is as if it was local in Amsterdam. Across Europe one can see via Pingdom that not all areas will be as fast, but with the distribution of CloudFlare edge  servers, all will be practical; 1-second pages say instead of half-second, and a little more for the video page, but by use of player-assisted 'poster' images it comes up visually much more quickly than it completes, so a few seconds will be fine there also.

These figures are assuming the caches are full at the edge servers. The very first access will be slower, if helped by CloudFlare's excellent connections, as always with a cache.

How much Railgun adds, for which we take this special configuration's effort, has to be complex. If you are running CNN-sized pages, it will measurably help a lot, as big boys and girls are using it, as well as other edge caches with similar (and very expensive) features. If you are running small pages, most of the time it will not be so visible. In between, in between.

However, I suspect Railgun is likely to speed up first-viewer-on-empty-edge-cache page speed also, due to its keepalive single connection and compressed, high-availability path. Similarly, it should help unexpectedly more than usual whenever there is network congestion and extended latency, which as anyone who uses or monitors them knows certainly happens a lot on transoceanic paths. As we note with the Netflix wars bringing it to visibility, it's not happening a little within North America itself. Edge caching and delta compression sending only in-page differences is clearly a way to insure and proceed, when it is free as in these Arcustech-type arrangements; at least I feel so for my present and future customers.


How can I set an alias dynamically based on request?

As far as I know, using the @web alias is discouraged if its determined automatically (which is the default behavior).
If you override it with a hardcoded value in production I think you should be fine.

Edit
After checking the documentation, the warning is now pretty dissuasive against using the @web alias :

When you actually use it in a site's base URL setting in the control panel, the warning is a little more moderated:

I'm not sure if its because the documentation is more up to date or if it's actually fine to use it when overridden.


IOHelper::fileExists() will return false for a few reasons:

Either PHP's realpath or is_file returns false. i.e. the given path doesn't exist or PHP doesn't have executable permissions on the folders leading up to that path or read permissions on the file itself.
You're using a case-sensitive file system and you're passing in a different cased path/filename than what's on the file system.


Using Element API to output Super Table fields

Here is a solution I found. Define an empty array, then loop over it, providing whatever keys you want to return from the Super Table fields. Simply by looping over $block->columnTextBlocks (the handle of my Super Table field), Element API returns the information for the fields within the Super Table.

 case 'twoColumnText':

    $SuperTableRows = [];

    foreach ($block->columnTextBlocks as $row){
        $SuperTableRows[] = [
            'fieldHandle1' => $row->fieldHandle1,
            'fieldHandle2' => $row->fieldHandle2,
            'fieldHandle3' => $row->fieldHandle3
        ];
    }

    $contentBlocksArray[] = [
        'twoColumnText' => [
            'columnTextBlocks' => $SuperTableRows,
        ]
    ];

break;

If you need additional information about the Super Table fields, such as Placeholder text, field id's, etc. you can add a generic call to the Super Table field like so (using the same names as my previous code example):

$contentBlocksArray[] = [
    'twoColumnText' => [
        'generic' => $block->columnTextBlocks,
        'columnTextBlocks' => $SuperTableRows,
    ]
];

Now in Element API, the "generic" object includes a customFields array for each field within the Super Table. This only becomes available when you loop over the Super Table field, otherwise it would be null.

Here are some pictures of what the data from Element API looks like.

Here is a simplified version:

'transformer' => function(Entry $entry) {
   $SuperTableRows = [];

   foreach ($entry->superTableFieldHandle as $row){
     $SuperTableRows[] = [
       'fieldHandle1' => $row->fieldHandle1,
       'fieldHandle2' => $row->fieldHandle2
     ];
   }

   return [
     'SuperTableRows' => $SuperTableRows
   ];
 },


Can I make Redactor add a 'title' attribute to img-tag?

None of the settings you can put in your Redactor config-file will do what you want. You can write a redactor plugin to do this, and then include your redactor plugin as a Craft plugin. One Craft plugin that does this is RedactorClips.

If your Craft plugin is mycraftplugin, and your redactor plugin files are myredactorplugin.css and myredactorplugin.js, then you store the redactor plugin files in the resources directory of your craft plugin, and in the craft plugin init() function, you call:

craft()->templates->includeCssResource('mycraftplugin/myredactorplugin.css');
craft()->templates->includeJsResource('mycraftplugin/myredactorplugin.js');


Try adding/changing the hyphenation settings in the config file? e.g.

// establishes minimum length of a word that may be hyphenated
"set_min_length_hyphenation" => 5,

// establishes minimum character requirement before a hyphenation point
"set_min_before_hyphenation" => 3,

// establishes minimum character requirement after a hyphenation point
"set_min_after_hyphenation" => 2,

I ran into a similar problem. There were defaults set, but to get it to work, I had to explicitly add them to my file.


localized site - except home, every page gives me a 404

I finally found the solution!
i was not aware, that the document-root HAS to point to the /web folder.
There were old web applications on the server, which prevented
to change the root. So i made the .htaccess file, to redirect to the
/web folder.
But apparently, this is not going to work.
So keep in mind, to point to the right folder.


Error after downgrading from Pro to Personal

I was only able to answer this because the OP sent a support ticket to and was able to look at their database. :)

When the site was setup in Craft Pro trial mode, the content was built out with multiple locales and those locales were enabled for the sections.

Craft Personal only allows for 1 locale, so when you try to save an entry in a section that was originally setup for multiple locales under Craft Pro, you get an pretty generic "can't save entry" message.

If you go back to Craft Pro and remove the other 2 non-primary locales, the Craft Personal entry saving will work again.


HTML code button missing from Rich Text "standard" view after 2.5 upgrade

Thanks to carlcs for pointing this out. If I edit the Standard.json file in craft/config/redactor/ as per these instructions (https://craftcms.com/help/redactor-ii-configs) it's fixed.

I find it odd that Craft 2.5 didn't come with this Redactor config fix included, rather than letting it break and leaving it up to developers to fix it. I can understand if you had custom configs, but the default Simple and Standard configs should come fixed with the install or upgrade, no?


Definitely a bug and just fixed it for the next release.


How do I use a Twig template to generate Email content from inside a plugin I'm making?

Thanks to Brad for providing the bulk of the answer. In more detail the line needing to be changed was this:

$notificationEmail -> htmlBody = craft()->templates->render('PLUGIN-FOLDER-NAME/TEMPLATE-NAME', ['theUser' => $user]);

I could then use {{ theUser }} (Which is a UserModel) in the TEMPLATE-NAME template to generate everything I needed.

So the full solution, to send an Email from a plugin, but using a Twig template to generate the HTML email content was:

$myEmail             = new EmailModel();
$myEmail -> toEmail  = $user->email;
$myEmail -> subject  = "Subject here";
$myEmail -> body     = "PLAIN TEXT CONTENT";
$myEmail -> htmlBody = craft()->templates->render('PLUGIN-FOLDER-NAME/TEMPLATE-NAME', ['theUser' => $user]);
craft()->email->sendEmail($myEmail);

Where $user was a variable containing a UserModel which I'd already got from previous code in the plugin I was writing.

https://craftcms.com/classreference/services/TemplatesService#render-detail for more detail (but for which I wish there were example code of how to use, and not just a dictionary).


You might be better off sending the values as an array, then you will only need one parameter.
{# Change the macro to check for the value in an array #}
{% macro is_active(segments) %}
    {% if craft.app.request.getSegment(2) in segments %}active{% endif %}
{% endmacro %}

{# Send an array to the macro #}
Link Title


Can entries disabled by default in Guest Entries plugin and in section be enabled from the front-end?

Currently, that won't work.

The Guest Entries plugin looks at the plugin's setting for whether that entry should be enabled for the given section or not, not anything from $_POST.

https://github.com/pixelandtonic/GuestEntries/blob/master/guestentries/controllers/GuestEntriesController.php#L227


offset works for matrix blocks the same way it does for entries.

So you can do this to skip the first 12

{# skip the first 12 blocks #}
{% for contentBlock in matrixField.offset(12) %}
  ...
{% endfor %}


Make segment in the middle of a route optional

Your regex is going to become more complex and potentially less specific if you try to address both scenarios in a single route as the height and width parameters match numbers and the final segment of your URL matches any characters that would be found in a URL segment.

It may be easier to handle this as two rules, the more specific one first:

'/images/<width:\d+>/<height:\d+>/<imageName:([-\w.]+)>'
'/images/<width:\d+>/<imageName:([-\w.]+)>'

Making this two rules you get around needing to matching both a number OR other characters in the third segment. If the second and third segment are numbers and the fourth segment is present, your first rule will match. If the third segment is not a number and there is no fourth segment, your second rule will match.

Also, with two rules you can easily test if height exists or not in your controller or template. If you combine that third segment into a compound rule, you may need additional logic in your template to sort out what value you are working with.


Using this technique to share the Craft app folder across different sites, results in each site having their own config folder. Since the license.key file that determines the licensing status of Craft lives in the config folder, setting up your sites like this will require a separate license for each site, as the domain2 site won't have access to the license.key file in domain1/config.


Why are my entries disappearing when {% if category | length %} is added?

My Category URL Formats was set-up incorrectly. Or rather, I needed to go to {handle}/{slug} to see the proper result.


Issue with validator getNameReplacementInFolder

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

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

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

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


Add active class and territory name to language switcher

The comparison is meant to be used within the for loop that loops your array of locales. And you can of course only compare the current locale tag craft.locale to real locale tags and not with fake ones like 'en_001' that Craft doesn't know about.

{% set locales = ['en', 'en_gb'] %}

{% for locale in locales %}
    {% set current = (locale == craft.locale) ? true %}
{% endfor %}

So you need to find a way to map real locales to your fake ones! The real ones for your craft.locale comparison and the fake ones to get your territories. But then there would be no need to compose fake ones to start with and you would simply map the real locales you installed and use in Craft to the territory names or territory codes for your output string. So let's do this.

{% set locales = {
    'en':    '001',
    'en_gb': 'gb',
    'hu':    'sk',
    'de':    'sk',
} %}

{% for locale, territory in locales %}

    {% set current = (locale == craft.locale) ? true %}

    {% set territory = craft.i18n.getLocaleData(craft.locale).getTerritory(territory) %}
    {% set language = craft.i18n.getLocaleById(locale).name %}
    {% set language = language|replace("/- #{territory}$/", '') %}

    {% if territory and language %}
        <li class="{{ current ? 'myCurrentLocale'}}">
            Territory: {{ territory }},
            Language: {{ language }}
        </li>
    {% endif %}

{% endfor %}


The section that entry #392 belongs to is called blog and it's Entry URL Format setting is set to blog/{slug}.

You also have quite a few entries (100 to be precise), with their slug set to: snippet generating a URI for that slug of blog/snippet.

That works great for the first one, but when you try to save the 2nd one, Craft sees that blog/snippet is already taken and will start appending numbers to the end to try and find a unique URI like so: blog/snippet-1, blog/snippet-2, etc.

But Craft wants to have a reasonable way to know when to stop trying to find a unique URI, so it will look to the maxSlugIncrement config setting and use that, which defaults to 100 - hence the error you're running into.

You either need to 1) use something to generate more unique entry slug formats - like post date/time or 2) increase the maxSlugIncrement config setting to a higher value.


It looks like this isn't possible. But what you can do instead is either:

Route them to a shared template using the category settings and use include programatically:

{% include 'myCatTemplate--' ~ craft.locale %}

Disable "Categories in this group have their own URLs" in the category settings and add your own dynamic routes.


Best way to delete submitted data in Sprout Forms?

Click the checkbox at the top to select all of them.


Since it appears that you are using Craft CMS 3, you can try the purify filter.

In your code, change this line:

{% set vidcode = embed.isSafe() | trim('<iframe') %}

To something like:

{% set vidcode = embed | purify | trim('<iframe') %}

Documentation:


I think you can do this in the template by using for example:

craft.request.getSegments

or

craft.request.getParam( name )

See the docs:

https://craftcms.com/docs/templating/craft.request


At the risk of being too general/closed for off-topic, before you choose any platform, I would ask these questions:

What sort of functionality  does your client require—now or in the future?
What kinds of products will the store support (eg bundles, custom products, variants, donations, etc).
What sort of budget / developer support can the client support or is required?

In general, Craft is the more nascent/new product so if your team's dev chops aren't familiar with Commerce, there can be a learning curve.
Magento does a lot of the box and if you need to hook into some obscure (or not so obscure) service, Magento probably already has a plugin for it. It has a bigger ecosystem but that doesn't mean Craft isn't up to the task.
Shopify can also be an option depending on what you're trying to do.
In general, Craft/Commerce really excels at customized e-commerce. If your client's needs are modest, for example selling simple products without customization, Shopify might actually be a better fit long term. However when you start to get into more niche businesses where there's customized shipping or products, the the tables tip more in favor of Craft.
Speed
You question also asks about speed. Fast is a relative turn. A lot is going to depend on 1) server infrastructure and 2) your own code.
Also:

What does a performance budget look like?
How many visitors/users are you expecting? Where are they located?
How will you measure the solution?

Compared to Magento, Craft is pretty light-weight. Magento is not known for being resource-friendly, however there is probably more documentation on how to make it speedy.
If you go with something like Shopify, you don't have to worry about infrastructure—which is one of the reasons it's popular.
Also related
Why choose Craft Commerce over Magento


Password validation for resetting password

I wasn't validating againts the field newPassword, only validating against password. Hence why I wasn't getting any feedback. Duplicating the validation for newPassword seems to have resolved this.


Can a JS string variable be used in Twig?

As Twig is rendered server side before passed to a browser for JS execution I found out that it can't be done except FOSsRoutingBundle which allows you to expose your routing in your JavaScript code. I don't know if that would be a great idea.

Anyway. I found workaround solution that seems to be working for me.

Here is the Ajax post action with simple window redirection.

// Send it to the server
$.post('/', data, function(response, textStatus, jqXHR) {

  if (response.success) {

    // Request for entry ID key string to be used in HTTP redirect link
    var entryId = response.id

    // HTTP redirect
    window.location.replace("{{ siteUrl }}" + entryId + "/someUri");

    } else {
    // response.error
  }

});

Don't forget Craft's routing!


Validating date fields in a plugin's settings

It turns out that because I'm now using my own settings model, I don't need to use AttributeType::Mixed for my date fields any more. (Thanks to carlcs for suggesting this.)

So I've removed the stuff I had in my Plugin's getSettingsHtml(), which massaged the fields before sending them to the template. And now, in theory, I only need to do this:

<?php
namespace Craft;

class My_SettingsModel extends BaseModel
{
    protected function defineAttributes()
    {
        return array(
            'myText' => array(AttributeType::String,
                            'column' => ColumnType::Text, 'required' => true),
            'myDate' => array(AttributeType::DateTime,
                            'column' => ColumnType::DateTime),
        );
    }

    public function rules()
    {
        $rules = parent::rules();

        $rules[] = array('myDate', 'date',
                        'format' => array('dd/MM/yyyy'),
                        'allowEmpty' => false,
                        'message' => 'Please enter a valid date');

        return $rules;
    }
 }

However, although the form requires me to enter dates - it doesn't accept empty fields - it won't accept the dates I'm typing in. e.g., if I enter 31/12/2016 it fails the date validation. Looking at Yii's date validation docs I think this should work...


How to keep staging install synced with member registration

You should have a look into project config if you haven't already.
It allows you to sync just the structural changes of your development, staging and live sites, without affecting the content/users.
This way you can still sync your production database to staging, but then you can just sync the structural changes back to production – no freezing necessary.


variable inside for loop is empty outside the loop

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

{% set imageUrl = '' %}


Figured it out:

<?php

return [
    'webhook' => 'http://example.com',
];


Uploaded images are saving to the server's temp folder and throwing 500 errors

Crappy shared web hosting?

That would be my guess. It seems imprudent to be developing a site on the same host as a live site, it has to share the (probably already stretched) resources available on a shared host and there isn't enough juice to run everything.

Solution? Get a $5 VPS, and see how it runs there. In my experience a properly configured $5 VPS will out-perform shared / managed hosting costing 5x the price. Most VPS can be billed by the hour/minute, so if you don't like it just cancel and you'll be charged only a few pennies.

Personally, I would recommend Linode + Serverpilot.

Both services can be cancelled without notice, so there's really no tie-in or big gamble.


Why does loop.index not work with replace?

Twig output tags won't work inside of Twig output tags.

You should be using '

'~loop.index~''

The overall approach seems a bit heavy-handed though.


Can I store Assets on a Cloud Service like Amazon S3?

Yes, you could install the Amazon S3 Plugin in order to select & configure that Volume type in your control panel.
After installing that you will get new volume type “Amazon S3” in Settings → Assets → New Volume.

Now you can create new column and using it you can store your assets in Amazon S3 cloud service.


Craft on Heroku with buckateer as a middleman for Amazon S3

I found a solution that lets you overwrites the core file S3.php without touching the core files.

By adding this snippet to config/general.php

// S3 override
const BUCKET_NAME = 'YOUR BUCKET NAME';
require_once('../craft/plugins/gm/S3.php');

return array(
   ...
);

And duplicate the S3.php file and add it to the plugins folder you can make the needed changes.


How to filter entries by checkboxes using Sprig

Checkbox input field names should be in array format (not specific to Sprig), so I expect this should work.
<input sprig type="checkbox" class="filter_checkbox" name="newsCat[]" id="checkbox_{{ category.id }}" value="{{ category.id }}" {{ category.id in newsCat ? 'checked' : '' }}>


Exposing current Commerce2 Cart via the Element API

The cart is not baked into \Craft, but craft\commerce\Plugin.

Try the following:

$cart = craft\commerce\Plugin::getInstance()->getCarts()->getCart();

Uses the following function:

/**
 * Get the current cart for this session.
 *
 * @param bool $forceSave Force the cart to save when requesting it.
 * @return Order
 * @throws Exception
 * @throws \Throwable
 * @throws \craft\errors\ElementNotFoundException
 */
public function getCart($forceSave = false): Order


How can I import a large number of new entries into Craft 3

One option is to create a Craft 2 site, import the entries there, and then upgrade that site to Craft 3.


The default URL to access Craft is /admin.

Note also this can be changed to anything you like using the cpTrigger config variable.


Get first X paragraphs, then output the rest

Seems like a huge hack to me but here's how to do it:
{# Split paragraphs using with a limit of 3 #}
{% set paragraphs = text|split('
', 3) %}

{# Get an array containing the first 2 paragraphs, and convert it back to a string, adding missing closing tags  #}
{% set firstParagraphs = paragraphs|slice(0, -1)|join('
') ~ '
' %}

{{ firstParagraphs|raw }}

{# The rest of the text is here, due to the limit in the split filter #}
{{ paragraphs|last|raw }}

To adjust the number of paragraphs in your first group, just change the limit parameter of the join twig filter (this is a bit counter intuitive, see the Twig documentation to understand the logic).


Passing data back to form on invalid submission

You can call setRouteVariables and not return anything from your controller so the request continues as normal.  Craft does this all the time with it's own controllers.  See this answer for the general controller workflow.


fileCache seems to expire even though I have it set to 0

You should be using craft()->cache with the cacheMethod config setting set to file (which it is by default) instead of craft()->fileCache.  The latter is deprecated and won't work in Craft 3.

Yii does have garbage collection on cache, and by default an item has a 0.01% change of being purged from cache regardless of expiry time.

If you think you're not being garbage collected, you can check the file modified time of the files in craft/storage/runtime/cache.  If you explicitly pass in 0 as an expiration time, Yii will set the file's modification date to a year out.


Making an entry grid with Batch 2,3 (2 in row then 3 in row)

With some help from HendrikEng's answer I figured out something that does work.

I had to make the batch bigger to an amount of 5 making the "row's" bigger. Also I had to set the position of the bigger block which always is the first or second of this batch so I could set this witha variable which changes if a new batch started.

This is the finalcode which works perfect:

{% for entry in craft.entries.section('cases')|batch(5) %}

    {% set bigBatchNr = 2 %}

    {% if loop.index is even %}
        {% set bigBatchNr = 1 %}
    {% endif %}

        {% for batch in entry %}
            {% if loop.index == bigBatchNr %}

            {% else %}

            {% endif %}
        {% endfor %}

{% endfor %}


How do I add meta title/description and intro text to a Channel index page?

From the docs:

Singles

Singles are used for one-off pages that have unique content requirements, such as:

home page
an About Us page
a Contact Us page

Unlike the other section types, Singles only have one entry associated with them, and they don’t have an editable Author, Slug, Post Date, or Expiration Date.

So create the fields you need, create a new single for your index page, add the fields to the single, set the single to load your index template, then code your new fields into the template


Eager-Loading is not like a hook or a callback. You wouldn't set variables within it. You'd want to use eager-loading to load your eventVenueId then in your loop you'd set the variable a little differently.

 {% set entries = craft.entries ({
          section: 'events',
          order: 'postDate desc',
          with: ['eventMainImage', 'eventVenueId'],
          relatedTo: category
  }) %}

 {% for entry in entries %}
    {% set venue = entry.eventVenueId[0] ?? null %}

Additionally you could look at eager-loading a Nested Set of Elements to further optimize your query if possible with the data you need off your eventVenueId elements.


How can I set an absolute image url for Open Graph Image tags?

I'm pretty sure the reason this is happening is because you did not set an absolute Base URL in your asset settings. So if you use /assets/images/folder in your asset settings, that's what the urls will look like on the frontend. If you instead use http://my-project.com/assets/images/folder, your asset urls will include the domain name.

I'd recommend setting up Yii Aliases in your config (if you haven't already) and using those instead of hard-coding the url. So you'd do something like this in Craft's general.php config:

'aliases' => [
    '@assetBaseUrl' => 'http://my-project.com/assets',
    '@assetBasePath' => '/path/to/web/assets',
],

And then in your asset settings you'd be able to use @assetBaseUrl/images/folder instead of http://my-project.com/assets/images/folder. Just a way to keep everything as DRY and clean as possible

The above solution should solve your issue, but fwiw, I'm pretty sure you can force your site to use absolute urls regardless of your asset settings. If you use the url() method and specify what scheme you want, I believe it will always resolve to an absolute url. So something like the following should work (but it feels very icky to me):

{% set seoImage = entry.featuredImage.one().getUrl('hero') %}
{% set absoluteImageUrl = url(seoImage, '', 'https') %}


Do email messages use control panel or translation file template when sending by key?

The answer is both. It will use whatever’s in the translation file by default, until an admin goes to Settings > Email > Messages and customizes it.


Short and sweet... I think you just need to add a second route.

'blog/archive' => 'controller/action/path',
'blog/archive/<year:\d{4}>' => 'controller/action/path'


Log in as different users in backend front end at the same time?

You can use "incognito mode" in your browser, or you use another browser or computer for this type of front end testing.


Update billing details for a subscription

I've solved this in the past by just showing the payment sources, and allowing the user to delete existing payment sources:
{% set paymentSources = craft.commerce.paymentSources.getAllPaymentSourcesByUserId(currentUser.id) %}

{% if paymentSources %}

                    Card details

                    Actions

        {% for paymentSource in paymentSources %}

                {{ paymentSource.description }}

                    <form method="post">
                        {{ csrfInput() }}
                        {{ actionInput('commerce/payment-sources/delete') }}
                        {{ redirectInput(entry.uri) }}
                        <input type="hidden" name="id" value="{{ paymentSource.id }}"/>
                        <button type="submit">Delete</button>
                    </form>

        {% endfor %}

{% endif %}

You can then show a form to add a new payment source:
{% set customer = craft.commerce.customers.getCustomer() %}
{#
    Note: this next line fetches a single subscription - if you support multiple
    subscriptions, you'll need to do it a little differently
#}
{% set currentSubscription = customer.getSubscriptions()|first %}
{% set plan = craft.commerce.plans.getPlanById(currentSubscription.planId) %}
{% set gateway = plan.getGateway() %}

<form method="post" accept-charset="UTF-8" autocomplete="off" novalidate>
    {{ csrfInput() }}
    {{ actionInput('commerce/payment-sources/add') }}
    {{ redirectInput(entry.uri) }}
    <input type="hidden" name="gatewayId" value="{{ gateway.id }}">

    {{ gateway.getPaymentFormHtml({})|raw }}

    <button type="submit">Add card</button>
</form>

This is probably the simplest answer to your question, though you can get creative with how you present the payment sources and the add card form to the user.


Using a GraphQL mutation to append a block to a Neo field

So the work around was to convert the Neo field to a Matrix. That worked for this instance since we're not storing anything complex but I'd sure like to figure out if/how Neo supports mutations.
mutation addRecipeReview($recipeId: ID, $blocks: [reviews_MatrixBlockContainerInput] = {review: {authorEmail: "", authorName: "", authorReview: "", reviewDate: "", reviewRating: ""}}, $sortOrder: [QueryArgument] = "") {
  save_recipes_recipe_Entry(id: $recipeId, reviews: {blocks: $blocks, sortOrder: $sortOrder}) {
    id
    reviews {
      ... on reviews_review_BlockType {
        id
        authorEmail
        authorName
        authorReview
        reviewRating
        reviewDate
      }
    }
  }
}

Variables:
{
  id: "1234",
  sortOrder: ["4321", "4322", "new:1"],
  blocks: [
    {
      review: {
        authorName: "Author Name",
        authorEmail: "Author Email",
        authorReview: "Review",
        reviewRating: "Rating",
        reviewDate: "Date Submitted"
      }
    }
  ]
}

The odd/silly part about the above is that you have to pass in an array of all the existing block IDs to sortOrder, and use the idiom "new:1" for your new block. If you skip the "new:1" it won't add the new block, and if you only pass in "new:1" but omit the existing block IDs it deletes all the existing blocks. You can pass an array of new blocks (the code above only has one) in the 'blocks' array, but you'll have to add "new:1", "new:2" ... up to how many blocks you have.


Just a hunch and not tested, but don't do this:

$group->id   = '';

My guess is by explicitly setting that to an empty string, Craft thinks it's dealing with an existing record and not a new one.


How can I add custom headers to an ElementAPI response?

You can do this by assigning your endpoint(s) to a function:

return [
    'endpoints' => [
        'my-endpoint' => function() {
            HeaderHelper::setHeader(['Surrogate-Control: max-age=300']);

            return [
                // ...
            ];
        }
    ]
];

UPDATE

Alternatively as of v1.2, you can do it from a separate plugin using the onBeforeSendData event:

public function init()
{
    craft()->on('elementApi.onBeforeSendData', function(Event $event) {
        HeaderHelper::setHeader(['Surrogate-Control: max-age=300']);
    });
}


How to get user's photo url without transform?

According to the Craft 3 source code, User::getPhotoUrl() has been deprecated. Use getPhoto() to access the photo asset (if there is one), and call its getUrl() method to access the photo URL. (Also mentioned in the changelog.)

So assuming you've set user to something already in your template, the correct way to get the photo in Craft 3 is:

{{ user.photo.url() }}


The field is returning a Map object, you then need to call what you want from there. The relevant documentation parts are:
Embedded map - https://docs.ethercreative.co.uk/maps/rendering/embed/#from-a-map-field
Static map - https://docs.ethercreative.co.uk/maps/rendering/static/#from-a-map-field
Based on your code and dump:
{# Fetch the Map object #}
{% set myMapField = craft.entries()
    .section("home")
    .one()
    .mapGoogle %}

{# The below should render Milky Way based on your dump #}
{{ myMapField.galaxy }}


Anyone curious about this answer, can checkout the GitHub thread referred to above:
https://github.com/boboldehampsink/import/issues/14

The most relevant comment for this answer is by boboldehampsink:

the documentation on category importing isn't complete yet. You have to fill in the complete path with titles, so: Category Title/Subcategory Title/Subsubcategory Title (for example)


After several iterations I came up with this that works. But still puzzled as when to use [ ] or { }.

{
    "buttons": ["html","undo","format","bold","lists","link","file"],
    "plugins": ["fullscreen","table","video"],
    "formatting": ["p"],
    "formattingAdd": {
        "heading": {
            "title": "Heading",
            "api": "module.block.format",
            "args": {
                "tag": "h2"
            }
        },
        "sub-heading": {
            "title": "Sub-Heading",
            "api": "module.block.format",
            "args": {
                "tag": "h3"
            }
        },
        "sub-sub-heading": {
            "title": "Sub-sub-Heading",
            "api": "module.block.format",
            "args": {
                "tag": "h4"
            }
        },
        "add-attr": {
            "title": "Make a link a button",
            "api": "module.block.format",
            "args": {
                "tag": "div",
                "class": "button"
            }
        }
    }
}


How can I get an entries author custom field?

Ah it would of been handy if I had of entered the assets loop!

  {% for asset in entry.author.authorImage %}
    <img src="{{ asset.getUrl() }}" alt="{{ entry.author.getFullName }}">
  {% endfor %}


What accurately will set asset paths for multilingual sites?

If each locale uses the same TLD but uses a subfolder for localized content (i.e. example.com/en, example.com/de, etc.). You can move between development, staging, and production environments without having to change settings in the admin panel by simply using an absolute path in the Admin assets source URL setting (i.e. /assets/img/uploads) and a relative path for the File System Path there (i.e. ../public_html/assets/img/uploads).

For more complicated setups, such as independent site URLs (i.e. example.com, example.co.uk, etc) for each locale, I've set asset paths by setting an assetsUrl environment variable in general.php like so:

'example.com' => array(
    'environmentVariables' => array(
        'siteUrl'        => '//example.co.uk/',
        'assetsUrl'    => '//example.com/'
    )
)

Then in the Admin panel's assets source settings, I set a relative path for the File System Path and use the {assetsUrl} environment variable for the URL.

With this setup you can also move between development, staging, and production environments without having to change settings in the admin panel.

Once {assetsUrl} is set in the Admin panel for the URL, writing {{ file.url }} in your template will return the full URL using the assets source URL setting.

Or, you can link to assets (e.g. scripts) in your templates using the assetsUrl environment variable.

{{ craft.config.environmentVariables['assetsUrl'] }}assets/js/main.js


I believe you need to use tweak the config/general.php file in order to have a baseUrl for a site that is a different domain name.
'siteUrl' => [
    'english' => 'https://www.mysite.com/',
    'japanese' => 'https://www. myjapanesesite.com/',
],

See documentation at: https://docs.craftcms.com/api/v3/craft-config-generalconfig.html#siteurl


Totally untested but this should work

$enabledSiteIds = (new Query())
    ->select('siteId')
    ->from('{{%elements_sites}}')
    ->where([
        'enabled' => true,
        'elementId' => $elementId
    ])
    ->column();

You might want to join the elements and entries table in order to gain only elements where elements.enabled is true too (and check the expiry date), otherwise you'll receive disabled entries


Yes, it would be possible. I don't think there's an easy (plugin) solution for this purpose, though. If your project has an active module, you could use that to save the click count and retrieve it from the DB.

Make sure your module works (in the default Craft project, it's as simple as uncommenting the module line in config/app.php)
Create a migration to create a table in which you store the click counts (per url, or by ID if each link has a unique ID)
Create a model to interact with your table
Create a controller method to handle the clicks (get DB row for URL, add 1, save it)
Create a template variable to get the click count for a URL

After that, all that's left is writing some JS to listen for link clicks and POST the URL to your controller method.

All in all, not very easy if you're new to PHP (be sure to read this before you start), but a nice first dive into Craft plugin/module development.


Whats the best way to create short URL's

You could make a plugin that generates a short URL using a link-shortener API (e.g. dev.bitly) for each of your entries and provides the URL as a custom read-only Field Type.


Sending activation emails to all pending users

foreach(\craft\elements\User::find()->status('pending')->all() as $user){
    Craft::$app->getUsers()->sendActivationEmail($user);
}

Fetch all pending users and send them the mail


The error "Variable "entry" does not exist means that your current page does not have a variable called entry available. This probably means the problem lies in how you have your Sections or routing set up.

If you remove Sprout SEO from this page and just try to access entry.title in your template, you will probably receive the same error. So, it will be best to troubleshoot that and confirm you have the entry variable available to the page before troubleshooting what might be going on in Sprout SEO.

Once you know the Single is setup correctly and able to display data from the entry variable, the next question would become why is the entry variable not available to the particular part of your page where you are trying to hand off information to Sprout SEO. To answer that, it would be helpful if you posted more information on what your template looks like, where outputting the entry variable to the page directly works, and where trying to pass the entry.id variable on the page throws an error.


Is there a way to check if any fields in a global set have content?

It's not exactly "quick", you'll have to do something like this:

{% if socialNetworkContent.branchFacebookProfile|length
       or socialNetworkContent.branchTwitterAccount|length
       or socialNetworkContent.branchLinkedInAccount|length
       ...
%}

Which is probably exactly what you're trying to avoid.

If you want to just make it a little easier to read, you can do something like this:

{% set x = socialNetworkContent %}

{% if x.branchFacebookProfile|length
       or x.branchTwitterAccount|length
       or x.branchLinkedInAccount|length
       ...
%}

The hurdle that you're dealing with is the fact that the socialNetworkContent object contains many other attributes besides just your custom field names. So there's not really any efficient way to "loop through" your custom fields without dealing with a bunch of extra junk.

Of course, you could build a plugin to create a simple boolean variable, but that sounds like overkill for this situation.


how to concatenate multiple variables and strings

Another option is to use the twig join filter:

{% set urlParam = [street, city, 'UT']|join(', ') %}

join concatenates the items in the sequence with the separator of your choice in between.