Setting shipping costs on a per-product basis Folks:

I've got a client with very specific shipping requirements. Essentially, he wants to assign specific shipping costs for every single zone for every single product. Like this:

Product A shipping to Canada = $25
Product A shipping to Continental US = $40
Product A shipping to Alaska and Hawaii = $60
Product A shipping to Europe Zone 1 = $100
Product A shipping to Europe Zone 2 = $125
Product A shipping to Europe Zone 3 = $150
Product A shipping to Asia Zone 1 = $200
Product A shipping to Asia Zone 2 = $220
Product A shipping to Asia Zone 3 = $230

Now multiply this by 25 products. And he wants to be able to change the shipping costs whenever he needs to so it will be essential that he can adjust it from the backend rather than through code.

Any thoughts on this? My initial idea was to use the Default Item Weight Rate option and have each product assigned a weight. Of course, the weight wouldn't reflect the actual weight of the product, it would just be a way of easily adjusting the shipping rate. The problem I see is that adjusting the weight would adjust the shipping cost across all zones rather than just the zone he wants to change.

Is my only option then to create a shipping category for every product and using Category Rate Overrides?

Were I doing this, I would create a single (or an entry, or a global I guess) with a table (or maybe Matrix) field that would hold the shipping price chart.

I'd then create a custom shipping plugin in Commerce, that references this data and returns the shipping cost.

This would give a very nice UI for editing the products shipping, and would be a simple plugin to make.

Here's an example function that gets rate from a table:

public function getRatesForZone($zone, $slug){

    $criteria = craft()->elements->getCriteria(ElementType::Entry);
    $criteria->section = 'freightData';
    $criteria->slug = $slug;

    $ratesTable = $criteria->first();

    $rates = [];
    foreach ($ratesTable->postRates as $row){

        if($row['destinationZone']==$zone){
            $rates = $row;
        }

    }

    // If we reach here we couldn't find rates, return nothing
    return $rates;

}

Beyond that you just implement a shipping rule/method - see  https://craftcommerce.com/docs/shipping-methods

In this case, a small amount of custom code  will give both a better result and better UI I think, rather than trying to shoehorn in to the methods Commerce provides (although note I have not really investigated the Commerce methods much of late - I find custom shipping is usually the more controllable way to go!)


Best way to delete submitted data in Sprout Forms? There are a few hundred form entries and manually going into each one and deleting sounds like far too much work!

Guess i could delete each form (there are 5) which would delete each form submisson. Then recreate the form again. Any other ideas? Thanks.

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


What's the differences between the Mailer and the Message classes? In the Craft 3 Class Reference (https://docs.craftcms.com/api/v3), there are two classes under craft\mail:

Mailer
Message

I found that I was able to send an email using this:

<?php

use craft\mail\Message;

$message = new Message();
$message->setTo('john@doe.com');
$message->setSubject("Hello world.");
$message->setHtmlBody("Hello world.");
$message->send();

But I found in some examples, like this one, that the email could be send using Craft::$app->mailer->send($message) instead of $message->send().

What's the difference between the Mailer and the Message classes? When should I use one instead of the other?

They're both valid options.

$message->send() is a wrapper for Mailer:

https://github.com/yiisoft/yii2/blob/master/framework/mail/BaseMessage.php#L41-L50

It will take an optional Mailer parameter.  If one is not passed it, it will default to the default Yii/Craft::$app->mailer and ultimately just call send() on it.


Why does loop.index not work with replace? Good day!

In Craft CMS 3, I'm tring to configure the replacement of tags for markdown via replace, everything works except for the tag {{ loop.index }}

Please tell me how to properly configure to work correctly {{ loop.index }}?

{{ block.markdownContent|markdown

 |replace('
', '
')
 |replace('
', '
')
 |replace('<a ', '<a class="link link-color"')
 |replace('
', '
')
 |replace('
', '

')
 |replace('
 ', '

')
 |replace('
', '
')
 |replace('
', '

{{ loop.index }}')
 |replace('
 ', '

')|raw }}

Can you advise other ways of realizing this task.

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

You should be using '

'~loop.index~''

The overall approach seems a bit heavy-handed though.


Is it possible to have lowercase globals? My question is simple and straightforward. Maybe I am making a mistake but it seems that all the text in a global field is always capital. I want to have 'Eng" in a global plain text field but it outputs "ENG"

If you have a global set named globalSet, and a plain text field in that set named textField, and the value you enter is Eng, then {{globalSet.textField}} will output Eng

Things that could be going wrong:

caps-lock: Did you enter ENG in the field in the first place?
|upper: {{globalSet.textField|upper}} will output ENG
CSS: text-transform: uppercase;
jQuery: $("*").text($("*").text().toUpperCase()); (or other jQuery)
all caps font
translations: {{globalSet.textField|t}} and a translation file with "Eng" => "ENG"

[edited to fold in suggestions from the coments - Marion]


Create new tables with a custom module Is it possible to create new tables in Craft when building custom modules or do you need to build a plugin for this?
Modules don't have the special "install" migration. So how does table creation work for modules? Is there a best practice for creating new tables for custom modules?

I was looking for an answer to this myself and found Running module migrations
It is basically saying you can only create the tables as part of your craft project - but not specific to your module. To create this project-wide migration run in your craft project folder (not your module folder):
php craft migrate/create [my_migration_name]

This will create the migration file and class in your craft's projects 'migrations' folder (it will display the exact path and file name after running the above command). For more info about the Migration class see https://craftcms.com/docs/3.x/extend/migrations.html#creating-migrations


Code for resending the activation email When logging in indicates the 'account has not been activated', how do I create a link for resending the activation email?

Update
I want users to be able to enter their email address in an input field and have that resend their activation link. Not in the backend, just frontend only!

I want to be able that users can enter their emailaddress in an input and that the activation link gets resend

You'll need to write a plugin, which can generate activation URLs using the UsersService:

echo craft()->users->getPasswordResetUrl($user);

If you want to send the user an activation email instead of echoing a link in the frontend, you can use the sendActivationEmail method instead:

craft()->users->sendActivationEmail($user);

Note that for both methods, $user should be an instance of UserModel, meaning you'll first need to pull the relevant user:

$user = craft()->users->getUserByEmail($userEmail);

As for the actual plugin implementation, it depends what you need/want (I'm guessing you're building your own login form/logic?). You could go with a basic template variable to output the activation URL:

Click here to activate your account now

...or you could create a controller which would provide a link for re-sending the activation email:

Click to resend activation email


Custom validation rules on frontend form What would be the best way to add some custom validation rules on forms submitted on the front-end without using specific field types for it?

I'm using the Guest Entries plugin that allows anonymous posts to the targeted section.  I'm new to Yii and Craft CMS and I cannot seem to find a way to extend the validation rules for the EntryModel (at least I suspect it needs to get done there).

If your validation rules are truly custom and aren't covered by the default Craft validation rules, the only way I can think of getting them into the Guest Entries EntryModel is to fork the plugin and add your own MyPluginEntryModel that extends EntryModel adding a rules method with your custom validation logic.

Read here for more details on that.


Calendar archives architecture I created a section on a site that shows a two-month calendar. The calendar has links to entries based on a release date. The release dates are created using a date/time filed. (Dates are different than the entry release date)

I'm very happy with the results so far. I took some ideas from this answer and a little flexbox magic. Everything is working great for the current/next month to show.

What I'm looking for is some ideas on how to display past dates. I want to create an "archive" section of the calendar where people can navigate to a month in the past to see the events that took place in that specific month.

Should I create a category group called "months" and then manually add months as they pass, changing the DateTime object?

Any ideas on the best way to display months in the past would be greatly appreciated.

You can get your past entries by month as explained here. Than it's just a matter of displaying them they way you want to.


Sort entry titles alphabetically excluding 'The'? I need to list the names of all of my entries in alphabetical order excluding 'the' (which could only be at the beginning). I've looked around online, but I was only able to find a code segment (which I've modified to fit my needs). However, it's still incorrectly sorting them as you can see in the attached image.

Current code:

{% for entry in craft.entries.section('partners').featuredMediaPartner('1').order('(CASE WHEN title LIKE "The %" THEN SUBSTRING(title, 3) ELSE title END ) asc') %}

Please help me fix this issue, thanks.

According to SUBSTRING, the first character starts at 1.  So if you wanted to start at the position immediate after The (with one space), you'd need to start at position 5.

Just did a test locally and it works as expected for me if I use:

.order('(CASE WHEN title LIKE "The %" THEN SUBSTRING(title, 5) ELSE title END ) asc')


What's the easiest way to migrate my local site data to my live site? I've finished my site locally, and would like to migrate my data to my production database.

I've already uploaded the templates, assets, etc, but I'm unsure how to 'dump and load' (referenced from this question ) my database to production.

I realize this may be a little bit more phpMyAdmin related, but I thought this question could help others who are just beginning work with Craft CMS!

Go into Utilities
Click "Database Backup", this will give you a .zip file of your data
Go into phpMyAdmin of your production site
Find your database, click Import
Upload .zip file


Does a plugin runs it's migrations on install? I'm developing a plugin, bumping the version number to run the migrations I'm creating but then, for sanity, checked they run when the plugin is installed for the first time, which doesn't seem to be the case.

Could someone clarify how to get the migrations to run on install?

The object of migrations is to provide a way for existing installations of your plugin to get the updated db schema as you update your plugin, without having to uninstall (which would mean they would lose all plugin data) and then reinstall your plugin.

  If your schema changes over the life of your plugin, you can write a migration to keep existing installations updated with the latest schema. Craft automatically checks for new migrations whenever a plugin’s version number changes.

https://craftcms.com/docs/plugins/migrations

This is because when a plugin is installed, Craft/Yii will go through your records and create the needed tables/columns as you have defined.

If a user downloads the updated plugin and replaces the current version, they won't have the new columns and things could break as they navigate and try to add data.

This is where migrations play an important role, they are to prevent existing users having to lose all plugin data by uninstalling and reinstalling, so when you change your plugin version, Craft will see there is an update and run through all the migrations to bring them up to the current version.

This is especially handy if for example someone has version 0.1.0 and they update to version 1.0.0, which could be quite a leap.

So in short, if you add new attributes to your plugin record, they will be added for new installations but migrations are only for existing installations


List Entries and Matrix I'm trying to list some entries from specific channel and get the access to matrix fields. The problem is that some of the entries are listed twice or even often. How do I remove the duplicates?

    {% for coupon in craft.entries.section('coupons').status('live').order('postDate asc') %}
        {% for content in coupon.contentBuilder %}
        {% endfor %}
    {% endfor %}

You'll have to build a list of the data and then display it.

{% set arr = [] %}

{% for coupon in craft.entries.section('coupons').status('live').order('postDate asc') %}
    {% for content in coupon.contentBuilder %}
        {% set arr = arr|merge([content.myUniqueFieldName: content]) %}
    {% endfor %}
{% endfor %}

{% for item in arr %}
    {{ item.title }}
{% endfor %}


Forcing creation of all transformations for all assets Regarding a similar question I only found the advice to delete a table in the database but because I don't like fiddling with the db very much I like to ask: Are there ways to force craft to generate all transformations for all assets/images?

There is such a function in ExpressionEngine in the CP and I try to replicate this behaviour. I also installed the ImageOptimize plugin for that reason but no luck with that also.

thank you very much!

Author of the ImageOptimize plugin... when you say no luck with that either, what is going wrong? Once you install ImageOptimize, and add an Optimized Images field type to your asset volumes, it will create all of those responsive image transform for you.

Check out the Using the Optimized Images Field section of the documentation.

It can't just create all of your image transforms for you, because unlike EE, you can create transforms via your frontend Twig templates as well, and there's no real way it can know what is being created there, or all of the possible permutations.


Array expecting string error when fieldtype is used within matrix Im getting an expecting string given array error on a variable in my fieldtype. When output / dumped to the template it is a string. This only happens when used within matrix field.

The trim function here is the specific line throwing the error:

$settings['colours'] = explode(',', str_replace(' ', '', trim($settings['colours'])));

getInputHtml() & prepValue()

public function prepValue($value)
{
    $colour = new FruitStyle_PaletteModel();

    if(is_array($value))
    {
        $colour->hex = $value['hex'];
        $colour->opacity = $value['opacity'];
    }

    return $colour;
}

public function getInputHtml($name, $value)
{
    craft()->templates->includeJsResource('fruitstyle/js/FruitPalette.js');
    craft()->templates->includeCssResource('fruitstyle/css/palette.css');
    craft()->templates->includeCssResource('fruitstyle/fonts/fruiticons/style.css');

    $id = craft()->templates->formatInputId($name);
    craft()->templates->includeJs('new FruitPalette("'.craft()->templates->namespaceInputId($id).'");');

    // String or JSON
    $settings = $this->getSettings();
    if(filter_var($settings['colours'], FILTER_VALIDATE_URL))
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_URL, $settings['colours']);
        $colours = curl_exec($ch);
        curl_close($ch);
        $settings['colours'] = JsonHelper::decode($colours, true);
    }
    else
    {
        $settings['colours'] = explode(',', str_replace(' ', '', trim($settings['colours'])));
    }

    return craft()->templates->render('fruitstyle/_fieldtype/palette/input', array(
        'id' => $id,
        'name' => $name,
        'value' => $value,
        'settings' => $settings,
        'specialOptions' => $this->_getSpecialOptions(),
    ));
}

It appears as though $settings['colours'] is an array... which you're then trying to trim and explode.

Can you var_dump($settings['colours'])?

p.s. Nice to see "colours" spelt "correctly" :)


Element API - 'String' to 'kebab-case' I want to convert a String into kebab-case.

'Hello there' -> 'hello-there'

I'm working in the Element API, so haven't got the pleasure of using the simple Twig filter. I guess there is a way of doing it in PHP. Any suggestions? Thank you

You can actually use the StringHelper::toKebabCase  function for this:

$string = 'Hello there';
$result = StringHelper::toKebabCase($string);
// => 'hello-there'


Listing categories alphabetically & total post count How do I list all categories in use alphabetically? And how to get the total post count from each category?

Cheers

The relatedTo param will do the trick:

{% set entries = craft.entries.limit(null) %}
{% for category in craft.categories.relatedTo(entries).order('title asc') %}
    {% set entryCount = entries.relatedTo(category).total() %}
    {{ category }} ({{ entryCount }})
{% endfor %}


Configure path craft uses for composer and php Is it possible to configure the PATH to composer that craft is using?
In a shared hosting (our server, lots of sites) php isn't available by default.
It's provided via redhat software collections. Each site can choose which version to run via environment variables. Since craft also uses composer; it means updates via it's web ui fail because when craft shells out to run composer; its not selecting which php it wants.

As I looked at it more and how php does environment variables; I discovered the thing that was different was the system $PATH variable.
In bash on linux; this is what sets the search order for trying to find executables like php and composer.
Run php -i from an command prompt and bash is search for an executable "php" in every folder of PATH. Note it stops when it finds the first match so the order of things in PATH is important.
So my problem is really that when craft runs a shell command; php/composer aren't in PATH.
putenv() does exactly that; allows php to set an environment variable for the duration of scrip execution. The very excellent dotenv library that craft depends on makes use of that.
The scl command line tools (source and scl) change PATH. Once I saw the expected values it was as simple as popping those over into the .env file for my site.
I added a PATH="/opt/rh/rh-php73/root/usr/bin:/opt/rh/rh-mysql56/root/usr/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin"
to the top of my sites .env file. (usually in the SITEROOT/craft/ folder)
and now updates succeed and database backups work too.
If you're using mamp or any other awkward environment where php isn't in the system path; this would likely work for you too.
Take note that variables set in a .env file WILL NOT overwrite an existing variable.
https://github.com/vlucas/phpdotenv/tree/3.6#immutability
a small change to your craft/web/index.php file is needed to change that behavior.
Change
Dotenv\Dotenv::create(CRAFT_BASE_PATH)->load();
to
Dotenv\Dotenv::create(CRAFT_BASE_PATH)->overload();
and then any settings in your .env file will be honored even if they already existing in the environment.


What is the checkbox for when editing Matrix fields? Referring to the screenshot below; I've just added a Matrix field to a new site, and I'm not sure what the checkboxes are for? The Matrix field just has two plain text fields. As far as I can tell, checking the box does nothing, and saving the entry unticks it. Might be a bit confusing for the client; any ideas?

The checkboxes can be used to select multiple matrix blocks at once to apply any action to the selected group. For example, you can select three different blocks and collapse, disable, or delete all of them using the settings gear on any of the selected blocks. You can also select multiple blocks are drag them all at the same time to re-order.


How to loop through Craft CMS query in Angular Given the following query sample, how can I loop through the entries past the first array in Angular?

Here is the query sample:

query sample ($section: [String], $type: [String], $slug: [String]) {
entries (section: $section, type: $type, slug: $slug) {
... on sections_sample_Entry {
  pageTitle
  description
  keywords
  canonical
  topBanner
  imageHero {
    ... on imageHero_ImageHeroData_BlockType {
      backgroundImage {
        title
        url
        ... on images_Asset {
         altText
       }
      }
      seal {
        title
        url
        ... on images_Asset {
         altText
       }
      }
      heroTitle
      supertitle
      subtitle
      heading
      bullets
      ctaButton
      }
    }
   }
  }
}

In the Angular template, I'm able to get and display the content within entries before the imageHero, anything after imageHero I have not been able to figured how to loop:

{{ entry.pageTitle }}

{{ entry.description }}

{{ entry.keywords }}

   {{ entry.canonical }}

   {{ entry.topBanner }}

How can I get entries.imageHero.heroTitle for instance?

The data return looks like the following when I console.log this query:

Got it working like this:

  <ng-template ngFor let-obj [ngForOf]="entry.imageHero">
    <h1>{{ obj.heroTitle }}</h1>
  </ng-template>

This also works:

{{ entry.imageHero[0].heroTitle }}


filtering elements between 2 dates I'm sure there must be an easy way to do this, but I can't work it out...

I'm trying to add date filters to the formerly submission export, but I can't work out how to filter out the submissions between 2 dates. I got it working with a bit of a hack:

$criteria = craft()->elements->getCriteria('Formerly_Submission');
$fromDate   = craft()->request->getPost('fromDate');
$fromDate = DateTime::createFromString($fromDate,   craft()->timezone) ;
$toDate   = craft()->request->getPost('toDate');
$toDate = DateTime::createFromString($toDate,   craft()->timezone) ;

//A bit of a hack, in my case these date fields are always the same anyway
$criteria->dateCreated = '>= ' . $fromDate->format(DateTime::MYSQL_DATETIME);
$criteria->dateUpdated = '<= ' . $toDate->format(DateTime::MYSQL_DATETIME);

I tried all sorts of ways to do it properly, things like

$criteria->dateCreated ='and, > ' . $fromDate->format(DateTime::MYSQL_DATETIME) . ', > ' . $toDate->format(DateTime::MYSQL_DATETIME)'

anyone know how to do it properly?

You call it a bit of a hack, but I think the way you're doing it is the proper way:

$criteria->dateCreated = '>= ' . $fromDate->format(DateTime::MYSQL_DATETIME);
$criteria->dateUpdated = '<= ' . $toDate->format(DateTime::MYSQL_DATETIME);

Your last example would work (with a syntax change) if you were you looking for a date range within a single field (either dateCreated or dateUpdated) like so, but not across two fields:

$criteria->dateUpdated = array('and', '>='.$fromDate->format(DateTime::MYSQL_DATETIME), '<='.$toDate->format(DateTime::MYSQL_DATETIME));


Splitting a Twig Variable into 2 Variables I want to split my variable into two new variables before and after the dash character "-".

How do I adjust my code below to enable this to happen?

{% set name = 'first-last' %}
{% set firstNameSlug = name|split('-')[1] %}
{% set lastNameSlug = name|split('-')[2] %}

{{ firstNameSlug }}
{{ lastNameSlug }}

If I'm following you, arrays are 0-indexed, so this would work (with a bit of cleanup).

{% set names = 'first-last'|split('-') %}
{% set firstNameSlug = names[0] %}
{% set lastNameSlug = names[1] %}

{{ firstNameSlug }}
{{ lastNameSlug }}


"Single" Entry page gives 404, even though it's enabled I added a new Single Entry on my site and populated it with content. When I try to access it at the URL I set, it only returns a 404 error, as if the page were disabled. It's not disabled, though. I also noticed that Live Preview also doesn't show up on the right side as it usually does when I edit this page; is that somehow related?
As far as I can tell, the page should be publicly accessible by all rights. I've set the URI correctly and every other setting that I know of. When I look under All entries, it gives me a clickable URI for my page as if it should work, but when I click this link, I get an inexplicable 404.
I'm using Craft CMS 2.6.3019.

This was occurring because I didn't have a template file for the page in question. I added it under /craft/templates/. All I had to do was copy another template used for news articles and adapt it to my specific page requirements. Then the page showed up flawlessly, as did the Live Preview button.


How can I merge a Modified Date and Time in Twig? I am trying to generate a modified date and time from a combination of content fields and the current date but I am getting stuck and keep hitting errors, so my logic is either not correct or  I am approaching this all wrong. Here is an explanation with some examples of what I am trying to achieve.
So I want to check if a child that is registered to a class (A class occurs on a specific day/time each week) that they only get to see a page if the date and time of their class is now in the past. As an example, a child is on a class Tuesday 4.15pm - 5.15pm - I want to ensure they only get to see the page at 4.15pm.
In the CMS I have a select list for the day, and related entries for the time slots, but these use standard time fields.
Here is how I have tried to approach it.
###First Generate a Modified Date based on the their class day. This will check if Tuesday is this week or next week. Like so:

#Get the class day for the child
{% set classDay = child.tuitionClass[0].weekday.label %}

#Set the next occurring date for the class day
{% set nextClass = now | date_modify('this ' ~ classDay) %}

This is fine so far and gives me a date to work with. I can compare today's date against the next class date to see if it has passed.
The part I am stuck on is the time aspect. I cannot figure out how to generate the modified_date with the class time so I can do the comparison on one object rather than two.
#Get the class time
{% set classStartTime = child.tuitionClass[0].classTime[0].startTime %}

How can I merge the class time with the modified date so that the nextClass is set to the date AND time of the nextClass. With the logic earlier it sets the time to default to 12:00 - the start of the day.
Everything I try I either hit an error Object of class DateTime could not be converted to string.
I could perhaps as suggested do the logic in two parts. First compare the date and then compare the time. But I was hoping for a single comparison.
Is anyone able to help out with this final part of the logic?
Thanks in advance.

Having done some further testing and research I believe this is a case of having to merge two date objects and ensuring that these are set as date/time objects when merging them into a variable.
Here are some examples way:

{% set thisWeeksDayAndTime = thisWeeksDay|date() ~ ' ' ~ classStartTime|time() %}

{% set thisWeeksDay = page.startDate|date_modify('this  ' ~ classDay ~ ' ' ~  classStartTime|time()) %}


Structure listing order & classes based on lightswitch value I have a structure called "Projects", which I am currently listing on a page. The layout looks like the below - with the every row starting or finishing with a .wide class thumbnail:

This is the code used to generate that layout (simpified here for clarity):

  {% for project in craft.entries.section('projects').all() %}

  {# Set a variable to check if it is a wide one or not #}
  {% set wide = 0 %}
  {% if (loop.index is divisible by(6) or loop.index0 is divisible by(6)) %}
    {% set wide = 1 %}
  {% endif %}

{{ project.title }}

    {% endfor %}

Some of the projects now have a lightswitch added (project.story) which makes them a "Story". These need to have a .story class added to them, and be injected into the layout every 6 entries, for as many as there are. Apart from that the standard project entries should list in the same order they appear in Craft. The Stories have a wider thumbnail image and some different content output in the listing.

If there are more stories than standard entries they should then all list at the bottom, likewise if there are more standard entries these should list out. Below are images of those two scenarios:

1)

2)

Can anyone please help with how I need to adjust my twig template to generate these layouts? I can add the .story class based on the lightswitch but am at a loss how to adapt the layout to have them appear where I need them to.

Thanks for any help

Mike

Whilst I can’t offer the exact template code for an answer right now as I am in bed (have I broke the stack rules?) it might be worth checking out the |batch filter.

Or taking elements of this answer and making it suit your requirements Making an entry grid with Batch 2,3 (2 in row then 3 in row)

And reading this https://twig.symfony.com/doc/2.x/filters/batch.html


Why would I get a "CHttpRequest is unable to determine the request URI" when creating a migration? I have logged into the server and attempted to create a migration for my plugin.  However I get this output:

exception 'CException' with message 'CHttpRequest is unable to determine the request URI.'

The request is targeting "/craft/app/framework/web/CHttpRequest.php:519".

Stack trace:
#0 /craft/app/framework/web/CHttpRequest.php(431): CHttpRequest->getRequestUri()
#1 /httpdocs/craft/app/services/HttpRequestService.php(816): CHttpRequest->getPathInfo()
#2 /httpdocs/craft/app/services/HttpRequestService.php(43): Craft\HttpRequestService->getNormalizedPath()
#3 /httpdocs/craft/app/framework/base/CModule.php(387): Craft\HttpRequestService->init()
#4 /httpdocs/craft/app/framework/base/CModule.php(103): CModule->getComponent('request')
#5 /httpdocs/craft/plugins/redactorclips/RedactorClipsPlugin.php(31): CModule->__get('request')
#6 /httpdocs/craft/app/services/PluginsService.php(136): Craft\RedactorClipsPlugin->init()
#7 /httpdocs/craft/app/etc/console/ConsoleApp.php(53): Craft\PluginsService->loadPlugins()
#8 /httpdocs/craft/app/framework/base/CApplication.php(165): Craft\ConsoleApp->init()
#9 /httpdocs/craft/app/framework/YiiBase.php(121): CApplication->__construct('/var/www/vhosts...')
#10 /httpdocs/craft/app/etc/console/yiic.php(76): YiiBase::createApplication('Craft\ConsoleAp...', '/var/www/vhosts...')
#11 /httpdocs/craft/app/etc/console/yiic(4): require_once('/var/www/vhosts...')

That's a bug in our RedactorClips plugin, actually.  Just fixed it, so if you grab the latest from here (https://github.com/pixelandtonic/RedactorClips), yiic still should run fine.


Have SEOMatic render a custom SEOMatic field I've got a few pages on my site that are not content managed.

I don't want to create entries for these pages, but I do want the SEO for these pages content managed.

My solution here has been to set up a global matrix block, with each block having a handle and seomatic field.

This way the SEO for these non-entries is content managed, but the pages themselves aren't.

Is there a way for me to tell SEOMatic to render a custom SEOMatic field? I tried {% do seomatic.meta.setAttributes(myCustomSeoMetaField) %} but had no luck, and can't see anything in the docs.

PS the reason I want to do it this way is partly because the Global/default SEOMatic settings didn't seem to be coming through on a non-entry, so I was hoping using some sort of default hook will take care of this also.

So the default global settings for SEOmatic should definitely be applied to pages that don't have corresponding entries in the CMS. That's what the global defaults do.

By far the easiest way to do what you want is just to create a Single that corresponds to these otherwise non-managed pages, and then you can set up whatever you like in the corresponding Content SEO settings.

If you don't want to do that, you can set everything yourself via the Twig API:

https://nystudio107.com/docs/seomatic/Using.html#seomatic-variables

You could try doing something like:

{% do seomatic.meta.setAttributes(myCustomSeoMetaField.metaGlobalVars)
%}

As per: https://nystudio107.com/docs/seomatic/Fields.html#template-access

But in general, I think this is a rougher work-around than just creating a Single for the previously non-content managed pages.

To be clear:

  PS the reason I want to do it this way is partly because the Global/default SEOMatic settings didn't seem to be coming through on a non-entry, so I was hoping using some sort of default hook will take care of this also.

This should not happen. You absolutely should get the default SEO settings on every page, so if this isn't happening for you, something deeper is wrong.


How to add CSRF cookie directive? I need to add the SameSite directive to my site's CSRF cookie, as explained in these mozilla security guidelines. According to the Craft docs, "Craft handles the cookie creation automatically." Is there a way I can configure the cookie?

It is actually possible but it's a little bit difficult for beginners. You'll need make use of Service Locators and overwrite craft\web\Response to change this method

foreach ($this->getCookies() as $cookie) {
    $value = $cookie->value;
    if ($cookie->expire != 1 && isset($validationKey)) {
        $value = Yii::$app->getSecurity()->hashData(serialize([$cookie->name, $value]), $validationKey);
    }
    setcookie($cookie->name, $value, $cookie->expire, $cookie->path, $cookie->domain, $cookie->secure, $cookie->httpOnly);
}

setcookie is the key here, because if you use it like that, you can't really include the parameter, so you need call it accordingly with options

setcookie ( string $name [, string $value = "" [, array $options = [] ]] ) : bool

Each yii\web\Cookie only has the following Attributes

public $name;
public $value = '';
public $domain = '';
public $expire = 0;
public $path = '/';
public $secure = false;
public $httpOnly = true;

Since there is no sameSite attribut you have to think about an intelligent way to set it. There is already a feature request for it. Maybe it's easier to ask about the current status.


Adding active class to globally cached navigation I have a structure which controls my main site navigation.
It's the same across the site so it is best to cache globally as opposed to a cache of the navigation or every url.

The last answer on this pages says that you can use Twig's replace filter to achieve this:
Would you use a Structure as navigation over multiple sections (channel entries, indexes and singles)?

My code below shows the active class being placed on the li tag but that doesn't work with the cache globally.

Can it be done with Twig's replace filter?

{% cache globally for 3 years %}
  {% set entries = craft.entries.section('navigation') %}

    {% nav entry in entries %}

      {# Check for entry type / get related entry #}
      {% if entry.type == 'customLink' %}
        {# Link to a custom url #}
        {{ entry.title }}
      {% elseif entry.type == 'relatedEntryLink' %}
        {% set linkedEntry = entry.relatedEntry.limit(1).first() %}
        {{ entry.title }}
      {% else %}
        {# Link to a structure entry #}
        {{ entry.title }}
      {% endif %}
      {# Repeat this for child entries #}
      {% ifchildren %}

{% children %}

      {% endifchildren %}

    {% endnav %}

{% endcache %}

Yes, you can!

The first thing you need to do is to add the entire cached content into a single variable:

{% set navigation %}
    {% cache globally for 3 years %}
        {# YOUR CACHED CONTENT #}
    {% endcache %}
{% endset %}

Then you need to add some dummy placeholder tags on your
 tag and your  tag which then can be used by |replace filter to make the replacement.

For

For  (You need to modify this for each different entry type)

{{ entry.title }}

After all this you'll have special "tags" in your cached content that you can run some replacement on, like this:

{{ navigation|replace({('data-url="' ~ craft.request.getUrl() ~ '"'): 'class="active"'})|replace({('data-class-' ~ craft.request.segment(1)): 'active'})|raw }}

You can run two |replace filters after each other, you could just split them up into two steps. Also, this code is untested - I just wrote it from my head so please be aware there might be some typos etc..


Users allocating permissions beyond their own I have set up a user group named Administrators, to be used for the person in charge of managing the website day to day. But I didn't tick the Admin box as I don't want them to be able to access plugins or updates etc.

I want them to be able to create users and fine tune the permissions of the users they create. So I ticked all the boxes in the User section. But if I log in as that Administrator I am allowed to change my own permissions (and all the other users) to access plugins.

This can't be right, how do I prevent them increasing their own permissions beyond those I have allocated them?

You should consider voting for this feature request: https://github.com/craftcms/cms/issues/915


Interpret TWIG's {% js %} as  in PHPStorm Does anyone know how to get PHPStorm interpret {% js %} as <script> for correct syntax highlighting in PHPStorm?
Background: I'am always doing this:
{% js at endBody %}
    {% if false %}<script>{% endif %}
    document.querySelector('body').classList.add('overlay');
    {% if false %}</script>{% endif %}
{% endjs %}

which I would like to avoid.

You can do this using PhpStorm’s Language Injections feature.
In fact, as of PhpStorm 2017.3, it has included support for {% script %} tags out of the box.
To extend that to {% js %} tags, go to Preferences → Editor → Language Injections, and search for “twig: custom statement javascript”. Double-click on it to edit it, and add the following line to the Places Patterns setting:
+ twigCustomStatement("js")

Click OK and then Apply to save.
You can also add support for interpreting {% css %} tag contents as CSS by duplicating that language injection, setting its Language ID to CSS, and setting its Places Pattern to:
+ twigCustomStatement("css")


onBeforeSaveUser event does not fire if basic user fields do not validate I have additional fields I check for in the onBeforeSaveUser event and add the errors to the errors array. The problem is my code doesnt even run if they miss the main fields or if the email is already in use or something like that... I would like to return ALL validation errors, not just the default field errors first.

If I go to my form and just press submit without filling anything it out it only complains about the username, email address and password. If I just fill those fields out, then it comes back and complains about all my other fields (a la my event handler). This is unexpected behavior. Am I doing something wrong or is there a way to address this?

I agree it's unexpected behavior, but for Craft 2 it won't change.

Craft 3 had a major overhaul of its event system and validation workflow where it works as you'd expect, though.


Twig errors on v3.1.19 Running Craft 3.1.19 and have started getting twig error in the control panel.  When I click on the utilities link I get this error:

Declaration of craft\web\twig\Environment::compileSource(Twig\Source $source) should be compatible with Twig_Environment::compileSource(Twig_Source $source)

And when I try to create a new field I get this error:

Key "defaultUploadLocationSubpath" in object with ArrayAccess of class "craft\fields\Assets" does not exist.

Any idea what is going on?

Thanks!

I also got the second error when trying to create a new field and the solution for me was running

./craft clear-caches/all

after a refresh it started working again


How can I query entries based on a Matrix Block Type? I'm using Element API and trying to create a query that returns a list of entries based on if the entry is using a specific Matrix Block Type.

I've tried a few different things including a query that does a search where the field contains any value, but it's not returning any entries.

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

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

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

Option 1: Implement a custom element query param.

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

<?php

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

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

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

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

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

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

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

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

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

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

Option 2: Use a custom Fractal resource class.

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

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

<?php

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

class MyElementResource extends ElementResource
{
    public $hasBlockType;

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

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

        return $query;
    }
}

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

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

Option 3: Just use Preparse

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

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

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

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

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


Query entries with latest video field containing a URL I would like to set up a query to find the latest news article that has a video attached to it ('video' is a matrix field with a block type that is also called 'video' and a field called 'videoUrl').
I know I can use the following query, but I get stuck defining searchQuery. Or is there another method?
{% set results = craft.entries()
.search(searchQuery)
.one() %}

No need to use search in this case.

{% set results = craft.entries.videoField(':notempty:').orderBy('postDate desc').one() %}


Looping through a Global with a Matrix field This might be a very simple question but I am pretty new to Craft with a EE background. Basically, I have a global containing contact details that use a matrix field, I’m literally just looking for the syntax to loop through the matrix blocks.

I have tried similar code to the successful matrix fields I have in other areas, but how do I reference the particular global? This is what I’ve attempted with no success:

{% for block in contactDetails %}
    {{ block.location }}
    {{ block.address }}
{% endfor %}

contactDetails being the name of the global. I’m sure this is very simple I just can’t figure it out.

{% for block in contactDetails.myMatrixField %}
     {{ block.location }}
     {{ block.address }}
{% endfor %}


Is it possible to hook into image transforms? I have a somewhat unique thumbnail need for a certain site. I need to watermark images with custom text (per image, not globally across the site). Is there a way to hook into the Craft image transform generation logic and insert/run my own logic?

I've experimented with craft()->on('content.onSaveContent', function(Event $event) { and it seems to work okay. It will run when you save/upload the asset. The downside is that it generates the thumbnail on save, instead of on demand (using Javascript) as the native Craft transform feature does.

So, is there a different event I can hook into? Or, is there a better way to adjust the transform generation logic.

Currently it’s not possible to hook into Craft’s own thumbnail/transform generation logic. Your best bet would be to write a plugin that independently adds the watermark.

You could give the plugin a Variable class that accepts the AssetFileModel object, grabs the image, stamps it with the watermark and saves it somewhere else, returning the URL to that watermarked image, or something like that.


What is the difference between 'nav' and 'for' for looping? I am new to craftcms and did a look through on the documentation just recently.

I am at the part where it explain about the Categories Field and found out that we can loop through the ElementCriteriaModel with the 'nav' keyword instead of 'for'.

I checked the twig documentation but there are no 'nav' keyword :|

So which one should I use?

for is part of the native Twig language.

for is for general usage... It's the basic, general looping structure that you'll use 99% of the time. You'll find that it closely mirrors for and foreach in other programming languages.

nav is defined by Craft, and doesn't exist natively in Twig.

nav is special... You'll only need it to loop through entries in a Structure section, or categories in a Category Group. The sole purpose of nav is to make it easier to create a menu or navigation.

One of the biggest benefits to using the nav tag is that you'll then be able to use ifchildren within it...

{% ifchildren %}
    <ul>
        {% children %}
    </ul>
{% endifchildren %}

The logical relationship between nav and its respective children is slightly complicated... and worthy of a separate post if you need further clarification. :)


Prevent Craft URLs containing # from redirecting I have a Structure setup where I'd like each child to link to an anchor within the parent page (see the attached image).

But when I use <a href="{{ subEntry.url }}"> and click on the link, it redirects to the parent URL without the # anchor.

e.g. http://localhost:3000/services/web-interactive-design#website-design redirects to http://localhost:3000/services/website-design

How can I prevent this from happening?

The setup you have there is creating routes within the system not overriding the URL property of your entry. If you just want to generate anchors you should uncheck "Entries in this section have their own URLs"

Then within your template for your top-level structure item run a loop and output the content with ids and then the anchors as links.

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

{% for entry in entries %}

{{ entry.title }}

{% endfor %}

{% for entry in entries %}

        {{ entry.content }}

{% endfor %}


How do I get Matrix elements to copy their content across language Locales? I returned to a site designed months ago, and added a second language to it.

From the beginning, this site had prominent composition of entries out of multiple elements in their matrix, with formatting choices selectable on the elements (like positioning and size for images; or position left or right for compound pull quote/citation blocks.

This all works fine, and now in languages. However, there is the fact that languages other than the first used seem not ever never to have their Matrix of content blocks copied over into the new language. The Matrix is there, of course, but empty.

This emptiness is the case with first save starting with an entirely fresh entry, which is a noted in the add as the only case at present where Craft normally copies content to other available languages, and very handily so.

Really I think this is a bug report, but maybe not?

Add:

At present copy over does, as commented below, operate only at the point of first save to a first language. If you edit after saving, only that first save will have been copied, and your edits won't be. If you add fields to the section, and fill them in for a first language, nothing will be copied for those to other languages.

This is clearly worth looking into for persons who use multiple languages/Locales, but isn't so simple to do well, and I believe it is somewhere down the list for Craft futures, likely properly so compared other desires. Worth mentioning, though ;)

Ok, in some conversation with Brandon which leaned this direction, I realized a different direction to temporarily solving most of this problem.

It turns out that a root of the issues is that marking a Matrix as translatable causes the base problem here, that the set of elements in an original language isn't copying at all into other Locales, as would be expected on first Save as all other kinds of elements do.

If you don't mark the Matrix as translatable, two good things happen:

All Matrix elements now do get copied over, so that you don't have to recreate the Matrix in its individual form for each Entry and language.
Text items marked as translatable do have their original text copied over, so that you have a starting situation for language translation

It's true that Assets marked as translatable show up empty rather than with their original content, but at least they are there.

We also don't really know what marking a Matrix as translatable should mean. I suspect it should mean that all contained elements are marked translatable, but we shall see.

The Craft crew is well aware of issues here, and plans a careful improvement of the whole area, which as complex isn't at the top of lists yet.

This little detail should get most of us through until that happens, and given we set up the non-translatability of Matrix elements, should make extra steps explainable to customer end users.


Loop through JSON object in Twig from the database I've written a custom plugin that stores data as JSON in a TEXT column (field_gridcontrol) in Craft's content table that looks something like this:

[
  {
    "id": "35", // id is an element's id
    "classes": "item w1 h2", // classes to add to the dom element
    "x": 0 // x coordinate on where it shows up in a grid
  },
  {
    "id": "56",
    "classes": "item w2 h2",
    "x": 0.25
  },
  {
    "id": "24",
    "classes": "item w1 h1",
    "x": 0.75
  }
]

I can print this as a string {{entry.fieldcontrol}}, which is all well and good, but I'd like to be able to loop through it as an object like a traditional element criteria model:

{% for block in entry.gridcontrol %}
  {% set entry = craft.entries.id(block.id) %}

    {{entry.title}}

{% endfor %}

However when I try this I don't get any errors, just an empty ul. I guess this is because it's not seeing gridcontrol as an object.

My question is: Did I go about structuring this the wrong way? I've seen other plugins, like nystudio107's SEOmatic, that store data this way. Or am I missing something super silly to get this up and running?

You'll simply need to decode the JSON string. Unfortunately, Twig doesn't ship with a json_decode filter, but there's a plugin.

Here's how you'd use it:

{% for block in entry.gridcontrol|json_decode %}
  {% set entry = craft.entries.id(block.id) %}

    {{ entry.title }}

{% endfor %}


How would I pull in the first Matrix block including certain blocks only I have a Matrix field setup. I want to be able to pull in the first Matrix block used to print a snippet, but only out of the blocks 'text' or 'textImage'. So the first one used, out of those two only.

This is what I have but it's pulling in the textContent block regardless, even if the text block is first.

    {% set textBlock = entry.body.type('text').first() %}
    {% set textBlock2 = entry.body.type('textImage').first() %}

    {% if textBlock %}

{{ textBlock.textContent|hacksaw(chars='100', append='...') }}

        {% else %}

        {% if textBlock2 %}

{{ textBlock2.text|hacksaw(chars='100', append='...') }}

        {% endif %}

    {% endif %}

Give this ago.

It will grab the first block that is either "Text" or "Text Image" and then you can use a switch statement to output your template depending on the block type.

{% set firstTextBlock = entry.body.type(['text', 'textImage']).first() %}

{% switch firstTextBlock.type %}

    {% case 'text' %}

{{ firstTextBlock.textContent|hacksaw(chars='100', append='...') }}

    {% case 'textImage' %}

{{ firstTextBlock.text|hacksaw(chars='100', append='...') }}

{% endswitch %}


Problems with Craft CMS development strategy Clearly Craft CMS is not a thing for non-developers (like WordPress or Drupal is). Despite the option to create fields, sections, etc. in the administration panel, we still need to code templates (twig, html, CSS, etc.). So for me it's kind of a weird relationship where we define those things in administration with ease and luxury (no programming at all), and then still need to code standard way upon it in templates.

In my opinion, this relationship creates a bunch of issues:

1) Let's say we work in team and some other dev decides to remove some fields (or change handle names), because he/she does not know my part in templates. The page is screwed! And it's hard to rollback, because, well it's database.

2) Content replication problem! Thanks god there is something upcoming in this area https://craftcms.com/news/craft-3-content-migrations, but still this is fishy - read on.

3) Request to DB are made for content definitions, that mostly stay the same all the time. No need for that.

The solution I see, in my opinion, is very simple.

Let programmers to define fields, sections, globals, etc. (most of the settings contents) programmatically. If we know how to code with Twig, it shouldn't be so hard to edit some Yaml or PHP array. There is nothing to lose!

After that:

1) No request to DB for code defined stuff. Huge performance gain.

2) There is no content replication problem for programmatically defined settings. It is just delivered via version control!

3) We can create unit tests, do code reviews, etc. for those content parts. Even extend to more functionality ... and always refer to version control (revert/analyze bad changes etc.).

Am I talking bananas?
BR, J

I do not know where your problem is? In Wordpress, you can build pages with CustomFields, and I think the same with Drupal.

Because you will have the same problem when Devs delete fields and play on the live system, the content is missing or the frontend error generated.

Therefore, it is simply forbidden to simply delete fields, they do the same nevertheless is not the CMS to blame, then that is Human Failure.

If you are familiar with the principle of the ContentBuilders (no static backend masks), then you would not get far with field configurations with YAML or JSON, then the editor determines which fields he needs for each article individually.

I'm not sure if it's so much performance gain when you put the fields into the filesystem, because Craft has to double into the filesystem for the representation of a field in the backend (general fieldstyle, the field configuration) and then into the database To pick up the content.

Craft 2 is fast, Craft 3 is even faster. Anyone who builds fixed fields does not have to worry about the backend performance.


How can I add a RichText-Field to my plugin's CP-section? I'm trying to add a redactor richtext field to one of my plugin templates in the CP.

I found macros for every field in craft/app/templates/_includes/forms, but a richtext macro is missing. I assume that I have to use a normal textarea-field and add some code to the controller or init()-function, but couldn't find anything by inspecting Craft's CP code.

To do this you'll need to take a few steps:

Load the necessary resources which include the redactor.css and redactor.js file.  And if you are using Craft's macros for your fields, the form macro file.

{% includeCssResource "lib/redactor/redactor.css" %}
{% includeJsResource "lib/redactor/redactor.js" %}

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

Add a class to your field that you will use to initialize your Redactor toolbar.  Here's a simplified textarea macro:

{{ forms.textareaField({
    class: 'myFieldsRedactorClass',
    name: name,
    value: (value is defined) ? value : ''
}) }}

Initialize the redactor field type with your desired toolbar.

(function() {
    $('.myFieldsRedactorClass').redactor({
        buttons: ['bold', 'italic']
    });
})();

Here's a related article on customizing Redactor toolbars from Straight Up Craft:
Custom Redactor Toolbars for the Rich Text Field in Craft CMS

Note:
One thing to be mindful of, which I'm not sure what to say about, is that if you have other Rich Text fields in your section with you custom field type, Craft is probably already loading these resources. I don't know if there is some way to check to see if these are loaded and only load the redactor css and js assets if they are not being loaded elsewhere.


Add entry author meta field in entries listing table in CP? In CP Craft Admin in the entries table view I d like to display some authors meta info.
How could I do that in my plugin?
I know public function modifyEntryTableAttributes(&$attributes, $source) and public function getEntryTableAttributeHtml(EntryModel $entry, $attribute)and but I cannot make it work.

You're on the right track with both of those. First, modifyEntryTableAttributes.

  Gives plugins a chance to modify the table columns shown on the entry index page.

This lets you name the column for your author info. It's a hook, so you'll need to add a public method with the same name as that that to your main plugin class. You can also limit the column to particular section by checking the $source variable.

public function modifyEntryTableAttributes(&$attributes, $source)
{
    if ($source == 'section:3')
    {
        $attributes['author'] = Craft::t('Author');
    }
}

Then to actually return the information, you need getEntryTableAttributeHtml.

  Gives plugins a chance to customize the HTML of the table cells on the entry index page.

Here you can just check for the attribute you set above, and return a string.

public function getEntryTableAttributeHtml(EntryModel $entry, $attribute)
{
    if ($attribute == 'author')
    {
        return $entry->getAuthor()->getFriendlyName();
    }
}


Where do I run validation before database insert? I'm trying to wrap my head around when to use a Model and when to use a Record (or both?).

I have both my Model and my Record. In my Controller I call my Service that creates my new Record instance before running the ->save(); command to save my new entry into the database.

Since my Record can run the validation process from my specified rules() array I'm wondering what I have my Model for?

Also since I'm running the actual database command from within my Service and dont have access to the Record in my Controller, how do I return the validation errors to my Controller for later use in my template variables?

Or do I run the validation on my Model in my Controller as well? Seems like I'll be doing the same thing twice if so.... or what am I not getting here? :P

Records and models are similar in that they are both containers for data, but records have the additional functionality/overhead of being able to write and read from the database via the Active Record pattern.  There is also not a 1:1 relationship between records and models.  A model can define attributes from multiple records.

In practice, records should never leave your service layer, because you don't want them floating up to the controller or template level, for example.  If that happened, then people could inadvertently insert/update/overwrite data directly from a template.

From your service, you do all of your Active Record / database related logic, and call populateModel(s) with the resulting data and return the models from your service and let those safely transport your data throughout your layers.

The general pattern for all of this, including validation, looks like this:

class SomeController extends BaseController
{
    public function actionDoSomething()
    {
        $myModel = new MyModel();
        $myModel->myProperty = 1;

        // Validate the model
        if ($myModel->validate())
        {
            // Pass it to the service.
            if (craft()->myService->doSomething($myModel))
            {
                // Success!
                $this->redirectToPostedUrl();
            }
        }

        // Return the model back to the template so the errors can be displayed.
        craft()->urlManager->setRouteVariables(array(
            'model' => $myModel
        ));
    }
}

Your service can grab the info it needs from the model and create or grab any necessary records.  It can then, if it needs to, call $record->validate() on any of the records.  If a record fails validation in the service, it can add those errors to the original model and return false like:

$myModel->addErrors($record->getErrors);

And those errors will bubble up to the template to be displayed.


Commerce: How can I dynamically create a discount for any given product? I am inspecting my cart when the user visits /commerce/cart and if the cart contains a specific product, I want to alert the user that they can redeem a credit for "x" item. If the users chooses to use the credit, I would like to assign the qualifying product a discount.

...
if ($lineItems) {
    foreach ($lineItems as $lineItem) {
        foreach ($lineItem->purchasable->product->foo as $bar) {

            ...
            // qualifying product found - return json to javascript
            ...
        }
...

$discount = new commerce_DiscountModel();
...
??
// apply discount to cart/update ui via javascript to reflect discount

I'm able get all the way up to creating a new discount. I assume I start by creating a new discount model and populate it with the price of the product I am wanting to discount? I'm not really sure where to start - thank you for any suggestions!

EDIT

First off, thank you, Jeremy for your help. I (think) I am slowly starting to understand. I don't understand how or why the handler is or isn't getting called.

Here is my updated main plugin file:

MyPlugin.php

public function init()
{
    error_log(__FUNCTION__); // this is logged

    craft()->on('commerce_discounts.onBeforeMatchLineItem',
        [
            craft()->myPlugin,
            'onBeforeMatchLineItemHandler'
        ]
    );
    ...
}

Then my service file looks like this:

MyPluginService.php

class MyPluginService extends BaseApplicationComponent
{
    public function onBeforeMatchLineItemHandler($event)
    {
        // this method never gets executed

        $cart = craft()->commerce_cart->getCart();
        $lineItem = $event->params['lineItem'];
        $discount = $event->params['discount'];

        error_log('line item: ' . $lineItem);
        error_log('discount: ' . $discount);
    }

    ...
}

If I change the name of the handler to "myPluginz" or something that doesn't exist, it throws an error, so I know I have the right syntax at least.

The handler was actually called once, but now it never gets executed. The product I have in my cart is promotable, and is not excluded from any sale. So it seems I am matching the criteria needed.

I also tried this straight from the docs.

public function init()
{
    error_log(__FUNCTION__); // this is logged
    craft()->on('commerce_discounts.onBeforeMatchLineItem', function ($event) {
        error_log(print_r($event, true)); // this is not executed

    });
}

I don't understand what I've done wrong to cause the event not to fire.

EDIT 2

Well, I think I have finally managed to get out of my own way. I'll update this thread as I progress through.

I would turn this on it's head slightly (assuming you can express the discount itself, i.e. what it does specifically to the discount item, using normal Commerce discount rules).

If you can, then you can basically make the application of the discount conditional based on what's in the cart.

Here's some sketch code - obviously you might need to change the logic etc

public function onBeforeMatchLineItemHandler($event){

$lineItem = $event->params['lineItem'];
$discount = $event->params['discount'];

$cart = craft()->commerce_cart->getCart();

$idOfItemToPossiblyDiscount = whatever;
$idOfParentItem = whatever;
$idOfDiscount = whatever;

/First check which discount we're thinking about applying
if($discount->id == $idOfDiscount){

    $shouldDiscount = false;
    if ($lineItem->purchasable instanceof Commerce_VariantModel){
        //First check if this is the item that might get discounted
        if($lineItem->purchasable->id) == $idOfItemToPossiblyDiscount)){
            //Ok, so we have that item in the cart now loop through $cart to see if the 'parent' item is in the cart
            foreach ($cart->lineItems as $item){
                if ($item->purchasable->$id) == $idOfParentItem){
                    //do nothing, but finish here - Commerce will carry on and apply the discount as long as
                    //we dont set event->performAction = false;
                    $shouldDiscount = true;
                    break;
                }
            }

        }

    }

    if(!$shouldDiscount){
        $event->performAction = false;
    }

}

Obviously at the template end of things you can loop through what's in the cart and do similar logic to show messages etc - e.g. if parent item is in, and not the discount item, present the offer, etc....


Logging from Bootstrap mode? We've been using bootstrap.php to have a basic PHP file run parts of some content-sync from a plugin we've written.

The sync is run from cron and this works great.

BUT - when the sync runs from the bootstrapped file - there are no logging info stored. I.e. the sync code works fine, but nothing is logged to: craft/storage/runtime/logs/<pluginname>.log - when triggering the sync from within the CP as a full-craft request, logging works fine.

Is there a way to get the bootstrap app to setup logging, so that logging from my plugin would work?

If you're doing it from a custom bootstrap script, you'd need to do something like this for plugin logging to work:

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

craft()->plugins->loadPlugins();
MyPlugin::log('My Message', LogLevel::Error);
craft()->end();


Export static html including images, CSS, JS etc For a client I need to export websites as static html (/w images, CSS, JS etc.), which I have created in Craft.

Unfortunately, I cannot find a plugin for this.

Can someone give me a hint, how do I start with this?

I see 3 options, none of which warrant the creation of a plug-in:

Get Craft to output all your URLs as a simple, unformatted list. Easy enough to do this with Twig templates, right (ask if not!)? Save this as pages.txt
Install wget. Simple to do on Linux (apt-get install wget probably), if you're on a Mac you can install it using brew install wget.
wget -i pages.txt
You should now have all the pages as lovely static .html files.

Get Craft to output pages as a big .json data file. Again, easy enough to do with Twig templates.
Use a 'Static CMS' to read in this JSON and use it to build out a reproduction as a static website. Personally, I'd use Middleman or Assemble.io if I was doing this - but I guess it depends if you're more comfortable with Ruby or Node.js respectively.

Ask yourself why you're doing this? Is it performance? Security? Maybe if you get up to date with use of the {% cache %} tags you'll have a much easier time!


White space added to start of template's There is white space being added to the start of my templates.

This isn't really an issue but because its happening to an RSS template that is breaking the feed and causing it to not validate.

When I edit the template in my text editor the white space is not there, so I think it is Craft adding when when rendering the template?

My code looks like this, you can see on line 1 there are no spaces before I declare the XML version. <?xml

However, on the front end it is rendering like so: I have highlighted the space in blue.

Because of this, the RSS template is not validating and is causing my feed to break.

This started recently, I am not sure if it is linked to a recent Craft update but it started happening around the same time.

Craft v3.0.26.1

Any help appreciated :) Thanks

As Brad kindly pointed out, I checked my files in the config directory and noticed a few spaces before I started the <?php in my /craft/config/imager.php file. I would never have thought to check this, so thanks Brad!


Trouble accessing setting My plugin structure was created by the plugin factory. I have a setting called ulStateClass and I have been able to change the value of that setting in the Setting for the plug in. Looking at the 3.0 Docs page for settings I see the example:

// From your main plugin class:
$foo = $this->getSettings()->foo;

// From elsewhere:
$foo = \ns\prefix\Plugin::getInstance()->getSettings()->foo;

My namespace is recoveryfinder\craftnav

In my services php file I have the following to test:

echo \recoveryfinder\craftnav::getInstance()->getSettings()->ulStateClass;

I am getting the error:

  Error Class 'recoveryfinder\craftnav' not found

Making progress with Craft and enjoying it. I am guessing that this is a misuse or misunderstanding of namespaces? How Do I correct this?

Little bit confused with your question, if you want to access your settings then you can do craft::$app->plugins->getPlugin('handle')->getSettings()->foo;


Can a model or record have conditional requirements? I have a form that spans two pages, with a required field on both pages and an optional field on both pages:

Form A - Page 1
- Question 1 (required)
- Question 2 (optional)

[User submits partial form to database]

Form A - Page 2
- Question 3 (required)
- Question 4 (optional)

[User submits partial form to database]

The Form is creating an ElementType in Craft and the questions are Custom Fields.  The user who creates the Form can arrange any number of custom fields required or optional on any number of tabs.

How do I think about validation for this workflow? When I create a Model to validate the forms being submitted, required fields should only trigger validation errors when the page they are on is submitted.

I'm happy to do more digging myself on this one if you can help point me in the right direction, but I'm not sure how to frame what I'd like to do.  Does anyone have a better framework of how to think about how to validate conditionally required fields in the context of Models, Records, Element Types, and Custom Fields?

I can think of a couple of options and I'll just throw them all out there.

Have a separate model per partial form and each model performs its own validation.
Have a single model, but have it override the rules() method and you can conditionally set what validations methods you want depending on the step you're on. Presumably, you'd want to pass in a step number either through the querystring or through POST.  You can see an example of how we're doing some conditional validation using this method for email settings in EmailSettingsModel.
Don't worry about any of Craft's/Yii's automagic validation classes and just have the controller manually do its own validation per form and return errors as necessary.


"A" or "B" in switch statements? Is it possible to provide different possible values per case?

I've tried the following formats without success.

{% case "A" or "B" or "C" %}
  {# run this if case matches A or B or C #}

I saw this done somewhere else so I thought I'd give it a shot

{% case "A" %}
{% case "B" %}
{% case "C" %}
  {# run this if case matches A or B or C #}

From the documentation it doesn't seem like this would be possible but wanted to check just in case. If not, any chance we'll see this sometime in the future?

As of Craft 2.6, this is now possible!
In fact, it works exactly like your first example:
{% case "A" or "B" or "C" %}
  {# run this if case matches A or B or C #}

Original answer...
Your first example is not currently possible, but might make for a good feature request.
Your second example is not possible, and most likely never will be. If it were added in the future, that would likely have a major (breaking) impact on all existing uses of the switch statement.
The way that Craft has implemented the case statement is by making it completely unnecessary to supply a break statement. In fact, the break statement doesn't even exist natively (though can be added with the MN Break and Continue plugin). The case statement will automatically end when it hits the next case statement, or the endswitch statement.
An actual solution would be to use a macro or include. If you have multiple case statements which should trigger the same behavior, I'd recommend wrapping that behavior into a macro/include, and calling that macro/include for each relevant case.


How can I reduce the number of queries when including a related item within a for loop I've created an alphabetical index of entries in my template. The code I'm using is in the gist below:

https://gist.github.com/jamiepittock/2635516e95317e5c6ed6

It results in a layout like the one in the following image (screenshot only shows "B":

The problem is it takes 704 database queries. If I don't include the category name ("Business People" under the Jeff Bezos entry on the screenshot) that drops to 22.

Is there anything other than caching I can do here?

Update:

I'll leave the original answer because they're certainly still viable options, this is now probably best solved by using the eager loading features that Craft 2.6 added.

A bit difficult to properly debug without seeing things like your content architecture, database profiling information, logs, etc.

But using the {% cache %} tag is certainly an option here.

If you're adverse to that, then you could also use a template hook that goes to a plugin method that would "eager load" the data you know you'll be needing for this particular page directly from PHP.

You can search Craft's app folder for '{% hook' to see how we're using that for the CP in a few places as well.


Craft 2.X Local setup error – Craft not connecting to MySQL (via Sequel Pro) Novice dev here, really struggling to get my local setup functioning. After a couple of days of wrestling with Apache config settings, I finally have Craft connecting via a VHOST setup. The problem –

Craft can’t connect to the database with the credentials in craft/config/db.php.

This should all be tried and tested as it came from my lead dev on this project and had been working, so it is likely something silly I have done in the set up. I just can't figure out what.

Thus far, I have downloaded the repo, installed all dependencies and have successfully got the local server running with npm run start. I've configured a Virtual Host and that's all running fine. I downloaded a copy of the production db from the live site and uploaded it to my local db (connect via Sequel Pro). Both db's have the same name.

My db.php file is:

return array(

// The database server name or IP address. Usually this is 'localhost' or '127.0.0.1'.
'server' => $_SERVER['DATABASE_HOST'],

// The name of the database to select.
'database' => $_SERVER['DB_NAME'],

// The database username to connect with.
'user' => 'root',

// The database password to connect with.
'password' => $_SERVER['DB_PASSWORD'],

// The prefix to use when naming tables. This can be no more than 5 characters.
'tablePrefix' => 'craft',

);

My VHOST is:

<VirtualHost *:80>

SetEnv DATABASE_HOST localhost
  SetEnv DB_NAME dbName
  SetEnv DB_PASSWORD dbPassword
  SetEnv DEV_MODE true
  SetEnv SITE_URL sitename.local
  SetEnv DB_PORT 3306
  DocumentRoot "/Users/username/Sites/sitename/public"
  ServerName www.sitename.local
  ServerAlias www.sitename.local
  ErrorLog "/Users/username/Sites/sitename/error_log"
  CustomLog "/Users/username/Sites/sitename/access_log" common
  <Directory "/Users/username/Sites/sitename/public">
    Options Indexes FollowSymLinks Includes ExecCGI
    AllowOverride All
    Require all granted
  </Directory>
</VirtualHost>

I'm stumped. The only think I have been able to find on similar threads seems to point to db version issues (which might be the case but I don't know how to check).

Does anyone have any ideas?

Rather then passing the database details in virtualhost. You should put the database server details in db.php file as below.

DB.php file below:

<?php

/**
 * Database Configuration
 *
 * All of your system's database configuration settings go in here.
 * You can see a list of the default settings in craft/app/etc/config/defaults/db.php
 */

return array(

    // The database server name or IP address. Usually this is 'localhost' or '127.0.0.1'.
    'server' => '127.0.0.1',

    // The database username to connect with.
    'user' => 'root',

    // The database password to connect with.
    'password' => '',

    // The name of the database to select.
    'database' => 'db_name',

    // The prefix to use when naming tables. This can be no more than 5 characters.
    'tablePrefix' => 'craft',

);

Your VHost file should be like below:

#
<VirtualHost *:80>
    ServerName crafty-coffee.local
    DocumentRoot "c:/wamp64/www/crafty-coffee/httpdocs"
    <Directory  "c:/wamp64/www/crafty-coffee/">
        Options +Indexes +Includes +FollowSymLinks +MultiViews
        AllowOverride All
        Require local
    </Directory>
</VirtualHost>

host file (C:\Windows\System32\drivers\etc) :

127.0.0.1   crafty-coffee.local
::1 crafty-coffee.local

This works perfectly for me. After this restart your Sequel Pro.


Solspace Freeform pass variable to form I have an Freeform entry field {{ pageForm }} where the user can select a form to display on the page.

And then in the page template I load the form in to the page using {{ entry.pageForm.render() }}. Cool.

I also want them to be able to choose the return URL from an Entries field e.g {{ entry.formThankyouUrl }}. Is there any way to pass that formThankyouUrl to the renderTag? E.g the below setup would be ideal..

Page template:

{% if entry.formPageForm|length %}
   {% set thankyouUrl = row.formThankYou.one() ?? null %}
   {{ entry.formPageForm.render() }}
{% endif %}

Form template:

{{ form.renderTag({
  returnUrl: thankyouUrl
}) }}

The reason I ask is that the default Return URL functionality in freeform is quite limited in that you have to paste in the URL, would be good to select it form a entries dropdown

Thanks

You can pass values from other Craft elements or from URL segments, etc to your Freeform forms. Specifically when using with the Element fieldtype, when wanting to override the return URL, you can do something like this:

{{ form.renderTag({
  returnUrl: entry.thankyouUrl
}) }}

When wanting to override Freeform field data values or options, you can do something like this:

{{ form.renderTag({
   overrideValues: {
      hiddenFieldHandle: entry.id,
      stateSelect: "AZ",
      availability: ["tue", "thu"],
   }
}) }}


Using an IF-statement to define the Entry URL Format Within a channel I have two kinds of possible article types, which I separate with the entry type feature. For the entry URL format I want to include the type, but only for one of the two.

I've tried channel{% if type.handle == 'xyz' %}/{type}{% endif %}/{slug} but without success.

I've tested "if 2 > 1" and it did output the type, so I guess the structure of the if-statement is correct. Does anyone have an idea how I could make this work?

Alright, I was able to figure it out myself:

channel{% if object.type == 'xyz' %}/{type}{% endif %}/{slug}

produces the desired results. The section for Dynamic Entry Titles in the docs pointed me into the right direction.


Selecting entries using a checkbox field I had what I thought was a very simple issue: Select some categories on the front-end, filtering by a Checkbox field.

The Checkbox has values, which correlate to Locales.

The end goal was to create a 'workaround' to the fact that you can't disable/enable a category per Locale.

So on the template, I attempted:

{% for collection in craft.categories.group('dressCollection').regionAvailability(craft.locale) %}

But that doesn't work.

Reply via Brandon:

A single field does probably make more sense here, as you have it.

You're close to getting it working, but your syntax for filtering categories based on craft.locale is wrong. Checkboxes fields store the selected option values as JSON, so if you check your craft_content table you will find values like

["option_1","option_2","option_3"]

When you do this:

.regionAvailability(craft.locale)

it is looking for a row where the regionAvailability value is equal to craft.locale. Even if only a single locale is checked, its value would still be ["locale_id"], not just locale_id.

So to fix this just change that parameter to:

.regionAvailability('*"'~craft.locale~'"*')

or

.regionAvailability("*\"#{craft.locale}\"*")

(both do the same thing; just pick the one you think is more clear)


Export Array of entries in modifyEntryTableAttributes I am trying to return an array of selected entries in the list view, but so far I can only get first() and last() to export the names, since it's only grabbing one entry. I would like to get a comma separated list of entries tied the that specific entry.

I have tried using find() and find()->title but it gives me an error.

Here's what I have right now.

    public function getEntryTableAttributeHtml(EntryModel $entry, $attribute){
     if ($attribute == 'sponsorEntries'){
      return '<span>'.$entry->sponsorEntries->first().'</span>';
     }
    }

and then I call it:

        // Artists
     public function modifyEntryTableAttributes(&$attributes, $source){
      if ($source == 'section:9'){
        $attributes['sponsorEntries'] = Craft::t('Sponsor');
      }
     }

but I would like to get return all the entries, not just the first() one like the screenshot below illustrates.

You'll need to use the find method rather than first and last, in order to pull all the entries.

Then, you'll have to loop through the entries, appending their titles to a variable which will be used for the attribute's HTML value in the list view.

Here, I'm pushing the entry titles to an array called $tempArray. After looping, the array is joined and returned as a comma separated list:

public function getEntryTableAttributeHtml(EntryModel $entry, $attribute)
{
    if ($attribute == 'sponsorEntries')
    {
        if ($sponsorEntries = @$entry->$attribute->find())
        {
            $tempArray = [];
            foreach ($sponsorEntries as $sponsorEntry)
            {
                $tempArray[] = $sponsorEntry->title;
            }
            // Will return "Awesome Entry, Another Awesome Entry"
            return implode(', ', $tempArray);
        }
    }
}

If you want to, you can also make the entry titles in the list view clickable – i.e., to make it easy for your content editor to edit those entries – by wrapping the titles in anchor tags and pulling the entries' cpEditUrl property:

if ($sponsorEntries = @$entry->$attribute->find())
{
    $tempArray = [];
    foreach ($sponsorEntries as $sponsorEntry)
    {
        $tempArray[] = 'cpEditUrl . '">' . $sponsorEntry->title . '';
    }
    return implode(', ', $tempArray);
 }

...or if you prefer, you can make the links point to the entries on the frontend, by using $sponsorEntry->url instead:

$tempArray[] = 'url . '" target="_blank">' . $sponsorEntry->title . '';


Saving fields to a GlobalSet Can anyone suggest on how to programatically save fields to a GlobalSet?
I’ve been following this: Programatically Adding Fields to a Layout

But, doesn’t seem to work with a global?

I am doing the following :

Create a new field group - works
Assign fields to field group - works
Create global set - works
Create field layout - works
Create field layout tab - works
Set fields to layout tab - nope

.

// get all the fields from company info fieldgroup
$Fields = $FieldGroup->getFields();
// Get field layout
$GlobalSetLayout = $GlobalSet->getFieldLayout();

// Create tab model
$GlobalSetLayoutTab = new FieldLayoutTabModel();
$layout = craft()->fields->getLayoutByType(ElementType::GlobalSet);
$GlobalSetLayoutTab->setLayout($layout);
$GlobalSetLayoutTab->setFields($Fields);

// Set the tab's fields
$GlobalSetLayoutTab->setFields($fields);

// setTabs() expects an array
$layoutTabs[] = $GlobalSetLayoutTab;

// Now, set the tabs back in the layout.
$layout->setTabs($layoutTabs);

Not sure if part of the issue is because Globals don’t exactly have a “tab”, but looking at others in the database it does seem to have one with the name “Content”

Something like this should work:

// Generate name and handle.
$globalSetName = "My Global Set";
$globalSetHandle = lcfirst(str_replace(" ","", ucwords($globalSetName)));

// Create a global set
$globalSet= new GlobalSetModel();
$globalSet->name = $globalSetName;
$globalSet->handle = $globalSetHandle;

// get all the fields from  fieldgroup
$fields = $fieldGroup->getFields();

// Get ids of the fields.
$fieldIds = array();
foreach ($fields as $field)
{
    $fieldIds[] = $field->id;
}

// Assemble the field layout
$globalSetLayout = craft()->fields->assembleLayout(
    array(
        'Content' => $fieldIds,
    )
);

// Set the field layout type.
$globalSetLayout->type = ElementType::GlobalSet;

// Set field layout on global set.
$globalSet->setFieldLayout($globalSetLayout);

// Save global set.
craft()->globals->saveSet($globalSet);


Sorting matrixblocks by earliest date from child table I have a matrix field (events), each of this blocks (event) contains a table (dates) with individual rows (date), those have a start date and a start time. I would like to sort the events (matrix blocks) by the earliest start date / start time. Also at some point I would only want to display future events.

Whats the "best" way to achieve this kind of sorting in a template (twig)? Would I have to loop through them and sort them "manually"? I think about something around sorting the child tables first and then sort the blocks by their first table rows.

Entry

Event A [matrixblock]

Dates [table]

Date 1 | (12/12/2015) [datetimefield] | (10:00) [datetimefield]
Date 2 | (10/10/2015) [datetimefield] | (10:00) [datetimefield]

Event B [matrixblock]

Dates [table]

Date 1 | (09/09/2015) [datetimefield] | (10:00) [datetimefield]
Date 2 | (10/10/2015) [datetimefield] | (10:00) [datetimefield]
Date 3 | (11/11/2015) [datetimefield] | (10:00) [datetimefield]

This simple case would sort Event B, Event A. Because of the earliest date being Date 1 of Event B.

Appreciate any input. Cheers.

This is a bit tricky to do from the template, but what I would suggest is to query for the Matrix blocks once,
than loop through the blocks and store the data to a new custom array.

The idea is, to build that array in a way that ensures, you can later apply sort and group Twig filters.

{% set allDates = [] %}
{% for block in entry.myEventsMatrix %}
    {% for row in block.myDatesTable %}

        {% set allDates = allDates|merge([{
            datetime: (row.myDateTime|date('c')),
            eventId: (block.id),
            event: block
        }]) %}

    {% endfor %}
{% endfor %}

When sorting an array of arrays with the sort filter, the inner array's first value is relevant, so make sure this is the
DateTime you want to sort by. Besides that, I included the block's ID "eventID" and the complete block model "event".

{% set datesGrouped = allDates|sort|group('eventId') %}

{% for eventId, datesInEvent in datesGrouped %}
    <h3>{{ eventId }}</h3>
    {% for date in datesInEvent %}
        {{ date.datetime|date('Y-m-d') }}
    {% endfor %}
{% endfor %}

Outside the "datesInEvent" loop you can access the events model with:

{% set event = datesInEvent[0].event %}


Question about breadcrumb links I am using Craft only for the blog section of my HTML site. I have integrated my existing breadcrumbs to the blog, but there is a problem.

When I am on the home page of the blog, the word "Blog" in the breadcrumb is linked, and I would rather it not be linked.

I would like the word "Blog" in the breadcrumb to be a link only after going to an article on the blog. Please see attached.

The code I am using right now is

Home

Blog

            {% for crumb in entry.getAncestors() %}

{{ crumb.getLink() }}

            {% endfor %}

{{ entry.title() }}

I am new to Craft - thanks for your help!

A conditional that keys off the presence of the second segment to determine what to show for the "Blog" link/copy will work.

{% set seg2 = "" %}
{% set seg2 = craft.request.getSegment(2) %}

Home

        {% if seg2 == "" %}
            Blog
        {% else %}
            Blog
        {% endif %}

    {% for crumb in entry.getAncestors() %}

{{ crumb.getLink() }}

    {% endfor %}

{{ entry.title() }}


Craft 2, MySQL database, Twig, JavaScript files I have created in Craft 2 CMS, under the profile of users (ex. parents), new tab for (children), where parents can fill in there children information.

The data is saved in a database under the craft_content

How can I use the dropdown in a Twig file, data for child to be shown?

Can anyone help with the code?

I have installed Neo plugin in Craft CMS

I have all ready created form, for parents profile that has child info. On website i need to add dropdown menu, in which is information of there children, so parents when is log on website, don't need to fill out information for children, they can choose from dropdown.

It sounds like you want to loop through the children (Entries?) and output the data as a dropdown menu...

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

<select name="fields[children]">
    {% for child in children %}
        <option value="{{ child.id }}">{{ child.title }}</option>
    {% endfor %}
</select>

For more information, see this thread...


Find related entries with the same tags I would like to retrieve related entries that have the same tags, not just one similar tag, but all of them.

At the moment I do something like:

{% set tags = entry.tagActualite %}
{% set relatedEntries = craft.entries.relatedTo(tags).id('not ' ~ entry.id).limit(5).find() %}

{% if relatedEntries | length %}
    {% for entry in relatedEntries %}
        do stuff
    {% endfor %}
{% endif %}

But it retrieves any entry with at least one similar tag.

How would i check against ALL tags ?

I believe you'll need to look at using the following syntax:

craft.entries.relatedTo('and', { targetElement: tags })

You might have some luck using the Similar plugin.


Is it Possible to Use Live Preview with Global Settings I know that out of the box one cannot use Live Preview with Global Settings.  I am wondering if it is possible to write a plugin or in some other manner get Live Preview to work with Global Settings.

Anything's possible, but not without hacking core files, which isn't recommended.

By default, global settings don't even have the concept of a "template", which is a fundamental part of getting a Live Preview request to work.


Categories not adding trailing slash In my general config I have enabled URLS to have trailing slashes.

'addTrailingSlashesToUrls' => true,

This is working for products and entries. But it is not working on Categories. Category links are not adding trailing slashes.

Is there some additional config I need to add/setup or is this a bug?

Whoops! Sorry. As I went to check the code I realised, I was using {{ category.uri }} instead of {{ category.url }}.


Insert action in front of template, while maintaining entry slug We are attempting to implement a number of Pardot forms within Craft templates.  Since Pardot's form actions do not allow us to dynamically specify a return URL, our best choice is to use the form's URL as the return URL.

Our page is /about/contact.  We want one of three things to happen on this page:

If the user has an identifying cookie on their machine, display only a comment field, for example
If the user does not have a cookie saved, display the complete form
If the user is returning from Pardot, set a cookie and display a thank you message.

It's important to us that we maintain pretty URLs, so we have created a route in routes.php:

return array(
  'about/contact' => array('action' => 'pardotForm/ManageForm'),
);

Our contact page is an entry in our Landing Page structure.  We've set that entry's slug to be something random so that Craft does not route to the default controller for that entry.  It is set to "contact-us-page".

We would like to maintain the actual slug on the contact page as "contact" so that we can use slug features in normal ways.

Is there any possible way to maintain our slug as "contact", our url as "about/contact", and still route to our 'pardotForm/ManageForm' action?

The easiest way to solve this, would be to use a template hook instead, and put all your PHP code in there.


Ajax Load more Posts On my blog i need a load more button on the bottom of each section that simply loads more posts when clicked. Everything i look at people are using other javascript libraries. I just want to use ajax no external libraries

{% for entry in craft.entries.section('news').limit(10) %}
{% set categories = craft.categories.relatedTo(entry) %}

            {% for asset in entry.newsFeaturedImage %}

            {% endfor %}

            {% for category in categories %}

                    {{ category.title }}

            {% endfor %}

                {{entry.title}}

                {{ entry.newsExcerpt|length > 150 ? entry.newsExcerpt|slice(0, 150) ~ '...' : entry.newsExcerpt  }}

                Continue Reading

   {% endfor %}

First you create a function to send the data to a custom controller

var offset = 10
var getElements = function(){
    var data = new FormData();
    data.append('offset', offset);
    data.append('action', 'plugin-name/controller-name/function-name);
    data.append(window.csrfTokenName, window.csrfToken);

    var xhr = new XMLHttpRequest();
    xhr.open('POST', '', true);
    xhr.onload = function () {
        // check for errors
        if(this.status === 200){
            var response = {};
            try {
                response = JSON.parse(this.responseText);
            } catch(error) {
                throw Error("server did not return valid JSON: " + this.statusText + ' ' + this.status);
                return false;
            }
            // append your response to the object/container you like
            offset += response.elements;
        }
    }
    xhr.send(data);
}

Then in your controller just fetch the entries

public function actionGetElements(): Response
{
    $offset = Craft::$app->getRequest()->getBodyParam('offset');
    $query = Entry::find()->section(['whatever'])->limit(10)->offset($offset);
    $elements = $query->all();
    $html = Craft::$app->getView()->renderTemplate('path/to/template', [
        'elements' => $elements
    ]);
    $fetchedElements = \count($elements);
    $totalElements = $query->count();
    return $this->asJson(
        [
            'html' => $html,
            'success' => true,
            'elements' => $fetchedElements,
            // check if the number of fetched element + offset is equal to the number of total elements
            // if that's the case you can hide the button to load more since there are no more elements
            'hideButton' => $fetchedElements + $offset === $totalElements
        ]
    );
}

Keep in mind to include a CSRF token data.append(window.csrfTokenName, window.csrfToken); and to include an protected $allowAnonymous = [ 'actionGetElements']; to your controller


Interner Serverfehler Interner Serverfehler

Weder Craft\EntryModel noch zugehörige Behavior haben einen Scope "competitionTitel".

what is wrong… it works fine til i delete one point in the menu

Somewhere in your templates, you're referencing a custom field competitionTitel that doesn't exist. It sounds like you might have recently deleted it.

It will probably look something like entry.competitionTitel in your template.  You either need to create that field or adjust your templates to not call it.