"Impossible to access an attribute on a NULL variable" I am getting this error returned whilst in Debug mode:

  Template Error

  Impossible to access an attribute ("gatewayHandle") on a NULL variable ("")

Not sure why this is getting flagged up. It is a variable which is accessed through the Dukt Video plugin? Seems to work when not in debug mode, but I am getting slow initial response times when loading, not sure if this is related to that issue.

I have attached the relevant page code:

{# Video Link :: if entry is of video type #}

{% if entries.section == "Videos" %}

    {% set video = entries.video %}

    {% if video.gatewayHandle == 'youtube' %}
        <a
            data-target="flare"
            href="http://youtu.be/{{ video.id }}"
        >
    {% else %}
        <a
            data-target="flare"
            href="http://vimeo.com/{{ video.id }}"
        >
    {% endif %}

{% else %}

{# Entry link #}

<a href="{{ entries.url }}">

Any help would be appreciated.

That message is telling you that gatewayHandle can't be accessed from video, because video is NULL. You're expecting the videos field to always contain an object, but in this case it is not.

I would suggest that you ensure that video actually contains a value before you attempt to reference one of its properties...

{% set video = entries.video %}

{% if video %}

    {% if video.gatewayHandle == 'youtube' %}
        ...
    {% endif %}

{% endif %}


How to get all (prepped) field values from an entry, indexed by field handle Getting field values, properly prepped, is covered here: What is getContent() / the ContentModel, and how do I use it to get and set custom field values?

I kept thinking this was in the Craft core.
Wasn't, so I made my own: https://gist.github.com/timkelty/933efd23264d79d91b7a

Has come in useful in plugin dev and some templating.


Ajax call to action 404 I've a trigger on my frontend that requires an action. I've started from the businessLogic template but I'm getting a 404 and can't find why.

My function

public function actionExampleAjax()
    {
      // Stuff
    }

How I call it

$.post('/actions/businessLogic/actionExampleAjax', data, function(response, textStatus, jqXHR) {
    // Stuff
});

The server response ( 404):

The system is unable to find the requested action "actionExampleAjax".

The action trigger is set to:

'actionTrigger' => 'actions'

The same approach works fine with a form submission, but I don't want to use a form in this case.

Any suggestion?

The URL you call using Ajax shouldn't include the action trigger, since Craft will add this to call the correct method in your controller when it interprets the URL.

So in the example you gave, your Ajax URL should be: /actions/businessLogic/exampleAjax

More details can be found in the Plugin Development docs.

Note that if you change the actionTrigger in the general.php config file, then you will need to change the first segment of the Ajax URL to match the new value for the actionTrigger.


Can't get locales to work properly So I've setup locales following the official guide and am going with the option where English (en_gb) is the default and Danish (da_dk) is in a sub-folder:

http://mysite.com      --> en default
http://mysite.com/dk/  --> dk sub-folder

In summary, I've set the locales in Settings -> Locales

I've enabled them for my section (which is a channel):

I've set the siteURL array (single domain config):

'siteUrl' => array(
    'en' => 'http://mysite.com',
    'dk' => 'http://mysite.com/dk/',
),

I've created the folder structure and copied the index.php file and .htaccess file across to the dk/ folder:

craft/
public_html/            --> mysite.com/
    .htaccess
    index.php
    dk/                 --> mysite.com/dk/
        .htaccess
        index.php

And I've made the edit to the dk/index.php file:

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

// Tell Craft to serve the Danish content
define('CRAFT_LOCALE', 'dk');

Viewing my entry in English works fine:

http://mysite.com/segment/title  --> Shows in English

Viewing the same entry in Danish directs to:

http://mysite.com/danishsegment/title --> Missing /dk/ in URL. Nothing shown

So the preview link for Denmark doesn't include the country segment in the URL (dk/) and results in a 404. Even manually adding dk/ to the URL results in a 404. It doesn't seem to be recognising the Danish locale at all.

Any ideas as to what I'm doing wrong?

UPDATE:

Here are the contents of my .htaccess files. All standard Craft with a Type to ensure PHP 5.6 is used:

AddType x-httpd-php56 .php

<IfModule mod_rewrite.c>
    RewriteEngine On

    # 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>

UPDATE 2:

The 'Offers' section (Channel) is set to have a different URL for each Locale:

Have you tried putting da_dk in as the key in the siteUrl array?


Feed Me: How to format CSV data for a table field Similar to the other post Feed Me: How to format JSON for a table field. I'm looking for a solution on how to format the CSV field so I can import it as a table field. Basically I have a list of products and each product has multiple serial numbers which I'd like to have each as a row in the table. So for the serial number field I've tried things like:

"[12345, 54211, 55511]"
"[{12345}, {54211}, {55511}]"
"[{"12345"}, {"54211"}, {"55511"}]"

Any thoughts on the best way to approach this field?

You can create a feed-me.php file under your /config directory, then you can configure the data delimiter:

<?php

return [
    '*' => [
        'pluginName' => 'Feed Me',
        'dataDelimiter' => '-|-',
    ]
];

On my side, that is not working all the time (if almost never), but the doc says it should!

(https://verbb.io/craft-plugins/feed-me/docs/get-started/configuration)

(https://github.com/verbb/feed-me/issues/449  ---> created just now)


Front end assets uploading, does not appear to be a an image error I have a front end form for entries. All other fields are working fine however my assets keep throwing errors.

My assets location is set to 'Images/{slug}' in the CP. Server info tells my Imagemagick is installed, on both local and staging environments.

However, when I submit an entry form with a file chosen for the assets field I get an error
'The file XXX does not appear to be an image.'
The odd thing is that the image does actually get uploaded and it's in the expected assets location, but the entry does not get created.

I should add that I can view it within the file directory, but the asset is not indexed into the Assets CP view.

Any ideas?

The issue lies if you have a Preparse field in that field layout, see details here: https://github.com/aelvan/Preparse-Field-Craft/issues/23


How do I output a file’s URL in a Matrix field? I have a Matrix field with Image, Caption, and PDF sub-fields. I can output the Image and Caption fine, but am having no luck with the PDF file.

Here is the code:

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

        {% set image = block.image.first() %}

        {% if image %}

        {% endif %}

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

        {{ block.caption }}

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

Download &rarr;

    {% endif %}
{% endfor %}

Assuming the field where your client can select the download is an asset field, you can use the following:

{% elseif block.type == "bladeBrochure" %}
    {% set download = block.download.first() %}
    {% if download %}
        Click me to download
    {% endif %}

Replacing block.download with the name of your field.


How to rename filename of asset before (or after) upload in Craft 3 I want to change the filename before the file is stored, to prevent ugly, long and weird filenames uploaded by users.

I've found an example for Craft 2, but because of the changes for events I can't rebuild this for Craft 3 (Change asset name on upload)

I also tried to change it a event, no luck;

Event::on(
    Asset::class,
    Asset::EVENT_BEFORE_HANDLE_FILE,
    function(AssetEvent $event) {

        $asset = $event->asset;
        $filename = 'filename'.md5(time()).'.'.$asset->getExtension();
        $asset->filename = $filename;
    }
);

Apparently the filename property is read-only, so you can only change properties like the title.

Any help is appreciated!

Well, after searching for this for more than 2 hours, I bumped into a working solution;

Event::on(
    Elements::class,
    Elements::EVENT_AFTER_SAVE_ELEMENT,
    function(ElementEvent $event)   {

        $asset = $event->element;

        if ($event->isNew && $asset instanceof craft\elements\Asset) {
            $newFileName = 'file-'.md5(time()).'.'.$asset->getExtension();
            Craft::$app->assets->moveAsset($asset, $asset->getFolder(), $newFileName);
        }
    }
);

In case somebody needs it!


Display a new entry modal when clicking on a relation field For a complex website we have nested a relation field inside a matrix.

It makes little sense for us to show the list of already created entries so we would prefer to directly display the new entry modal when clicking on a relation field. Our goal is to facilitate the editors lives and thus avoid multiple modal nesting... (See below).

Thank you in advance for your advice. Peace.

I'd rather look into nesting Super Table fields within your Matrix block types than relating Entries. The Entry element type and its relationship field come with a lot of inappropriate UI for the use case you're trying to solve.

Another approach would be to write a plugin that provides its own element type and relationship field / modal UI.


Issue with rendering a template from a plugin function I have an issue with rendering a template from within my controller in my plugin. It just seems to re-direct to the dashboard instead of bringing up the template.

I have a widget on the dashboard that calls an action in my plugin's controller file. This works as I can print_r the object I am creating. However when it gets to the render code it just keeps re-directing back to the dashboard. I've even tried stripping out all the code apart from the render call and it still does it. The code making the call is:

return craft()->templates->render('pluginName/index.html');

Which is currently the only code in the plugin function. The plugin has a templates folder where the index.html is held. I've also stripped the template down so it only contains the following:

{% extends "_layouts/cp" %}
{% set centered = true %}
{% set title = "The Title"|t %}

{% set content %}

List the users

{% endset %}

Any clues anyone.

I haven't tried calling a template from a controller, so I may not be any help but I've used

...->render(...)

in my main plugin Class like this:

MyPlugin.php

return craft()->templates->render('myplugin/_settings', array('settings' => $this->getSettings()));

Maybe the render method is looking for another argument?

EDIT

Oh wait... I was wrong, it looks like I do...

MyPluginController.php

$vars['users'] = craft()->user->listUsers();
$this->renderTemplate('myplugin/index', $vars);

Then I have a variables file:

MyPluginVariable.php

public function getContacts()
{
    return craft()->contactForm->getUsers();
}

Which ties back to the my service:

MyPluginService.php

public function getUsers()
{
    return MyPluginRecord::model()->findAll(array('order' => 'dateCreated desc'));
}

Maybe that will help get you rolling?


Edit multi-select field from front end I'm trying to set up a front end user profile that will allow the user to use the multi-select field. When I update from the CP, the changes are reflected on the front end, but this isn't working when trying to update from the front end form.

Is there anything I'm missing?

{% set languageOptionsIds = user.providerLanguages %}

<label for="providerLanguages">What languages do you work with?</label>
{% for option in currentUser.providerLanguages.options %}
    <input type="checkbox" id="providerLanguages" name="fields[providerLanguages][]"
    {% if option.selected in languageOptionsIds %}checked{% endif %} value="{{ option.selected }}">{{ option.label }}
    </input>
{% endfor %}

I believe that you can get the options directly from the 'currentUser' entry, without referring to 'user' separately (they are likely the same thing in this case anyway):

<label for="providerLanguages">What languages do you work with?</label>
{% for option in currentUser.providerLanguages.options %}
    <input type="checkbox" id="providerLanguages" name="fields[providerLanguages][]"
    {% if option.selected %}checked{% endif %} value="{{ option.value }}">
        {{ option.label }}
    </input>
{% endfor %}

The value is also available as 'option.value' instead of 'option.selected'.


Using a plugin, how can I manipulate entry data? I am trying to develop a plugin and what I want to do in this plugin is to be able to access the contents table that is already defined in the database and get and update entries in this table. What would be the best practice to do this? I know records can create new tables but how can I access or manipulate an already created table that is not part of my plugin but is created in the database by default?

You are correct in stating that Records typically define a new custom table for your plugin. However, don't forget that Craft already comes with many pre-existing Records.

Take a look inside this folder:

/craft/app/records

Although based on your question (and the ensuing comments thread), it looks like you may not need to tap directly into any Records at all. I'd recommend you peruse the built-in API to see what may help you get the job done.

Specifically, take a look at the EntriesService API...

  http://buildwithcraft.com/docs/apis/entriesservice

I suspect that everything you need to do can be done using those methods. After all, they already allow you to get, modify, and delete entry data.

An important thing to note when dealing with the EntriesService API... You're not directly accessing Entry Records. Instead, you'll be dealing with Entry Models. This is greatly preferred, and you'll find that it's much easier to do what you want with a Model. (Behind the scenes, your model will tie into an Entry Record as needed.)

On a separate note, it looks like you'll need to take advantage of Events. You mentioned in a comment that you'd like an action to take place "when an entry is saved". To do that, you'll definitely want to take advantage of the entries.onSaveEntry event.

In summary, I don't think that you will need to create a custom Record, nor build your own custom Yii query.


Setting Imager crop position dynamically I have a simple dropdown attached to each asset that allows the user to select the desired crop position (in %, so '0% 0%' , '0% 50%' , and so on).

In my twig template I have this inside a for loop

{% set entryImage = entry.pageHeader.first() %}
{% set imageCrop = entryImage.cropPosition %}

  {% set transformedImages = craft.imager.transformImage(entryImage, [
        { width: 1680, jpegQuality: 75 },
        { width: 1080, jpegQuality: 75 },
        { width: 680, jpegQuality: 70 },
        { width: 480, jpegQuality: 70 }
      ], { ratio: 21/9, position: 'entryImage.cropPosition' }) %}

As you can see, I've set the crop position inside the imageCrop variable and when I print it to screen the correct value is there.

But how the hell do I get the value that is set inside that imageCrop variable into my transformedImages array? I keep getting errors like: Undefined offset: 1.

If the value of imageCrop is a string in the correct format (ie 50% 50%, 0% 0%, or similar), this should do it:

{% set entryImage = entry.pageHeader.first() %}
{% set imageCrop = entryImage.cropPosition %}

{% set transformedImages = craft.imager.transformImage(entryImage, [
    { width: 1680, jpegQuality: 75 },
    { width: 1080, jpegQuality: 75 },
    { width: 680, jpegQuality: 70 },
    { width: 480, jpegQuality: 70 }
  ], { ratio: 21/9, position: imageCrop }) %}


getResourcePath() for folders in a plugin I have a plugin that has an folder inside of it's resources. I need to iterate through those files.

To get the path, I tried craft()->resources->getResourcePath('folder-name'), but it seems to only succeed if the file exists, not a folder.

I want the folder so I can use IOHelper::getFolderContents($folder).

Do I just need to build the path myself ($folder = craft()->path->getPluginsPath() . 'myplugin/resources/svg/';), or am I missing something?

The ResourcesService getResourcePath method will only work for files.

The PathService getResourcesPath method will get you the resources path, after which you can append your folder name.

$folder = craft()->path->getResourcesPath() . 'svg/';


Axios post function got 400 bad request I created a Vue component. And in this component, I use axios to send post request when it's mounted, CSRF token also included, but still got 400 status. Anyone know why?

Just found the solution:

npm install qs

and

import qs from 'qs'

...
const actions = {
    auth({ commit }, { email, password }) {

        axios.post('url', qs.stringify({
            your token data here
        })).then((res) => {
            console.log(res.data)
        }).catch((err) => {
            console.log(err)
        })
    }
}


Sprig/Snaptcha CSRF issue/question We have a site using Sprig and Snaptcha. One of our forms is always returning a 400 error "Unable to verify your data submission" which is usually a CSRF issue but thought Sprig takes care of CSRF?
The only solution seems to be disabled CSRF validation so suppose question is:

if we are using Snaptcha on POST form submissions would that be sufficient (eg is CSRF needed), and
any thoughts why sprig might be generating or submitting an incorrect CSRF token?

Cheers
Cole

From your code sample it looks like you may be using Blitz to cache the page, in which case this is likely neither a Sprig issue nor a Snaptcha issue. A CSRF token is a dynamic token which should not be statically cached. You would normally use the {{ craft.blitz.csrfInput() }} tag but since you are using Sprig, I'd recommend you look into implementing the dynamic content example instead of using the craft.blitz tags.
As an aside for future reference, you'll get better support if you can post an issue in the appropriate Github repository along with code samples and the specific version numbers of the plugins in question.


JSON response displayed as plain text on submission when creating/editing an entry I am running Craft Pro 2.2.2601. When I submit an entry, I am getting back JSON rather than being redirected to a success page.

For example, I just go to:

/admin/entries/pages/new

I fill out some fields and click Save. It kicks me to the next page that displays JSON as the source as opposed to an "Entry saved" flash message:

{"success":true,"title":"Services","cpEditUrl":"http:\/\/www.test123.com\/admin\/entries\/pages\/22-services","author":{"id":"1","enabled":"1","archived":"0","locale":"en_us","localeEnabled":true,"slug":null,"uri":null,"dateCreated":{"date":"2014-11-04 15:44:04","timezone_type":1,"timezone":"+00:00"},"dateUpdated":{"date":"2014-11-04 15:44:04","timezone_type":1,"timezone":"+00:00"},"root":null,"lft":null,"rgt":null,"level":null,"username":"test123","photo":null,"firstName":null,"lastName":null,"email":"test123@gmail.com","preferredLocale":null,"admin":"1","client":"0","status":"active","lastLoginDate":{"date":"2014-11-07 02:01:58","timezone_type":1,"timezone":"+00:00"},"invalidLoginCount":null,"lastInvalidLoginDate":null,"lockoutDate":null,"passwordResetRequired":"0","lastPasswordChangeDate":{"date":"2014-11-04 15:44:04","timezone_type":1,"timezone":"+00:00"},"unverifiedEmail":null,"newPassword":null,"currentPassword":null,"verificationCodeIssuedDate":null},"postDate":"11\/6\/2014"}

The page also contains the posted data, so refreshing re-submits the form post. I have disabled JS compression and it worked once (got the "Entry saved" flash message), but now it is back to spitting out JSON.

I'm guessing you're on MediaTemple?

http://buildwithcraft.com/help/forms-returning-json


Comparison "or" conditional I'm trying to use a conditional to do something if the first segment matches This or That. But I'm unable to come up with the right operator for the "or"

{% elseif craft.request.firstSegment == 'This' || 'That' %}

What's the proper operator here? Thanks!

You want:

{% if craft.request.firstSegment == 'This' or craft.request.firstSegment == 'That' %}

or this would work:

{% if craft.request.firstSegment in ['This', 'That'] %}


Custom-created or personalized products with Craft Commerce? I’m building a webshop with Craft Commerce where customers will be able to customize/personalize parts of clothes based on a predefined set of options.

With a pullover for example, customers should be able to change material, color and prints of the body, sleeves and cuffs individually. The different options are individual products themselves and have their own stock information. So the product bought by the customer will be composed of several product variants for different parts of the pullover.

With Woo Commerce for example there is a Composite Products Plugin, that seems like a solution to this: https://woocommerce.com/products/composite-products/

Is there a similar plugin for Craft Commerce, that would help me with building this feature? Or is there another way of solving this?

Thanks!

I don't think there is a plugin for this, so the only way to solve this would be to build the plugin for this yourself, if you have the skills or resources for this. It could be solved by creating a purchasable with (optional) relations to all the products needed, checking the stock of those products on adding it to the basket, and/or on checkout.

What I would start with, though, is creating an issue on Commerce's Github, to see if others have a need for this and hope that Pixel & Tonic's crew will do it for you ;)


Get entries based on multiple fields in controller I am trying to get the entries based on multiple fields.
Fields can be of type tags, checkbox, radio box, and number.

In my controller currently what I tried is.

$extrafilter will be like

Array
(
    [0] => Array // other field
        (
            [handle] => amenities
            [value] => laundry
        )

    [1] => Array // tag field
        (
            [handle] => technologies
            [value] => 45
        )

)

Code to narrow down the result.

use Craft;
use craft\elements\Entry;
use craft\elements\db\ElementQuery;

$entryQuery = Entry::find();
$entryQuery->section($sectionName);

if ($extrafilter && !empty($extrafilter[0])) {
  $relatedTo = [];
  $fieldList = [];

  foreach ($extrafilter as $key => $value) {
     $relatedTo[] = $value['value'];
     $fieldList[] = $value['handle'];
  }

  $entryQuery->relatedTo = array(
        'targetElement' => array_merge(['and'], $relatedTo),
        'field' => $fieldList,
  );
}
$entries = $entryQuery->all();

This works for Tags but for other fields it dont give any result.

I checked these Questions

Display entries that meet multiple tag params

I haven't tested it but it should give you a pretty good idea on how to set this up.

public function actionTest() {
    $entryQuery = Entry::find()->section('mySection');

    // All the element relations. For example tags and categories.
    // These have to be Element objects. For example craft\elements\Tag.
    $myArrayWithTags = [/* ... */];
    $myArrayWithCategories = [/* ... */];
    $allRelations = array_merge($myArrayWithTags, $myArrayWithCategories);

    // Filter by relations
    $this->_applyRelationFilter($entryQuery, $allRelations);

    // Filter by custom fields
    $this->_applyFieldFilter($entryQuery, 'myRadioField', 'value2');
    $this->_applyFieldFilter($entryQuery, 'myNumberField', 3);
    $this->_applyFieldFilter($entryQuery, 'myCheckboxField', ['option1', 'option2']);

    // Build response string
    $content = "Entries:
";
    $content .= "
" . json_encode($entryQuery->all()) . "
";

    // Respond
    $response = Craft::$app->getResponse();
    $response->content = $content;
    return $response;
}

private function _applyRelationFilter(ElementQuery $query, array $elements) : array {
    $relatedTo = [];

    // Build the list of relations in the correct format
    foreach($elements as $element) {
        array_push($relatedTo, [
            "targetElement" => $element
        ]);
    }

    // Create an array with and as the first value so
    // the result only contains elements that have all the set relations
    $relatedTo = array_merge(['and'], $relatedTo);

    // Set query relatedTo
    return $query->relatedTo($relatedTo);
}

private function _applyFieldFilter(ElementQuery $query, string $handle, $value) {
    $query->andWhere([
        ('content.field_' . $handle) => $value
    ]);
}

You need to have the following imports:

use Craft;
use craft\elements\Entry;
use craft\elements\db\ElementQuery;

Info about querying by custom field:
https://craftcms.stackexchange.com/a/22995/9754


Revolution Slider and Craft CMS conflict on placeholders Revolution Slider is using Placeholders like this {{param1}}.
This is conflicting with Twig's variables.

Is there a workaround that Twig will ignore this for example?

You can stop Craft from parsing curly brace tags in your template code by using the Twig Verbatim tag. Here's an example:

{% verbatim %}{{ this.wont.be.touched }}{% endverbatim %}

You can use it to stop a single tag from being parsed, or encapulate an entire block of code on your page for multiple tags. Useful for languages like AngularJS that use the same double curly brace format.

More info at http://twig.sensiolabs.org/doc/tags/verbatim.html


Craft Commerce Arrange a delivery booking plugin? Is there a booking plugin available for Craft Commerce that would let you arrange a delivery via a calendar interface with AM and PM timeslots? Or would it need to be custom developed for Craft.

The client's shop already has this functionality via it's current custom CMS, but we'd like to move it over to Craft Commerce if possible. And this looks like one of the sticking points as there doesn't seem to be anything like it currently.

I'm not aware of an existing plugin for Craft/Commerce that would do this and a search through https://straightupcraft.com/craft-plugins/ doesn't reveal much more.

Sounds like it would need to be custom plugin development.


Restricting relationship field by author First site using Craft and impressed thus far.

I'm going to be allowing CP access for all users, and these users will have access to multiple channels. I want them to be able to relate their entries from different channels to each other, but only be able to select from their own entries within the relationship field.

I can't seem to find anywhere that allows this. I did a test with 2 separate users, and when I went to relate, I could see the other user's entries available for relationship in the entries relationship field. This won't be acceptable as each user should be in their own silo and only have the ability to relate their own entries.

Is there any way I can accomplish this that I'm missing? (edit: without custom field type)

Craft's permission system doesn't go down to the field level, which is what you're looking for.

You'd either have to replicate the functionality you're looking for on the front-end of the site, or develop a custom field type that took into account custom permissions for your users.


How do I render pages with dynamic content from a json feed I am building a module to show a job/vacancy-list and the detailpage of a job, the data is fetched from a remote json feed.

Currently I have the following routes to a controller in my module

return [
  'job' => 'job-offers-module/job/process',
  'job/detail' => 'job-offers-module/job/detail',
];

And loading twig templates eg.

namespace modules\joboffersmodule\controllers;

use Craft;
use craft\web\Controller;
use craft\web\View;

class JobController extends Controller
{
  protected $allowAnonymous = true;

  public function actionProcess(){
    return \Craft::$app->view->renderTemplate('joblist');
  }
  public function actionDetail(){
    return \Craft::$app->view->renderTemplate('jobdetail');
  }
}

But I keep getting an error that the entry can not be found... Do I need to register the paths in the module as a handle?

How can I load an entry from my within the module and pass it to the templates?

To fetch an entry from your module and pass it to a template you can do:

$entry = \craft\elements\Entry::find()->one();
return \Craft::$app->getView()->renderTemplate('path/to/template', ['entry' => $entry]);

Then in your template, you will have access to an entry variable.


Cannot access plugin controllers when plugin does not have a "cp section" Due to a permission check in \Craft\WebApp::processRequest(), I cannot access my plugin controller through the control panel templates. Also I cannot grant the user access because the plugin does not have a "cp section".

I have a fieldtype that loads data through an ajax-request, but this does not work if the user looking at the pages does not have access to the plugin.

Simple solution would be to always show all plugins (with controllers) in the permission overview, so that I can grant access if needed.

If you don't want to give the user specific access to your plugin, I think the only solution is to allow anonymous access to the controller action. But of course, this would make the controller accessible to alll anonymous users, also outside the control panel.


PHPUnit testing for Craft plugins or controllers Is it possible to implement PHPUnit into Craft CMS? If so, where can I find a good explanation or tutorial? I already tried a Github link for a plugin (testing the plugin).

But I am new to both but really want to TDD the plugins. Any example pages or a quick guide would be great!

There is a good example of testing with PHPUnit in a Craft plugin here: https://github.com/selvinortiz/craft.loath and an example on how to stub out the global craft() class here: Stub out the global craft() object for PHPUnit tests

Note that testing in Craft should be a lot easier/convenient in the upcoming Craft 3.


Element API: how can I return entries via username? Struggling to get this feed work with Element API. I'm trying to return all entries created by a specific username. I've tried several different methods, but none of them work.

Here is the latest version of what I've tried:

'dealers/<username:{username}>.json' => function($username) {
  return [
    'elementType' => 'Entry',
    'criteria' => [
      'section' => 'listings',
      'username' => $username
    ],
    'paginate' => false,
    'transformer' => function(EntryModel $entry) {
      ...

Completely untested, but something like this should work:

'dealers/<username:(.*)>.json' => function($username) {
    $author = craft()->users->getUserByUsernameOrEmail($username);

    return [
        'elementType' => 'Entry',
        'criteria' => [
            'section' => 'listings',
            'authorId' => $author->id
        ],
        'paginate' => false,
        'transformer' => function(EntryModel $entry) {
            ...


Set a maximum quantity for cart items I’m using the Digital Products plugin to sell licenses so that users are listed on the site for a certain amount of time.

The options are something like "buy 3 month", "buy 6 month" etc. You see, the concept of the cart doesn’t really apply here. There would be no point in buying "3 month" twice.

That’s why I’d like to set the items in the cart always to the quantity of 1. Even better would be if I could empty the cart each time a product is added to the cart. That’s because people are supposed to select between the given options, not buying several options at once or multiple times.

Any hints?

You should be able to handle this with some logic in a plugin listening to events like:

https://craftcommerce.com/docs/events-reference#commerce_cart.onbeforeaddtocart

The parameters for this include both the order as it stands, and the lineItem being added to the cart, which gives you the opportunity to manipulate both.  You could clear the order, and chec the qty of the lineitem being added is 1 at this point (and change it if needed).

Obviously it would be good to have some front end stuff in place limiting the quantity to 1 as well.


Can't find the "share entry" functionality I have Craft Pro (2.1.2564) and cannot locate the "share" functionality outlined below.
When I edit an entry, The Live Preview button in Chrome (OSX) has only the Live Preview button with the eye icon and then an arrow. That row triggers the Live preview and not any sharing function.

http://buildwithcraft.com/updates#build2554
Added a “Share” button next to entries’ Live Preview button, which opens the current entry/draft/version on the front end, with a tokened URL that can be shared with others without requiring them to be logged in.

The arrow is the Share button. If it’s just opening Live Preview for you, please get in touch with us directly – support@buildwithcraft.com.


Repeat entries but starting from offset I have a structure that I am using for a schedule, it has 1 entry per day (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday).

What I want to do is only show the 3 days from the current day.

i.e if today is Thursday, it will show the Thursday, Friday & Saturday entries.

I have used the following to control the offset which works great.

{% for entry in craft.entries.section('schedule').offset(now|date('w')).limit(3).find() %}

My problem is, when I get to Friday or Saturday it wont show Sunday because that is the first entry of the structure.

Is there anyway I can have it loop around to start the list of entries again?

You can't do this with the criteria parameters offset and limit. I would suggest to first get all the IDs of your section and then use Twig's handy cycle function to get those entry IDs you're interested in.

That function starts to read an array from the beginning again, when it reaches it end, so that's exacly what you need here. So when you want to get the 8th element of an array of length 7, it returns the first element (monday)!

The first element / ID of your array is in position 0, so I sustracted 1 from the week day number before passing it to the cycle function.

{% set allIds = craft.entries.section('schedule').ids() %}
{% set nextIds = [] %}

{% set start = now|date('w') - 1 %}
{% set end = start + 2 %}

{% for i in start..end %}
    {% set id = cycle(allIds, i) %}
    {% set nextIds = nextIds|merge([id]) %}
{% endfor %}

{% set entries = craft.entries.id(nextIds).fixedOrder(true) %}


Changing root folder name I would like to change the root folder name where my Craft install is currently at.  for example: website.com/dev to website.com/draft1.  When changing the folder name on my server and the site URL in the Craft admin settings to match, I get an error.  What am I missing?  Will I need to reinstall Craft from scratch under the new URL?

No need to go through the installation process again.

I assume that /dev is a folder under your public html folder that Craft's public index.php file lives in.

So Craft's index.php lives in something like:

/path/to/public_html/dev/index.php

And what you want to do is change the site to live in:

/path/to/public_html/draft1/index.php

If that's the case, you'd just need to move anything in the public_html/dev folder over to public_html/draft1 and update your siteUrl.  That's either been defined in your craft/config/general.php file or under Settings->General in the control panel, depending on how your site is setup.

If you've defined any custom environment paths in craft/config/general.php, they might need to be updated as well.


PayPal Currency - Item bag total price does not equal the orders totalPrice, some payment gateways will complain We are using PayPal standard as an option for payments which works in the main currency (GBP) but not in any of the others eg (CAD). We're seeing in the plugin logs for craft commerce:

[Forced] Item bag total price does not equal the orders totalPrice, some payment gateways will complain.

Any ideas on what could be wrong? It seems that this is a problem with PayPal adding up the totals and seeing they are wrong? but this is all done on craft side so not too sure.

Luke very helpfully got back to me to sort the problem, but in case it helps anyone else.

The immediate fix is to disable sending the item bag (cart information to PayPal) and using it purely to change the payment amount. But I will attempt to explain in full below.

You disable the cart info being sent to PayPal in your commerce.php settings with:

'sendCartInfoToGateways' => false

Strangely this is the first time we have seen this issue. But it is due to the following in Commerce:

Commerce stores all values in the system in a single base store currency. This means the cart, the discounts, shipping, and anywhere a currency amount is stored is stored as the default base currency.

The payment currency feature is purely designed to allow the charging of the order price in a different currency. The feature allows the customer to know the exact amount to be charged to their card in the currency of their card - without any surprise conversion rate determined by their bank.

Paypal, when it receives the cart information (line item prices etc) is being supplied amounts in that base currency from commerce. Paypal adds up the cart amounts and compares it to the amount that we want to charge the customer in the chosen payment currency. Obviously, the amount we are changing is in the other currency differs from this total.

At first the thought might come as a solution to convert the line items amounts to the other currency for PayPal, but this doesn't work; we do the conversion of the totalPrice of the order for the payment currency feature, and converting each line item and adding them up would usually come up with a different total due to rounding.


Base fieldtype validation working with model validation? How can you ensure that the base fieldtype validation (required etc) and error messages are still applied when validating $value via the validate($value) function??

Validate method in fieldtype class:

public function validate($value)
{
    if(is_array($value) && $value['type'] != '')
    {
        $linkModel = $this->_valuetToModel($value);
        $validated = $linkModel->validate();
        return $validated ? true : $linkModel->getAllErrors();
    }
    return true;
}

Validate method of custom model that the fieldtype populates and returns to the template:

public function validate($attributes = null, $clearErrors = true)
{
    switch($this->type)
    {
        case('email'):
            if( !filter_var($this->value, FILTER_VALIDATE_EMAIL) )
            {
                $this->addError('value', Craft::t('Please enter a valid email address.'));
            }
            break;

        case('tel'):
            $regexp = '/^[0-9+\(\)#\.\s\/ext-]+$/';
            if(!filter_var($this->value, FILTER_VALIDATE_REGEXP, array('options' => array('regexp' => $regexp))))
            {
                $this->addError('value', Craft::t('Please enter a valid telephone.'));
            }
            break;

        case('custom'):
            if(!filter_var($this->value, FILTER_VALIDATE_URL))
            {
                $this->addError('value', Craft::t('Please enter a valid url.'));
            }
            break;

        case('entry'):
            if($this->value == '')
            {
                $this->addError('value', Craft::t('Please select an entry.'));
            }
            break;

        case('asset'):
            if($this->value == '')
            {
                $this->addError('value', Craft::t('Please select an asset.'));
            }
            break;

        case('category'):
            if($this->value == '')
            {
                $this->addError('value', Craft::t('Please select a category.'));
            }
            break;
        // default:
        //     Craft::dd(parent::validate($attributes, null));
        //     $this->addError('value', Craft::t('Please select a sdfasdfsd.'));
        //     break;
    }

    return !$this->hasErrors();
}

Completely untested and this whole pattern feels hacky to me, but something like this should work:

From your field type:

public function validate($value)
{
    if(is_array($value) && $value['type'] != '')
    {
        // Validate the field type.
        $errors = parent::validate($value);

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

        $linkModel = $this->_valuetToModel($value);

        // Validate the model.
        $validated = $linkModel->validate();

        return $validated && empty($errors) ? true : array_merge($linkModel->getAllErrors(), $errors);
    }

    return true;
}

From your model:

public function validate($attributes = null, $clearErrors = true)
{
    switch($this->type)
    {
        case('email'):
            if( !filter_var($this->value, FILTER_VALIDATE_EMAIL) )
            {
                $this->addError('value', Craft::t('Please enter a valid email address.'));
            }
            break;

        ....

    }

    return !$this->hasErrors();
}


How does one get an order confirmation email to fire immediately in Commerce 3? Curious if there is a way to fire order confirmation emails immediately? Basically how this was handled in Commerce 2.

There are cases, and I'm dealing with one currently, where there is no command line access to the hosting or the possibility of setting up cron jobs and the likes to trigger the queue on an interval...

Is there a workaround?

There are a couple of options here.

Number 1

If you have the config setting runQueueAutomatically set to false you could call the controller action queue/run via ajax from your success page. This would trigger the queue to run.

Number 2

You can use the EVENT_AFTER_COMPLETE_ORDER event to run some custom code, in a module or plugin. In that code you can include Craft::$app->getQueue()->run() this will also trigger the queue to run. e.g.

Event::on(Order::class, Order::EVENT_AFTER_COMPLETE_ORDER, function(Event $e) {
    Craft::$app->getQueue()->run();
});


Craft CMS Database Structure and Schema Schematics Is there somewhere that we can find a the schematics of crafts database structure/schema. We  are looking into developing a database migration workflow between development and production environments.

Thanks

Tools like Navicat and MySQL Workbench both have ways of analyzing a database and generate a schema map from it, so you can visualize the tables, foreign keys, etc.


Is it possible to extend twig with 'Twig_SimpleTest'? I was on the Twig StackExchange forum and found an answer that suited my needs.

But I can't for the life of me figure out how to implement this into a Craft CMS Plugin.

I'm familiar with Twig_Function_Method and Twig_Filter_Method, but I can't find anything on Twig_SimpleTest.

Has the option to include "tests" been omitted from Craft CMS?

When you call Craft's TemplatesService->getTwig() (craft()->templates->getTwig()), you get an instance of the Twig environment and from there you could be able to call addTest.

100% untested, but something like this should work:

$twig = craft()->templates->getTwig();
$twig->addTest(new My_Twig_SimpleTest());


Get entries NOT related to categories is it possible to grab all the entries in a section that arent related to a category?

So something like

craft.entries.section('news').relatedTo('not',category)

Doesnt seem to work but is there some other syntax?

If you want to do it in a single query, Marion's answer is probably the best.

Otherwise, you could do something like this:

{% set idsHavingCategory = craft.entries.section('news').relatedTo(category).limit(null).ids() %}

{% set omitIds = 'and, not ' ~ idsHavingCategory|join(', not ') %}

{% set entries = craft.entries.section('news').id(omitIds) %}

Inspired by this article, which shows how to (1) grab ids, and (2) query against them:

  http://webstoemp.com/blog/manipulating-craft-elementcriteriamodel-with-twig/

Also references related solutions found in these answers:

https://craftcms.stackexchange.com/a/4930/45
https://craftcms.stackexchange.com/a/4573/45


Parent are not set anymore after saveElement() In this code I try to create a new Entry and set a Parent to it.
The sectionId and the typeId are actually the same.
$navigationItem = new Entry();
$navigationItem->typeId = 4;
$navigationItem->sectionId = $navigationSection->id;
$navigationItem->title = $entry->title;
$navigationItem->setParent($herbsNavigationEntry);

$navigationItem->setFieldValue('navLink', '/tags/' . $entry->slug);

if (!Craft::$app->elements->saveElement($navigationItem)) {
    Craft::error('Couldn’t save the entry "' . $entry->title . '"', __METHOD__);
}

Before saving I get this:

But after the Craft::$app->elements->saveElement($navigationItem),
the parent disappears.
What did I wrong?

You need to use newParentId:
$navigationItem = new Entry();
$navigationItem->typeId = 4;
$navigationItem->sectionId = $navigationSection->id;
$navigationItem->title = $entry->title;
$navigationItem->newParentId = $herbsNavigationEntry->id;

$navigationItem->setFieldValue('navLink', '/tags/' . $entry->slug);

if (!Craft::$app->elements->saveElement($navigationItem)) {
    Craft::error('Couldn’t save the entry "' . $entry->title . '"', __METHOD__);
}


Impossible to access an attribute ("created_at") on a boolean variable ("1") I have read a number of related threads but am still puzzled what this error actually means or how to fix it.

This triggers the error:

                {% set tweets = craft.twitter.get('statuses/user_timeline', {count:2}) %}

               {% if tweets %}

Latest Tweets

                    {% for tweet in tweets %}
                    {% set tweetDate = date(tweet.created_at).diff(now).format('%a') %}
                    {% if tweetDate == 0 %}
                    {% set tweetTimeAgo = 'today' %}
                    {% else %}
                    {% set tweetTimeAgo = tweetDate ~ ' days ago' %}
                    {% endif %}

                          {{ tweet.text|autoLinkTweet }}

                          @{{ tweet.user.screen_name|raw }} /
                          Posted {{ tweetTimeAgo }}

                    {% endfor %}

                  {% endif %}

What would fix this?

That error basically means that you're trying to use the variable tweet as an object/iterable, but it's actually just a boolean (true/false).

Assuming the plugin you're using (i.e. craft.twitter) is Dukt's Twitter plugin, I think this is just a matter of your syntax being a bit off. The Dukt plugin's craft.twitter.get() method actually returns a response object where the
tweet objects are nested in an array called data. In other words, you can't loop on the object returned by craft.twitter.get() directly; you'll need to use the array in that object's data property:

{% set response = craft.twitter.get('statuses/user_timeline', {count:2}) %}

{% if response.success %}
    {% set tweets = response.data %}
    {% for tweet in tweets %}
        {% set tweetDate = date(tweet.created_at).diff(now).format('%a') %}
        ...
    {% endfor %}
{% else %}

An error occured:

{{ response.data|json_encode(constant('JSON_PRETTY_PRINT')) }}

{% endif %}

The above example is lifted from the plugin's documentation (although in the actual docs there's a typo, which could well be the cause for your issue). Note that the example also accounts for Things Going Wrong (tm), which is always a good idea when you're working with a third party API.

If the plugin you're using is not Dukt's, you'll need to check your plugin's documentation, to verify you're using it correctly. As a debugging effort, you might also want to try and dump() the response object variable to verify that it contains what you think it contains:

{% set tweets = craft.twitter.get('statuses/user_timeline', {count:2}) %}
{{ dump(tweets) }}

Note that the dump() method only works when devMode is set to true, and should not be left in production code.


How to re-populate form with old values when submitted from a controller? I have a form in a template which makes a request to the specified action (a controller).

The controller decides that there is an issue with the inputs and needs to provide error output for the user. To do this I am using the flash error feature of Craft.

However, I'm unsure how to re-populate the form with the old values when it is next shown.

At the moment I am redirecting to the form page again using $this->redirect but the user inputs get erased each time.

There are several things you may need to dig into more to get the full picture here but here's a general idea of how you can approach this in Craft 3.

Flash errors are useful to display a message in the Control Panel, but you'll need to prepare a model with errors and signal to the controller that the form submission has failed to return errors to your template. Also, it's not necessary to use the redirect method in this situation as the Controller request can return your errors to the template simply by preparing them using setRouteParams and returning null.

A common pattern that Craft and several plugins use to do this is as follows. The method below would be the method in your controller that receives the form submission:

public function actionMyControllerAction()
{
    $this->requirePostRequest();

    // Build a model of the data you are submitting
    $model = new MyModel();
    $model->someOptionalAttribute = Craft::$app->getRequest()->getBodyParam('someOptionalAttribute');

    // The `getRequiredBodyParam` method can help validate required fields
    $model->someRequiredAttribute = Craft::$app->getRequest()->getRequiredBodyParam('someRequiredAttribute');

    // After you prepare the model, hand things off to a service
    // to validate and/or save things to the database
    // The "saveThisModel" method can run any additional
    // validation you need to run, add errors to the model,
    // and return `false` if validation fails
    if (!Plugin::getInstance()->myService->saveThisModel($model)) {

        Craft::$app->getSession()->setError(Craft::t('my-plugin', 'Unable to save item.'));

        // This is where you name the thing you are returning to your template with errors.
        // In this example, the 'myModel' variable would be available to your submitted template
        Craft::$app->getUrlManager()->setRouteParams([
            'myModel' => $model
        ]);

        return null;
    }

    Craft::$app->getSession()->setNotice(Craft::t('my-plugin', 'Item saved.'));

    // Redirects to wherever the submitted 'redirect' input points to
    return $this->redirectToPostedUrl();
}

If validation fails, in your template, the myModel variable will be available and you can access all errors as an array, or an array of errors for an individual field. You'll need to loop through this in your template. For simplicity here, I'm just dumping them:

All Errors:

{{ dump(myModel.getErrors()) }}

Errors for a specific field:

{{ dump(myModel.getError('someOptionalAttribute')) }}

You may also have to add some conditional logic around checking if the myModel variable exists or has errors. You can use Craft's form macros in your template to help with this. Search the Craft codebase templates folder for forms. and you'll find several examples. Here's a simplified Text Field macro that would display an error for the Categories title field.

{% import "_includes/forms" as forms %}

{{ forms.textField({
    label: "Title"|t('app'),
    siteId: category.siteId,
    id: 'title',
    name: 'title',
    value: category.title,
    errors: category.getErrors('title'),
    required: true,
    maxlength: 255
}) }}

In this case, the Craft Categories controller the actionSaveCategory is returning the category variable to the template using the same pattern that is described above:

if (!Craft::$app->getElements()->saveElement($category)) {

    // ...

    Craft::$app->getSession()->setError(Craft::t('app', 'Couldn’t save category.'));

    // Send the category back to the template
    Craft::$app->getUrlManager()->setRouteParams([
        'category' => $category
    ]);

    return null;
}


Obfuscation of an asset's file path? I'm building a site with digital downloads of PDFs via the excellent Charge plugin and need to include some basic obfuscation of the path to files to prevent people from just being able to predict them. I was thinking maybe I can use the UID of the assets to identify it, is this possible? If not any suggestions are welcome.

I guess that each of these PDFs are related to an entry using an assets field.

If this is true, you could add an extra field "Random Path" to that entry and use that field's value as a segment of your PDF's URL.

You can achieve this by setting the upload location for the PDFs to a subfolder named after that field's value. You set the subfolder path (i.e. to {randomPath}) in Settings → Fields → "myAssetField" → Default Upload Location.

If the randomPath field has a value of mUampRNYxcwXampC9QX, an PDF file mySecureFile.pdf is saved like so: /myPdfFolder/mUampRNYxcwXampC9QX/mySecureFile.pdf (in fact it is moved after the entry is saved).

To generate random strings for that field, use the fantastic Craft plugin "Randomm" by Fred Calsen.


Craft CMS 3 admin panel returns 404 with SSL I'm using MAMP Pro for local development and was gong to set up my site with SSL this time around. I got a self-signed cert for local dev and I can go to my development site over https:// without any trouble but when I try to go to the control panel I get  404 error. I've updated the .htaccess file as suggested on Enforcing SSL for CP Requests but I still get a 404 error. All the Stack articles I could find on this issue were of no help either. Any suggestions? Something obvious that I'm overlooking?

tl;dr: In my case, adding AllowOverride All back in to httpd.conf fixed the issue.

I was having the same issue on my staging server. I noticed that, in addition to /admin throwing a 404, all of my site's subpages were 404-ing. This cause me to try the unrouted index.php url for a subpage (mysite.com/index.php?p=subpage) and it worked! Note, this wasn't working for /index.php?p=admin because it was properly routing to /admin/login. Plugging in /index.php?p=admin/login worked.

I ran through the Craft guide for removing index.php from urls. Everything was set up properly, but my server admin found that AllowOverride All had been commented out of httpd.conf during a server update and was never un-commented. Adding AllowOverride All back in to httpd.conf fixed the issue.


Fetch entries filtered by array within custom field I'm using the multidate field plugin, which is excellent at presenting dates but I need to return entries based on testing the first date in there. I typically test with the entries loop, like so:

{% if product.dates.dates[0] | date('U') > now | date ('U') %}

but would prefer to only get entries fitting that criteria in the first place. Is there any way to fetch entries according to the first value in a an array like this?

{% set products = craft.commerce.products.dates(somehow only test the first value in the dates array here) %}

The field looks something like this:

dates [ // this is the custom field name
    dates [ // this is the dates array within the custom field
        [0] // this is the date object I want to test against
        [1]
        [2]
    ]
]

That plugin doesn't provide a custom element type, so there's no way for it to have a chance to modify the main elements query when fetching the data.

In its existing form, you'll have to do the filtering on the Twig side like you're doing to grab the one you're looking for.


Feed Me and Assets Field - Mapping Trouble I'm trying to import a JSON file to map a bunch of asset paths to their appropriate related entries.  While I've followed the instructions in the docs, I'm still having trouble connecting the file path in JSON with its related Assets field.
I have the following JSON structure, with "Record Id" representing the path to the file on the server, and "Parent ID" representing a field in my section to which I can identify the correct entry to map the asset.
[
  {
    "Record Id": "http://reminc.info/uploads/Call Reports/9s0353ca7831970c344b6afd2949eade4bf42_Agrati Reilingen, D 20120-02-11_ss.doc",
    "Parent ID": "zcrm_4320009000001781082"
  }
]

I've verified that the file path maps to a file on my server, and that the "Parent ID" value matches the field within the target entry.
All this said, Feed Me is failing to import the URL to create the link to the asset.
What am I missing?
Thanks!

1.) Have you set the feed to update existing entries?
2.) Try to url-encode the URL in the JSON, it contains special chars like spaces.


Installing Craft 3 on Cpanel Can I install Craft 3 using cPanel instead of composer. Any suggestion or guide on it? I tried find tutorials but found for Craft 2, not for Craft 3.

Here's a Mijingo resource that should help: https://mijingo.com/blog/manually-installing-craft-3


How do I get the full path of an asset? I've written a simple plugin that attaches to the onSaveEntry event. I'd like to access the image, extract the colours from the image using https://github.com/brianmcdo/ImagePalette and then save these colours to a field. I've managed to access the entry, but can't seem to find how to get the path and filename of the image?

Any help would be greatly appreciated!

Thanks

You should be able to get it with the getURL() method?

Something like this should work (NB! have not tested the code myself):

$image = $entry->image->first();
if ($image) {
    $url = $image->getUrl();
}


How do I set up the Rich Text Editor Field (Redactor) for code snippets? I'm trying to set us the Rich Text Editor for inputting code snippets. I've almost got it working except when I go back to edit the entry Redactor removes spaces I entered to format the code. Also setting the tabAsSpaces doesn't seem to work. It still adds tab space.

Here is what I have in Redactor config.json

{
    toolbar: false,
    visual: false,
    tabAsSpaces: 2,
    cleanOnPaste: false,
    cleanSpaces: false,
    cleanStyleOnEnter: true,
    paragraphize: false,
    minHeight: 200
}

And in the template

{% spaceless %}

    {{- block.html|replace({'&':'&amp;', '<':'&lt;', '>':'&gt;'})|raw -}}

{% endspaceless %}

Not sure if it helps, but I accomplished this using a plain text field (with multi-line enabled). Then I just used CSS to format the field in a way to make it look like a code snippet...

Screenshot of field in the Control Panel:

I used the Control Panel CSS plugin to add this CSS:

#fields-myfieldhandle textarea.nicetext {
    font-size: 13px;
    font-family: Menlo, Monaco, monospace, sans-serif;
    color: #cccccc;
    background-color: #222222;
    padding: 14px 16px;
}

Then, in my Twig template, I display it like this:

{{ block.code|e }}

May or may not be the solution you're looking for, but I've been very satisfied with it!


Organize Entries in Admin Panel I'm trying to sort the entries. Is there a way to do this without using the filters given? Can this be done manually?

Are you wanting to drag entries up and down to sort them? As far as I'm aware the only way to order manually would be to use a Structure and not a Channel.

Alternatively if you just want to manually order them for use in a for loop (such as showing news items), you could add an entries field somewhere (in a global, a news page, a homepage, or somewhere else convenient). Then you can reference that list for your entries output. That would let you manually order them.


How does the allowAutoUpdates setting differentiate? I'm not quite sure from the documentation what the difference is between 'minor' and 'build' updates.

How would the allowAutoUpdates general config setting have treated the update from 2.4.2726 to 2.5.2750?

What would happen when the 2.5.x update was released, depending on whether that setting was true, minor or build?

Craft's version numbers follow this pattern:

major.minor.build

So your update was a minor update and you could have blocked it with the settings build-only or false.


How to do CSS/JS bundles/minifying in Craft 3 I would like to combine all of my sites JS-files into one bundle - and perhaps also obfuscate it.

Same goes for CSS-files.

How would I do that in Craft CMS 3?

Craft doesn't output any code unless you write it, so you have complete freedom to use any standard front end build process and include the built files in your templates. There are a few plugins that help with this depending on build process though, such as:

https://plugins.craftcms.com/mix
https://plugins.craftcms.com/twigpack
https://plugins.craftcms.com/minify
https://plugins.craftcms.com/assetrev


Execution timeout problem when trying to add new field I've been having some problems since I've updated yesterday to craftcms v3.4 (was 3.3). When I try to add a new field via the admin, it takes an enormous amount of time (almost 5min, had to raise the nginx timeout and php execution timeout) on my local dev setup.
Amount of fields I have are pretty minimal for now.
I'm running following craft plugins:

"aelvan/imager": "^2.3",
"barrelstrength/sprout-fields": "^3.5",
"clubstudioltd/craft-asset-rev": "^6.0",
"craftcms/cms": "^3.0.0",
"craftcms/redactor": "^2.4",
"mikestecker/craft-videoembedder": "^1.1",
"sebastianlenz/linkfield": "^1.0",
"verbb/navigation": "^1.2",
"verbb/super-table": "^2.3",
"vlucas/phpdotenv": "^3.4.0"

Does anyone have an idea what the problem could be? Doesn't feel very manageable at the moment.

Thanks in advance.

Some common steps to find the culprit.

Always work in dev mode
Enable Debug Toolbar or read the brief tutorial by nystudio107
Disable all the custom plugins one-by-one.
Once development is done, switch to production mode and disable log.
Adjust Mysql and Server minimum configuration based on your site load.
There is no need to use multiple cache strategy.
Activate useful admin dashboard widget only.
On the entries page, activate the most useful Table Columns only.

Check system report information in the dashboard, make sure all the suggested requirements are fulfilled.


Count all unique values We are building a family community website with more than 600 members all over the world.

In craft.users we have added many fields and one of them is country.

We want to display and count all countries.

Example of the desired output could be something like:

Our members are living in the next 5 countries

the Netherlands (545)
Chili (26)
USA (14)
Italy (6)
Sweden (8)

Something like this should do the trick:

{% set usersGroupedByCountry = craft.users.limit(null)|group('postaddress.country') %}

    {% for country, users in usersGroupedByCountry %}
        {% if country and users|length %}

{{ country }} ({{ users|length }})

        {% endif %}
    {% endfor %}

Note that if you want to order the list of countries, you'll need the SuperSort plugin. Here's how you would sort the list alphabetically:

{% set usersGroupedByCountry = craft.users.limit(null)|group('postaddress.country)|supersort('ksort') %}

Also note that if you have a lot of users (say, hundreds), it is probably a good idea to wrap the whole thing (including the {% set usersGroupedByCountry ... %} part) in a {% cache %} tag pair, for performance reasons.


Sort entries by a related entry (lastName) and then paginate I have two channels books and authors

I need to list all books sorted alphabetically by author. I have this working with the following code:

    {#
    // loop through authors so we can sort books
    // by author last name
    #}
    {% for author in craft.entries.section('authors').order('lastName').all() %}

        {# find all books related to the author #}

            {% for entry in craft.entries.section('books').relatedTo(author).all() %}

{{ entry.title }}

            {% endfor %}{# end books for each author #}

    {% endfor %}{# end authors #}

This works fine, but I"m not sure how to paginate this. I want to paginate the books which is the nested loop and will likely only contain 2-4 books per author.

If I paginate the authors loop I'll have 5 authors per page but each author will have a different number of books so each page will have different number of books. Not what I want.

If I paginate the book loop it's not going to see all the books only the ones from the author of the current author loop.

However the total number of books is 100+. How do I paginate the total number of book results.

--------------

If it were possible to do the alpha sort based on the related field without nesting for loops that would be ideal? Is this possible?

------------- UPDATE ----------------

add a new field to the books channel where the authors last name is manually added and now using .order('authorLastName') which works but it clunky becaue they have to select the author from the authors channel and add in their last name in a second field.

If I understand correctly, then it may be better to loop through the books rather than the authors, then group by author. I'm not 100% on this syntax but may send you down a good path...

Set the query

{% set query = craft.entries.section('books').order('author.lastName').all()|group('author.lastName') %}

Loop and divide

{% paginate query as pageInfo, pageEntries %}

{% for author, books in pageEntries %}

{{ author.lastName }}

        {% for book in books %}

{{ book.title }}

        {% endfor %}

{% endfor %}

{% if pageInfo.prevUrl %}Previous Page{% endif %}
{% if pageInfo.nextUrl %}Next Page{% endif %}


Create a Structure page with entries list I have created a Structure page 'Products' with a URL of '/products' so that I can write a description etc, but then I would also like to pull in the Products into the template. I'm a little unsure on how best to achieve this.

The Sections are created as follows;

Page
Handle: page
Type: Structure
URL Format: {slug}
Entry Template: page/_entry

Product
Handle: product
Type: Channel
URL Format: products/{slug}
Entry Template: products/_product

In ExpressionEngine I would have pulled in a Channel entries tag for the page and then another entries tag for the products.

If your channel is products, you list them like this on their index page (which is presumably your '/products' page)

{% for p in craft.entries.section('products') %}
  {# p is our product. display it however #}
  {{p.title}}
{% endfor %}


Smart Map plugin, HAVING SQL and GROUP BY elements.id It seems like most Craft queries contain GROUP BY elements.id but this seems to clash with a HAVING clause when using the Smart Map plugin.

Where does this come from and is it possible to override/remove this?

The HAVING clause comes from this piece of code:
// Modify query
$query
    ->addSelect($haversine.' AS distance')
    ->having('distance <= '.$filter->range)
;

The variables going into this query modification are:

$haversine - A complex formula which determines the relative distance of each address from the center point.
$filter->range - The maximum search distance. (defaults to 25)

This code exists so that your proximity search results can be sorted by closest locations. It will be triggered any time you chain this into your Twig query:
.myFieldHandle(params)

You can see the full details of how this all ties together in the documentation here:

https://plugins.doublesecretagency.com/smart-map/sorting-entries-by-closest-locations/

There should be no conflict with any existing GROUP BY clause... Smart Map does not set or modify that aspect of the query. And there is no inherent conflict between HAVING and GROUP BY, as demonstrated by this w3schools example, which utilizes both in combination.


Public link for an invoice When an order is submitted on the Craft Commerce website I'm currently building, an email is automatically sent to the customer. Inside this email is a link to download an invoice for that specific order.

I had accomplished this by putting the following link into my emails

Download your invoice

It's not ideal as you could actually download any invoice by changing the order.number, but we fixed that by using a url proxy.

But I realised a few minutes ago that this link is not public and requires a login. Which I don't want.
Is there any way to generate a public link for the invoice?

You could write a simple plugin, that exposed an anonymous controller action that mimicked Commerce's Commerce_DownloadsController's actionPdf() method.


A&M Form Table Field Submission I'm trying to submit a form containing items from a users' cart, using A&M forms, but cannot seem to populate the table field with the items. I'm using the code below:

{% for item in cart.lineItems %}
    <input type="hidden" name="fields[selections][{{loop.index}}][col1]" value="{{item.qty}} x {{item.description}}">
{% endfor %}

For some reason, though, it's creating the rows in the table, but not actually populating it with any content. Any idea what to do to get it to work?

Thanks!

I know I'm a bit late to this, but I think it's because your {{ loop.index }} is not 0-indexed, which is necessary for the array.  It should look like this:

<input type="hidden" name="fields[selections][{{ loop.index0 }}][col1]" value="{{ item.qty }} x {{ item.description }}">

You also need an extra valueless hidden field above the loop to collect all the values into one array:

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

You can see a fuller example on how to format the HTML for all fields of all types on this StraightUpCraft page.  Scroll to the very bottom for tables.


Sort entries by global variable category I'm picking a season category (spring, summer, fall, winter)  in a global variable that should dictate what entries come to the top of non-season category pages. These entries are already on a category page, sorted by their main category. I need extra sorting to showcase the "Spring" entries, for instance. Something like this:

Without the season global variable chosen

Test post 1 (Summer)
Test post 2 (Spring)
Test post 3 (Spring)
Test post 4 (Winter)
Test post 5 (Winter)

With the global variable "Spring" chosen

Test post 2 (Spring)
Test post 3 (Spring)
Test post 1 (Summer)
Test post 4 (Winter)
Test post 5 (Winter)

Basically, I want to bring the entries that are using the chosen Global Variable Category to the top, the remaining entries can be sorted by postDate descending. These entries are in a Structure btw, if that matters.

Structure = 'generalContent'
Category Field = 'season'
Global Variable = 'season.season'

Simplified code of my category page.

{% paginate craft.entries.section('generalContent').relatedTo(category).order('lft desc') as entries %}
  {% for entry in entries %}
    {{ entry.title }}<br>
  {% endfor %}
{% endpaginate %}

One solution is to retrieve the entry ids for the season entries and all entries separately; subtract the 'season entry ids' from 'all entry ids' (using craft's without twig filter); then merge the two arrays back together (using twig's merge filter) in the proper order. You can then use this new id array to generate an elementCriteriaModel which can be used in your paginate expression.

{% cache %}
    {% set season = season.season.first() %}
    {% set seasonEntryIds = craft.entries.section('generalContent').relatedTo(season).order('lft desc').ids() %}
    {% set allEntryIds = craft.entries.section('generalContent').order('lft desc').ids() %}
    {% set nonSeasonEntryIds = allEntryIds|without(seasonEntryIds) %}
    {% set sortedEntryIds = seasonEntryIds|merge(nonSeasonEntryIds) %}

    {% paginate craft.entries.id(sortedEntryIds).fixedOrder(true) as entries %}
        {% for entry in entries %}
            {{ entry.title }}<br>
        {% endfor %}
    {% endpaginate %}
{% endcache %}

Since there are a lot of queries happening here, it might also be a good idea to wrap the code in 'cache' tag.


Why is category.getUrl() returning incorrect subdomain? Forgive me if this is a server configuration or other issue unrelated to craft, but perhaps someone has some insight on what might be causing this, and how to fix it.

When using a simple category.getUrl() for subnav, I am getting odd results where the subdomain is not 'www', but instead something else, like 'ddd' or 'w2w'. This is only happening in the production environment. And results vary depending on which page the nav is included on. Very strange.

{% set categories = craft.categories.group(group).all() %}
{% for category in categories %}
    {{ category.title }}
{% endfor %}

Any ideas are much appreciated? Thank you.

Looks like the problem was using @web for the 'Base URL' setting in 'Settings > Sites'.

I replaced this with an environment variable BASE_URL="https://www.domain.com" defined in the .env file, and setting $BASE_URL in the 'Base URL' field.

No idea why @web doesn't work reliably here, but so be it.

Feel free to delete this question, but I thought I would leave it for others who may encounter the same problem.


Posting children to a Structure This question is a follow up of a previous question see: (Entry Form - Multiple Entries & Entry Type & Parent)

I am trying to add multiple children to a pre-existing multi level structure:

Level 1
--Level 2 (The parent where I am adding the children)
----Child 1
----Child 2
..etc

My Controller:

public function actionSaveAnimals(){
$this->requirePostRequest();

if($rodentsData = craft()->request->getParam('rodent')){
  $rodentErrors = [];
  foreach ($rodentsData as $rodentData){
      if (array_key_exists('entryId', $rodentData) && $rodentId = $rodentData['entryId']) {
          if (!$rodent = craft()->elements->getElementById($rodentId)) {
              throw new Exception('Could not find rodent with the given Id');
          }
      } else {
          $rodent = new EntryModel();
          $rodent->typeId = 6; // change your entryType Id here
          $rodent->sectionId = craft()->request->getParam('sectionId');
          $rodent->parentId = craft()->request->getParam('parentId');
          $rodent->authorId = craft()->request->getParam('authorId');
      }

      $rodent->getContent()->setAttributes($rodentData['fields']);

      if (!craft()->entries->saveEntry($rodent)) {
          $rodentErrors[] = $rodent->getErrors();
      }else{
          $rodentErrors = [];
      }
  }
  // include errors of each item
  craft()->urlManager->setRouteVariables(array(
      'rodentErrors' => $rodentErrors
  ));
}

}

And my form:

<form method="post" accept-charset="UTF-8">
{{ getCsrfInput() }}
{# your plugin name and function name #}
<input type="hidden" name="action" value="experiment/SaveAnimals">
{# the id of your section for me its 4 you need to change this value to your section Id #}
<input type="hidden" name="sectionId" value="4">
{# enable the entry #}
<input type="hidden" name="enabled" value="1">
{# id of your entry leave it blank to insert a new entry, insert a id to change an existing entry#}
<input type="hidden" name="entryId" value="">
<input type="hidden" name="parentId" value="{{ entry.id }}">
<input type="hidden" name="authorId" value="{{ currentUser.id }}">

    Amount of Animals
    {#<input class="pa3 input-reset ba bw0 br2 w-100" type="number" id="Cage__Amount" placeholder="5" max="10" required>#}
    <input type="text" name="rodent[0][fields][title]" value="Add Identifier">
    <input type="text" name="rodent[1][fields][title]" value="Add Identifier">

  <button class="bg-dark-blue white ph3 pv2 input-reset pointer ba bw0 f5 dib lh-copy w-100" type="submit">Create experiment</button>

I am currently getting this error:

Trying to get property of non-object

From EntriesService.php(468)

if ($entry->getSection()->type != SectionType::Structure)

Any help much appreciated!

The section ID was incorrect - set correctly and this function works.


Table fields, default single empty row, and never returning as empty? I'm having a small problem with table fields. My issue is that by default a table fields starts with one row. Even if you leave this row empty (no values at all in any column) the field will never return as empty because that row exists even though it has no value. In order to get an empty field check like this to work:

{% if entry.whiskeyTableHandle | length %}

You have to actually delete that first empty row rather than simply leave it blank.

I cannot count on my client to remember to delete the row to indicate an empty field.

Would there be any way to have the table field show in the CP publish page with no rows visible by default? That means if nothing is added to the field it will properly return as empty.

You could test if the first cell is empty

{% if entry.whiskeyTableHandle|length and entry.whiskeyTableHandle[0][0] %}
{% endif %}

Or you simply remove all default rows in the field’s settings.


Generate previews of PDF files (Craft 3) Is it possible to auto-generate PDF preview images with Craft 3 transforms?

Or are there any Craft 3 plugins that do this? I see a few Craft 2 versions.

I created a plugin specifically to do this -
https://github.com/bymayo/craft-pdf-transform

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

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


Uploading Asset Doesn't Clear GraphQl Cache with VueJS/Axios Context:
I have a VueJS method that uses a form and Axios to upload an asset to an entry's asset field.
The method successfully uploads the asset to the entry, and I can prove that fact via the CraftCMS admin interface. So this works.

Problem:
I then have another VueJS method that calls on CraftCMS' GraphQL service to list the assets in the entry's asset field. This works, and returns the assets. But if I add more assets using my VueJS/Axios method above, the assets are added just fine (as confirmed on the CraftCMS admin side), but the GraphQL cache is not updated. So when I refresh the page and make another call to GraphQL, it never shows the new asset(s) unless I manually clear the GraphQL cache in the Craft CMS admin interface.

Questions:

Can I force the GraphQL cache to be cleared from some kind of javascript / Axios call, or some kind of Twig call on the same page as it loads?
Can I prevent GraphQL from caching?
Is this a GraphQL/CraftCMS bug?
Amy I crazy to think any of this?

Thanks for any ideas/help!

VueJS Method to Load the Asset list

  created () {
    //Define a global self variable
    var self = this;
    //Load our query
    var queryData = {query: '{entries(section:"caseStudy",id:{{entry.id}}) {...on caseStudy_caseStudy_Entry{id,csImages{id,url,}}}}'};
    //Get authorization
    var queryHeaders = {headers: {'Authorization': 'Bearer ABCDEFG'}};
    //Fetch data from the system using our query
    axios.post('/api', queryData, queryHeaders).then(function(queryResponse) {
        //Set the uploadAssets data.
        self.uploadedAssets = queryResponse.data.data.entries[0].csImages;
      }).catch(function (queryError) {
        console.log(queryError);
    });
  },

self.uploadedAssets Will contain the assets on the asset field as desired. But if I upload new assets using the following VueJS method, GraphQL won't see the new asset(s), but I can prove that they uploaded just fine bucasue in the CrafCMS admin side I can see the news asset(s) in the entry form.

VueJS method to upload the asset to CraftCMS, which works fine.

 uploadImage(event) {
  //Get the current form data
  var formData = new FormData(document.getElementById('formCaseworkEdit'));
  //Upload the form data to CraftCMS
  axios.post('/', formData).then(function(response) {
      //Call a function to retrieve the new list of assets
      self.getNewImage(response, self);
    }).catch(function (error) {
      console.log(error);
    });
 },

self.getNewImage(response, self); Will run the same GraphQL Query from the create() function , but will return the "old" listing of assets. When I manually clear CraftCMS caches, this list returns the new items.

Welp, as they say, "There's a config setting for that" - :facepalm: - If you add the following to your /config/general.php file it will disable GraphQL caching completely:

  //Disable GraphQL Caching
  'enableGraphQlCaching' => false,

To reference it from a .env environment variable use this instead:

  // Disable GraphQL Caching from .env variables
  'enableGraphQlCaching' => (bool)getenv('ENABLE_GQL_CACHING'),

Got this info from the amazing folks over at nystudio107 via this post:
https://nystudio107.com/blog/using-the-craft-cms-graphql-api-on-the-frontend

Ideally if there was a way to flush the GraphQL cache at the time I need it that would be more precise, but disabling the GraphQL cache all together solves the problem.


Craft 3 User Registration form errors not showing for custom fields I've built a front end user registration form and everything is working well with it except that it's not showing errors for my custom fields. They're set as required in the CP, but the form submits even if they aren't filled in. When the standard required fields aren't filled in the for returns an error but none for the custom fields.

I understand first and last name can't be required. In the example below my custom required fields are participantPhone and participantCity.

<form method="post" accept-charset="UTF-8">

      {{ csrfInput() }}
      <input type="hidden" name="action" value="users/save-user">
      {{ redirectInput('sign-up-ty') }}

      {% macro errorList(errors) %}
        {% if errors %}

            {% for error in errors %}

{{ error }}

            {% endfor %}

        {% endif %}
      {% endmacro %}

      {% from _self import errorList %}

      <input id="username" class="form-control" type="text" name="username" {%- if user is defined %} value="{{ user.username }}"{% endif -%} placeholder="username">

      {% if user is defined %}
        {{ errorList(user.getErrors('username')) }}
      {% endif %}

      <input id="firstName" class="form-control" type="text" name="firstName" {%- if user is defined %} value="{{ user.firstName }}"{% endif -%} placeholder="first name">

      <input id="lastName" class="form-control" type="text" name="lastName" {%- if user is defined %} value="{{ user.lastName }}"{% endif -%} placeholder="last name">

      <input id="email" class="form-control" type="text" name="email"{%- if user is defined %} value="{{ user.email }}"{% endif %} placeholder="email">

      {% if user is defined %}
        {{ errorList(user.getErrors('email')) }}
      {% endif %}

      <input id="password" class="form-control" type="password" name="password" placeholder="password">

      {% if user is defined %}
        {{ errorList(user.getErrors('password')) }}
      {% endif %}

      <input id="participantPhone" class="form-control" type="text" name="fields[participantPhone]" {%- if user is defined %} value="{{ user.participantPhone }}"{% endif -%} placeholder="phone">

      {% if user is defined %}
        {{ errorList(user.getErrors('participantPhone')) }}
      {% endif %}

      <input id="participantCity" class="form-control" type="text" name="fields[participantCity]" {%- if user is defined %} value="{{ user.participantCity }}"{% endif -%} placeholder="city">

      {% if user is defined %}
        {{ errorList(user.getErrors('participantCity')) }}
      {% endif %}

      <input id="register-button" class="btn btn-outline-primary" type="submit" value="Register">

  </form>

From the code

// Don't validate required custom fields if it's public registration
if (!$thisIsPublicRegistration) {
    $user->setScenario(Element::SCENARIO_LIVE);
}

You have to create a custom controller


A-Z filter menu - limiting output to one when there are multiples I have a A-Z menu to filter entries by their first letter.

ALL

    {% for entry in craft.entries.section('membershipDirectory').order('title asc') %}

{{ entry.companyName|slice(0, 1) }}

    {% endfor %}

Issue I have is if there are 4 entries beginning with 'C' the output will be:

A B C C C C D E F...

Can I limit each letter once so I'll get 1 'C' is there are 1+ entries starting with 'C'?

UPDATE:

I'm now getting the right number of instances created but no text inside my . Likely a rookie error somewhere:

{% set allEntries =
craft.entries.section('membershipDirectory').order('title asc') %}
{% set allEntriesByFirstCharacter =
 allEntries|group('companyName|slice(0, 1)|lower|replace("/[^a-z]/",
 "0-9")' ) %}

ALL

    {% for allEntries in allEntriesByFirstCharacter %}

{{ entry.companyName|slice(0, 1)|lower|replace("/[^a-z]/", "0-9") }}

  {% endfor %}

You can use the group filter and create a 2d array with the letter as the first index and the entries as second index.

{% set allEntriesByFirstCharacter = allEntries|group('companyName|slice(0, 1)|lower|replace("/[^a-z]/", "0-9")' ) %}

The string passed in the filter will get rendered as an object template an equal results will be grouped by the same key.


Craft Commerce eWAY payment error I am having some problems on integrating Craft Commerce with eWAY.
When I submit the payment form, I get this error:

  Error: [Payment error: EWAY_CARDNAME Required, EWAY_CARDNUMBER Required, Invalid EWAY_CARDEXPIRYMONTH, Invalid EWAY_CARDEXPIRYYEAR, EWAY_CARDCVN Required]

Should the eWAY gateway plugin be converting the form input field names to these eWAY field names?

Which eWay are you implementing?

We have used eWAY Rapid Direct with no issues for over a year now with Commerce.

They key most people seem to miss is that you must implement the CSE - Client Side Encryption part of the eWay process before the gateway submission to eWay will wok.  This is documented by eWay here:

https://eway.io/api-v3/#how-it-works

In essense you just need to include some JS on your payment form page.  On that page you accept the card number etc pretty much as normal, but before you pass it to eway is must be encrypted on the client machine.  Here's some scrappy JS to show what I mean first include the eWay JS:

                    {# Include EWAY CSE JS #}
                {% if craft.config.devMode %}
                    <script src="https://secure.ewaypayments.com/scripts/eCrypt.debug.js"></script>
                {% else %}
                    <script src="https://secure.ewaypayments.com/scripts/eCrypt.js"></script>
                {% endif %}

...and in your payment form have something like this as you will need it later (I store my key in the commerce config file so I can set a dev vs live one based on environment, but you could jstu hardcode it below or whatever):

              {% set paymentMethods = craft.commerce.paymentMethods %}
                  <input type="hidden" name="CSEKey" value="{{ paymentMethods[1].settings.CSEKey }}">

Then, you need to deal with the actual encryption side of things...something like this should do it for you:

        var method = $('input[name=paymentMethodId]:checked', '#submitOrder').val();

    if (method == 1) {
        // EWAY Client Side Encryption - See https://eway.io/api-v3/#encrypt-function

        // EWAY CSE - encrypt the card number and the CCV on the client's machine so it's never seen by us or anyone else.
        // Pull the values from the test input fields (fake*)
        // and inject the encrypted version into the real fields
        var $fakeCardNumber = $("#fakeNumber");
        var $fakeCcv = $("#fakeCvv");
        var $cardNumber = $("input[name=encryptedCardNumber]");
        var $ccv = $("input[name=encryptedCardCvv]");

        // get the unencrypted values and remove all spaces from the numbers
        var cardNumber = $fakeCardNumber.val().replace(/\s/g, "");
        var ccv = $fakeCcv.val().replace(/\s/g, "");

        // and now re-set them to the encrypted values if these are actually filled in
        if (cardNumber) {
            $cardNumber.val(eCrypt.encryptValue(cardNumber, CSEKey));
        }
        if (ccv) {
            $ccv.val(eCrypt.encryptValue(ccv, CSEKey));
        }
    }

That's not the most beautiful code, but I think once you've implemented that (which you need tom to be compliant with eWay) - you will find things drop into place easily enough from there.


Altering Structure order doesn't update cache I have 2 structures that are used for Menus on the site. Each entry is a link to either an entry / asset or external URL. The hierarchy is used to generate a menu .

To save on page load time, the two menus are both wrapped up in {% cache globally %} tags which has worked really well to speed up things.

My problem is that when altering the position / hierarchy of the structure entries from Craft, the front-end doesn't update accordingly which I can only put down to the cache blocking the update, as the structure isn't re-triggering the cache update.

Any tips for long term maintenance on this site feature? Some of the content editors will want to alter this stuff, but without disabling the cache myself? The only user that can manually flush the template cache is myself, the admin.

Thanks in advance y'all!

Merry Christmas! :-)

After Greg Stewart's help I found that the reason that the Cache wasn't updating when altering the hierarchy of the Structure is:

There were Stuck background tasks.

Here is the official documentation on the matter.


Front end edit: entry doesn’t get saved I am trying to make entries editable from the front end and pretty much follwed the docs.

When i visit my edit view, the entry-from is filled with their respective values but unfortunately no changes are being saved back when i update those and submit. A redirect is also not happening. The old form just loads again.

Not errors too. The site is localized so could this be a problem? Should i add the locale to my inputs?

I've run into this situation in various scenarios as well where a front-end entry form fails to save anything and just seems to be reloading the page. Almost always it has had to do with overlooking a required field or some other small detail, as Douglas mentions in his comment.

If all of your fields are not required, make sure you are still setting fields like the Title field, which are necessary for your Entry to save properly.

One way to help troubleshoot is to take a look at all of the errors you are getting back. If you are just trying to output errors for the fields you are submitting you may be missing seeing an error for another field that is giving you an error but that you are not outputting.

When a front-end entry form fails to submit, Craft will add any errors to the EntryModel and return it to the page. If you have devMode enabled, you can dump all of the errors from your submission with the following line of code to help troubleshoot:

<pre>{{ dump(entry.getErrors()) }}</pre>


Removing x-powered-by and changing cookies names for security? I noticed that anyone interested in finding out what software is used for my website could find that out very easily just by looking at the headers and cookies received by craft.
You can find two headers that will expose craft:

"Set-Cookie": "CraftSessionId=".
"X-Powered-By": "Craft CMS".

Thats concerns me because if any security vulnerability will be found on craft, than immediately my site could be more exposed to threats. also, it will be easier for attackers to plan an effective attack against my website, because using craft means that i use SQL, php, twig and more.

I understand that it helps spreading the word on the cms. But i thinks that in some cases it may be better to remove it.

I have two questions:

Will it be against the terms and agreements of craft to remove those headers?
Will writing a plugin for it be the best way, or maybe there is a better way?

Thanks ahead!

Will it be against the terms and agreements of craft to remove those headers?
Will writing a plugin for it be the best way

No to both questions – just add the following config values to your /config/general.php file:
'sendPoweredByHeader' => false,
'phpSessionName' => 'WhateverYouWant',

Also, check out this excellent post by Brad Bell on the topic of Craft and security.


Is there any way to adjust the width of the custom field in the admin panel? I want to adjust the width as ( 25%, 50%, 75%, or 100%) of the custom field in the admin panel.

You can adjust it by following below steps:

First go to Settings > Sections > Select Edit Entrytype of a section.

Then choose your Custom field and then you find four pieces block icon on the right upper corner that are used to set the width of the field in the entry form. So you can adjust width by clicking on that particular block.

For Ex-  If you want to set width 50% then you have to choose 2 blocks. Each block contain 25% of 100% width


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

https://craftcms.com/docs/templating/user-registration-form

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

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

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

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


Filter out part of _layout on a specific template I have a site consisting of 15 templates, all of which extend _layout.html.  There is just one page (homepage) which needs to omit a chunk of the _layout.html.  Is there something I can add to _layout which says "if I'm on the homepage leave this chunk of code out"?

Many thanks

Martin

Sorry... while searching for an answer to something else I discovered the solution to this :/

{% if craft.request.getSegment(1) != index.uri %}

    .... leave this chunk of code out

{% endif %}


Is it possible to allow logging at LEVEL_INFO without logging all the SQL queries? We're currently logging our site at LEVEL_INFO to have a good idea of what's happening on the site. We find it useful, and appropriate, to log informational messages at that level rather than at ERROR or WARNING. However most of these INFO messages are drowned out by the sheer volume of SQL query logging. I did some digging and found that Yii DB Connections can be configured to not log all the queries.

https://github.com/yiisoft/yii2/blob/ec089fea5a684de1e358995bf36522ec6834e71b/framework/db/Connection.php#L410

This setting is then checked here:
https://github.com/yiisoft/yii2/blob/bdb7c6491061b48c16b0fdbcba791ccd514a91d9/framework/db/Command.php#L1112

Ideally we'd like to be able to log queries at the TRACE or DEBUG level but it doesn't look to be possible.

Is there a simple way to disable the logging in the craft config? If not Would it be possible by extending an existing Craft class?

Any pointers or help would be appreciated. Thanks in advance!

This is what we ended up using.

<?php
    return [
        'components' => [
            'log' => [
                'targets' => [
                    [
                        'class' => PsrTarget::class,
                        'logger' => $logger,
                        'levels' => [YiiLogger::LEVEL_ERROR],
                        'logVars' => [],
                        'addTimestampToContext' => true,
                    ],
                    // Split the targets to specifically exclude classes which spam the logs, while
                    // ensuring errors thrown in those classes are still logged.
                    [
                        'class' => PsrTarget::class,
                        'logger' => $logger,
                        'levels' => $logLevels,
                        'except' => [
                            'yii\base\View::renderFile',
                            'yii\db\Command::*',
                            'yii\db\Connection::*'
                        ],
                        'logVars' => [],
                        'addTimestampToContext' => true,
                    ],
                ],
            ],
        ],
    ];


My plugin's custom fields don't show values when entry saved as draft When entries with plugins custom fields are saved as a draft, the data previously entered in the custom field is not visible. It is saved in the database but doesn't show in the edit screen.  The data will show in the fields when the entry is published.

  {{ forms.dateTimeField({
    label: "Start Date"|t,
    instructions: "When should the event start?"|t,
    id: 'eventStartDate',
    name: name~'[startDate]',
    value: (fieldData ? fieldData.startDate : null),
    errors:''
  }) }}
  {{ forms.dateTimeField({
    label: "End Date"|t,
    instructions: "When should the event end?"|t,
    id: 'eventEndDate',
    name: name~'[endDate]',
    value: (fieldData ? fieldData.endDate : null),
    errors: ''
  }) }}

Is there a different way to output the data to the template so it shows in both?

When you save a draft, all of the fields’ POST data is saved in the craft_entrydrafts table, exactly as it showed up in POST. When the draft is loaded, it’s that raw POST data that is passed to your field type’s getInputHtml() method - not whatever the field type would have returned in prepValueFromPost().

So your getInputHtml() method just needs to be aware that there’s a chance that the $value passed to it may be raw POST data, and react accordingly in that case.

If your field type is storing dates and you’re using Craft’s built-in date/time templates (_includes/forms/date.html and _includes/forms/time.html, which are rendered by that dateTimeField() macro in _includes/forms.html), then the POST data will look like this, for whatever input name you passed in.

array(
    'date' => '[localized date string]',
    'time' => '[localized time string]'
)

That looks like it would be tricky to deal with. Thankfully, Craft’s DateTime class has a handy-yet-awkwardly-named createFromString() static method which will check to see if a passed-in value follows that array format, and normalize it into an actual DateTime object for you, taking the localized date/time formats and timezones into account for you.

So all you need to do, from your get field type’s getInputHtml() and prepValueFromPost() methods, is check to see if $value['startDate'] and $value['endDate'] are arrays, and if so, run them through DateTime::createFromString().

We happen to have an existing field type that does the same thing: Store Hours. Rather than dealing with just two dates per field, it's actually dealing with with 14 (an Open and Close time for each day of the week), but it should be easy enough to adapt its code for your needs. Here’s its field type file: https://github.com/pixelandtonic/StoreHours/blob/master/storehours/fieldtypes/StoreHoursFieldType.php