Can I use isEditable() on a global? I have a headline global.

I am trying to see if headline is editable by using this code block, but it is not working.

Can I use isEditable() with my headline global?

{% if headline.isEditable() %}

        Edit Headline

{% endif %}

No, the isEditable property isn't supported for Global Sets.

The confusing thing is that the GlobalSetModel class does actually have an isEditable property, however it will always return false. The reason is that this property is inherited from the BaseElementModel class, where it will return false unless the element type overrides it to (potentially) return something else. An example of the latter is the EntryModel class, which also inherits BaseElementModel but overrides  isEditable to test if the current user is allowed to edit the entry.

It'd be interesting to hear P&T's reasoning for not "enabling" isEditable for Global Sets, although to be honest – needing to give users the ability to edit global variables from the frontend sounds like an edge case at best, and probably not a very good idea.

On that note, my best advice for a workaround would be to simply use a Single instead of a Global Set.

However, if you need/want to use a Global Set, you can easily work around the issue by creating a custom plugin exposing a isGlobalSetEditable template variable method. Something like this should work:

public function isGlobalSetEditable(GlobalSetModel $globalSet)
{
    return craft()->userSession->checkPermission('editGlobalSet:'.$globalSet->id);
}

In your template, you could then do something like this:

{% if craft.myPlugin.isGlobalSetEditable(headline) %}
    Edit me
{% endif %}

If you're not familiar with plugin development, I'd advice you to check out the official docs on the subject, and to download the excellent Business Logic Plugin as a starting point – it even has a Variable class where the above isGlobalSetEditable method could be dropped right in.


Re-usable Field Layouts I've Googled & searched on here, but have not been able to find the answer I need.

I come from using Advanced Custom Fields in the WP environment, and one feature that was great about ACF was being able to define the templates a field grouping would/can show on.

Take Craft for example. I have a grouping of fields that when combined form the banner "field layout" for a section. However, that "field layout" can be used on multiple other sections and even single pages. Without me having to re-create it on every single or section, is there a way that's much more efficient?

I am also using the Reasons plugin https://github.com/mmikkel/Reasons-Craft which enables me conditional fields. And I believe this is where the efficiency concerns are coming from. Because I am having to set the conditionals on each field layout. And if I decide to change something, I will need to change it across all other field layouts.

No, unfortunately there's no way to re-use a Field Layout in Craft.

You might want to consider adding a feature request at http://feedback.buildwithcraft.com.


Display variant title on cart page only for items with more than one variant I want to display the variant title only on line items which have more than one variant.

On the Image you can see the bold Product title and undeneath there is the variant title (Format A2). As you can see the last line item has only one variant so it's unnecessary to show the title there twice.

How do I write the conditional to show the title only on products with more than one variant?

On the Product page I just wrote it like this:

{% if product.variants | length > '1' %}
  {% for purchasable in product.variants %}
     {{ purchasable.title }}
  {% endfor %}
{% endif %}

But in the cart it's a line item and not a product so this code doesn't work. How do I have to apply this to a line item?

If you are using separate product types - some with variants, some without:

Then what you're looking for is basically:

{% for lineItem in cart.lineItems %}
    {% if lineItem.purchasable.product.type.hasVariants %}
       {# the purchasable is the chosen variant - display the product AND variant title #}
       {{ lineItem.purchasable.product.title }} <br>
       {{ lineItem.purchasable.title }}
    {% else %}
        {# no variants, just use the title from the product #}
        {{ lineItem.purchasable.product.title }}
    {% endif %}
{% endfor %}

If you're using just one product type, some entries of which have one variant and others more:

Basically you need to get back from the lineItem to the product so that would be something like this:

{% if lineItem.purchasable.product.variants|length > 1 %}
    {{ lineItem.purchasable.title }}
{% else %}
    {{ lineItem.purchasble.product.title }}
{% endif %}

...
(I've not tested these directly, just coded here in the browser but that should be pretty
close!)


Craft CMS Product Types I am trying to setup some products in my test website. I am unsure how I should go about creating the products. Should each product category be created as a product type?

An example is, if I have some art, how should I construct the products?

Imagine if I have these different "things" on the shop:

Prints
Paintings
Illustrations
Something
Something Else

I tried to create a different product type for each but then I ran into issues because I needed a template for each product type. Also I couldn't view the archive page.

Should I create an "Art" product type and work out a way to display these? Or just create each as individual product types?

I am also confused about templating with archive/entry pages. Say if I have  templates/shop/art/_entry.twig does craft automatically know that the archive template should be in the same directory?

Answered at https://craftcms.stackexchange.com/a/22468/7356

"Product Types are really for the content of the fields and field layout of each product plus basic options for things like tax/shipping category defaults.

For full categorization in menus and site structure, we recommend putting a category field on all products."


Parent/child Single sections I'm trying to create parent/child Single sections without using Structures.  So in other words, create a Single section and assign it a parent Single section.  Is this possible?

Ignoring the obvious "use a Structure" answer, I suppose you could fake a "hierarchy" by placing a child and parent entry field on each of your Single sections and manually assigning entries as relationships.

Then your Twig template could would just be checking those fields and building the family tree based on the relationships.


After switching from PHP 5 to 7 for a local 2.x install, I can't login I have Craft running locally, the latest 2.x branch. When I change the server to run PHP 7 instead of 5.x, the local Craft frontend still works, but I can't login to the backend. It says "Invalid username or password", even after doing the reset password process.

Trying to prep a site for upgrading to Craft 3, but if I can't even get Craft 2.x running on PHP 7... :-/

Turns out that it was a PHP configuration issue.

Under Windows, the paths in php.ini need to include a drive letter (eg. c:\xampp\php7\). By default they're root-relative (eg. \xampp\php7). When I originally installed XAMPP with PHP 5.x, it adjusted the paths automatically. But when I manually copied the PHP 7 folder into XAMPP to set it up for version switching, I overlooked the path discrepancy.

In this case, it was the inability of PHP 7 to set sessions that was causing the odd behavior.


Extend a Commerce (v2) order template in the control panel Is there a way to extend (extend, not replace) the default Commerce order templates in the control panel?
I'd like to display important custom fields in a prominent way on the first tab. (and not tucked away on a second tab as is normal with custom fields)

I found the solution in another question:
Writing a plugin that triggers on a Control Panel Template Hook?

Based on this answer we can use:

Craft::$app->getView()->hook('cp.commerce.order.edit.main-pane', function(array &$context) {
    return 'My Button!';
});


Can I exclude a commerce address by ID when retrieving a list of addresses? I would like to retrieve a list of all commerce customer addresses except for one. When working with entries, this can be done with the {id: 'not ' ~ some.id } parameter. This doesn't seem to work with craft.commerce.customer.addresses.

I'm currently achieving what I need with the following code:

{% set customerAddresses = craft.commerce.customer.addresses %}
{% for address in customerAddresses %}
    {% if address.id != craft.lhngroups.orgCommerceAddressId %}
        output the address
    {% endif %}
{% endfor %}

This works, but it throws off some {{ loop.index }} operations I'm trying to perform since the actual array of addresses contains 1 more address than what I'm displaying.

I still haven't found a succinct way to exclude a particular address by ID within the commerce customer addresses tags, but I did come up with the following as a way to get a nice clean set of addresses I want to iterate over.

Rather than use a conditional in my loop, I decided to create the collection first, with the address I want to exclude being kept out of the collection. This gets the job done!

{% set customerAddresses = [] %}

{% for address in craft.commerce.customer.addresses %}
    {% if address.id != craft.lhngroups.orgCommerceAddressId %}
        {% set customerAddresses = customerAddresses|merge([address]) %}
    {% endif %}
{% endfor %}


Ajax Function on a search form not working in Safari & IE I made an ajax function so my page wont refresh and my search window wont disappear on form submit. It works fine in all browsers but it keeps refreshing on Safari.

Here is my code:

{% if not craft.request.isAjax %}
    {% set pagingJs %}
        $(function () {
            $('#searchBtn').click(function (e) {
                $( ".searchResult" ).remove();
                $( ".noResult" ).remove();
                e.preventDefault();
                var search = $('#searchField').val();

                $('#loading').show();
                $.get( "/?q="+search, function( data ) {
                    data = $('#searchQuery', data).html();
                    $( "#searchQuery" ).append(data);
                });
            });
        });
        $( document ).ajaxStop(function() {
           $('#loading').hide();
        });
    {% endset %}
{% includeJs pagingJs %}
{% endif %}

Try attaching the listener on the forms submit event instead, and prevent that instead of just the click on the button. Something like this (make sure you change the selector for your form):

{% if not craft.request.isAjax %}
    {% set pagingJs %}
        $(function () {
            $('#myForm').on('submit', function (e) {
                e.preventDefault();

                $( ".searchResult" ).remove();
                $( ".noResult" ).remove();

                var search = $('#searchField').val();

                $('#loading').show();
                $.get( "/?q="+search, function( data ) {
                    data = $('#searchQuery', data).html();
                    $( "#searchQuery" ).append(data);
                });
            });
        });
        $( document ).ajaxStop(function() {
           $('#loading').hide();
        });
    {% endset %}
{% includeJs pagingJs %}
{% endif %}


RSS throwing 404 error I used this example to create an RSS feed in Craft, saved it as “feed.rss”, uploaded it into the “craft/templates” directory. When I go to www.my-website.com/rss, I get a 404.

What am I missing here? Any help is highly appretiated.

Thanks!

You have named the file feed.rss, and you are trying to access it by going to /rss. So I can see two issues here:

The template file needs to be either .html or .twig, as per the
tutorial you have referenced
The name of the template file will dictate the URL for that template. If you re-name your template file to feed.twig, you access that template by going to /feed


Expire an entry according to a date field Ich have a concert entry which I want to expire after the concert is over.

How do I do that?

I was able to hide past entries like this:

{% set present = now|date_modify("+1 day") %}
{% for entry in craft.entries.section('concert') %}
     {% if entry.konzertdatum > present %}
       {{ entry.konzertdatum|date('d. M. Y - H:i')}} - Concert Bla
     {% endif %}
{% endfor %}

But ist it also possible to expire this entry altogether os its marked in the CP?

Or would it be better to use the post_date as a concert timestamp and then show somehow only future dates?

You can set the Expiration Date in the control panel. It is at the bottom of the column on the right (on wide screens), or at the bottom of the page (on narrow screens). I don't think there is any way to set the Expiration Date from the konzertdatum, so you would have to either use the Expiration Date as the concert date, or maintain both of them.


Cache invalidation to automatically update all cached template content? I am using the cache tag in my templates. How can I assure that a site visitor always gets the data directly from the cache and never has to wait for it to be generated?

My cache gets invalidated quiet often, as this happens each time new content is created or edits are made.

Any idea on how to trigger the recreation of all cached template content automatically?

.

Edit:

To better explain my use case: some of my craft.assets and craft.entries calls result in a lot of DB queries. Without the template being cached this leads to 3+ seconds delay in page-load. Using Craft cache this is solved for all but one site visitors, because there is still the first visitor, that has to trigger the caches to be created.

I think you shouldn't ignore this single user and hope someone comes up with a solution as additional 3+ seconds in page-load can easily cause customer loss. Further I'd appreciate a solution feasible with core functions, as I consider performance being a key component to every site.

.

2nd Edit:

The reason I started a bounty on this question was to get more attention on it from the community and also from P&T. This seems to work out so far, so thank you all for your thoughts on this and for having this interesting discussion, which is sometimes a little too technical for me (who's not a php/server developer). I actually don't know what to do which the bounty points, but for me it was already worth spending them (who cares for pts anyway?)!

I built the Cache Warmer plugin recently, which takes a blanket approach to refreshing your pages cache, by getting entries url with the .getUrl() method, and then send of batch requests to those url's.

I'm currently using it together with the Cache Clear plugin, when deploying changes to our site, and it's working well. This is a very simplistic approach to a potentially complex problem, so I would say a more granular cache invalidation/refresh strategy might be needed, depending on your use case.

However, I think there is something to be said for this approach on small to medium sites.

I want to at least add some hooks, so that you can warm up single entries/elements as well. My plugin doesn't know which pages your cached elements are living on, but there is a big chance those pages will be hit and warmed up - as long as they're located in a section, and that section is toggled in the plugin settings.


Redactor advanced table formatting? We have a client who has quite complex tabular data they need to add to their site. Hitherto they have been preparing these in Excel then pasting in but we are hitting issues with the way Redactor interprets merge table cells.

Short of editing the HTML for each of these via source (quite laborious and cannot really expect to do this each time the client wants to add/udpate a table) is there any way through redactor to add more complex table cell formatting?

There is a tables plugin for Redactor, to easily create tables direct in the editor. On top of that, I think I'd approach this using the Redactor Clips plugin to pre-create a number of tables that cover the client requirement, as that will also allow you to better control the way tables are created and also set up some client-friendly table styles.


Validate attachments for file size? Does anyone know if it's possible to validate the size of an attachment for Sprout Forms file upload? I'd like to limit attachments to a maximum file size.

I'm not sure if that's possible since I never used Sproud Forms but you can easily create a custom field type with the additional validation rule.

Create a Plugin you can use Pluginfactory.io for that and install it
Create a new Field
Just extend the basic AssetsFieldType

class myNewAssetField extends AssetsFieldType{

}

Take a look at the default validation rules for BaseElementFieldType

public function validate($value)
{
    $errors = array();

    if ($this->allowLimit && ($limit = $this->getSettings()->limit) && is_array($value) && count($value) > $limit)
    {
        if ($limit == 1)
        {
            $errors[] = Craft::t('There can’t be more than one selection.');
        }
        else
        {
            $errors[] = Craft::t('There can’t be more than {limit} selections.', array('limit' => $limit));
        }
    }

    if ($errors)
    {
        return $errors;
    }
    else
    {
        return true;
    }
}

Copy the function above in your new class and include something like this somewhere

foreach ($value as $assetId){
    $asset = craft()->assets->getFileById($assetId);
    if($asset->size >= 10){ // insert your size here
        $errors[] = Craft::t('Your file is too large');
    }
}

It took me about 5 minutes to create this new field type to allow the validation of file sizes

If you want to make it look pretty and create a setting to dynamically set the individual max file size for each field you can include the function getSettingsHtml in your new class and change add your new value (for example maxSize) you can then grab the new size with $this->getSettings()->maxSize


Using Sprout SEO, how do I use the seoDivider setting in templates? Sprout SEO has a setting in the admin screens to "Select the character that will be used between Title segments". I think it's called seoDivider, but I can't see how to use this in my templates, and can't see any reference to it in the documentation.

The SEO Divider setting will be used if you select the "Append Site Name to all Titles" setting on the Basic SEO tab of your Default, and then override your title via code or a Meta Basic Field type.

For example, if the pipe character is selected as the divider:

Code Override Blog Post Name | Website Name

Meta Basic Field Override Title Value | Website Name


Contact form: Twig_Error_Runtime error upon submission Using the standard P&T contact form, I'm getting the following error when form is submitted (running locally):

Twig_Error_Runtime

Impossible to access an attribute ("fromEmail") on a string variable ("") in "_layout" at line 149 (C:\xampp\htdocs\mysite\craft\app\vendor\twig\twig\lib\Twig\Template.php:460)

#0 C:\xampp\htdocs\mysite\craft\app\etc\templating\BaseTemplate.php(41): Twig_Template->getAttribute('', 'fromEmail', Array, 'any', false, false)
#1 C:\xampp\htdocs\mysite\craft\storage\runtime\compiled_templates\3\5\352f325e7c58d6329a0dbf553a172b2811c881b391a544d0f295665ec793e2af.php(251): Craft\BaseTemplate->getAttribute('', 'fromEmail', Array)
#2 C:\xampp\htdocs\mysite\craft\app\vendor\twig\twig\lib\Twig\Template.php(340): __TwigTemplate_352f325e7c58d6329a0dbf553a172b2811c881b391a544d0f295665ec793e2af->doDisplay(Array, Array)
#3 C:\xampp\htdocs\mysite\craft\app\vendor\twig\twig\lib\Twig\Template.php(314): Twig_Template->displayWithErrorHandling(Array, Array)
#4 C:\xampp\htdocs\mysite\craft\storage\runtime\compiled_templates\2\a\2a1532ab9a7fc5ec6775a274eca668a2af4e295ac7764368b23c762497284924.php(27): Twig_Template->display(Array, Array)
#5 C:\xampp\htdocs\mysite\craft\app\vendor\twig\twig\lib\Twig\Template.php(340): __TwigTemplate_2a1532ab9a7fc5ec6775a274eca668a2af4e295ac7764368b23c762497284924->doDisplay(Array, Array)
#6 C:\xampp\htdocs\mysite\craft\app\vendor\twig\twig\lib\Twig\Template.php(314): Twig_Template->displayWithErrorHandling(Array, Array)
#7 C:\xampp\htdocs\mysite\craft\app\vendor\twig\twig\lib\Twig\Template.php(325): Twig_Template->display(Array)
#8 C:\xampp\htdocs\mysite\craft\app\vendor\twig\twig\lib\Twig\Environment.php(293): Twig_Template->render(Array)
#9 C:\xampp\htdocs\mysite\craft\app\services\TemplatesService.php(223): Twig_Environment->render('404', Array)
#10 C:\xampp\htdocs\mysite\craft\app\controllers\BaseController.php(74): Craft\TemplatesService->render('404', Array)
#11 C:\xampp\htdocs\mysite\craft\app\controllers\TemplatesController.php(201): Craft\BaseController->renderTemplate('404', Array)
#12 C:\xampp\htdocs\mysite\craft\app\framework\web\actions\CInlineAction.php(49): Craft\TemplatesController->actionRenderError()
#13 C:\xampp\htdocs\mysite\craft\app\framework\web\CController.php(308): CInlineAction->runWithParams(Array)
#14 C:\xampp\htdocs\mysite\craft\app\framework\web\CController.php(286): CController->runAction(Object(CInlineAction))
#15 C:\xampp\htdocs\mysite\craft\app\framework\web\CController.php(265): CController->runActionWithFilters(Object(CInlineAction), Array)
#16 C:\xampp\htdocs\mysite\craft\app\framework\web\CWebApplication.php(282): CController->run('renderError')
#17 C:\xampp\htdocs\mysite\craft\app\framework\base\CErrorHandler.php(368): CWebApplication->runController('templates/rende...')
#18 C:\xampp\htdocs\mysite\craft\app\etc\errors\ErrorHandler.php(264): CErrorHandler->renderError()
#19 C:\xampp\htdocs\mysite\craft\app\framework\base\CErrorHandler.php(351): Craft\ErrorHandler->renderError()
#20 C:\xampp\htdocs\mysite\craft\app\framework\base\CErrorHandler.php(218): CErrorHandler->renderException()
#21 C:\xampp\htdocs\mysite\craft\app\etc\errors\ErrorHandler.php(128): CErrorHandler->handleException(Object(Craft\HttpException))
#22 C:\xampp\htdocs\mysite\craft\app\framework\base\CErrorHandler.php(131): Craft\ErrorHandler->handleException(Object(Craft\HttpException))
#23 C:\xampp\htdocs\mysite\craft\app\framework\base\CApplication.php(740): CErrorHandler->handle(Object(CExceptionEvent))
#24 [internal function]: CApplication->handleException(Object(Craft\HttpException))
#25 {main}

Running latest Craft Pro 2.4.2700 and latest contact form plugin. What could be causing the error?

The problem was that the redirect page was not setup. Once I threw up a test page there, the error no longer triggers.

What's odd is that the error page gave little clue (at least to me) as to what was happening.


How to remove hidden HTML from Radactor editor in CrafCMS 3 I am using Redactor 1.0.1 plugin in Craft 3, When copy/paste from any website into WYSISWG boxes, hidden HTML is included. How do I remove that?

If it's only for you, you can activate/use the source plugin to switch the view. That way no html is generated when you paste something

Maybe this option can help you too. There is also a paste callback you can use to change the inserted html


Having an issue with assets, while i am upload the image from the admin When i have upload the image using below settings that will give me an error  The error message was: "Error uploading the file: The file system path "/public_html/src/assets/images/" set for this source does not exist.

general.php file

<?php

 $siteUrl = array(
    'en_gb' => 'https://www.ancamotion.com/',
    'de' => 'https://www.ancamotion.de/',
    'zh_cn' => 'https://www.ancamotion.cn/',
    'zh_tw' => 'https://www.ancamotion.com.tw/',
);

return array(

    '*' => array(
        'devMode' => false,
        'extraAllowedFileExtensions' => 'exe, xml',
        'maxUploadFileSize' => 67108864,
        'omitScriptNameInUrls' => true,
        'timezone' => 'Australia/Melbourne',
        'setPasswordPath' => array(
            'en' => 'securezone/resetpasswordform.html',
                 'de' => 'securezone/resetpasswordform.html',
                  'cn' => 'securezone/resetpasswordform.html',
        ),
        'setPasswordSuccessPath' => array(
            'en' => 'password/thanks-reset.html',
                'de' => 'password/thanks-reset.html',
                'cn' => 'password/thanks-reset.html',
        ),
    ),

   'ancamotion.com' => array(
        'siteUrl' => $siteUrl,
        'environmentVariables' => array(
            'basePath' => '/public_html/',
            'baseUrl'  => 'https://www.ancamotion.com/',
        ),
    ),
   'ancamotion.de' => array(
        'siteUrl' => $siteUrl,
        'environmentVariables' => array(
            'basePath' => '/public_de/',
            'baseUrl'  => 'https://www.ancamotion.de/',
        ),
    ),
   'ancamotion.cn' => array(
        'siteUrl' => $siteUrl,
        'environmentVariables' => array(
            'basePath' => '/public_cn/',
            'baseUrl'  => 'https://www.ancamotion.cn/',
        ),
    ),
   'ancamotion.com.tw' => array(
        'siteUrl' => $siteUrl,
        'environmentVariables' => array(
            'basePath' => '/public_tw/',
            'baseUrl'  => 'https://www.ancamotion.com.tw/',
        ),
    ),

);

my settings from website admin Assets are

File System Path --> {basePath}src/assets/images/

URL --> {baseUrl}src/assets/images/

Can anyone help me with this?

Thank You in advanced.

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

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


Craft 3 Field Plugin not firing $view->registerJs in entry versions I am creating a Craft 3 plugin. It seems to work fine when editing regular entries but when I open a revision the JS I'm injecting using the below doesn't appear on the page.

$view->registerJs($js, View::POS_HEAD);

This does work on regular entries. Any ideas?

This is by design. Revisions are not meant to be editable.


Is it possible to create a page that shows only a specific post type with its own url? I have a website with a shop section with the following URL structure: homepage/shop/category/the-product.

I would like to add a page after the category to filter between post types within that category, and I want to be able to access it through the entry type slug in the URL.

I also need to change the template to match the Entry Type.

If this is possible, how do I do it?

Thanks ahead!

Certainly possible and simple too :)

First in the CP go to:

Category->Settings

You'll want to set your Category URL formats and Category Template to reflect your URL scheme and desired location of your template file.

Then create an _entry template in the directory you specified above for example /categories/_entry.twig

When you head to the URL above your template will load with an entry variable that reflects whichever category you are browsing to.

In the _entry template to get all the entries related to the current category:

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

(note this will default to 100 entries if you want more append .limit(101) etc. or .limit(null) to get them all.

and finally to load a layout based on the entry.type simply:

{% include ["_layouts/types/" ~ entry.type, "_layouts/types/default"] %}

where the default layout is for all entries that don't need any special layout.


How to split the user login error message between username and password? Hoping this is possible. I want to split the username and password error message to return it separately depending whether it is username or password that is incorrect and not just a the generic (Invalid username or password) message. How do I go about this? I don't require answers as to whether it is more secure or not just whether it is possible.

Cheers

There is not a built-in way. If you take a look at the UserSessionService, you'll see that messages are returned based on an error code. When a username and password combination fail, it triggers this single message to be returned.


Matrix field within a matrix field I am working on a product page where I want to give the option to the user to select between which sections they want to use eg banner section, description section, video section etc.

Now since the product pages might have some differences between them eg the description section on one product contains an extra image and an extra video I figured out that I can use a matrix field that contains a super table (plugin that allows matrix field within a matrix field) and another matrix field. By doing that I give the user the option to select the content they want to use within the sections.

Am I overcomplicating things here and is there a cleaner way of achieving the same logic?

I see what you're asking. Instead of using SuperTable, you could create a block type that has two rich text fields in it, Column 1 and Column 2. Alternately, you can create a separate channel for repeating content types (a CTA, for example) and make a block type that simply relates to that content (block type is 'entries').


Can we set properties to establish a valid asset per field? Craft will let us define what file-type is valid for a given asset field, but there are many times where I'd like to enforce other properties too - e.g., a minimum dimension for valid images uploaded to that field (i.e., dimensions must be larger than 800x600). Is there a way to do that?

Currently I can only see Craft enforcing file-types and file-size limits if they're too large (e.g., 4Mb is too big). I'd like some more options to avoid clients uploading unsuitable files.

Currently, no. The only file-based validation Assets fields have right now is the type. If you want to enforce a certain size, you can do that on the template end using image transforms. I would suggest adding some instruction text to your Assets field that provides a minimum suggested size, and note that smaller images will be scaled up and look gross.

That said, if you really want to enforce a minimum width/height, or other properties, you can do so by writing a plugin that provides its own field type, which extends AssetsFieldType and overrides its validate() method with your custom validation:

public function validate($value)
{
    // Let AssetsFieldType do its validation first
    $errors = parent::validate($value);

    if (!is_array($errors))
    {
        $errors = array();
    }

    if (is_array($value) && !empty($value))
    {
        foreach ($value as $fileId)
        {
            $file = craft()->assets->getFileById($fileId);

            if ($file)
            {
                if ($file->width < 600 || $file->height < 400)
                {
                    $errors[] = Craft::t(
                        '{filename} must be at least 600x400px.',
                        array('filename' => $file->filename)
                    );
                }
            }
        }
    }

    if ($errors)
    {
        return $errors;
    }
    else
    {
        return true;
    }
}


How to work getFieldValue for assets I have been implementing my own PHP plugin code.

In that, I need to get an asset field in user info. If I can get if the asset is set on the field or not, it is enough.

I can get the values of text and radio button fields with $user->getFieldValue function.
However, it does not work for asset fields.
How should I do for asset?

I have solved it by myself.

$asset = $user->getFieldValue(FIELDHANDLE)->one();
$user->setFieldValues([ 'FIELDHANDLE' => $asset->filename ]);


Linking to Search Results Ok what i'm trying to achieve is a set of links which have "search parameters" attached to them. Which would be a "category" and an "option.field".

Then when these links are clicked they display search results according to the parameters.

Not sure even where to start with something like this, could it be achieved with data attributes?

Is it even possible? Or have would I have to jerry-rig a form to do this via radio buttons?

Thanks for any help you can give.

You can use either get (via a direct link) or post (via javascript) which can be accessed in your search template using [craft.request.getParam(name)][1], and then either display the template (if a direct link) or return it (via ajax) to your original template.

For a full example using post and ajax see this question or this question. These examples use post and a form, but you could easily adapt this to place your variables in attributes and then retrieve and send those using javascript:

Link

In javascript:

$('.js-triggerhook').on('click', function(e) {
    e.preventDefault();
    var option = $(this).attr('data-option),
        category = $(this).attr('data-category'),
        url = $(this).attr('data-url'),
        data = "option=" + option + "&amp;category=" + category;
    // send post data
    $.post(url, data, function(result) {
        $('#search-results').html(result);
    }, 'html');
})

Or for a direct link using get:

Link

Or for a way to do either on the fly, just by including the class 'js-sendAsAjax':

Link

Then in your javascript:

$('.js-sendAsAjax').on('click', function(e) {
   e.preventDefault();
   var href = $(this).attr('href').split('?'),
       url = href[0],
       data = href[1];
    $.post(url, data, function(result) {
        $('#search-results').html(result);
    });
});


Get product custom fields in plugin I'm writing a plugin for Craft Commerece that performs action on commerce_orders.onOrderComplete

I need to check the value of product custom field (Matrix) in order to determine action parameters.

I tried to use $lineItem->purchasable->product->myCustomFieldHandle, but this returns me ElementCriteriaModel without any data entered for product in this field.

Any ideas on how to get actual data saved in custom field for product?

I am pretty sure it's the same for a product as it is for any other Craft element, like an entry.

To get simple fields:

$lineItem->purchasable->product->myCustomFieldHandle

To handle matrix fields, just loop through the matrix blocks:

$matrixBlocks = $lineItem->purchasable->product->matrixFieldHandle;
foreach ($matrixBlocks as $block){
    echo $block->id;
    echo $block->fieldHandle;
    if ($block->fieldHandle == "whatever"){
          etc
    }
}

Certainly that works with SuperTable fields on a product, pretty sure it's the same with matrix fields.


Imager plugin using it's transformImage method doesn't produce correctly resized images I'm using the lovely "Imager" plugin to produce a srcset of images, however it seems to only produce one size of image, which isn't really what i was expecting!

My code is:

{% set image = entry.image.first() %}
{% set transformedImages = craft.imager.transformImage(image, [
    { width: 1370, height: 600 },
    { width: 1000 },
    { width: 800 },
    { width: 600, jpegQuality: 65 },
    { width: 400, jpegQuality: 65 }
], { position: image.focalPoint, mode: 'crop', jpegQuality: 80 }) %}

Have i missed something here?

Turns out google chrome dev tools was lying to me when i hovered over the images in a srcset and told me their natural size was different to their real size. All working grand!


User data segregation for multi-sites in Craft 3? How will data be handled in Craft 3, when it comes to the 'multi-site' feature?

Will most structured data will be accessible across sites?

What about user data?

If I have 'Site A' and 'Site B' running off the one install and someone creates an account on Site A, will they also have an account on Site B?

Will we be able to restrict which CP users see data from which site?

Craft 3 multi-site is an extension of locales in Craft 2, so how the data is stored is virtually identical.

The difference is that locales in Craft 2 are tied to language/country codes, but sites in Craft 3 are more abstract concepts that are user defined.

  If I have 'Site A' and 'Site B' running off the one install and someone creates an account on Site A, will they also have an account on Site B?

User accounts are global.  They are not created on a per-site basis, but they can be restricted on a per-site basis through user/user group permissions.

  Will we be able to restrict which CP users see data from which site?

User/user group have site permissions for elements that support it just like they have "locale" permissions in Craft 2.


Error: Call to undefined function Craft\mb_convertOcase() after updating to 2.6.3017 Just updated Craft 2.6.3002 to 2.6.3017 and am getting the following error in the CP & front-end: Call to undefined function Craft\mb_convertOcase() /craft/app/helpers/StringHelper.php(558). On line 558 of this file, I have return mb_convert_case($string, MB_CASE_UPPER, static::UTF8);. Where is O coming from?

Screenshot of error & stack trace:

I performed a manual upgrade as documented at https://docs.craftcms.com/v2/updating.html#manually-updating and the error automagically disappeared. Therefore, it looks like there was a glitch in the One-click Updating in this particular case.


Image transforms not working on front-end I'm able to upload images correctly to the server. I can see the thumbnail and view the larger image inside the control panel on the Assets page. However, the front-end image transforms result in a 500 error.

The fix (for my project) was to enable the PHP output_buffering directive.

I added this to the account specific php.ini file for the hosting account.

output_buffering = On

This from the web hosts docs to explain why this fix worked:

*"Doing a header redirect requires outputting an HTTP header with the response. The problem is, if PHP has already begun outputting the body of the document, it cannot then output a header because the headers ended when the body started.

Output buffering prevents PHP from outputting any part of the body of the document until the output buffer is flushed (or PHP exits). This allows you to output headers at any time."*
http://kb.site5.com/php/how-to-repair-headers-already-sent-php-errors/

Another thing to try is add 'imageDriver' => 'gd, to your config file. This helped me with issues on a different server.
https://docs.craftcms.com/v2/config-settings.html#assets


Error when trying to update Craft or install any plugin When I try to update Craft, or install any plugin from the plugin store, I get the following error):
Composer was unable to install the updates.

Error: The url supplied for the path (plugins/redactor) repository does not exist

Composer output: Package "craftcms/vue-asset" listed for update is not installed. Ignoring.
Loading composer repositories with package information

If I try installing a plugin through the command line, I get a similar error:
 [RuntimeException]
 The 'url' supplied for the path (plugins/redactor) repository does not exist

Here are the contents of my composer.json file:
{
  "require": {
  "craftcms/cms": "3.5.2",
  "craftcms/contact-form": "2.2.7",
  "craftcms/feed-me": "4.2.3",
  "craftcms/redactor": "2.6.1",
  "craftcms/simple-text": "2.0.2",
  "vlucas/phpdotenv": "^3.4.0"
},
  "require-dev": {
  "yiisoft/yii2-shell": "^2.0.3"
},
  "autoload": {
    "psr-4": {
    "modules\\": "modules/"
   }
},
  "config": {
    "sort-packages": true,
    "optimize-autoloader": true,
    "platform": {
    "php": "7.0"
  }
},
"scripts": {
  "post-root-package-install": [
    "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
  ]
},
  "repositories": [
    {
      "type": "path",
      "url": "plugins/redactor"
    }
  ]
}

The redactor plugin is already installed and working properly, so I'm not sure why it's causing an issue. Does anyone know what's causing this issue and how to fix it? Any help is appreciated.

"repositories": [
    {
      "type": "path",
      "url": "plugins/redactor"
    }
  ]

With that in your composer.json file, you're telling Composer to look in a plugins/redactor folder from the root of your project and use that to satisfy the "craftcms/redactor" dependency (instead of pulling it from packagist.org).
https://getcomposer.org/doc/05-repositories.md#path
That error is saying that the plugins/redactor folder doesn't exist. The most common use-case for that is you've got a separate fork of the plugin you're using, but if that's not the case, you can remove that whole repositories section and it'll start using the official redactor release from packagist.


How to Auto-generate a Title based on a multiple entries titles? (using a Entries field type) I have two sections (both Channel type):

Releases
Movies

Releases have one Entries field type, the source is Movies
So, I want Auto-generate a Release title from Movies, like this: Titanic, Avatar, Toy Story
This works { movies.one().title } as a Title Format on the Releases Settings but display just the first movie: Titanic, the question is how can load all the entries titles? to get Titanic, Avatar, Toy Story as a title
I do a research and I get this: How can I set an entry title automatically, based on a related entry? but again that display only the first entry title.

Not sure if this can be done in the shorthand syntax, but you can do this using Twig for the dynamic title format. The key is to use map to turn an array of entries into an array of titles and then join them. Something like this should work:
{{ object.movies.all()|map(movie => movie.title)|join(', ')|default('No movies selected') }}

Also note the default filter, which is a nice fallback in case no entries are selected in your movie field.


Get the current section handle I can't help but think this is a silly/obvious question, but I'm trying to retrieve the current section handle so I can use it as a class.

Maybe I'm going about it wrong, but {{ handle }} does nothing.

Any ideas?

One thing that’s important to remember is that there’s no inherent relationship between your templates and sections. Any template can show any entry from any section. So there’s no such thing as the “current section”.

If your section has the “Entries in this section have their own URLs” setting checked, and you’re requesting one of that section’s entries’ URLs, then the section’s template will get loaded automatically and an entry variable will be available to it, which represents the entry whose URL you requested. But that doesn’t mean that you couldn’t have loaded the same template some other way (e.g. via an {% include %} tag from another template), or that you couldn’t have manually fetched that entry some other way (e.g. with craft.entries).

Anyway, if you have an EntryModel variable set (such as that entry variable that you’d automatically get when accessing an entry’s URL), you can access it’s section using entry.getSection(), and you can access that section’s handle via its handle property.

{% set section = entry.getSection() %}
{% set handle = section.handle %}

That could be simplified to:

{% set handle = entry.getSection().handle %}

or even:

{% set handle = entry.section.handle %}


Smart Map - setting an icon size I'm trying to figure out how to set the size of a marker on a map.

{% set options = {
  zoom: 6,
  markerOptions: {
    icon: 'https://www.mysite.com/images/map/marker.png',
    scaledSize: 'new google.maps.Size(20,20)'
  },
} %}

It pulls in my marker file correctly, but I don't know what the correct option is to make it scale.

It's a 40px square image, but I want it to show at 20px, so it doesn't look like garbage on a retina screen.

Help?

As of Smart Map v2.4.2, it is now possible to build more elaborate markers using a nested syntax for the markerOptions value. Try something like this...
{% set options = {
  zoom: 6,
  markerOptions: {
    icon: {
      url: 'https://www.mysite.com/images/map/marker.png',
      scaledSize: 'new google.maps.Size(20,20)'
    }
  }
} %}


Creating locale-specific entries from plugin Can you create an Entry with content only for a specific Locale? For instance, I have U.S. English (en_us) and German (de) locales setup for a section. I want to create entries, but only populate one locale. Is this possible?

$entry = new EntryModel();
$entry->getContent()->title = 'Testing Locale';
$entry->sectionId = '14';
$entry->typeId = '16';
$entry->locale = 'de';
$entry->localeEnabled = true;

$entry->setContentFromPost(array('plainTextField' => 'Test'));

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

The resulting code above creates the entry fine, but content is present for both locales. Is this expected behaviour?

This is expected behaviour though, it's better (in my opinion) than leaving everything empty.

As Andrew said in his comment, you could by default disable all locales on this section so your entry wouldn't be published in multiple locales.

You can do this by going to the settings of your section:


How do you add support to manage content in multiple languages in a plugin with a custom Element Type? We have a plugin with custom Element Types that allows a user to create a field layout using custom fields.

We understand how to setup a localized site and add translation files.  This question is specifically about how to add support for the user to be able to add content in multiple languages via the custom fields as they add new Entries to a Custom Element Type.

It would be nice to see a list of all the steps we need to consider.  Ideally, the answer could double as the page we would have read in the documentation instead of posting this question =)

Update:

For reference, these are the tables that appear to have a locale column in the default Craft database.

craft_categorygroups_i18n
craft_content
craft_elements_i18n
craft_entrydrafts
craft_entryversions
craft_locales
craft_matrixblocks (ownerLocale)
craft_matrixcontent_body (and any other Matrix field's content table)
craft_routes
craft_searchindex
craft_sections_i18n
craft_templatecaches

It all starts in Your ElementType where you need to return true on the isLocalized function (Line 62 in BaseElementType.php).

Setting this to true will tell Craft that data is stored per-locale, and it's local choices are based on your Element Model's getLocales function. You can get a basic example from Line 231 of BaseElementModel.php.

Craft's Entry Element actually allows you to choose which locale's are used on a per section basis. You can see an Entry gather its locales on Line 54 in EntryModel.php and Line 57 in SectionModel.php. A section stores its locale options in a related table via SectionLocaleRecord.

The rest should be handled by Craft so long as you set localeEnabled to true and locale to a locale ID in your model before passing it along to saveElement.

The rest of the work is templating, which you can reference how P&T do it in templates/entries/_edit.html.


Does Craft CMS support these features? I am evaluating different CMS. I need to know if Craft CMS supports these features:

Preview function for different devices, screen sizes and screen configurations(portrait/landscape)
Is it possible to publish only a subset of my website?
Is lazy loading supported? E.g. loading images on scrollto?
Does a frontend created with Craft CMS use much .js code? Can I minimize the amount of .js code (for performance reasons)?
Is mobile first approach supported?
Are URLs SEO-friendly?
Can I integrate Onsite-Banners from external Ad servers?
Does the cms contain Digital Asset Management?
Which media file types are supported?
Is there any REST API provided?
Does the CMS internal search engine support synonyms and how about the error tolerance?
Can I login to the CMS on mobile devices? Do I have good usability when doing so?
Do I upload high resolution images and later on these are generated and maybe compressed for target devices?

Preview function for different devices, screen sizes and screen
  configurations(portrait/landscape)

Yes it has live preview. However this isn't per device. You can open the entry with a secret url and then user your browser tools to check different devices

  Is it possible to publish only a subset of my website?

Yes, each entry can be turned on or off

  Is lazy loading supported? E.g. loading images on scrollto? Does a
  frontend created with Craft CMS use much .js code? Can I minimize the
  amount of .js code (for performance reasons)? Is mobile first approach
  supported? Are URLs SEO-friendly?

Yes, it's all how you code it. You can do whatever you want. Craft makes no assumptions or requirements

  Can I integrate Onsite-Banners from external Ad servers?

Yes code as you want

  Does the cms contain Digital Asset Management? Which media file types
  are supported?

Yes, full list here:

  Is there any REST API provided? Does the CMS internal search engine
  support synonyms and how about the error tolerance?

I'm not sure

  Can I login to the CMS on mobile devices? Do I have good usability
  when doing so?

Yes you do. I've done this myself and it was easy to move around

  Do I upload high resolution images and later on these are generated
  and maybe compressed for target devices?

Yes you can and then you can set transforms to crop/resize/compress as you want. Targetting per device that all depends on your html.


Animated GIFs not working in Craft with ImageMagick installed When I upload a GIF I either get the first frame or a garbled image (https://share.getcloudapp.com/L1u7BXrA).

Looking around at similar questions, Craft needs ImageMagick installed to properly transform GIFs after upload.

I can confirm ImageMagick is installed and being used as the image driver (https://share.getcloudapp.com/BluZKGYw).

Server has php-imagick and imagemagick installed.

I have 'imageDriver' => 'imagick' set in general.php

Using Amazon S3 to store images.

Anything else I should be trying? Thanks.

I ended up applying this configuration to config > general.php so GIFs aren't transformed.

'transformGifs' => false

https://docs.craftcms.com/v3/config/config-settings.html#transformgifs


Grouping/sorting for easier view of Craft::log messages Is there any way to group or sort my own "Craft::log()" calls for my Plugins?

It's a bit tedius to go through the Application->Logs each page load to try and find my own log messsages.

Maybe someone has a better approach to this?

Your plugin can keep its own log using MyPlugin::log('Message', LogLevel::Error);. A log method gets created automatically by extending BasePlugin. The plugin log will be located in craft/storage/runtime/logs/ along with the default logs.

As a side note: The log files can be watched from the command line using tail -F /full/path/to/log/file rather than having to constantly reload the log in a text editor. Although apparently some text editors also support live updates as well.


Craft 3 - Searching by date field - Calling unknown method: craft\behaviors\ElementQueryBehavior On a website upgraded to Craft 3 - having issues pulling events by date.

Error Is:

Calling unknown method: craft\behaviors\ElementQueryBehavior::eventDate()

The Error occurs on the last line of my code below.
I'm done alot of searching but unable to find the correct method I should be using now.

    {% if (category is defined) and (category is not empty) %}
    {% set params = { section: 'events', orderBy: 'eventDate', relatedTo: category } %}
    {% else %}
    {% set params = { section: 'events', orderBy: 'eventDate' } %}
    {% endif %}
    {% set j = 0 %}
    {# Retrieve all of the events for the month, and group them by day #}
    {% set groupedEvents = craft.entries(params).eventDate('and', '>= ' ~ startdate, '<= ' ~ enddate) | group('eventDate|date("Y-m-d")') %}

UPDATE
Ok think found the issue - needed square brackets.

{% set groupedEvents = craft.entries(params).eventDate(['and', '>= ' ~ startdate, '<= ' ~ enddate]) | group('eventDate|date("Y-m-d")') %}

Was missing the square brackets

{% set groupedEvents = craft.entries(params).eventDate(['and', '>= ' ~ startdate, '<= ' ~ enddate]) | group('eventDate|date("Y-m-d")') %}


Removing index.php from URL even after .htaccess updates? I am a little afraid to post this, but I'm running into an issue and haven't found a solution yet. I've been able to successfully remove the "index.php" from all my URLs, however I'm still finding that if I manually add "index.php" to any URL, I can still view the page and am not redirected to a URL without "index.php". For example:

http://domain.com/events/

Works just fine, but if I visit http://domain.com/index.php/events/ I can still view the page. Any idea on how to force it to redirect me to just http://domain.com/events/?

Here's my .htaccess file for reference:

# ----------------------------------------------------------------------
# Remove index.php from URLs
# ----------------------------------------------------------------------
<IfModule mod_rewrite.c>
  RewriteEngine On

  # Force trailing slash
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^(.*[^/])$ /$1/ [L,R=301]

  # Force www
  RewriteCond %{HTTP_HOST} =domain.com [NC]
  RewriteRule ^(.*)$ http://www.domain.com/$1 [R=301,L]

  # Send would-be 404 requests to Craft
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]
  RewriteRule (.+) index.php?p=$1 [QSA,L]
</IfModule>

Is this even possible with Craft? Thanks in advance!

There's nothing unique or special for doing this with Craft CMS - you should be able to use this method for just about any web app running in a LAMP stack. See this post on removing index.php from the URL with Apache/mod_rewrite/.htaccess.

TLDR: add this bit to the end of your .htaccess file before the closing  tag.

If Craft's index.php is at the domain root, such as example.com/index.php, this should do it:

# Redirect to same url without index.php
RewriteCond %{THE_REQUEST} ^GET./index\.php(/.*)?$ [NC]
RewriteCond %{REQUEST_URI} !^/index\.php/admin\b [NC]
RewriteRule ^index\.php(/(.*))?$ /$2 [R=302,NE,L]

If it lives in a subfolder, do this instead:

# Redirect to same url without index.php
RewriteCond %{THE_REQUEST} ^GET./subfolder/index\.php(/.*)?$ [NC]
RewriteCond %{REQUEST_URI} !^/subfolder/index\.php/admin\b [NC]
RewriteRule ^subfolder/index\.php(/(.*))?$ /$2 [R=302,NE,L]

(In both examples, replace admin on the 2nd line with whatever your site’s CP trigger is set to, if you’ve changed it.)


Plugin Development: find source group used by field I'm writing a plugin that works with Fields in various ways, one thing I need to do is get the category source groups available to a particular category field. I have the field's handle and id and can get it's FieldModel instance from that. But that fieldModel doesn't appear to have any information about what sources it is using.

So for example, I have a Category field named 'peopleClassification', and it has the category group 'peopleWhoWorkHere' as it's source set in the field settings page.

When I inspect the FieldModel object for the peopleClassification field, I'd expect to see the id or handle for the peopleWhoWorkHere group somewhere inside the object. I'm dumping the variables and checking the API docs, and I don't see a way to do that.

I thought that the CategoriesService might have a method for returning sources for a given field ID, but I couldn't find anything.

Does anyone have suggestions on where in the API I can connect these two? It's obviously possible, else Craft wouldn't work at all.

To clarify, I'm not working with specific entry objects here, I'm trying to match field handles to group handles.

@carlcs answer got me to the info I needed (thanks). Here's how I completed it.

$field->getFieldType()->getSettings() returns an array with various pieces of meta data including a source field with a value like group:42. That number is the category group ID I needed to create an instance of category group object.

list($type, $gid) = split(':', $field->getFieldType()->getSettings()['source']);

Then use $gid to load an instance of the Group from categories service

$categoryGroup = craft()->categories->getGroupById($gid);

$categoryGroup contained the info I needed, including the group's handle, which I used to create a list of categories.

From the FieldModel you need to get the FieldTypeModel and then its settings. Something like this:

$settings = $field–>getFieldType()->getSettings();


Put simple content into Craft and grab it in JavaScript I want to put a few simple text fields into Craft CP and then be able to retrieve them with JavaScript.

What is the best way to structure this in Craft? I'd like to be able to create/edit an "entry" and then do something like this:

<script type="text/javascript">
    var homepageContent = {{ craft.entries.homepageContent }};
    console.log('details: ', homepageContent);
</script>

The homepage content entry in Craft needs to have ~2-3 fields attached to it.

I created the 3 fields that I think I will need to be editable on the homepage. Now I'm unsure how to get these tied to be able to enter an "entry" into something like a Homepage Content group?

One way to go about this is to use the JSON Expand plugin from Familiar Studio:

https://github.com/familiar-studio/craft-json-expand

It's pretty easy to use:

{% set hpContent = craft.entries.section('homepageContent').find() %}

Then you can just grab the data you need from the json object like:

<script type="text/javascript">
    var homepageContent = hpContent|json_expand|raw }};
    console.log({{ hpContent|json_expand|raw }});
</script>

One caveat I've found though is that content in Rich Text editors doesn't output.  If you're just using simple text fields, then you should be fine.  If you do need something Rich Text-like, you could use Craft's |markdown filter on data from a simple text field.


Redactor - Superscript button Is there a possibility to ad a 'superscript' button to redactor?

Edit: I found an explanation here: How can I use <small> <sub> <sub> within a redactor/rich-text field?

But I can't get it to work.

I copy this snippet form: http://imperavi.com/redactor/examples/buttons-sup-and-sub/ to  craft/app/resources/lib/redactor/plugins/subsup.js

if (!RedactorPlugins) var RedactorPlugins = {};

RedactorPlugins.scriptbuttons = function()
{
    return {
        init: function()
        {
            var sup = this.button.add('superscript', 'Superscript');
            var sub = this.button.add('subscript', 'Subscript');

            // make your added buttons as Font Awesome's icon
            this.button.setAwesome('superscript', 'fa-superscript');
            this.button.setAwesome('subscript', 'fa-subscript');

            this.button.addCallback(sup, this.scriptbuttons.formatSup);
            this.button.addCallback(sub, this.scriptbuttons.formatSub);
        },
        formatSup: function()
        {
            this.inline.format('sup');
        },
        formatSub: function()
        {
            this.inline.format('sub');
        }
    };
};

Then I call the plugin in a custom.json file like this:

{
    buttons: ['link','bold', 'italic','unorderedlist','orderedlist','image','html'],
    plugins: ['fullscreen', 'subsup'],
    toolbarFixedBox: true
}

But that results in nothing. What do I miss?

I had a similar problem so created a plugin to add some of these extras to Redactor.

Redactor Extras for Craft

https://github.com/elliotlewis/Redactor-Extras
Available plugin are:

Superscript and Subscript
Word count
Alignment
Custom plugin


What are the yaml files in config/project? Should I commit them? See the title. I'm currently committing the YAML files to our git repo so they deploy to our production server. Is that appropriate? Should I ignore the config/project folder?

Those are your Project Config files.
You'll definitely want to 1) read up on it so you're using it properly and 2) commit those files to your repo. :)


Matrix field breaks backend Entries > 'page-name' page. "Endless" recursion error? In backend Entries > 'page-name' I could only see the left nav side bar, and the top "header" bar (breadcrumbs + page name + save button), when ever there was a Matrix field on the page.
I noticed that the last line rendered (marked in blue) had a height of 0, so I started poking around in the CSS.

After disabling a display: none; (marked in green below) for the div immediately below the last div shown, I could see part of the page plus the error message shown in the screenshot below.

To me, it looks like some "endless" recursion error.

Does anyone have any idea on what might be going on here?

Thanks in advance for any light you might shed on this!

/Monkey

Edit: added the top screenshot to show what the page looked like before I changed the CSS.

Brad was right, it was xDebug that was the culprit. So here's what I did:

In the Linux terminal I ran:

sudo gedit /etc/php5/mods-available/xdebug.ini

In the xdebug.ini file I added the line below and saved.

xdebug.max_nesting_level=256

In the Linux terminal I ran:

sudo service apache2 restart

Done.

Note: if the this does not fix it, try changing the command in step 1 to:

sudo gedit /etc/php5/conf.d/xdebug.ini

or just edit your php.ini file where ever it may be located.


Passing Matrix block to a macro I want to fetch a specific block from a Matrix global then pass it through a macro which returns a response based on the block type. However, if I try to use slice the type doesn't appear to be available to the macro. Has anyone experienced something similar?

eg if I set {% set timelineText = timeline.timeline %} (where first timeinline is my global and second timeline is my Matrix field) then fetch a specific block from the Matrix: {% set period = timelineText|slice(0,1) %} should return the first instance/block from the field. I can then pass this to my macro: {{ _self.doPeriod(period) }}

My macro is

{% macro doPeriod(content) %}
{% switch content.type %}
{% case 'quote' %}
    ...
{% case 'period' %}
    ...
{% endswitch %}
{% endmacro %}```

But this returns the following error: Key "type" for array with keys "0" does not exist

Any thoughts?

First, you need to import your macro, and not just call {{ _self.doPeriod() }}. From the documentation:

  When you define a macro in the template where you are going to use it, you might be tempted to call the macro directly via _self.input() instead of importing it; even if seems to work, this is just a side-effect of the current implementation and it won't work anymore in Twig 2.x.

I always do: {% import _self as self %}

slice returns a sequence - in your case an array with one element, and the key is 0. Your macro is expecting a matrix block, not an array, which is why you get that error.

If you only want the first block, then {% set period = timelineText.first %} and period will be a matrix block. {{ self.doPeriod(period) }} will work.

If you want to call doPeriod on all of the matrix blocks, then:

{% for period in timelineText %}
  ... {{ self.doPeriod(period) }} ...
{% endfor %}


How to create sub-nav when using a structured navigation heirarchy? I have my navigation in a Structure like here and I want to build a sub-navigation on my Information page containing Specials, Reviews, and About, but I can't figure out how.

{% set active_item = craft.entries.section('navigation').nextSiblingOf(48).first() %}

doesn't give me what I need (and I really don't like handling with id's).

There is an nice recipe on the craftcookbook.net site from sprocketeer that explains exactly this.

{% set topEntry = craft.entries.depth(1).slug('information').first() %}

    {% nav subEntry in topEntry.getDescendants() %}

{{ subEntry.title }}
            {% ifchildren %}
{% children %}
{% endifchildren %}

    {% endnav %}


How do I prevent Twig from encoding HTML? I've created a field type that stores its value as a model. That model’s __toString() method returns the result of a craft()->templates->render() call:

public function render()
{
    $render = craft()->templates->render('myplugin/templates/mymodeltemplate');
    return $render;
}

public function __toString()
{
    return $this->render();
}

When I output the model from a template, like so:

{{ entry.myField }}

Twig encodes the resulting HTML as a string with HTML entities.  Running the string through html_entity_decode() before returning it in __toString() doesn't help.  I'm assuming this string formatting is happening somewhere at the Twig level.

Being new to Craft, I'd love to understand a little more of what's going on here.  How does the string representation of an element model get passed to and handled by Twig?

Whenever you output anything with Twig’s {{ output tags }}, the contents will get encoded by default. You have to pass the content through the |raw filter in order for it to be output verbatim.

{{ entry.myFieldHandle|raw }}


Trying to build params to be able find entries related to an entry and that are related to a specific category I want to generate a list of  events that are related to a specific festival and that are related to a specific category. This goal sits alongside some others that are inspiring me to attempt this in a single template and to do so via building params that are then passed to Craft entries tag. Using Craft 3.

First the base params - these return a fine result.

{# Set base criteria for event query #}
{% set params = {
    section : 'events',
    orderBy : 'eventStartDateTime asc',
    relatedTo: [
        { element: entry.id }
    ],
    limit: null
} %}

Next here are the params to try and get the events associated with a specific festival entry and that are related to a specific category.

{# Segment 4 is about categories #}
{% if craft.app.request.getSegment(4) %}
    {# segment 4 is the category slug #}
    {% set cat = craft.app.request.getSegment(4) %}
    {% set relationParam = {
        relatedTo: ['and',
            { targetElement: cat },
            { element: entry.id }
        ]
    }%}

    {% set params = params|merge(relationParam) %}
{% endif %}

What I am seeing in this second scenario is I am not getting results filtered by the category. Feel like I am close but missing something, likely fundamental.

I think the answer you’re looking for is here.

TL;DR:

  relatedTo method accepts a CategoryModel, not the title(slug) of a category.


How do you use 'if' to stop an empty Matrix block from displaying? On a complex page, where there are different sections that need to be present in the template, but may not all have content added via Craft entries I need to stop the empty areas from being output (e.g. a set of div's that will create an ugly empty space in the page).

I can successfully do this for empty simple entries - like this:

{% if entry.modelTitleType %}

{{ entry.modelTitleType }}

{{ entry.modelIntroType }}

{% endif %}

So the div enclosed by the 'if' statement is only output if there's an entry added for 'modelTitleType'.  But I cannot get this to work for a Matrix entry!

How do I wrap an 'if' statement around a Matrix block like this, so it is only output if there's data added?

    {% for block in entry.modelDataType1 %}
        {% if block.type == "type" %}

{{ block.typeName }}

        {% endif %}
    {% endfor %}
    {% for block in entry.modelDataType2 %}
        {% if block.type == "type" %}

{{ block.typeName }}

        {% endif %}
    {% endfor %}

I've tried:

{% if entry.modelDataType1 %}

But this doesn't work...

Any help would be very much appreciated!

Many thanks.

If a Matrix field / block is empty it won't output at all but you can try checking the length in an if statement like:

{% if entry.modelDataType1 | length %}
    // matrix content here
{% endif %}


Can plugin have two links in admin navigation? Is it possible to add another link to admin navigation? For example I have plugin clients which has it's own Button in the admin menu, in the same plugin i have newsletter so I would like to have that Newsletter in that menu as well.

The top links in the CP header are often called nav tabs.

Beyond the "default" nav tab for your plugin (pointing to the plugin's CP section), it's possible to declare additional tabs via the modifyCpNav hook (added in Craft 2.3.2640):

public function modifyCpNav(&$nav)
{
    $nav['mypluginhandle-newsletter'] = array('label' => 'Newsletter', 'url' => 'mypluginhandle/newsletter');
}

Of course, this will only create a tab with a link pointing to whatever you put in the url property. If you haven't already created the page for the newsletter, you'll need to do so by creating a route to a template or controller:

public function registerCpRoutes()
{
    return array(
        'mypluginhandle/newsletter' => 'myPluginHandle/newsletter',
    );
}

Read more about the registerCpRoutes hook in the official docs.

Both the modifyCpNav() and registerCpRoutes() methods should go in your plugin's main class.


How to get a list of unique related entries from within a related entries loop Bear with me as I am not sure the best way to explain this.
But to try and summarise... how can I loop through related entries (locations) inside a a related entries loop (exams -> related to the current entry/page) but ONLY output the locations and ONLY output the unique locations (ie. I don't want it t show location1, location1, location2, location1. I just want it to show location1 and location2 (once - unique).
This is where I am at, but not working yet.

Here is a screenshot to try and illstrate:

I only want Bushy to appear once, not 4 times.

So my page is setup like this;
First I set the Mock Exams to find all the Mock Exams related to the current entry (page).
Like so:

{% set mockExams = craft.entries
  .section('mockExams')
  .with('location')
  .relatedTo({
  targetElement: entry,
  field: 'mockExamCategory'
})
  .all() %}

I am then using this code to list all the mock exams in 2 separate areas on the page.
This works fine and as expected.

However, I need to then get all the unique location entries that are related to the mock exams.
I took me ages to fathom this out on how to to do this. I only managed with some great support through the Discord channel.

Anyway, the way this was finally achieved was as follows:

  {% set uniqueLocations = [] %}
  {% set uniqueLocationsIds = [] %}
  {% for entry in mockExams %}
    {% set locations = craft.entries.section('locations').relatedTo(entry.id).all() %}

    {% for location in locations %}
      {% if location.id not in uniqueLocationsIds %}
        {% set uniqueLocationsIds = uniqueLocationsIds|merge([location.id]) %}
        {% set uniqueLocations = uniqueLocations|merge([location]) %}
      {% endif %}
    {% endfor %}
  {% endfor %}

{% for location in uniqueLocations %}
  {{ location.title }}<br />
  {{ location.address }}
{% endfor %}

I have written this up for reference if anyone else comes across this.

But also for anyone more experienced in Craft - is this the most efficient way or is there a more efficient/streamlined approach?

How about this?

{% set uniqueLocations = craft.entries.section('locations').relatedTo(mockExams).all() %}

{% for location in uniqueLocations %}
  {{ location.title }}<br />
  {{ location.address }}
{% endfor %}


Turning static website to Craft? I have been working as a freelance web designer now for over 2 years, building websites using plain html, css and jquery.

Most of my clients require simple showcase websites that look well, load fast, well optimised for Google, are easily navigated and show a portfolio of projects. Most also require a blog.

My question is, what is the level of knowledge required in order to take a static html, css website and add Craft CMS to it. The only areas of the website that I would want my clients to have access to would be for them to complete simple tasks such as adding on another project page with an image slider and project details or to add a blog post with a few pictures.

I have little to no knowledge of PHP and don't have the time to learn anything too advanced.

All replies would be very much appreciated. Thanks.

First of all to use Craft you need a server and a database - e.x. Apache and MySQL so it's not just PHP. Assuming you will get your hands on pre-installed craft instance basic configuration is pretty straightforward. Also you need to understand craft concepts of sections, fields, relations. Then you can setup blog or portfolio. Next you need to create views (TWIG language).

There are different plugins to help you with your content. Like this one (blog). Installing plugin is as simple as copy folder and then hit install button in the CP.

Read this answer where I included some resources to get you going with Craft.


Craft Commerce: Steps Bar in Checkout I'm trying to use the Craft Commerce example template code to show a progress bar throughout the checkout process. It currently doesn't correctly display the % value of progress through the checkout. It is just blank.

The url for my checkout is page is: website.com/shop/test/checkout

To see if it was a styling issue I did a test and set a manual override on the span's width with 50% - the styling then comes into play.

Has anyone else encountered this issue? I don't want to assume anything but the equation to make it kick in doesn't seem to be working.

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

      {% if currentStep is not defined %}
        {% set class = "done" %}
      {% endif %}

{{ step.label }}

    {% endfor %}

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

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

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

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

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

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

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


Images are broken when I upload them I have just started using craft today and I have hit a bit of a bump with Images.
I created and asset for Work and set it up to point to assets/images/work/ I was able to upload the image but when I tried to preview the 'Work' page the image was going to /work/assets/images/work relative URL I am guessing.
I tried then to define and environment variable like this:

'environmentVariables' => array(
  'baseAssetUrl'  => 'http://192.168.99.100:8080/',
  'baseAssetPath' => './',
),

Updated my asset group to the following:
{baseAssetPath}assets/images/work/
{baseAssetUrl}assets/images/work/

But when I try preview the page the image is broken and the variable has not been interpreted

<img src="{baseAssetUrl}assets/images/work/_360xAUTO_crop_center-center/test.jpg" alt="Test">

And I can't upload the image I get the following error message:

Upload failed for test.jpg. The error message was: “Error uploading
the file: The file system path “{baseAssetPath}assets/images/work/”
set for this source does not exist.”

Any ideas what am I missing?

It was a simple misunderstanding of how the general.php should be structured.

I had environmentVariables outside of the '*' => array(

So it's now:

return array(
  '*' => array(
    'omitScriptNameInUrls' => true,
    'sendPoweredByHeader' => false,
    'devMode' => getenv("CRAFT_DEVMODE") == "true",
    'environmentVariables' => array(
      'baseAssetUrl'  => 'http://192.168.99.100:8080/',
      'basePathPublic' => realpath(dirname(__FILE__)).'/../../html/',
    ),
  ),
);
?>


How do I delete a tag? Where in the Craft Control Panel can I globally delete a tag?

Not from a specific entry, but completely out of the system.

Currently it’s not possible to delete tags (or otherwise manage them).


How do I pass variables to loops within includes? How do I pass variables to a loop within an include?

This is my partial:

{% for photo in photos %}
    <img src="{{ photo.projectPhotos_photo_image.first().getUrl('projectThumbnail') }}"
{% endfor %}

I'm calling it from a template with this:

{% set projectEntries = craft.entries({
    section: 'project'
}) %}
{% set vars = {
    photos: projectEntries
    }
%}
{% include "_partials/photo-tile.html" with vars %}

All well and good

but

What if I want to abstract this from my partial:

src="{{ photo.projectPhotos_photo_image.first().getUrl('projectThumbnail') }}"

In other words, I'd like to pass the src, {{ photo.projectPhotos_photo_image.first().getUrl('projectThumbnail') }} , into the partial but I don't know how!

If I try to do it from the template like this (through photoSrc), it fails, saying the 'photo' is undefined:

{% set vars = {
    section: "category",
    category: category,
    pageOneTitle:  categoryTitle,
    photos: projectEntries,
    photoSrc: photo.projectPhotos_photo_image.first().getUrl('projectThumbnail')
    }
%}

Any tips?

You can't reference a variable (photo) created inside the partial loop outside the partial (and loop) – it doesn't exist yet – so what you're trying to achieve isn't possible.

What you could do, is to abstract the important bits, namely the field and transform handles:

{% set vars = {
    photos: projectEntries,
    photoField: 'projectPhotos_photo_image',
    photoTransform: 'projectThumbnail'
} %}
{% include "_partials/photo-tile.html" with vars %}

And inside your partial:

{% for photo in photos %}

{% endfor %}

If that doesn't cut it, you'll probably want to use a macro:

{# Your macro file, e.g. /templates/_macros/photoTile.html #}
{% macro src(photo) %}
    {{ photo.projectPhotos_photo_image.first().getUrl('projectThumbnail') }}
{% endmacro %}

{# Inside your partial #}
{% from '_macros/photoTile' import src %}
{% for photo in photos %}

{% endfor %}

(If you're wondering about the {{- -}} syntax in the above example, the dashes are just to remove whitespace from the rendered src string – you also wrap the code inside the macro in {% spaceless %}{% endspaceless %} tags.)


"Forbidden" response when saving entry with HTML code in matrix field I have a matrix field which the user can paste YouTube etc. embed code into, which is working fine with YouTube, but SoundCloud embed code causes it to return a page which simply says "Forbidden".

I've tried every combination of plain text, rich text, purify & clean HTML etc.

Trial and error has shown the problematic part of the embed to be this:

width="100%" height="166"

However I can't seem to pin down which part of this is actually the problem.

I tried a few variations to try to see what's going on...

The following fragments are saved fine:

%" h
w="100%" h
w="100%" h=
w="100%" h="
"100%" h
100% 166
width="100%"
width="100" height="166"
width=100% height=166

The following are not saved and return Forbidden:

width="100%" height="166"
w="100%" h="166"
w="100%" h="1
100%" h="1
"100%" "166"
width="1%" height="1"

I've tried pasting the same SoundCloud embed into various other fields across the site, it's fine everywhere else.

Curious!

There are a couple possible explanations for this.

You have Suhosin installed, a PHP extension that enhances security by placing some pretty drastic restrictions on what data can be sent to the server. To find out, visit /admin/utils/phpinfo and search the page for "suhosin". If you see any references to it, you have it installed. Ask your host to uninstall it, or possibly just configure it to be allow this specific use case (and expect to have similar requests in the future).
Your server (Apache or nginx) may be configured to deny traffic to the request URI. Check your server logs for recent forbidden/403 activity.


How do I display data from an entry field related to each user in a user listing page? I am displaying a list of users with entries in the Design section using a Route. I am using this code for that and it seems to be working to display the correct users:

{# Grab all the Design Entries #}
{% set designs = craft.entries.section('designs').find() %}

{# Group by the authorId #}
{% set entriesByAuthor = designs|group('authorId') %}

{# Grab all of the users with the userIds in entriesByAuthor #}
{% set designers = craft.users.id(entriesByAuthor|keys).group('members') %}

Although the issues I am having is trying to display data from fields from the entries by these users. For example, entries in the Design section also have images associated with them. I am trying to display the first image from the 'screenshots' field from the Designs section:

{% for assets in designers %}
    {% for image in assets.screenshots %}

        {% if image %}

        {% endif %}

    {% endfor %}
{% endfor %}

This does not give an error, but does not display anything for the image. I also tried adding .first() to this to get the first image from each entry, but that resulted in an error.

Any help will be appreciated! I have searched thoroughly for information about displaying entry fields from a user list (instead of just user fields) and I have not been able to find this information. (I also tried several other methods, such as relatedTo.)

Thanks!

You already have the right array of Design Entries grouped by your Designer's user IDs with this line:

{% set entriesByAuthor = designs|group('authorId') %}

Now all you have to do is to loop through this entriesByAuthor array. Use this syntax to iterate over Keys and Values:

{% for key, value in entriesByAuthor %}
    {{ key }}: {{ value }}
{% endfor %}

Within the loop key is the authorId you grouped by and value is an array of EntryModels that share the same value for the authorId property. To list the Design entries you have to nest another for-loop and iterate over that array of EntryModels.

To retrieve other Designer data besides the ID you first need to grab the UserModel. Create a new ElementCriteriaModel with the authorId as a parameter and use the first() function to get the model.

{# Grab all the Design Entries #}
{% set allDesigns = craft.entries.section('designs').limit(null).find() %}

{# Group by the authorId #}
{% set allDesignsByAuthor = allDesigns|group('authorId') %}

{# Loop through all Design Entries grouped by the authorId #}
{% for authorId, designsByAuthor in allDesignsByAuthor %}

    {# Grab the Designer's UserModel #}
    {% set designer = craft.users.id(authorId).first() %}

{{ designer.name }}

    {# List the Designer's Design Entries #}
    {% for design in designsByAuthor %}

{{ design.title }}

        {# List the Screenshots #}
        {% for image in design.screenshots %}

        {% endfor %}

    {% endfor %}

{% endfor %}

.

Edit:

Only now I got it, why you did this line to grab the UserModels with an ID of allDesignsByAuthorId|keys. This is in fact a good idea if you want list the users in another sort order than the user ID. Because I don't think you can do that with the approach I posted above.

Here's how you proceed after you fetched the Designers with a sort order of your desire. Loop through the array of Designers and create a new ElementCriteriaModel for each designer to grab the Designs using the Designer's user ID as the value for the authorId property.

{# Grab all the Design Entries #}
{% set allDesigns = craft.entries.section('designs').limit(null).find() %}

{# Group by the authorId #}
{% set allDesignsByAuthorId = allDesigns|group('authorId') %}

{# Grab all of the users with the userIds in allDesignsByAuthorId #}
{% set designers = craft.users.id(allDesignsByAuthorId|keys).order('lastName') %}

{# Loop through the array of Designers #}
{% for designer in designers %}

{{ designer.name }}

    {# Grab all of the Design Entries created by this Designer #}
    {% set designs = craft.entries.section('designs').authorId(designer.id).find() %}

    {# List the entries #}
    {% for design in designs %}

{{ design.title }}

        {# List the Screenshots #}
        {% for image in design.screenshots %}

        {% endfor %}

    {% endfor %}

{% endfor %}

.

2nd Edit:

You only need to show one image for each Designer? Do it like so:

{# Grab all the Design Entries #}
{% set allDesigns = craft.entries.section('designs').limit(null).find() %}

{# Group by the authorId #}
{% set allDesignsByAuthorId = allDesigns|group('authorId') %}

{# Grab all of the users with the userIds in allDesignsByAuthorId #}
{% set designers = craft.users.id(allDesignsByAuthorId|keys).order('lastName') %}

{# Loop through the array of Designers #}
{% for designer in designers %}

    {# Get the total number of Design Entries created by this Designer #}
    {% set totalDesigns = craft.entries.section('designs').authorId(designer.id).total() %}

    {# Grab the latest Design Entry created by this Designer #}
    {% set design = craft.entries.section('designs').authorId(designer.id).first() %}

    {# Grab the first screenshot image of that entry #}
    {% set image = design.screenshots.first() %}

    {# Output #}

{{ designer.name }}

{{ totalDesigns }}

{% endfor %}


How to return a hierarchical list of a site's page structure using the ElementAPI I'm experimenting with using Craft in a headless way and am successfully using the Element API to return all the data required to show individual pages.

However, to be able to show sub navigation and where a particular page fits into my site's 'structure' hierachy, I'd like to pull out the entire page hierarchy and then use that info in my application.

Does anyone know how to go about that using the Element API?

Thanks in advance for any clues.

Cheers,

Jim

It's not the most economical way to do it but if you don't have hundreds and hundreds of entries, this should do it for you:

<?php
use craft\elements\Entry;

function getChildren($entries){
    foreach ($entries as $entry) {
        $items[] = [
            'title' => $entry->title,
            'slug' => $entry->slug,
            'level' => $entry->level,
            'children' => $entry->hasDescendants ? getChildren($entry->children) : false
        ];
    }
    return $items;
}

return [
    'endpoints' => [
        'structure.json' => function() {
            return [
                'elementType' => Entry::class,
                'criteria' => [
                    'section' => 'structure',
                    'orderBy' => 'lft asc',
                    'level' => 1,
                    'limit' => null
                ],
                'transformer' => function(Entry $entry) {
                    return [
                        'title' => $entry->title,
                        'slug' => $entry->slug,
                        'level' => $entry->level,
                        'children' => $entry->hasDescendants ? getChildren($entry->children) : false
                    ];
                },
            ];
        }
    ]
];


Checking if Matrix fields are empty or not? In a Matrix field i want to check if block.logolink (simple text) OR block.logolinkDropdown (dropdown with empty field) are empty or not:

{% if block.logolink or block.logolinkDropdown %}

If i check them with {{ block.fieldHandle }} they're empty. But still it passes the condition.

Where's my mistake in this statement?

{% for block in entry.logomatrix %}
{% switch block.type %}

{% case "logo" %}
{% if block.logobild %}
    {% for logo in block.logobild %}
    {% if block.logolink or block.logolinkDropdown %}
        {% if block.internerLink %}

        {% else %}

        {% endif %}
    {% else %}

    {% endif %}

    {% endfor %}
{% endif %}

{% case "textbutton" %}
...

{% endswitch %}
{% endfor %}

You can get a dropdown field's selected value by using entry.fieldhandle.value. So if entry.fieldhandle.value|length should do the trick. I think you can even omit the length filter in this case, as if you do it with the plain text field. Both an empty string and the length of an empty string resolve to false.


Getting Service Unavailable when setting up domain name Currently I'm trying to push my deployed website to the actual domain name it needs to be under using DigitalOcean. The website works perfectly when accessing it directly from the droplets ip address.

I've set the name servers on GoDaddy to be Digital Ocean's, but when trying to access the Craft site at the domain name URL it throws a craft error saying

  "Service Unavailable,Our site is temporarily unavailable. Please try
  again later."

Is there something I need to do in Craft to make sure it knows about the domain name change?

Have a look at this document: https://craftcms.com/docs/multi-environment-configs

You can configure it differently for local, staging, production, etc, by the name of the domain name


Order entries by related "Year" category and paginate? I have a section called Library, and a category group called libraryYears. The categories in that group are just years (2021, 2020, 2019...)
Each entry in the Library is related to a year in the libraryYears via a related Entries field called theYear.
I want to list all Library entries in order of the related year, so 2021 entries first, followed by 2020 entries, and so on. I don't need year headings, I just need them to be in order of year. But I also want to paginate them so there are only 10 per page.
I tried toying around with the group filter, but can't get it going with pagination.

You could sort using the multisort filter (docs) then paginate using Yii's ArrayDataProvider - see this post for reference.
{# Fetch your entries and order by theYear descending #}
{% set allEntriesByYear = craft.entries()
    .section('library')
    .orderBy('postDate DESC')
    .theYear(':notempty:')
    .with(['theYear'])
    .all() | multisort(e => e.theYear[0], direction=SORT_DESC) %}

{# Create your custom pagination #}
{% set dataProvider = create({
    'class': 'yii\\data\\ArrayDataProvider',
    'allModels': allEntriesByYear,
    'pagination': {'pageSize': 4}}) %} {# Change this to the number you need per page #}

{% set results = dataProvider.getModels() %}

{% set currentPage = dataProvider.getPagination().getPage() + 1 %}
{% set totalPages = dataProvider.getPagination().getPageCount() %}

{% if currentPage > 1 %}
    {% set prevPage = currentPage - 1 %}
{% endif %}
{% if currentPage < totalPages %}
    {% set nextPage = currentPage + 1 %}
{% endif %}

{% if results | length %}
    {% for entry in results %}
        {{ entry.title }} - {{ entry.theYear[0] }}

    {% endfor %}
{% endif %}

    {% if prevPage is defined %}
        < Previous page
    {% endif %}

    {% if nextPage is defined %}
         - Next page >
    {% endif %}


Manipulating the map in JS - [GM] Unable to find map I love the new Google Maps plugin, it seems really promising.
I am really struggling to manipuluate the map in JS in the new Google Maps plugin.
I have a dynamic map that filters fatal and serious injury crashes (by mode of transportation, outcome, and year) and adds KML layers.
I'm successfully loading the map in Twig — Now I am working through manipulating it in JS but can't seem to get past the first step.

Console: [GM] Unable to find map "mapAlpha"

  {% set fatalities = craft.entries.section('crashes').outcome('fatal').all() %}
  {% set injuries = craft.entries.section('crashes').outcome('injury').all() %}

  {% set options = {
    'id' : 'mapAlpha'
  } %}

  {% set map = googleMaps.map([], options)
    .zoom(12)
    %}

  {% do map.markers(fatalities, {
    'icon': '/assets/images/ui/red-dot.png',
    'infoWindowTemplate' : '/modules/info-bubble.twig'
  }) %}
  {% do map.markers(injuries, {
    'icon': '/assets/images/ui/blue-dot.png',
    'infoWindowTemplate' : '/modules/info-bubble.twig'
  }) %}

  {{ map.tag() }}

  <script>
  {% js %}
    var map = googleMaps.getMap('mapAlpha');

  {% endjs %}
  </script>

At a glance, it sounds like it's just a matter of waiting for everything to finish loading. You are trying to call a map which has not yet been initialized.
Good news! The tag method includes a callback option which allows you to specify a JavaScript function to be called after the map has finished loading...
{{ map.tag({
    'callback': 'moreJavascript'
}) }}

{% js %}
    function moreJavascript() {
        var map = googleMaps.getMap('mapAlpha');
        console.log(map);
    }
{% endjs %}

Take a look at this practical example of how someone could use the callback option to enable marker clustering... I know that you aren't trying to cluster your markers, but the broader execution is the same.


Commerce: How can I check if I am on a specific product page? I know there are ways to check current section. I would like to check if I am on a specific product (commerce) page.

I am able to do this in a plugin by checking line item(s) and the product type. Is there a similar way to do the same at the twig level?

You can use the same approach as the link provided in your question. Only, instead of an entry, you're working with a product.

For example:

template.twig

{# Get the current section - set fallback(s) for entries or products or ?? #}
{% set section = entry.getSection() | default(entry.getSection() ?? product.getType() ?? null) %}
{% if section %}
    {% set handle = section.handle %}
    {{ handle }} {# myProductType #}
{% endif %}

Here we are checking if we're on an entry. If not, we've set a fallback to check if we're on a product page. If nothing, the we return null.

Once we've got our section, we can check the handle. Then it's a matter of checking for the type you are looking for.

...
{% if handle == 'myHandle' %}

We've got a winner!

{% endif %}


I need to embed some forms into a new site We are moving to a new Craft site and we have some forms that live on our form server. I am wanting to embed these forms into the appropriate pages.
There is a PHP file that I can download that looks Like this:
<?php

date_default_timezone_set(@date_default_timezone_get());
header("p3p: CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"");
session_start();

require("/var/www/html/machform/machform.php");

$mf_param['form_id'] = 10824;
$mf_param['base_path'] = 'https://myform.mydomain.com/';
$mf_param['show_border'] = true;
display_machform($mf_param);

?>

Or I can get embed codes for iFrames, etc...What I don't see is a way to add the embed code into an existing page.  Is there a plugin for that? How do I edit the HTM to embed the form on the page?
Thanks for helping this Craft NooB.

You can always make a 'Plain Text' field, named iframe and allow it to have multiple lines. You can put your embed code in there.
Then you can add the iframe in your template with {{ entry.iframe|raw }}.
For (a little) more info about the raw filter: Here's the twig docs


Dates for entries are in different language When the user wants to edit the Post Date or Expiry Date of an entry (channel/structure), the calendar is in Welsh language.
I have no clue how this happened.
How can I change this?
Thank you

If you go to that user's account settings, then click on the "Preferences" tab, I'm guessing they have their "Formatting Locale" setting set to Cymraeg.


Element API + JSON data in template Is there any way to include the JSON response from element API in a template. Let's take the following example:

/case-studies.json returns:

{
    data: [
        {
            title: "American Express",
            color: "#0000ff",
            url: "http://localhost:3340/index.php?p=case-studies/american-express"
        },
        {
            title: "Bosch",
            color: "#ffffff",
            url: "http://localhost:3340/index.php?p=case-studies/bosch"
        }
    ]
}

I want to known if I can include this JSON object into my template case-studies/index.html, so it looks like:

<!DOCTYPE html>
<html>
    <head>
        <title></title>
    </head>
    <body>
        <...>

        <script>
            window.data = [
                {
                    title: "American Express",
                    color: "#0000ff",
                    url: "http://localhost:3340/index.php?p=case-studies/american-express"
                }, {...}
            ];
        </script>
    </body>
</html>

I just wanna avoid the first ajax call when I load the page for the first time by including the data in the HTML body. Further on, I will use Ajax calls instead.

I can't think of a clean way to do this.

The Element API plugin currently will set JSON headers on the response and return the data JSON encoded, so it's not easy to directly embed in a template.

A few options I can think of would be to fork the plugin and add the ability to return JSON in the format a template can directly utilize.  Or you could have a wrapper plugin that made an AJAX call to the Element API endpoint, grabbed the response and massaged the data into a format your template could directly utilize.