Craft doesn't come with a PHP library for audio, so there's no core solution for your problem.

But what you could do is to make a plugin, add such a library to it and provide duration and bitrate Twig filters to your templates.

EDIT:

You could try out my new "Asset Metadata" plugin. It makes use of the getID3 PHP library to extract all sort of metadata from your assets.

To make your life a bit easier, I added further beautified metadata properties like a sound file's playtime duration in ISO 8601 date interval format (i.e. PT1H21M48S), or a photo's exposure time as a ratio.


Search for non-existing tags shows all entries

That is only logical. Your tag will be null so your query is actually
{% set entries = craft.entries.relatedTo(null).order('title').limit(null) %} and that results in
{% set entries = craft.entries.order('title').limit(null) %}
So in the end you will fetch all entries.
This is what you need

{% set tag = craft.tags.slug(tag).first %}
<!-- check if the tag exists -->
{% if tag %}
    <!-- the length filter actually fetches all entries -> executes the query and caches all entries
    so you can just fetch them in the beginning. You'll gain no performance boost with that filter -->
    {% set entries = craft.entries.relatedTo(tag).order('title').limit(null).find() %}
    {% if entries %}
        {% for entry in entries %}
            <!-- code here you fetched entries -->
        {% endfor %}
    {% else %}
        <!-- you have a tag but no entries related to that tag -->
    {% endif %}
{% else %}
    <!-- you have no tag -> you won't find any entries -->
{% endif %}


This would probably require a plugin with a controller which you could post the order id to when clicking the button. Within the controller you could then query the database to get each line item and add it to the cart within a service if it is in stock and still enabled. The final step would then be to redirect to the basket or posted url.

The docs here should help you get started: https://craftcms.com/docs/plugins/controllers


How can I use the password confirmation modal on other forms?

I copied and modified the built-in craft AccountSettingsForm.js and placed it in my own plugin to test and it seems to work great. You will need to adapt it for your own use of course. It is currently triggered on elements that have a class 'btn confirm', and just prints 'Password Confirmed!' on success to the alert window.

Create a button in your plugins CP template file:

<input type="submit" class="btn confirm small submit" value="{{ 'Confirm'|t }}" >

And include the new js file PasswordConfirmation.js, which is:

(function($) {

PasswordConfirmation = Garnish.Base.extend(
{
    isCurrent: null,

    $lockBtns: null,
    $currentPasswordInput: null,
    $spinner: null,

    modal: null,

    init: function(isCurrent)
    {
        this.isCurrent = isCurrent;
        this.$lockBtns = $('.btn.confirm');
        this.addListener(this.$lockBtns, 'click', 'showCurrentPasswordForm');
    },

    showCurrentPasswordForm: function()
    {
        if (!this.modal)
        {
            var $form = $('<form id="verifypasswordmodal" class="modal fitted"/>').appendTo(Garnish.$bod),
                $body = $('

'+Craft.t(this.isCurrent ? 'Please enter your current password.' : 'Please enter your password.')+'

').appendTo($form),
                $passwordWrapper = $('
').appendTo($body),
                $buttons = $('
').appendTo($body),
                $cancelBtn = $('
'+Craft.t('Cancel')+'
').appendTo($buttons),
                $submitBtn = $('<input type="submit" class="btn submit" value="'+Craft.t('Continue')+'" />').appendTo($buttons);

            this.$currentPasswordInput = $('<input type="password" class="text password fullwidth"/>').appendTo($passwordWrapper);
            this.$spinner = $('
').appendTo($buttons);
            this.modal = new Garnish.Modal($form);

            new Craft.PasswordInput(this.$currentPasswordInput, {
                onToggleInput: $.proxy(function($newPasswordInput) {
                    this.$currentPasswordInput = $newPasswordInput;
                }, this)
            });

            this.addListener($cancelBtn, 'click', function() {
                this.modal.hide();
            });

            this.addListener($form, 'submit', 'submitCurrentPassword');
        }
        else
        {
            this.modal.show();
        }

        // Auto-focus the password input
        if (!Garnish.isMobileBrowser(true))
        {
            setTimeout($.proxy(function() {
                this.$currentPasswordInput.focus();
            }, this), 100);
        }
    },

    submitCurrentPassword: function(ev)
    {
        ev.preventDefault();

        var password = this.$currentPasswordInput.val();

        if (password)
        {
            this.$spinner.removeClass('hidden');

            var data = {
                password: password
            };

            Craft.postActionRequest('users/verifyPassword', data, $.proxy(function(response, textStatus)
            {
                this.$spinner.addClass('hidden');

                if (textStatus == 'success')
                {
                    if (response.success)
                    {
                        alert('Password Confirmed!');

                        this.modal.hide();

                    }
                    else
                    {
                        Garnish.shake(this.modal.$container);
                    }
                }

            }, this));
        }
    }

});

new PasswordConfirmation;

})(jQuery)

The next step would be to make it more generic so that it returns true, or executes a callback method, so that the result function can be customized per-use, and perhaps improve the instantiation so that you can pass it your own jquery selectors.


This will exclude empty categories, meaning they don't have any entries associated with them.

{% set entryIds = craft.entries.section('channelHandle').ids() %}
{% set categories = craft.categories.relatedTo({ sourceElement: entryIds }).group('categoryGroupHandle') %}

{% for category in categories %}

{{ category.title }}

        {% set entries = craft.entries.section('channelHandle').relatedTo(category) %}
        {% for entry in entries %}

{{ entry.title }}

        {% endfor %}

{% endfor %}


The solution is:

{% if "itching" in submission.symptomCheckerSymptoms.value %}
{% endif %}


How do I (also) cycle a class on a Matrix block?

The loop.index0 variable will be incremented for each block, regardless of type, so assuming every other block is a header, it's not surprising that the cycle method prints "even" for every text block.

I think what you need is a different variable which only increments whenever you hit a text block (note that this variable should be declared outside the for loop):

{% set textIndex = 0 %}

{% for block in entry.articlebody %}

    {% switch block.type %}

        {% case 'heading' %}

{{ block.heading }}

        {% case 'text' %}

{{ block.text }}

            {% set textIndex = textIndex + 1 %}

    {% endswitch %}
{% endfor %}


Craft 3: Get Data from a custom Table via createCommand()

You can use either an activeRecord  for it

$customer = Customer::find()
    ->where(['id' => 123])
    ->one();

Or a query

$rows = (new \craft\db\Query())
    ->select(['id', 'email'])
    ->from('user')
    ->where(['last_name' => 'Smith'])
    ->limit(10)
     ->all();


Sprout Form submit: The CSRF token could not be verified!

The form code in the template was wrapped in a {% cache %} tag.


frontend editing, show selected category

Something like the following should work. This assumes that your category field handle is 'jobCategory', and has a limit set to 1.

{% set categories = craft.categories.group('jobCategory') %}
{% set entryCategory = entry.jobCategory.first %}
<label for="fields[jobCategory]">Job Category:</label>
<select id="jobCategory" name="fields[jobCategory]">
    {% for category in categories %}
        <option value="{{ category.id }}" {% if category.title == entryCategory %}selected{% endif %}>{{ category.title }}</option>
    {% endfor %}
</select>


Here's what I'm using:

# Remove the www from the URL
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]

# Exclude root files
RewriteCond $1 !^(favicon\.ico|favicon\.png|fb_share\.jpg|apple-touch-icon\.png|apple-touch-icon-precomposed\.png|index\.php|robots\.txt) [NC]

# Exclude asset folders
RewriteCond $1 !^(assets|uploads)/ [NC]

# Remove index.php
RewriteRule ^(.*)$ /index.php/$1 [L]

You could also set up a CNAME record from www.domain.com to domain.com in your DNS.


Entries related to an entry in a list of entries

Thank you very much for your support. The code shown in the question is correct.

I have replaced the relationship field - and now it works perfect. The problem could have been that I defined the field first as a number field an then changed to a relationship field - but this is just speculation.


Not natively, but it would be pretty easy for a plugin to add a widget that does something like that.

I don't see anything currently on Straight Up Craft that would fit that bill, unfortunately.


I believe what you're trying to accomplish can be done with a plugin.

Perhaps this OAuth plugin could at least offer some boilerplate for you: https://dukt.net/craft/oauth/

dukt's github also has some provider-specific plugins: https://github.com/dukt


How do I add a new item or object to an existing object?

When you use the Twig curly brace {}, key/value pair syntax like you've got imagerConfig set to, you're using the Twig hash literal.

In Twig, if you want to add to an array or hash after it has already been created, you can use the merge filter.

Something like this should do what you're looking for:

{% set imagerConfig = { jpegQuality: 80, pngCompressionLevel: 4 } %}

{% set width = { width: 1000 } %}

{% set imagerConfig = imagerConfig|merge(width) %}

{% set largeLogo = craft.imager.transformImage((logo.getUrl('LargeLogo')), imagerConfig) %}


Receiving PHP Warning on move to Production

So Brad tracked down the issue being Twig needs at least PHP 5.2.7 to run. As of 1.34, the minimum requirement was bumped to PHP 5.3.3. Craft bumped up Twig to 1.35 in version 2.6.3001

https://twig.symfony.com/doc/1.x/intro.html

My clients server was actually running 5.3.29. The server default was 7, bumping it up to php 5.4 fixed the site.


Error clearing a field via migration script

I figured it out. I'm not sure understand the why of it. But here is the how:

$product->setFieldValue('components', []);
Craft::$app->elements->saveElement($product);

I guess setFieldValue() does some other stuff in it that the magic methods do not.

The more you know! :)


Have Craft deliver single page despite having a directory of the same name in the public folder?

You could update the links to your static HTML to point to the files directly

http://mygreatnewcraftsite.com/events/myoldstaticfile.html

or modify your .htaccess file like I described here: "Is it possible to tell Craft to ignore requests to under a certain path?"


Using Form to update User Profile and submit form

Yep, that's totally do-able. Check out this article to see how to create a registration form.

Then check out this article to see how to create the update profile form.

The thing to note is that any custom fields like address or city need to be pre-pended with fields.

So, let's say you want the user to enter their city. On your front-end form the markup looks like this:

City

<input id="city" type="text" name="fields[city]"
{%- if currentUser is defined %} value="{{ currentUser.city }}"{% endif %}>
    {% if currentUser is defined %}
        {{ errorList(currentUser.getErrors('city')) }}
    {% endif %}

... and so on.

Make sure that your field handle(s) in the CP align with what you call them on your front-end form.

Here is how you can check for the current user.

Here is another great example of how to populate custom fields in your profile/registration form.

Hope this helps!


getTransactionByHash() must be of the type string, null given

When you redirect to the gateway's site to accept payment, within the data they receive, they usually ask for the URL to return to after payment is made.

This URL should point to the PaymentsController::actionCompletePayment() controller action, but have the param ?commerceTransactionHash=YOUR_TRANSACTION_HASH appended to it.

My guess is that the error you are getting is being triggered in PaymentsController::actionCompletePayment() on line 346:

$hash = Craft::$app->getRequest()->getParam('commerceTransactionHash');

$transaction = Plugin::getInstance()->getTransactions()->getTransactionByHash($hash);

Where it is passing null to getTransactionByHash.

Once it is able to get the transaction, it will call your gateway's completePayment method where you can inspect the request data from your gateway.

Hope that helps.


How Do I Add a rel="canonical" HTTP Header to Embedded PDF Files?

So the problem you're running into is all about context. Twig operates in the context of the http request for the parent page; so any headers you add via Twig will be added to the page http header, which is not what you want.

This could be done server-side, as the article you reference mentions. But it becomes a bit more involved when we're dealing with dynamic content, which presumably we are if a CMS is in the mix.

Because what you need is something that will intercept the http requests for documents you want to affect the header of, and then set it based on the dynamic page where it's coming from.

You could accomplish this via a plugin by writing a controller that sets the headers and then returns the actual file. Then in your Twig code, you'd link to the controller not the PDF file.

If you're using SEOmatic for Craft CMS 3, you can use the built in seomatic.helper.seoFileLink() function to do all of this for you.


Customise errors when validating model data?

In addition to Brad’s answer (which is what I was looking for), you could also use template-specific messages using conditionals if for some reason you only needed to override the global error in a certain place. Unlikely but here’s an example:

{% if errors.attributeOne is defined ? errors.attributeOne | length %}

Custom message.

{% endif %}


I suspect this isn't so much a problem with the strategy as the implementation of the MatrixBlockModel, which is the object type you're trying to merge with a standard Twig "object" or associative array (not sure exactly what Twig uses, behind the scenes).

If you're trying to provide some defaults for various Matrix fields, those ought to be set within the fields, individually.

Otherwise, I think the solution you need is something like this:

{# ... #}
{% set blocks = entry.matrixBlockField %}
{% for block in blocks %}

  {% set options = {
    'class': 'episode',
    'more': 'Listen to this interview...',
    'slug': craft.request.firstSegment,
    'linkUrl': interview.url
  } %}

  {% include '_includes/blocks/half-block.html' with {
    options: options,
    data: block
  } %}
{% endfor %}
{# ... #}

In your partial, you have a bit more work ahead of you, but the special behavior of Twig's ternary operator should help:

{{ data.field ?: options.fallbackField }}

I may be misunderstanding the problem, though— is there something about fetching the MatrixBlockModel elements that appears to be going wrong? As a general rule, I try and avoid using any Twig/Craft reserved words/terms for variable names, but I don't think that's the root of the problem here…


Craft strips out parenthesis in file names.

I can't see a way... uploads ultimately get run through FileHelper::sanitizeFileName(), which has a hard-coded list of disallowed characters in a file name (including parenthesis).

https://github.com/craftcms/cms/blob/develop/src/helpers/FileHelper.php#L128-L166


How do I access AJAX data within a controller method?

Any properties of the object you pass into Craft.postActionRequest()’s second argument will be available to Craft as POST parameters, so you can get to them with HttpRequestService::getPost():

$sData = craft()->request->getPost('Data');

foreach ($sData as $temp)
{
    $wine = $temp['wine'];
    // ...
}


Not sure i understand well, but to be sure: you want to be able to filter for (let's say you sell shirts) a Red AND Large shirt, so it filters only the shirts which contain the color red and that are available in large?

On that note, have you tried setting relatedToParam to and instead of or?

The answer you linked seems to work for multiple selections that are not related. For example: i want the website to show me all the red shirts and all the large shirts, but not necessarily just the red large shirts.

Following that logic, changing relatedToParam to and should do the trick?

EDIT (2019-02-07):

So, i tried quite a few solutions and that seems to be working, please read the comments.

EDIT 2:

There was an issue!
For example, if no size was selected, the loop simply won't do nothing. You could switch the loop to start with types, but then again, if no type is selected, same problem.
Now it's working but still really NOT versatile.
Feel free to edit or comment with a better solution!

{% set sizes = craft.tags.group('size').all() %}
{% set types = craft.tags.group('type').all() %}

{# You'll need to separate tags inside the query itself #}
{# ?size=......&type=...... #}

{# The split filter doesn't work directly on getParam #}

{# Error when getParam is empty #}
{# Because it is set to [] and we can't split on an array #}
{# You will need to find a little condition to make it bulletproof #}

{% set selectedSizesIds = craft.app.request.getParam('size') ?? [] %}
{% set selectedSizesIds = selectedSizesIds|split(',') %}

{% set selectedTypesIds = craft.app.request.getParam('type') ?? [] %}
{% set selectedTypesIds = selectedTypesIds|split(',') %}

{# You can actually use a if inside a print statement #}
{# Take a look at the "checked" print condition #}

{% for size in sizes %}
    <input type="checkbox" name="tags[]" value="{{ size.id }}" {{ (size.id in selectedSizesIds) ? 'checked' : '' }}>{{ size.title }}</input>
{% endfor %}

{% for type in types %}
    <input type="checkbox" name="tags[]" value="{{ type.id }}" {{ (type.id in selectedTypesIds) ? 'checked' : '' }}>{{ type.title }}</input>
{% endfor %}

{# Where it gets tricky #}
{% set relatedToParam = ['and'] %}

{# Loop through the second set of tags while looping through the first set of tags #}
{# Still not quite sure that's the best way to go but it works well #}

{% if selectedSizesIds|length > 0 %}
    {% for size in selectedSizesIds %}
        {% if selectedTypesIds|length > 0 %}
            {% for type in selectedTypesIds %}
                {% set relatedToParam = relatedToParam|merge([
                    { targetElement : [size,type] }
                ]) %}
            {% endfor %}
        {% else %}
            {% set relatedToParam = relatedToParam|merge([
                { targetElement : size }
            ]) %}
        {% endif %}
    {% endfor %}
{% elseif selectedTypesIds|length > 0 %}
    {% for type in selectedTypesIds %}
        {% set relatedToParam = relatedToParam|merge([
            { targetElement : type }
        ]) %}
    {% endfor %}
{% endif %}

{% set relatedToParam = relatedToParam|length > 1 ? relatedToParam : null %}

{% set entries = craft.products.type('accommodation').relatedTo(
    relatedToParam
).all() %}

{% for product in entries %}
   {{ product.title }}
{% endfor %}


You've just got quotes wrapped around a simple string. Try something like this instead...

{% if segment1 in ['one','two','three'] %}

That will check to see if your segment1 value is in the array of possible matches.


How to omit certain tag from (% cache %)

Unfortunately, the vanilla {% cache %} tag doesn't have a way to escape or ignore certain content.

The obvious workaround is to have more than one {% cache %} tag, where the content that shouldn't be cached sits between/outside those tags.

If you can't do that, another option is to use output buffering and injection. Basically, you cache whatever you need to cache, but {% set %} the output to a variable, rather than rendering it immediately. The important bit: Inside the content that you cache, you put some sort of placeholder value where you want the un-cached content to render. This placeholder can be whatever you want, but make it something that isn't likely to also appear in the actual content (e.g. "%%%foobarbaz%%%").
Then, {% set %} the un-cached content to a variable also – and finally, when you print the cached content, you use the |replace filter to replace the placeholder value in the cached content with the variable containing the un-cached content. Something like this:

{# Set the cached content to a variable #}
{% set cachedContent %}
    {% cache globally using key craft.request.path %}

        {# A bunch of taxing queries here #}

I am content.

        {# Injection point for un-cached data #}
        %%%foobarbaz%%%

I am more content.

    {% endcache %}
{% endset %}

{# Set the uncached content to a variable #}
{% set uncachedContent %}

I am some content that never is cached wooooo

{% endset %}

{# Print the whole thing #}
{{ cachedContent|replace('%%%foobarbaz%%%', uncachedContent)|raw }}

Finally, there's a plugin which may work for you.


Use of tag.slug instead of tag.title in a custom route

You do not have to change your route. Instead modify your template where you are linking the tag.

Instead of using

{{ tag.title }},

Use

{{ tag.title }},

UPDATED

To clarify the above snippet goes in the template that generates the link to take the the user to your _tag.html template, not in the _tag.html template itself.

Your route should be as below:

UPDATE 2

Above snippet updated to match your example above.

UPDATE 3

As the tag variable made available to your template is now the tag’s slug, make sure to update the code to query for the tag model to use the slug param.

{% set tag = craft.tags.slug(tag).first() %}


Upload asset failed to open stream: Invalid argument

I'd check the permissions and make sure that Craft has write permissions to the craft/storage folder first.


Product Categories, Structures and Channels

Typically, I will create a single for each product "home" page, and then a channel for my products or sub-pages. I will generally use a channel vs. a structure unless I know I want to manually control the order or nest entries.

Let's say I have a website about automobiles. I would create a section (single) called cars. That section would have the url of site.com/cars and the template would be located at /templates/cars/index.html. This is the template that would be responsible for pulling in all of the cars I have.

This is where things can get tricky, or not...all depends on how you want to roll.

If you created a channel called automobiles (or whatever you like), you could enter each car you have as an entry within the channel. Then on your cars single, you can tell Craft to loop through all entries in the automobiles channel.

Since you can't nest a channel entry, I would use categories to "tag" your cars. For example, I would create a category called Sports Cars and relate any sports cars I have to that category. You could also create a category for Trucks or Vans to help group/classify each car you had.

This would also allow you to create sudo-landing pages for each type of car. For example, site.com/cars/sports-cars would get all entries that are tagged as a sports car. You could do this for trucks, or you could even divide categories up into trucks/4-wheel-drive so not only would a truck show when I requested trucks, it would also show in my 4-wheel-drive options.

From an authoring experience, this is great. I don't care specifically where I have to create the entry - all I know is that I have a car, and it goes in the cars "bucket" (automobiles channel). It's within that entry (the car entry itself) you are choosing where it is available to the end user.

You could even create different entry types for the kind of automobile you are creating. This would allow you to have a cleaner screen as some fields don't apply for all automobiles.

To illustrate a structure, think about the staff who is in charge of this car-selling company.

I would create a structure called staff. It would have the url of site.com/about/staff and a template of /templates/about/staff/_entry

From there you could create an entry for each person. You can then create "parent" entries for the hierarchy of the office.

For example:

- Management
    |-- Bob McKenzie
    |-- Doug McKenzie
- Sales Team
    |-- Tyler Durden
    |-- Agent Smith

By using a structure here, you can not only manually set the order of which group (management or sales) is first, but you can also arrange the order of the team members within.

So to answer your question directly:

  I would like to display a parent page which lists all products, but then 6 sub-pages which show only the products in that category. I use the word category without specifically meaning the Craft CMS category

I would do this:

Create a single and give it a name of the url that you would like to show all products on. To use my example, this would be cars.

Create a Category to relate your products to Ex: Sports Cars.

Then create a channel - called Products. Every product will go here. When you are creating these product entries, use a Channel Field type so you can select which category the given product belongs to (Sports Cars).

Then on your cars page, you would tell Craft "Hey, get every single product".
If I navigate to site.com/cars/sports-cars you can tell Craft "Hey, only get me cars that are related to sports cars".

Kind of a long-winded answer, hope it helps get you going.


Is it possible to define a 'richtext' fieldtype as 'MEDIUMTEXT' in DB?

Defining your a plugin with it's own field type that extends RichTextFieldType might work (haven't tested), but your current code is slightly off.

The field type class/file name needs to be PluginHandle_FieldTypeNameFieldType before Craft will even recognize it.

Also, the ColumnType enum uses MediumText, not Mediumtext.

Really, what we should probably do is make this a setting on the field type because it does pop up every so often and there currently isn't a clean answer.


Add Section Name to SEOmatic Title Field

So you can do this via Twig as discussed here: https://github.com/nystudio107/craft-seomatic#twig-templating

...but you can also just make an Single for your Index page (this is what I usually do) and all of this will "just work" including the SEO sidebar previews in the CP.


Can I simply update from 2.6.2779 -> 2.6.2958, shared hosting

Just make a backup of files and database first then click update (or upload a new /craft/app folder if you've got automatic updates turned off) - there are no breaking changes in Craft 2.6


Ended up using the nitro tutorial instead. Thanks @Oli!


This has now been solved by the addition of the convertFilenamesToAscii config setting introduced in Craft 2.4.

If you are working on a multilingual site, you might also find the limitAutoSlugsToAscii config setting useful.


How to display the last 4 digits of the credit card used for a Craft Commerce purchase

I'm not sure whether you're referring to displaying this in the Control Panel somewhere or on the front-end of a site in a user account area.

Assuming it's on the front-end of a site and you've already got a reference to the order, it'd be something like:

{# Grab an order #}
{% set order = craft.commerce.orders.id(15).first() %}

{% if order %}
    {% Grab all of it's transactions %}
    {% set transactions = order.getTransactions() %}

    {# Loop through all of them looking for the one(s) you're interested in on this order.  Here, we just grab the first. #}
    {% set transaction = transactions[0] %}

    {# Output the reference #}
    {{ transaction.reference }}
{% endif %}

Keep in mind that the reference value is a response that comes back directly from the particular payment gateway, so it may or may not even be JSON, much less include the last 4 digits of a credit card number.  If it is JSON, XML, etc. then you'll need to parse that value looking for where they save the last 4 digits.


Migration from “Focal Point Field" for Craft to Native Craft 3 image focal point

The inherent problem that you're going to have is that Craft CMS 3 focal points are per asset, and Focal Point Field is per field.

So you could have multiple Focal Point Fields that have different Focal Points for the same Asset... and then how would you map them?

A migration could be done, but there would have to be some compromise to take the above into account.


Error 'form[fieldName] :  is invalid' while submitting multiple checkboxes

I'm not sure if it can make a difference, but you should try to remove the white space between the two array in the name attribute.

Then I think you may have to format the date value with the date filter.

<label>
    <input :class="{ error: error['formDate'] }" type="checkbox" name="fields[formDate][]" value="{{ date.value|date('Y-m-d') }}">{{ date.label|t }}
</label>


Is there a way to have checkbox field labels translatable?

Short of hardcoding all these checkbox values and applying the translate tag on them

That's actually the only way to translate field names, checkbox labels/values and whatnot: taking advantage of Craft's static text translation feature by hard coding the strings you want to translate in a translations file (e.g. /translations/en.php).

An example: If one of your whiskey field's option labels is "Irish", but you want it to be "Welsh" for a certain locale, you can add the following to the returned array in that locale's translation file:

'Irish' => 'Welsh',

Of course, it's also possible to translate the field name itself, i.e.

'Whiskey' => 'Whisky',

There's a big problem though – Craft's static text translation has no idea about context, meaning that it's not possible to tell Craft that the above translations belong to the whiskey field only. In other words, both Whiskey and Irish will be translated across the board. Sometimes that's what you'd want, but often it's not – a translated value may work in one place, but not in another.

One way to solve this, is to use namespacing for all the static strings you want to translate. The naming convention is entirely up to you, but here's how I do it for fields – the following two values are used for the field's name and instructions, respectively:

field.whiskey.name
field.whiskey.instructions

With this namespacing pattern, the first part is the type of content this string belongs to (a field), the second part is the field's handle (which is obviously never translated) and the last part is what the string actually is (the name and the instructions, respectively). This works for other types of content as well, consider section.news.name, entryType.link.name, categoryGroup.editors.name etc.

For "nested" properties, such as a checkbox option's label, I usually write them out like this:

field.whiskey.option.irish.label

For Matrix blocks, the namespacing scheme admittedly is a little bit ridiculous:

field.someMatrixField.block.bio.name
field.someMatrixField.block.bio.text.name
field.someMatrixField.block.bio.text.instructions

The big downside to namespacing field names, option labels, section names etc. is that you have to add a translation for all locales (even your "default" locale), in order to not have the namespaced, "raw" value displayed to your users. In other words, it's definitely a bit more work than just translating plain ol' strings, but the big win is having granular control over all your translated fields, and being able to translate the same value differently for different use cases. It's the only way to go, in my opinion – at least when you have a fair number of strings to translate.

Anyway, here's how your translations file (e.g. /translations/en.php) could look with namespacing for the whiskey field:

return [
    'field.whiskey.name' => 'Whiskey',
    'field.whiskey.option.irish.label' => 'Welsh',
];

As for the frontend, your static string translations will work there, too – just add the |t filter to the labels:

{% for option in entry.whiskey.options %}
    <li>{{ option.label|t }}: {{ option }}</li>
{% endfor %}


How to update (or CRUD) products (or entries) via API?

Tl;dr: Mutations in GraphQL seems to be the way to go - but GraphQL in Craft doesn't yet support mutations on Commerce elements. As for now, you have to create a Craft CMS Plugin. Follow the progress of mutations support on GitHub
Alternative 1 (sort of)
According to #9667 - the 3rd party CraftQL-plugin lets you do CRUD on everything* via Mutations (GraphQL way of altering data) - so that's an alternative while we wait to the native GraphQL functionality to support Mutations (see https://github.com/craftcms/cms/issues/4835 for status on that one. It's a part of the 4.0 milestone)
Also, Pixel & Tonic has added support for Mutations to the 4.0 milestone for Craft CMS on the built in GraphQL plugin. So it's coming.
* Well, not everything. CraftQL supports the following entities: entries, sites, draft, assets, globals, tags and users. The documentation contains a section about third-party field support that probably lets you implement support for mutating Craft Commerce-fields and other 3rd party fields.
I've added a Feature Request on Craft Commerce regarding GraphQL and mutations. Let's see what they answer.
Alternative 2 (only real alternative in 2019)
Also, if you can't wait for mutations in Craft Commerce, you can create your own Craft Plugin. Have a look at my question "How to accept incoming Webhooks", which helps you along with creating a plugin that can do things like creating and modifying products in Craft.


If I'm understanding you correctly, it sounds like you're trying to add another Assets Source Type.

Unfortunately, this isn't possible in Craft 2. This feature is expected to be introduced in Craft 3.

  Volume Types

  Asset Sources have been renamed to “Volumes” in Craft 3, and their API has been dramatically simplified. In addition to Craft’s built-in Local, S3, Google, and Rackspace Volume types, plugins are now able to supply their own. There’s even a base Volume class that makes it really easy to implement Flysystem-based Volume types.


Pictures (Assets) not showing (error 404)

I called my directory "icons" (www.example.com/icons/) which was obviously not a good idea. After renaming the directory to "img/icons" it works perfect!


Output tags from matrix fields related to an entry

To get tags defined within a matrix field, you will first want to loop through the matrix-blocks in your matrix; and then loop through the tags in your tags field defined in each block.

{% for block in entry.myMatrixFieldHandle %}
    {% for tag in block.myTagsFieldHandle %}
        {{ tag.title }}
    {% else %}
        No Tags found.
    {% endfor %}
{% endfor %}

Also, for retrieving tags defined in a tags field on an entry (as in your example), you can simply retrieve the tags through the tags field directly, rather than using relatedTo(entry).

{% for tag in entry.myTagsFieldHandle %}
    {{ tag.title }}
{% else %}
    No Tags found.
{% endfor %}

For more information please see the documentation for tags and matrix fields.

Update

If you want to output your tags as you have them displayed in your screenshots, then use this:

    {% for block in entry.technologyField %}
        {% if block.type == "tag" %}
            {% for tag in block.technologyTag %}
                {{ tag.title }}
            {% else %}
                No Tags found.
            {% endfor %}
        {% endif %}
    {% endfor %}

However, I can also see some potential problems with your naming system and how you are using matrix blocks. Here are some suggestions for improvement.

You don't need to end each Tag Group handle with 'TagGroup', as you already know that it's a Tag Group (so instead of 'technologyTagGroup', you can simply call it 'technology').
You don't need to end each field handle with 'Field', as you already know that it's a field (so instead of 'technologyField', you can simply call it 'technology').
Matrix block types support more than one field — I suspect that instead of having 3 separate block types defined, you actually only want 1 block type defined (let's call it 'technology' for example), with three fields in it: 'text', 'media', and 'tags' (or 'technologyTags' if you prefer).
When using a Tags Field Type (or Assets, Entries, Categories or anything else with more than one item), it is generally a good practice to name the field handle plural so that you always know that it contains more than one of something (so instead of 'tag' the field should be called 'tags').
If you followed #1, #2, #3, #4 above then the code to output your tags would be:

{% for block in entry.technology %}
    {% for tag in block.tags %}
        {{ tag.title }}
    {% else %}
        No Tags found.
    {% endfor %}
{% endfor %}

If you later define another Block Type then when looping through the blocks you will need to check block.type, and only include those that have a Tags Field defined with the handle your looking for ('tags' in this case). For example:

{% for block in entry.technology %}
    {% if block.type == "technology" %}
        {% for tag in block.tags %}
            {{ tag.title }}
        {% else %}
            No Tags found.
        {% endfor %}
    {% endif %}
{% endfor %}


seo.twittercard is an ElementCriteriaModel. To access the actual asset, you need to use seo.twittercard.first (or equivalently: seo.twittercard.first()).

However, you should always check that this exists before referencing it:

{% if seo.twittercard|length %}
  <meta(name='twitter:image:', content='{{ seo.twittercard.first.getUrl() }}')>
{% endif %}

And yes, this is a fine way to store images used globally across the site.


How does Craft automatically wrap `fields[]` around name attributes?

I believe its the namespace twig template function - and fields typically use the default namespace as fields. This is defined under templates/_includes/fields.html

Looking at that file (below), you'll notice that if you don't provide a namespace variable to the include, it'll use fields.

{% if element is not defined %}{% set element = null %}{% endif %}
{% if namespace is not defined %}{% set namespace = 'fields' %}{% endif %}

{% namespace namespace %}
    {% for field in fields %}
        {% include "_includes/field" with {
            field:    field.getField(),
            required: field.required,
            element:  element,
            static:   (static is defined ? static : null)
        } only %}
    {% endfor %}
{% endnamespace %}

In another scenario, you might have the following in your regular templates:

{% namespace 'myNamespace' %}
  <input id="test" name="test">
  <input id="another-test" name="another-test">
{% endnamespace %}

Which would produce the equivalent, rendered HTML of:

<input id="myNamespace-test" name="myNamespace[test]">
<input id="myNamespace-another-test" name="myNamespace[another-test]">

Its particularly useful in plugins or other complicated field handling where you don't have to worry about settings up name attributes (heaven forbid you have to change all your field name attributes with lots of fields!). This way, you can easily provide a wrap of context to your fields, while keeping the form elements pretty lean.

Another important factor is the ID generation, which also flows onto labels for field - useful for accessibility.

In PHP, this is done with the TemplatesService::namespaceInputs method...

craft()->templates->namespaceInputs($element, $namespace);

You can read a detailed breakdown of how this method works in the class reference docs...


Craft 2.6 Asset Upload 500 Error (on Heroku with Amazon S3)

My answer to my own question: after exhausting all avenues I ended up having to abandon Heroku for this Craft site. I moved the Craft site over to a DV server at Media Temple, moved over the database, and everything is working fine.


How to apply a discount or sale to a variant?

Variants can not be selected when setting up discounts in the UI.

We have variant-based sales/discounts high on the list for the next version of Craft Commerce, but nothing planned to make available in the short term. It will also allow sales and discounts to work with any custom purchasable.

I tried to think of a way around it, and the one way I can came up with in the short term is a little hack:

You could use the description field to limit the discount to specific variant SKU's.

So all discounts would work and be set up as they normally would, but with a condition on the product, but if you got them to put the keyword "ONLY" into the description and then got them to paste the variant SKU into the description. i.e:

ONLY the red tubs (SKU162839) are on discount.

or

Discount ONLY applies to SKU78439 and SKU94300

You could then add the following event listener into a plugin:

// So far this would only be called when the discount has
matched with everything else about the product.
craft()->on('commerce_discounts.onBeforeMatchLineItem',
function($event){
   $lineItem = $event->params['lineItem'];
   $discount = $event->params['discount'];

    if (stripos($discount->description, 'only') === false) {
        return; // do nothing, and let the discount match as it normally would, because the discount does not have 'only' in the description.
    }else{
        if (stripos($discount->description, $lineItem->sku) === false) {
            $event->performAction = false; // since this SKU is not in the description string, then don't apply this discount
        }
    }
});

I wrote the above code without testing, but something along those should work.

Alternatively you could place a custom field on the product which list the variants on discount, and have the above event listener check use that information on the product (instead of matching the SKU on the discount description).

Sorry it's a bit of a hack for now, we will get discounts on variants in the next version of Commerce.

Hope that helps.


Craft config files usually allow to return environment-specific arrays. So you could just configure different endpoints like so:

return [
    '*' => [],
    '.com' => [
        'endpoints' => [
            'api/example<ext:(.json)?>' => function() {
                // example API config for live environment
            },
        ],
    ],
    '.dev' => [
        'endpoints' => [
            'api/example<ext:(.json)?>' => function() {
                // example API config for dev environment
            },
        ],
    ],
];


There is no event or hook that I'm aware of that can intercept the template rendering process directly. You would likely need to instigate this from within your template. I would suggest perhaps using a plugin variable either directly, or as a wrapper for your plugin service method (if you need to do something more complicated).

Something like the following:

Note: This is adapted from the 'BusinessLogicTemplate' plugin which provides a great starting point for plugin development.

<?php namespace Craft;

class MyPluginVariable
{

    /**
     * Whatever you want to output to a Twig tempate
     * can go into a Variable method.
     *
     * HOW TO USE IT
     * From any Twig template, call it like this:
     *
     *     {{ craft.myPlugin.exampleVariable }}
     *
     * Or, if your variable requires input from Twig:
     *
     *     {{ craft.myPlugin.exampleVariable(twigValue) }}
     *
     */
    public function exampleVariable($optional = null)
    {
        return "And away we go to the Twig template...";
    }
    public function formatBody($body)
    {
        /* process $body and return it to the template */
        return $body;
    }

}

Then in your template:

{{ craft.myPlugin.formatBody(entry.body) }}


In Commerce how can I have a customer update custom fields on an order after the order is completed?

Create a new plugin with a new controller class that enables this.

e.g.,

plugins/myplugin/MyPlugin.php

<?php
namespace Craft;
class MyPlugin extends BasePlugin
{
    ... the usual stuff from https://pluginfactory.io/ etc ...
}
?>

plugins/myplugin/controllers/My_OrdersController.php

<?php
namespace Craft;

class My_OrdersController extends BaseController
{

    public function actionUpdateOrder()
    {
        // basic security precautions
            $this->requirePostRequest();

        // get the fields
            $orderNumber = craft()->request->getPost('orderNumber');
            $customField = craft()->request->getPost('customField');
            $order       = craft()->commerce_orders->getOrderByNumber($orderNumber);

        // do the stuff
            if ($order &&
                $order->customer->userId == craft()->userSession->getUser()->id &&
                $customField != '')
            {
                    $order->setContentFromPost(['customField'=>$customField]);

                    // Lets also change the Order Status
                        $order->orderStatusId = 3; // this line changes the Status if wanted. Use the ID of the custom status.
                        $order->message = "Order status changed to 'To be cancelled' by customer";

                    craft()->commerce_orders->saveOrder($order);
            }
    }
}

Front end form:

<form action="" method="POST">
    <input type="hidden" name="action" value="myplugin/orders/updateOrder">
    <input type="hidden" name="redirect" value="shop/customer/order?number={{ number }}">
    <input type="hidden" name="orderNumber" value="{{ number }}">

        Custo Field
        <input type="text"
                name="customField"
                value="{{ order.customField }}"
        />

    <input type="submit" class="button warning" value="Confirm"/>
</form>


Show just the first row of a table (stored in globals)

first() and limit() are methods of the ElementCriteriaModel. Since a table is not an element, but just a plain array, you should use array filters.

So use Twig's slice filter instead.

    {% if companyDetails.telephoneNumbers | length %}
        {% for row in companyDetails.telephoneNumbers | slice(0, 1) %}
        {{ row.number }}
        {% endfor %}
    {% endif %}
    Call us


Completely untested, but something like this should work:

public function getPageUrl($slug)
{
    $criteria = craft()->elements->getCriteria(ElementType::Entry);
    $criteria->slug = $slug;
    $entry = $criteria->first();

    if ($entry)
    {
        return UrlHelper::getUrl($entry->uri);
    }
}


If you look at the MemCacheConfig.php file, you'll see that it's expecting a single property, "servers", which contains an array of associative arrays with properties. So, try this as your memcache config:

<?php
return [
    'servers' =>
[
  [        // A memcached server hostname or IP address.
             'host' => 'localhost',
             // Whether or not to use a persistent connection.
             'persistent' => true,
             // The memcached server port.
             'port' => 11211,
             // How often a failed server will be retried (in seconds).
             'retryInterval' => 15,
             // If the server should be flagged as online upon a failure.
             'status' => true,
             // The value in seconds which will be used for connecting to the server.
             'timeout' => 15,
             // Probability of using this server among all servers.
             'weight' => 1,
    ]
  ]
];


Live Preview not working in some sections

It is expected behavior.  Live Preview is meant to show you what that entry will look like on the front-end of your site with the template specified in that section's setting.

If that entry doesn't have a URL as defined in the section settings, then there is nothing to preview.


Contact Form Plugin - Not sending/receiving emails?

Welcome to Craft!

You mention you haven't configured any kind of mail server—this is almost certainly the issue.

There are a few mailer adapters for Craft, the availability of which will depend on whether you're using Craft 2 or Craft 3.

That said, the easiest route will probably be to use the built-in SMTP method, configured in the Settings -> Email screen of the Admin.

I'd recommend checking out Mailgun or Sendgrid as third-party services that handle mail delivery—this way, you're not responsible for maintaining your own mail server. Both offer generous free tiers that should cover most use cases.

Each should provide you with some SMTP credentials you can drop into Craft's settings.

Be aware: some ISPs will block SMTP traffic over the standard port. If you still have trouble sending mail, look at the docs for your chosen provider and see if they support sending over an alternate port.

Good luck!


On our servers we only have the Internet Explorer installed which results in this behavior.

When accessing the site with Chrome or Firefox everything works as it should.


Is it possible to limit users to adding/editing entries in specific categories?

Entry permissions are sort of an all or nothing thing. If they can publish entries, they can publish all entries or just their own entries. The tricky part of this kind of permission is that Craft doesn't know if a category field will be on a particular entry type.

A possible way to make this work is to create a custom plugin that fires the entries.onBeforeSaveEntry event, and checks each user's category access with the entry's categories. Granted, you run into the issue of them being able to remove the category to remove any problems.

A second option is to give them a special front-end portal area that will let them edit entries, and let you filter those entries to what they can edit. You will also then be able to omit fields that you don't want them to edit (including the categories that prohibit their access).


As per your comments, I've gleaned that the problem is really because of an incorrect assumption about how RewriteConds apply to RewriteRules.

So I'm guessing your .htaccess looks more like this:

RewriteCond %{HTTP_HOST} ^site1\.com [NC]
RewriteRule ^someurl.asp /folder/page? [R=301,L]
RewriteRule ^news.asp /news/news-listings? [R=301,L]

RewriteCond %{HTTP_HOST} ^site2\.com [NC]
RewriteRule ^someurl.asp /folder/page? [R=301,L]
RewriteRule ^news.asp /news-galleries/news-listings? [R=301,L]

So there are multiple RewriteRules to some of the RewriteCond statements. You're expecting site2.com/news.asp to go to site2.com/news-galleries/news-listings?, but instead it's going to site2.com/news/news-listings? because it's strictly obeying the mod_rewrite rules.

This is because RewriteCond statements only apply to the RewriteRule that immediately follows them. So your site2.com/news.asp request is actually matching the second RewriteRule in the above example.

RewriteMap to the rescue

If you have a lot of URLs you're needing to manually rewrite under multiple condition scenarios, this can get complicated because you would have to define the same RewriteCond statements for each RewriteRule.

Here's a better way - use RewriteMap (not yet tested):

RewriteMap "site1.com" "txt:/path/to/file/site1.com.txt"
RewriteMap "site2.com" "txt:/path/to/file/site2.com.txt"

RewriteCond %{HTTP_HOST} ^site1\.com [NC]
RewriteRule ^(.*)$ "${site1.com:$1}" [R=301,L]

RewriteCond %{HTTP_HOST} ^site2\.com [NC]
RewriteRule ^(.*)$ "${site2.com:$1}" [R=301,L]

That would be it. One RewriteMap, RewriteCond and RewriteRule per domain. Then your site2.com domain rewrite-map file would look like this, for example (simple space-seaparted, key-value pairs):

news.asp /news-galleries/news-listings?

Hope that helps provide a more flexible, manageable solution :)


How I’ll get an entryId based on a given URL?

I'm assuming that "welcome" is also your page slug.

You could query the craft_elements_i18n table (pseudo code):

$sql = "select id from craft_elements_i18n where slug = 'welcome' limit 1"
$result = get($sql);
$entry_id = $result['id'];

Then feed that into your function.
Replace 'welcome' with a read of the uri to make it dynamic.


Currently, this may be a bit challenging to pull of with Sprout Forms v1.1.0

We do have several features and improvements in the works that will help you achieve this in the future though, including:

Full control over customizing the template HTML
The ability to customize the value of the name="" inputs
The option to submit form data to third-party URLs
Control over hidden fields

While I don't have a release date for you — the features above are currently under development.

I'll plan to revisit and update this post once we release those features.


There currently isn't any Tag management in Craft, but if you think there should be, consider voting for this feature request.

In the meantime, there is a 3rd party plugin called Tag Manager that will let you delete tags, although it won't show you which ones aren't in use.

There is a help article that shows how to select all of the tags that are in use.  From there you could diff it with the full tag list to see the ones that aren't in use.


It was an issue with the /tmp folder filling up. Have to regularly make sure it's emptied. If the /tmp folder has proper permissions this should happen automatically.


Querying for an exact match on a Matrix block field with multiple types

When I understand Brandon correctly in this answer Query for blocks across Block Types using the new field parameter?, it's not possible to set up what you want with a criteria model.

What you can do though is to add additional custom query conditions to the dbCommand after running the criteria model through the buildElementsQuery function.

public function getMatrixBlocks($matrixFieldId, $fieldValue)
{
    $criteria = craft()->elements->getCriteria(ElementType::MatrixBlock);
    $criteria->fieldId = $matrixFieldId;

    $dbCommand = craft()->elements->buildElementsQuery($criteria);

    $params = array(
        ':myFieldHandle' => $fieldValue,
    );

    $conditions = array('or',
        'content.field_myBlockTypeA_myFieldHandle=:myFieldHandle',
        'content.field_myBlockTypeB_myFieldHandle=:myFieldHandle',
    );

    $dbCommand->andWhere($conditions, $params);

    return $dbCommand->queryAll();
}


General question: Has anybody ever used Craft along with ElectronJS to create a native based app?

So if you're using Craft as an API service, whether via the ElementAPI or via GraphQL w/the CraftQL plugin, anything you like can talk to it, including a PWA app, a native PWA, an iOS app, whatever.


Got it working now, namespace issue :s. The autoloaded classes are in the Craft namespace and i didnt prepend this to the dynamicly generated class names. Time to take a break...


Solved

There is an environment override in SEOmatic's settings. This was set to local instead of live.


How to fill the custom fields of users from the front-end form?

You can do so by using the fields[customFieldHandle] syntax.

For example, here's how you'd populate location and bio custom fields.

Location
<input type="text" id="location" name="fields[location]" value="{{ currentUser.location }}">

Bio
<textarea id="bio" name="fields[bio]">{{ currentUser.bio }}</textarea>


Copy of Craft instance generates "An unknown error occurred" for login

So I am going to answer my own question here: The solution was that something, I don't know what, what messed up in the DB. So I dropped the DB and then copied it over again from the original. That fixed it.  I never got an indication in the logs that the DB was the issue I just decided to start with replacing it and then work backward if necessary.

Thanks for the tips. At least it eliminated the obvious issues.


Using 'replace' with a regex is throwing an error. Any ideas why?

I'm not sure what's going on with the story.html part, but you'll need to double escape your regex.

Assuming you have an entry already with a story Rich Text field, it'd look like this:

{{ entry.body|raw|replace("/<p>\\s*(<a .*>)?\\s*(<img .* \\/>)\\s*(<\\/a>)?\\s*<\\/p>/iU", "\1\2\3") }}


If you're using phpmail or sendmail under Settings->Email in the control panel, they are notoriously unreliable at delivering emails consistently.

Try using a proper SMTP relay or a transactional email provider like Mandrill.


/login page in Craft keeps redirecting to home page. What could be causing that?

/login is the default login page for Craft (see https://craftcms.com/docs/config-settings and scroll down to the users section ). You can override it by adding something like this to your config file:

'loginPath' => 'members/login',


Deploying Craft on Apache Server - Error code 255

That error was due to the php version not being specified when I had executed the command. I've tried running it with the specified path to the current php version and it seemed to work.


How do you modify the entry data before the template is rendered?

Definitely possible; you'd need to write a plugin or module in PHP to do it though. Probably it could listen to for the View::EVENT_BEGIN_PAGE event, and get the injected element via $element = Craft::$app->urlManager->getMatchedElement()

Something sorta like this:

use craft\web\View;

// ...

    $request = Craft::$app->getRequest();
    if ($request->getIsSiteRequest()) {
        // Handler: View::EVENT_BEGIN_PAGE
        Event::on(
            View::class,
            View::EVENT_BEGIN_PAGE,
            function () {
                Craft::debug(
                    'View::EVENT_BEGIN_PAGE',
                    __METHOD__
                );
                $element = Craft::$app->urlManager->getMatchedElement();
                if ($element !== null && ...) {
                    // ...do something
                }
            }
        );
    }

To make things clean, rather than modifying the element itself, I'd probably inject a new Twig variable, something like entryTransformed or something that your templating code could access.


The database will be storing the date as seconds since 1970 (epoch) and your view on that is not localised. However, the front end date is localised for your time zone.

Of this I am more sure than that the sun will rise tomorrow (thanks to a recent rise in right wing politicians).


Is it possible to have different plugin settings per locale?

I haven't used foxycart plugin, but looking at the '_settings.html' file, it looks like it stores both the 'storedomain' and 'apikey' as part of the plugin settings. I would suspect that you would need to fork the plugin and modify it.

You could possibly add additional settings to the plugin for the different domains (i.e. storedomain-en, storedomain-es, apikey-en, apikey-es), and then add some logic in the plugins main 'init' method to pick up the different settings based on the current locale.

$settings = craft()->plugins->getPlugin('foxycart')->getSettings();
\FoxyCart_Helper::setSecret($settings['apikey-'.craft()->language]);
\FoxyCart_Helper::setCartUrl("https://" . $settings['storedomain-'.craft()->language] . "/cart");

Or, you could set the 'storedomain' and 'apikey' in your multi-environment config array:

return array(
    '*' => array(
        'storedomain' => array(
            'en' => cart.en.domain.com,
            'es' => cart.es.domain.com',
        ),
        'apikey' => array(
            'en' => 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
            'es' => 'YYYYYYYYYYYYYYYYYYYYYYYYYYYYYY',
        ),
    ),
    ...
);

and then retrieve them using something like:

$settings = craft()->plugins->getPlugin('foxycart')->getSettings();
$storedomain = craft()->config->get('storedomain');
$apikey = craft()->config->get('apikey');
\FoxyCart_Helper::setSecret($apikey[craft()->language]);
\FoxyCart_Helper::setCartUrl("https://" . $storedomain[craft()->language] . "/cart");

You would probably also need to go and modify some the variable methods to return the localized versions, so that when you asked for 'storedomain', it returned the correct value. I.e. :

<form action="https://{{ craft.foxyCart.storedomain }}/cart" method="post" accept-charset="utf-8">

I have no idea what other integration points the foxycart plugin has with craft however. If it attempts to sync data in any way with foxycart, it might not like switching accounts like that.

Overall this sounds pretty messy. I would proceed with caution.


How I can output Craft Commerces Stripes Publishable Key in a template

Like this:

{% if cart.paymentMethod.class == 'Stripe' %}
    {{ cart.paymentMethod.settings.publishableKey }}
{% endif %}


Craft 3 Plugin not returning custom field value

Found my answer here

// get $_POST['foo']['bar'], if it exists
$bar = Craft::$app->request->getBodyParam('foo.bar');

or inserting it into my code

Event::on(Elements::class, Elements::EVENT_AFTER_SAVE_ELEMENT, function(Event $event)
{
    $request = Craft::$app->getRequest();

    if($request->getBodyParam('fields.sendEmail') == 1)
    {
        $html = $request->getBodyParam('fields.sendEmail');
        $subject = "testing";
        $mail = "example@gmail.com";
        $this->sendMail($html, $subject, $mail);
    }
});


Okay - got to the bottom of this.
Was using the wrong setting. Should have been setPasswordSuccessPath not setPasswordSuccess!


Found a solution by how Entry Form handles it.

Assuming you've posted fields with names such as jobData[reference]:

$fieldsLocation = craft()->request->getParam('fieldsLocation', 'jobData');

$this->entry->setContentFromPost($fieldsLocation);

The setContentFromPost() method of the EntriesController class sets the ElementType.


Is it possible to modify the input format for dates in front end form?

Paul, when I change the Locale setting to British English (en_gb) within the database, the Post Date field's date-format changes to dd/mm/yyyy.

In DB: databaseName > craft_locales > Change "en" to "en_gb"

Let us know how you get on :)


Craft 3: how can I set dynamic Base URL in sites setting?

So as of Craft CMS 3 RC7, they added a new alias() Twig function.

So what you can do is something like this in your general.php:

'aliases' => [
    '@basePath' => getenv('CRAFTENV_BASE_PATH'),
    '@baseUrl' => getenv('CRAFTENV_BASE_URL'),
],

(or whatever/however you want to set them). These aliases can be used in sites’ Base URL settings, volumes’ Base URL settings, and Local volumes’ File System Path settings in the AdminCP.

And then in your templates, you can do something like:

{{ alias('@baseUrl') }}
{{ alias('@baseUrl/assets/img/' }}

To resolve the alias there. I changed Craft 3 Multi-Environment to leverage aliases in this way (rather than having them in the .custom config), and it's documented in detail in the Asset Volumes and Aliases.

You do not need to be using Craft 3 Multi-Environment to utilize them in the same way, this is just a live example that's handy to point to.


Interne Serverfout after one click update

Interne Serverfout (Internal Server Error) is a fatal error that has happened and your web server killed the request.

Usually, fatal errors like this are either because PHP times out, or runs out of memory... the underlying error message will be either in your web server's error logs or Craft error logs.

Try editing your php.ini file and increasing the memory_limit setting to at least 256M, and the max_execution_time setting to at least 120.

If you’re not sure where your php.ini file is located, create a PHP file called ini.php alongside your index.php file with this:

php
echo 'Loaded php.ini: ' . php_ini_loaded_file();

Then access that file in your web browser by going to http://your-project.test/ini.php.

Once you’ve made your changes, restart your web server, restore your database from a pre-update attempt database backup and then try again.


Tons of ways to skin this cat; a simple option is to use string concatenation, which could look like the below example. Note that I'm actually creating a new variable for classes at the top of the macro, which IMO helps clean up the markup a little bit and also makes it a bit more clear what's going on – you can continue to do this logic "inline" if you want to, of course.

Also note that the default filter has been omitted from the Twig statement rendering the classes variable; it's redundant now because the classes variable will always be set.

{% macro button(label, link, width, classes, colours, textclasses, alignment) %}
    {% set classes = 'flex pa2 pa3-ns ph3 tc lh-solid f7 f6-ns link underline-hover z-999 br2 mv3 tracked-moreflex pa2 pa3-ns ph3 tc lh-solid f7 f6-ns link underline-hover z-999 br2 mv3 tracked-more' ~ (classes ? ' ' ~ classes) %}

{{ label }}

{% endmacro %}

The important bit is the ... ~ (classes ? classes) part, which basically appends the classes macro parameter to the default classnames, if the parameter is set.

A variation on the above solution, and – in my opinion – maybe a bit cleaner, is to use an array that is joined (i.e. flattened to a string):

{% macro button(label, link, width, classes, colours, textclasses, alignment) %}{% macro button(label, link, width, classes, colours, textclasses, alignment) %}
    {% set classes = ['flex pa2 pa3-ns ph3 tc lh-solid f7 f6-ns link underline-hover z-999 br2 mv3 tracked-moreflex pa2 pa3-ns ph3 tc lh-solid f7 f6-ns link underline-hover z-999 br2 mv3 tracked-more', classes]|filter|join(' ') %}
    ...
{% endmacro %}

Basically, in the above the classes variable is an array containing the default classes and whatever was passed in the classes parameter. The array is piped through the filter Twig filter, which removes any null/undefined values (i.e. it removes the classes parameter value if one wasn't set), and finally join(' ') which merges the two array values together with a space (which means it's now a string and you can do {{ classes }} to print the whole thing).


This post helped me with my issue with a different approach (except of using the kebab filter the slug of the tag is used for the route)

Use of tag.slug instead of tag.title in a custom route

as I think that makes lot more sense then using the title, maybe it would be a good idea to update the article in the support section of the craftcms website.


Does craft have any build in function for countries like locales?

The closest thing I can think of is to pull the data from the 'territories' part of a craft/app/framework/i18n/data file.

For 'en_us', that would be something like this:

{% set localeData = craft.i18n.getLocaleData('en_us') %}
{% set allTerritories = localeData.getAllTerritories() %}


"PHP Warning: var_export does not handle circular references" when devMode = true

The current solution i know of is to change CLogFilter's default dumper from:

public $dumper='var_export';

To:

public $dumper='print_r';

It even has a comment above it:

/**
 * @var callable or function which will be used to dump context information.
 * Defaults to `var_export`. If you're experiencing issues with circular references
 * problem change it to `print_r`. Any kind of callable (static methods, user defined
 * functions, lambdas, etc.) could also be used.
 * @since 1.1.14
 */

My previous answer was criticised because I obviously wasn't clear enough. As for the age of this question, it's only 2 months old.

Note: I've told P&T about this.


Unit Testing with current version of Craft

I found a bootstrap that works for me apart from an issue with the database connection.

I can't find the link now but here is the code:

<?php
define("CRAFT_ENVIRONMENT", "dev");
// PHP sucks at resolving symlinked directories
define('CRAFT_BASE_PATH', realpath(str_replace("plugins/myplugin", '', dirname(__FILE__))).'/');

// Define app constants
defined('CRAFT_APP_PATH')          || define('CRAFT_APP_PATH',          CRAFT_BASE_PATH.'app/');
defined('CRAFT_CONFIG_PATH')       || define('CRAFT_CONFIG_PATH',       CRAFT_BASE_PATH.'config/');
defined('CRAFT_VENDOR_PATH')       || define('CRAFT_VENDOR_PATH',       CRAFT_BASE_PATH.'app/vendor/');
defined('CRAFT_FRAMEWORK_PATH') || define('CRAFT_FRAMEWORK_PATH', CRAFT_APP_PATH.'framework/');;
defined('CRAFT_PLUGINS_PATH')      || define('CRAFT_PLUGINS_PATH',      CRAFT_BASE_PATH.'plugins/');
defined('CRAFT_STORAGE_PATH')      || define('CRAFT_STORAGE_PATH',      CRAFT_BASE_PATH.'storage/');
defined('CRAFT_TEMPLATES_PATH')    || define('CRAFT_TEMPLATES_PATH',    CRAFT_BASE_PATH.'templates/');
defined('CRAFT_TRANSLATIONS_PATH') || define('CRAFT_TRANSLATIONS_PATH', CRAFT_BASE_PATH.'translations/');
defined('YII_TRACE_LEVEL')          || define('YII_TRACE_LEVEL', 3);
// Load Yii
require_once CRAFT_APP_PATH.'framework/yiit.php';
Yii::$enableIncludePath = false;
require_once CRAFT_APP_PATH.'Craft.php';
require_once CRAFT_APP_PATH.'etc/web/WebApp.php';
require_once CRAFT_APP_PATH.'Info.php';
// Craft shits itself if there is no server or request path
$_SERVER['HTTP_HOST'] = 'dev.copywheat';
$_SERVER['REQUEST_URI'] = '/';
// Load test database
$config = require_once CRAFT_APP_PATH.'etc/config/test.php';
$config['params']['dbConfig'] = array();

// Create app instance
$app = new \Craft\WebApp($config);
// Load plugin
require_once CRAFT_PLUGINS_PATH.'myplugin/mypluginPlugin.php';

I'm still having issues with the db connection.  Have had to resort to modifying the craft/app/etc/config/defaults.db in order to override the environment file which does work for me at the moment.


Nginx Vhost Config - Get page based on translated URI and without parameters in url

Ok, I got it working with:

nginx vhost config:

location /en/ {
    try_files $uri $uri/ @enrewrites;
}

location /nl/ {
    try_files $uri $uri/ @nlrewrites;
}

location / {
    try_files $uri $uri/ @rewrites;
}

location @enrewrites {
    rewrite ^/en/(.*)$ /en/index.php?p=$1 last;
}

location @nlrewrites {
    rewrite ^/nl/(.*)$ /nl/index.php?p=$1 last;
}

location @rewrites {
    rewrite ^(.*) /index.php?p=$1 last;
}

And in general craft config:

'omitScriptNameInUrls' => true,


Redirect and locale issues when using Valet / Caddy Server

Discussion with solutions here https://github.com/laravel/valet/issues/179


Invalid username or password, errorCode:0 but I'm using correct credentials

Ok I've solved the issue. PHP was trying to save the sessions into a non-existing directory.

To check the current session path, I've added var_dump(session_save_path()); in Craft's /public/index.php (was set to /var/lib/php-fpm/session).

Fix was to update session.save_path setting in the php.ini to point to the right directory with correct permission.

Hope this helps someone in the future.


How to extend Craft.BaseElementIndex for a custom Element Type

Not really an answer to your question but some thoughts..
I've tried your code with my form builder and I noticed two things (the first is really obvious)

When you overwrite the default init function everything will (of course) break because all the important staff happens there, you can make your calls in the afterInit() function. Craft.js Line 3573

// Give sub-classes a chance to do post-initialization stuff here
this.afterInit();

This function handles the sort for Craft. Craft.js line 2721 link to git

setStoredSortOptionsForSource: function() {
    // Default to whatever's first
    this.setSortAttribute();
    this.setSortDirection('asc');

    var sortAttr = this.getSelectedSourceState('order'),
        sortDir = this.getSelectedSourceState('sort');

    if (!sortAttr) {
        // Get the default
        sortAttr = this.getDefaultSort();

        if (Garnish.isArray(sortAttr)) {
            sortDir = sortAttr[1];
            sortAttr = sortAttr[0];
        }
    }

    if (sortDir !== 'asc' && sortDir !== 'desc') {
        sortDir = 'asc';
    }

    this.setSortAttribute(sortAttr);
    this.setSortDirection(sortDir);
},

The important part is: var sortAttr = this.getSelectedSourceState('order'), (line 2726) and since sortAttr (at least for me) was never null in my tests - the sortAttr = this.getDefaultSort(); is not triggert. This is because Craft caches the sort order for the user but I don't know how/when this happens. However: when I overwrite line 2729

if (true || !sortAttr) {
    // Get the default
    sortAttr = this.getDefaultSort();

    if (Garnish.isArray(sortAttr)) {
        sortDir = sortAttr[1];
        sortAttr = sortAttr[0];
    }
}

And use

getDefaultSort: function() {
    return ['dateCreated', 'asc'];
}

I was able to change the default sort. Hope it helps a little bit

Note: this will break the default Craft caching. Normally the default sort options runs only once, after that is keeps the sort order that the user specified. You could overwrite the function for your tests and remove the always true condition when it goes live for a reliable way to get your function triggert.


What attribute type should I set in the record or model to create a TEXT type in the database?

Ok worked out a solution to the attributes. You can set them like this:

array(AttributeType::String, 'column' => ColumnType::Text,  'required' => false)

By defining the column, so hopefully this will help someone else.


Point directly to a structure or channel with Entries field

In addition to Aaron's answer, is there a specific page that is going to list the events on the front end? I'm assuming you're probably outputting the events list (for example) via that channel's index page now?

What's nice about Craft is there's lots of way to skin the cat here. It also does some things that aren't necessarily intuitive, like in this case: there's not really a great way to handle the content of the "index" directly or link to it without a couple workarounds.

Linking to a specific section is a little too far removed for my taste but on certain sites with a ton of different sections, I can see where it might be a necessary evil to keep things sane.

Depending on the complexity of the site, I've found creating a master Pages structure that can also double as the navigation to be an option. Authors can see a bird's eye view of their content in Craft's nice tree view. If the top level section happens to be another Channel or Structure, for example, then you can bring it in via your templates.

Doing it that way also gives the benefit of being able to put in introductory text for that section. For example, a Careers page might want to have details about the company before you bring in the jobs; or your Events page might want to mention something about requiring registration, etc.  That makes your Twig logic a bit more complex or tie up an Entry Type depending on what you're doing but it can be manageable. This question goes into more detail about this.

Some people have also used Singles in this way. I find Singles not that useful but again YYMV.

(It would be great to be able to have a Single's functionality—a one-off field layout—in a Structure without having to resort to having to create another entry type that a user can change—but that would be a feature suggestion.)


How I can capture previous and current URL to a hidden form field

In the context of Craft 3,

<input type="hidden" name="referrerUrl" value="{{ craft.app.request.getReferrer()" />

<input type="hidden" name="currentUrl" value="{{ craft.app.request.getAbsoluteUrl() }}" />

You can see other methods off of the web/Request object you can use here: https://docs.craftcms.com/api/v3/craft-web-request.html


The most straightforward way would be to use a Categories field.

The value that a Categories field returns to the template is an ElementCriteriaModel, which fits perfectly as a value for the .relatedTo parameter.

So you could do something like:

{% set featuredEntries = craft.entries.relatedTo( entry.selectedCategories ) %}

The only circumstance where I can envision a Checkboxes field being better suited to this use-case is if you need to only provide a specific subset of the categories in a group.

(If you want to make all the categories from a group available for selection, using a Categories field is definitely best; otherwise you have to go back and update the options of your Checkboxes field every time a category is created, changed, or deleted.)

In that case, I recommend using the category IDs as the option values for your checkboxes, so that you can pass them to an ElementCriteriaModel like this:

{% set featuredEntries = craft.entries.relatedTo( entry.selectedCheckboxes | join ) %}


How can I install modules with Composer?

Craft Plugins require that a "type":"craft-plugin" property is defined in each composer.json file. Composer refers to this to help manage and install the plugin. Craft Modules do not currently have this support.

You can see all package types that Composer Installer supports here. There is still a way to achieve what you're trying to do though...

Composer Installers Extender allows you to create your own custom package type. So we could create craft-module ourselves. Just make sure your module has this "type":"craft-module" in it's composer.json

Now we can define some extra settings that tell Composer to put the modules into the modules directory. Incorporate the following into your projects composer.json file:

"require": {
  "oomphinc/composer-installers-extender": "^1.1",
  "vendorname/modulename": "dev-master"
},
"autoload": {
  "psr-4": {
    "modules\\": "modules/",
    "modules\\modulename\\": "modules/modulename/module/"
  }
},
"extra": {
  "installer-types": ["craft-module"],
  "installer-paths": {
    "modules/{$name}": ["type:craft-module"]
  }
},

Note: Make sure your module no longer exists in your vendor directory as you may be hit with some potential conflict warnings.


You've got a little ways to go before that will work as a plugin... I'd highly recommend getting a little more familiar with the basic anatomy of a plugin...

Craft Docs - Anatomy of a Plugin

Basically, you'll want to take the "task" method that you have and move it to a *Variable.php file. Then you will be able to call that variable via a Twig template...

{{ craft.taskShortcut.task(attributes, content, tag) }}

You can learn more about variables here: Template Variables

However, you'll still need your main *Plugin.php file, but the methods inside will be different (Your Primary Plugin Class).

This will most likely be the folder structure of your plugin:

/craft/plugins/taskshortcut
                           /TaskShortcutPlugin.php
                           /variables/TaskShortcutVariable.php


Best practice on how to hand over variables with links?

You're options are:

Adding it as a parameter in the querystring (e.g. domain.com?key1=value1)
Submitting it though a form and grabbing the value from POST.
Setting the value in a cookie and retrieving it on the next page using something like this plugin.
Writing a plugin with a Twig function that wraps Craft's craft()->userSession->setFlash() method, which will store a key->value pair in session for exactly one request.  You can retrieve the value via craft.userSession.getFlash().

Note that there are limitations to the size and complexity of the data you can pass along with all of these, but especially options 3 and 4, so it's best to stick with simple strings.


Can fields be reused with a different name per section?

One of these might help (I use the first one):

https://plugins.craftcms.com/fieldlabels
https://plugins.craftcms.com/relabel


Out side of what you have mentioned, I recall Discourse being mentioned on the Google+ Community. That's written in Ruby, though.

Vanilla Forums is open-source and written in PHP. It's also comes with SSO (Single-Sign On), and can be embedded into another site via an iframe.

There are currently no announced forum plugins native to Craft.


My guess is that you've got xDebug installed and you're running into this: Why are some entry detail views empty in the control panel?

Or your php.ini file's memory_limit is set to something low and you're running out of memory and it needs to be bumped up.


Allowing duplicate slugs in category paths

Jamie's answer is correct.

If you set your Settings → Categories → Category URI Format to {parent.uri}/{slug} you will then be able have multiple time the same slug.

Craft will take the parent into consideration when saving the category therefore allowing you to have (in your case) byc/saturday and wbr/saturday


Treat links in redactor/rich text field differently depending on entry type

This is a high-level question, with multiple problems to solve. First, you'll need to parse the HTML from the Rich Text field for <a> tags. Then, you'll need to find a way to match the href attributes for those <a> tags to entries, and finally, you'll need to set classnames to the <a> tags (depending on the matched entry's Entry Type) and spit the rewritten HTML back out (saving it back to the entry if you want the classnames to persist).

Please note that the code in this answer isn't really tested, and there are multiple ways to skin your particular cat (or cats, as it were). Hopefully you'll take something away from it, though.

First, in order to parse the HTML for <a> tags, I'd recommend using DOMDocument, which is a built-in HTML parser (PHP5+). DOMDocument makes it super easy to find all the <a> tags in your HTML, and is much safer than using regular expressions. Here's how that could look:

$dom = new \DOMDocument();
$dom->loadHTML($html);
$links = $dom->getElementsByTagName('a');

Next step is looping through all the <a> tags; attempting to pull Entries from their href attributes. Note that those href attributes might be reference tags (e.g. {entry:11:url}) or either a relative or absolute URL, and ideally, your code should account for all of those variations:

foreach ($links as $link) {

    $href = $link->getAttribute('href');

    if (strpos($href, '{entry') !== false && strpos($href, 'url}') !== false) {
        // Reference tag – get entry by ID
        $reference = explode(':', $href);
        $entryId = (int) $reference[1];
        $entry = craft()->entries->getEntryById($entryId);
    } else {
        // URL. Make sure the site url is stripped and get entry by URI
        $uri = ltrim(str_replace(craft()->config->get('siteUrl');, '', $link->getAttribute('href')), '/');
        $entry = craft()->elements->getElementByUri($uri);
    }

}

Finally, DOMDocument makes it super easy to add a classname back to the <a> tags, depending on the Entry Type:

// Add classnames based on the Entry Type handle
switch ($entry->type) {
    case 'work' :
        $link->setAttribute('class', 'work-link');
        break;
    case 'news' :
        $link->setAttribute('class', 'news-link');
        break;
}

One minor gotcha to note, is that DOMDocument will add HTML structural tags ('html', 'head', and 'body') to your HTML. A bit of regex takes care of that:

$html = preg_replace('~<(?:!DOCTYPE|/?(?:html|head|body))[^>]*>\s*~i', '', $dom->saveHTML());

Here's the complete code, for context:

// Create a new DOMDocument instance and find all <a> tags. I like to use mb_convert_encoding to ensure that the HTML content is UTF-8 encoded, but your mileage may vary
$dom = new \DOMDocument();
$dom->loadHTML(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'));
$links = $dom->getElementsByTagName('a');

// Loop through the <a> tags
if ($links && $links->length > 0) {

    foreach ($links as $link) {

        // Try to get entry from href attribute
        $href = $link->getAttribute('href');

        if (strpos($href, '{entry') !== false && strpos($href, 'url}') !== false) {
            // Reference tag – get entry ID
            $reference = explode(':', $href);
            $entryId = (int) $reference[1];
            $entry = craft()->entries->getEntryById($entryId);
        } else {
            // URL. Make sure the site url is stripped
            $uri = ltrim(str_replace(craft()->config->get('siteUrl'), '', $link->getAttribute('href')), '/');
            $entry = craft()->elements->getElementByUri($uri);
        }

        if ($entry && $entry->elementType == ElementType::Entry) {

            // Add classnames based on the Entry Type handle
            switch ($entry->type) {
                case 'work' :
                    $link->setAttribute('class', 'work-link');
                    break;
                case 'news' :
                    $link->setAttribute('class', 'news-link');
                    break;
            }

        }

    }

}

Phew. That takes care of the HTML, but depending on your need, you'll have to decide on an approach for when and where you want to rewrite your Rich Text content – i.e., where and when you'll place and call the above code (or something like it).

You have two options (it isn't clear from your question which of these you want):

a) Add the classnames when the entry is saved (permanent)
b) Add the classnames when the content is output in a template (not permanent)

If you want to add the classnames to links in the Rich Text content permanently, I'd recommend creating an event listener for the entries.saveEntry event, rewriting the HTML before re-saving the entry. The below would go in your plugin's primary class:

public function init() {
    parent::init();
    craft()->on('entries.saveEntry', array($this, 'onSaveEntry');
}

public function onSaveEntry(Event $e) {
    $entry = $e->params['entry'];
    $html = isset($entry->richTextField) ? $entry->richTextField->getRawContent() : false;
    if ($html) {
        ...
        $entry->getContent()->setAttribute('richTextField', $html);
        if ($entry->validate()) {
            craft()->elements->saveElement($entry);
        }
    }
}

For option b), I'd suggest writing a Template Variable method or a custom Twig Filter. A Template Variable would be a little bit easier, and would enable you to do the following in your template to print the HTML with the classes added:

{{ craft.myPlugin.addEntryTypeClasses(entry.richTextField) }}

A custom Twig filter offers a marginally more elegant template syntax:

{{ entry.richTextField|addEntryTypeClasses }}

Here, addEntryTypeClasses is a custom function (a template variable method or a Twig filter, respectively) that you'd have to create, where you could add the above code. To avoid the need to use the |raw filter in your template, add the following when you return the $html variable:

public function addEntryTypeClasses($html) {
    ...
    return TemplateHelper::getRaw($html);
}

In all of the above examples, ... is where you'd put the DOMDocument code. Ideally, all of that code would go in a custom Service method, making it easy to perform the DOMDocument operation on any HTML content from basically anywhere (Twig Filters, Variable methods, hooks and/or event listeners), as well as keeping your plugin code tidy and nice, but it isn't a must.

Keep in mind though that with option b), it would be a very good idea to cache the output, as the operation can be costly if you have a lot of links in your Rich Text field (Craft will have to hit the database for each link, every pageload).

Finally, if you don't fancy the DOMDocument approach, you could look at different approaches entirely – for instance, you could write a custom Redactor plugin, which could do basically the same thing as the above DOMDocument solution, only with JavaScript (jQuery) instead of PHP. Here's an example of a Craft Redactor plugin you could take a look at to get started: https://github.com/jpdevries/styles

If you're interested in more examples regarding custom Twig filters and DOMDocument specifically, I wrote a plugin called Retcon HTML which streamlines a lot of common HTML rewriting operations. It won't help with your specific issue, but the attr filter comes pretty close :)


Your virtual hosting config looks good to me.  However, how are you running SSL?
You've only shown the port 80 / non-SSL config and it shows a redirect to https so the DocumentRoot probably differs between port 80 and 443 versions vhost stanzas.
Make sure DocumentRoot is the same in both places and you should be able to load up Craft without the www-craft-test prefix.


You can output the primary site’s Base URL like this:

{{ craft.app.sites.primarySite.baseUrl }}

(craft.app.sites maps to craft\services\Sites.)

If your Base URL begins with an alias, you will need to parse it:

{{ alias(craft.app.sites.primarySite.baseUrl) }}

Altertatively, if you need to link to a sub-page of the primary site (not just its Base URL), you can do that with the siteUrl() function, which has a siteId argument.

{% set primary = craft.app.sites.primarySite %}
{{ siteUrl('sub/path', siteId=primary.id) }}

Note that if your primary site’s Base URL contains the @web alias, that will always just return the host info for the current request. So you may need to replace that with a hard-coded base URL (or use a custom alias) before this works as expected.


Craft URLs intermittently being cached as /index.php/my-page/ or /index.php?p=my-page

There is an explanation of why this can occur on the Craft help section here: http://buildwithcraft.com/help/why-index.php


If I try to preview a previous revision of an entry, I get "an unknown error occurred"

This bug was due to an issue with the Stringify library and was fixed in Craft 3.3.16.1, as stated by Brad Bell in his comment on the original question.

Upgrading to Craft 3.3.16.1 fixes this issue.

(I'm posting this as an answer in case anybody else runs into the same issue.)


Forward users to the right template according to the current active site's language

I'm not sure there's a good solution for this in Craft 2 without some custom plugin logic.

To be fair, this was the same behavior in Craft 3 until pretty recently as well.

You might want to comment on that Github issue to see about the feasibility of backporting something to Craft 2 for this.


How can I add an option group to the select Macro from CraftCMS forms macros

I had the same issue and managed to get it working like so:

{{ forms.selectField({
    options :[
     {optgroup:'North Island'},
     {label : 'Foo', value: 'foo'},
     {label : 'Bar', value: 'bar'},
     {optgroup:'South Island'},
     {label : 'Baz', value: 'baz'}
    ],
    name: name,
    value : value
})}}

So I guess in php (if working from a plugin) your array would need to look like:

array(
 array('optgroup' => 'North Island'),
 array('label' => 'Foo', 'value' => 'foo'),
 array('label' => 'Bar', 'value' => 'bar')
 array('optgroup' => 'South Island'),
 array('label' => 'Baz', 'value' => 'baz')
);

This then would output it like this in the admin area


Group looped entries into blocks and wrap in markup every x number of loops

The array slice something you are looking for is Twig's batch filter. Here's how you'd set up the groups and use loop.index to generate the class name.

{# Use the `find()` method to return an array of EntryModels #}
{% set selectedWork = craft.entries.section('selectedWork').find() %}

{# Group entries using the `batch` filter #}
{% set selectedWorkGrouped = selectedWork|batch(9) %}

{% for group in selectedWorkGrouped %}

    {# Set class using the loop index from outer loop #}
    {% set panelClass = 'panel--' ~ loop.index %}

        {% for entry in group %}

                {{ entry.title }}

        {% endfor %}

    </div

{% endfor %}


How would I detect whether an entry's asset field has been updated on save?

Have you tried the $element->isFieldDirty() method, or checking through the $element->dirtyFields array for your asset field, rather than checking revision dates?
There may be a good reason why you're not using those, but I thought I'd suggest it in case you hadn't considered it.


Asset Meta Fields vs Section with Asset field + the other fields?

Personally I would add the fields to the asset. Totally depends on what order you prefer to fill in the data.

Are you going to fill in all the data yourself or a client? If so, ask them what they prefer.


Get last change timestamp in header response

If you've already got a reference to the entry, this should do it:

HeaderHelper::setHeader('MyHeader', $entry->dateUpdated);


So, turns out the issue was with the $app = require 'bootstrap.php'; line in app/index.php.  There was another directory for smarty template engine that was getting pulled from for the bootstrap file.  After removing that conflicting file, the issue was resolved.  Strange issue, but hopefully can help if anyone bumps into this in the future...


The reason that you get that odd URL with the {% redirect %} tag is just because there's some whitespace at the beginning of the value returned from your helpers.msuLink() macro. Using the |trim filter (which removes whitespace from both ends of a string) fixes that:

{% redirect helpers.msuLink(entry)|trim %}

If you prefer, you could also modify your macro so it returns the value without whitespace, by using the {% spaceless %} tag – then you don't need the |trim filter:

{% macro msuLink(entry) %}
{% spaceless %}
    {{ 'https://reg.msu.edu/Courses/Request.aspx?SubjectCode=' ~ entry.deptCode ~ '&CourseNumber=' ~ entry.courseNumber ~ '#Results' }}
{% endspaceless %}
{% endmacro %}

As for the conditional, I don't believe you want the craft.entries query there – just put the following at the top of your courses/_entry.html template (note that I'm also putting the {% import %} statement outside the conditional – it doesn't really matter but its cleaner and shouldn't impact performance):

{% import 'partials/_helpers' as helpers %}

{% if entry.type == 'outsideCourse' %}
    {% redirect helpers.msuLink(entry)|trim %}
{% endif %}

{# Rest of template below #}
...

If you decide that having the outsideCourse URLs 404 instead of redirect makes the most sense (I believe it would, and is cleaner, in most cases), the easiest way to achieve that is to put this at the top of your entry template:

{% if entry.type == 'outsideCourse' %}
    {% exit 404 %}
{% endif %}

{# Rest of the template below #}
...


On Craft Client, what does the client account get?

From here:

  The Client’s Account is not an Admin account like yours, so they will not be able to access the Settings section or administrate your Admin account. They’ll be able to do everything else, though.


Implication of old task backlog suddenly being released

The only time I can think of where this might be an issue is if you had a "Find and Replace" task that was part of the task backlog.  Those are triggered from the "Find and Replace" tool under Settings->Tools in the control panel.

Otherwise, you should be safe just letting the backed-up tasks finish catching up.


Pass aspect ratio as variable into imager

Your variable assignment is wrong. {% set customRatio == 1/1 %} should be {% set customRatio = 1/1 %}.


403 forbidden error when moving entries in structure

You've probably got a multi-node/web server setup in Fortrabbit, but haven't setup memcache for PHP session storage. They have an article on how to do it here: https://help.fortrabbit.com/craft-3-tune#toc-cache-amp-session-on-the-professional-stack

Moving items in a Structure in Craft requires a working PHP session.


You have a few options here:

Use an Entries field (as a Global or as a fields on a Single maybe?) to chose the entries and order them
Make the Entries a Structure section, so you can set the order
use craft.entries({ ids: [3, 1, 2], fixedOrder: true }) and query the Entries by ID (if they'll never be deleted and you're cool with hard-coding the order)
create an order field on that entry type to query them by, also with craft.entries()

It's up to you what the best solution would be, given your set-up, but you have plenty of options.


Under your Rich Text field settings, if you uncheck the "Purify HTML?" option, the tel: reference will stay in tact.


This looks like the Button Box plugin, also from the team who developed Pimp My Matrix.


Adding a new block type to Matrix causes subfields and subfields of other block types to disappear

Bumping php.ini's max_input_vars to a higher value as described in the answer here fixed it.


Define email environment-specific email settings?

Currently email settings aren't multi-environment aware, so there is no native way to do this.

Probably worth adding to the feedback site, as this has come up before, though.


Pulling the currently rendered field layout inside the CP

It looks like EntryTypeModels have a fieldLayoutId attribute. By inspecting the route params, we can get the entry type ID, and then create a model from that. Other than this, I haven't been able to find anything passed to the FLD.

    $params = craft()->urlManager->getRouteParams();
    $variables = $params['variables'];
    $matches = $variables['matches'];
    $entryTypeId = $matches['entryTypeId'];
    $entryType = EntryTypeRecord::model()->findById($entryTypeId);
    $fieldLayoutId = $entryType->fieldLayoutId;

Hopefully this helps!

Edit:

I also found that a fieldLayoutModel is passed to the fieldlayoutdesigner.html template when it is included. See the include in templates/settings/section/_entrytypes/edit.html as an example. Content from the FieldLayoutModel is then loaded.

I know you said you would rather not load with ajax, but it is definitely better than nothing. I don't see any hook or event that gives you access to this information.

You could do something like

var fieldLayoutId = '{{ fieldLayout.id|e('js') }}';

from within your included js file and then go pull your metadata via ajax.


Flexible content requirements for Matrix

If these Matrix fields are going to have a lot of fields then I'd recommend taking a look Pimp my Matrix to keep them well organised.

If you're wanting to make your Tables more powerful and have more field types check out SuperTable.


I think you're asking how to output custom fields based on their type.

Something like this should work:

{% for lineItem in cart.lineItems %}

// Is the current line item a variant purchasable?
{% if className(lineItem.purchasable) == 'craft\commerce\elements\Variant' %}

  {% switch lineItem.purchasable.product.type.handle %}
    {% case "clothing" %}
        // Only output the varHeight if the product type is clothing
        {{ lineItem.description }}<br>
        Var Height: {{ lineItem.purchasable.varHeight }}
    {% default %}
        {{ lineItem.description }}
  {% endswitch %}

{% else %}

  // Non variant purchasable
  {{ lineItem.description %}

{% endif %}

{% endfor %}


How do I make a service only runable by the server?

Along with Brad's answer, one additional easy check in your code would be to see if the $_SERVER['REMOTE_ADDR'] is the server's IP and then bail if it's not.

That means you'd have to spoof the server's IP address AND guess the key. No better than a username/password combination but should be secure enough IMO.


Certainly seems doable to me. And the complexity would depend on how comfortable you are with PHP.

But roughly you'd follow the same format as the Aviary Image Editor plugin for Craft where you have the user enter their imgix API key from their account and store that in the database. Then your plugin would be a wrapper for the imgix API calling their web service methods whenever you need to interact with them.