Is it possible to clear caches and re-index assets programattically? When migrating a Craft site, I'm used to...

deploying files
checking my config, tweaking as necessary
loading a database backup
running "Update Asset Indexes" and "Clear Caches" from the control panel

That last step is always important because random oddities and broken images are fixed site-wide because of caching and transforms. Now I'm attempting to automate the process with a Docker deploy script, so I'm wondering: is there any way to Update Asset Indexes and Clear Caches programmatically?

I know that you can nuke the craft_assettransformindex table and delete the contents of /craft/storage/runtime/assets and /craft/storage/runtime/cache (related question), but is that really doing the exact same thing?

Note that by "programmatically," I generally mean anything you could achieve from a Linux terminal: MySQL commands, PHP or shell scripts, etc.

I guess it depends. So, behind the scenes, Craft can have different cache drivers. You might use the db or file cache, or something like Redis or Memcache.

Took a peek at ClearCachesTool, and it looks like it's doing the things you mentioned:

craft()->db->createCommand()->truncateTable('assettransformindex');
craft()->db->createCommand()->truncateTable('assetindexdata');

As well as deleting all the internal cache folders (runtime/cache, assets, compiled_templates, temp), including any plugin cache paths that have registered via registerCachePaths.

craft()->db->createCommand()->delete(static::$_templateCachesTable);

It also deletes the templates cache.

I guess what you're looking for are these:

CacheService->flush()
ClearCachesTool->performAction() (does most of the clearing)
craft()->templateCache->deleteAllCaches(); (called in ClearCachesTool - TemplateCacheService)

So yes, you can either bootstrap Craft and call a php file from the commandline, or add a plugin with an action that you GET/POST to after deployment.

The former, you can do with the included bootstrap.php file (as of 2.2)

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


Unable to output position select value Please someone tell me where I'm going wrong with this. I have a Matrix field called Page Builder (pageBuilder) and have different matrix blocks for outputting information in different ways.

This code in the entry template works fine for every field except for the one called Placement (placement) which is a position select field. I can't for the life of me get it to output anything at all :-(

Please tell me where I'm going wrong on this one as I'm sure it's going to be something stupid with my code syntax somewhere but just can't tell where for the life of me!!

{% for block in entry.pageBuilder %}

{% switch block.type %}

    {% case "textBlock" %}

        {{ block.text }}

    {% case "callToAction" %}

        &lt;h3&gt;{{ block.blockColour }}&lt;/h3&gt; {{ block.text }}

    {% case "sectionBlock" %}

        {{ block.text}}

    {% case "threeColumn" %}

        {{ block.column1 }}
        {{ block.column2 }}
        {{ block.column3 }}

    {% case "smallColumnLargeColumn" %}

        {# CAN'T GET THIS NEXT BIT WORKING #}
        {% switch block.placement %}
                {% case "left" %}

Code to output if left

                {% case "right" %}

Code to output if right

        {% endswitch %}
        {# ----------------------------------- #}

        {{ block.column1 }}
        {{ block.column2 }}

{% endswitch %}
{% endfor %}

If you're looking to just output the value of the PositionSelect field, it's block.placement.

See here for more info: http://buildwithcraft.com/docs/position-select-fields#templating


Removing index.php causes Not Found error on secondary pages I'm moving an existing site to the new server and spent a couple of days trying to make this work.

Home page of the site loads just fine. Other pages load too if I add /index.php/ to the url. Otherwise I get 'Not Found' error.

Have gone through all the suggestions here: https://craftcms.com/support/remove-index.php, here: https://craftcms.com/support/why-index.php, and here: https://craftcms.com/support/enable-path-info. Everything checks out.

My .htaccess in /public_html:

<IfModule mod_rewrite.c>
   RewriteEngine On

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

</IfModule>

I'm on a clean install of Apache server. Made sure I have all the required extensions and config matches suggestions on the Craft site.

Thanks to @brad-bell - his comment on another post pointed me in the right direction. I thought that I already checked on mode_rewrite but I didn't.

  The Apache mod_rewrite module wasn't installed, so the  block of Craft's default .htaccess file was being
  skipped not allowing index.php to be rewritten in the URL.

Enabling mod_rewrite solved the issue.


Dragging images inside of rich text editor On Redactor's website, they provide a demo with an image that you can click on and drag around the editor to relocate it among the text.

Video example from Redactor's website

Trying this same functionality in the rich text editor in the Craft control panel doesn't work though. I even copied the demo HTML from Redactor's website and pasted it into Craft, without any luck.

Video example from Craft control panel

Has anybody been able to get this working or have any idea why this functionality would be missing in Craft?

Just looked into this and it’s a Craft bug. If you add an image manually using the “Insert URL” option, the image can be dragged around, but not if you use the “Choose image” option, which opens Craft’s image selection modal.

Saving the entry and coming back to it (or just typing Command + S) will also make the image draggable, regardless of how you added it.

We’ll get this fixed.


Update Asset Indexes for new files in s3 not working We uploaded a lot of images to the S3 bucket that is connected to our assets in Craft, but when we run "Update Asset Indexes" on the settings page, those images aren't added to the assets in Craft.

I'm pretty sure that the settings for the asset source is correct (images that we upload via Craft are working). And it doesn't seem to be related to a time-out, because we updated the php and nginx settings, and now it finishes after ~70s instead of 60s.

What are we doing wrong?
Is it even possible to import images this way?

We ended up using this cli tool:
https://github.com/rsanchez/craft-cli

We still had to tweak the php memory limit in the php config: memory_limit 2048M

But eventually we managed to index 21.000+ images this way.


How to recover a previous draft? I pasted in incorrect copy in my product description window in the dashboard, then updated the entry. Is there a way to find/revert to my previous draft? Thank you.

In your Entry click on the revision list next to the entry title.


How I’ll get an entryId based on a given URL? I want to configure deeplinks for an app and want to set up 'universal links'. Right now I'll send an entry id to the element api to get the right content. But with universal links I didn't have a entry id, only a url. Based on the url I'll need to get the right entry instead of based on the entry id.

Down here is my current endpoint to get the right entry based on a id. But if I didn't have an id how can I get the entry id based on the url.

for example website.com/pages/welcom has entry id 123, in the app I can open it with sending 123 to the api endpoint. With universal links I open a link from my mail app for example then the app launches and I can send 'website.com/pages/welcom' to the api but how I'll get the right content from that page that has entry id 123.

'api/pages/<entryId:\d+>' => function($entryId) {

        requireLogin();

        return array(
            'elementType' => 'Entry',
            'criteria' => ['section' => 'pages', 'id' => $entryId],
            'transformer' => function(EntryModel $entry) {

                $bodyBlocks = [];
                foreach ($entry->contentBlokken as $block) {
                    switch ($block->type->handle) {
                        case 'tekst':
                            $bodyBlocks[] = [
                                'text' => $block->description->getParsedContent(),
                            ];
                            break;
                    }
                }

                return array(
                    'id' => $entry->id,
                    'title' => $entry->title,
                    'description' => $bodyBlocks,
                );
            }
        );
    },

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

You could query the craft_elements_i18n table (pseudo code):

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

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


Querying across relationships in a template I have two Sections on my site: Country and Alert. The Alert section has a relation with Country via an "Entries" field. An Alert represents something that is happening in a particular country for a period of time so it will have a post date and an expiry date.

In my template, I want to show a list of the 5 Countries that have currently active Alerts (ideally ordered by the country with the latest Alert).

I'm not sure how query across relationships in Craft (outside of using the relatedTo query, but that only allows you to related to one entry, not a number of entries)? It seems all relationships are handled in a separate relation table in the DB.

How can I achieve an query such as this within a Craft template?

OK, here is one solution I've come up with, which seems to work and (I think) avoids 1+ queries:

{% set groups = craft.entries({
    section: 'alert',
    with: [
        'country',
    ]
}).orderBy('postDate desc').status('live').all() | group(alert => alert.country[0]) %}

    {% for country, alerts in groups | slice(0, 5) %}

            {{ country }}

                {% for alert in alerts %}

{{ alert.title }}

                {% endfor %}

    {% endfor %}

I would prefer being able to handle this entirely in queries though


How can I append a structure entry and set its order? I'd like to attach children to a specific Structure entry in a specific order...

  Entry A
  Entry B

  Imported Entry 2
  Imported Entry 1
  Imported Entry 3

  Entry C

I've got a $records array to turn into imported entries:

array(
    'name'      => 'Whatever',
    'updated_at' => '2014-02-27T04:14:29Z',
    'position'   => 1, // int representing the sort order
    [...]
)

As I'm looping through my array to create new Craft Structure Entries, I need to be able to define the parent (Entry B), I'm just not sure how. I've figured out how to attach new children to Entry B, I just don't know how to programmatically set their order. My imagination writes code that looks like this:

$parentCriteria = craft()->elements->getCriteria(ElementType::Entry);

$parentCriteria->search  = 'slug:entry-b';
$parentCriteria->section = 'sectionName';
$parentCriteria->type    = 'sectionType';

$entries = $parentCriteria->find();
$parent = $entries[0];

foreach ($records as $row)
{
    $entry = new EntryModel();

    $entry->sectionId = 4;
    $entry->typeId    = 4;
    $entry->parentId  = $parent->id;
    $entry->authorId  = 1;
    $entry->postDate  = $row->updated_at;
    $entry->title     = $row->name;
    $entry->sortOrder = $row->position; // ← quite impossible!

    $success = craft()->entries->saveEntry($entry);
}

It's $entry->sortOrder that's completely made up—how do you attach an entry to a specific parent in a specific order?

If you're adding them all as new entries anyway, why not just sort the records before you create the entries?

usort($records, array($this, 'sortCategoriesByPosition'));

Add that before your foreach loop, then...

private function sortCategoriesByPosition($a, $b)
{
    if ($a->position == $b->position)
        return 0;

    return ($a->position < $b->position) ? -1 : 1;
}

Stop trying to make things harder than they should be.


Using a virtual host result in internal error I'm trying to setup a virtual host to access my craft project through ontherocks.dev, without any success yet.

www.ontherocks.dev : correct response
www.ontherocks.dev/admin : Apache 404
www.ontherocks.dev/index.php/admin : redirected to www.ontherocks.dev/admin/install with an Apache 404

I didnt "install" craft yet, which explains the redirect. Here are my config files for the virtual host :

httpd-vhosts.conf

<VirtualHost *:80>
  ServerName ontherocks.dev
  DocumentRoot "C:\wamp\www\y-lynx"
  ServerAlias www.ontherocks.dev
 DirectoryIndex index.php
</VirtualHost>

hosts file in system32/drivers/etc

# localhost name resolution is handled within DNS itself.
#   127.0.0.1       localhost
#   ::1             localhost
127.0.0.1       ontherocks.dev

Thanks for your help !

Looks like the .htaccess file included with Craft is not being read or you didn't rename it (should be .htaccess with the period at the beginning).

That's why /index.php/admin is working but /admin/ is not.

One other possibility is Apache is setup to ignore .htaccess files. If that's the case, add this to your httpd-vhosts.conf file.

<Directory "C:\wamp\www\y-lynx">
    AllowOverride All
</Directory>

(If you already have a <Directory "C:\wamp\www\y-lynx"> block, just add in AllowOverride All somewhere inside.)


What is a Webhook Signing Secret? I could not find any documentation on the 'Webhook Signing Secret' used in Commerce Settings > Gateway > Stripe Gateway. Can someone tell me what this is, what it's used for and typically what I should be entering as a value? Not sure if this is even required? References or insight most appreciated.

Webhooks are like callback events. Basically when something happens on Stripe's side (eg a new customer created, a trial subscription cancelled, etc.) your application can get notified as well and take the appropriate action.
They're less useful when your application controls that entire process but in the case of subscriptions, let's say the customer's card declines after month 2. You definitely want to get notified when that happens and take the appropriate action since Stripe is taking care of those payments.
A webhook signing secret is optional but it's basically a signature for verifying that whatever webhook Stripe is sending is legit. Stripe uses a secret key that Commerce can use to verify that Stripe was the really author of that webhook call which can help prevent things like replay attacks.
It's less useful in the case of smaller applications but if you're building something with Stripe Connect where multiple users can authenticate, get payouts, etc. it becomes essential.
In the case of security, nothing is ever binary. Much like CSRF protection, you want layers of an onion and signing secrets provide another layer of protection.


Multiple Craft install configuration in subdomains I was playing around that quiet long time, because I didn't want to post the question right away I encounter on some difficulties. But here I go.

The goal

is to have separate craft installs for each subdomain.

The problem

When I hit enter to start installation, I get this The requested URL /admin was not found on this server. Have tried with *index.php?p=admin *, but with no effect.

I've set up virtual host subdomain.craft.dev
Checked, if the host loads anything. It does.
Uploaded public files to subdomain.craft.dev and edited

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

P.S Could I simply use $craftPath = '../subdomain.craft';? I've tried it at first without positive results.
Created folder subdomain.craft above the webroot. In it, uploaded craft folder and set the permission for required directories recursively.
Edited db.php to the needs of Craft's installation.
Run the install by visiting the host address subdomain.craft.dev:8888/admin

I also use MAMP. Here's my general process (I've used generic names in this example; but feel free to rename folders, hosts, as needed):

create the folders for your two sites:

/Applications/MAMP/htdocs/domain.craft.dev
 /Applications/MAMP/htdocs/subdomain.domain.craft.dev
Download craft, unzip and copy the public and craft folders to your new folders:

/Applications/MAMP/htdocs/domain.craft.dev/craft
 /Applications/MAMP/htdocs/domain.craft.dev/public
 /Applications/MAMP/htdocs/subdomain.domain.craft.dev/craft
 /Applications/MAMP/htdocs/subdomain.domain.craft.dev/public
Create two new hosts in MAMP, 'domain.craft.dev' and 'subdomain.domain.craft.dev'; set the 'document root' to the respective '/public' folders; start server. (I also have the server set to serve on port 80 instead of the default 8080; which avoids problems with your craft configuration).
Using Sequel Pro (phpMyAdmin), create two new databases. 'craft_domain' and 'craft_domain_subdomain'.
In each of the sites.

Rename 'public/htaccess' to 'public/.htaccess'
Set permissions on the following folders and all contents to 777 (for now; will want this more restrictive on public servers)

craft/app
craft/storage
craft/config (technically only need it on the license.key file)

(optional) delete 'web.config' from 'public' and 'craft' folders (assuming you don't need them)

Open 'craft/config/db.php' and set the database connection details (server, port, user, password, database).
Open 'craft/config/general.php' and set your config settings, if any.
Open 'public/index.php' and confirm that $craftPath = '../craft'
Navigate to your site in the browser (domain.craft.dev) and (subdomain.domain.craft.dev) and follow on screen instructions to continue install.
Have a beer and celebrate. (maybe 2... one for each site?)

(Did I miss anything?)

Advanced. For steps 6, 7 and 8 above, I actually use a slightly different setup. Instead I use this multi-environment configuration method from the craft cookbook site which allows you to define your environments from within your 'index.php' file; combined with Ben Parizek's technique as described in this answer for automatically configuring 'siteUrl' and 'basePath' environment variables. Note: doesn't work well if MAMP is set to serve on port 8080.


Is it possible to take an excerpt from the first rich text area in a matrix? I have blog articles set up on the site i'm working on to be built using a matrix, much the same way as in the features video about the matrix field. So it is entirely possible for an article to start with an image or a video.

What i'd like to be able to do is find the first text entry in the matrix and pull the first 155 characters out of it, creating an excerpt. The point of this is to pass that into a meta og:description tag (and i guess meta description too!)

Is it possible to do that with matrix content?

You can filter by block type: http://buildwithcraft.com/docs/matrix-fields#filtering-by-block-type

In short:

{% set ogDescription = false %}

{% for block in entry.myMatrixField.type('richText').limit(1) %}
  {% set ogDescription = block.text | striptags | slice(0, 155) %}
{% endfor %}

{% if ogDescription %}
  ...
{% endif %}

Also, this was suggested in the comments:

{{ entry.myMatrixField.type('richText').first() | striptags | slice(0, 155) }}


Max # of entry types? Is there a limit to the number of different entry types a section can have? For this project I might need 50+.
I think I need more content to meet the quality standards so I'll explain: my client wants to create multiple reports for her customers to fill in. My client is comfortable with craft backend and knows how to create fields/sections/etc. I want to keep all the report entries together. Ergo a Reports section with a different entry type for each report.

Brad mentions there's no limitations on entry types, though whether it's a good idea long term for maintainability and UI purposes is another story.
Entry Types are the most useful when your content is quite different among them but you still want to keep entries together in the same section.
For example, in a News section, you might have a Link to Page entry type where you link off to different websites and a Blog Entry type where they're just regular entries. (John Gruber's Daring Fireball site is a good example of this.
In my experience, when a user starts to see a dozen or so entry types, it can start to become pretty overwhelming... here's what 50 of them staring you in the face might look like:

Entry types are useful because they each have their own set of fields.
However, from a maintainability standpoint, let's say you want to add or move a field in every report. Doing it to 2 or 3 entry types is pretty straightforward but doing it consistently to 50? Way harder—whether you're using YAML files or the GUI!
The 80/20 rule might be helpful here: I'm guessing 80% of the reports generated are probably going to fall into 20% of their types. That just narrowed down the number of entry types to 10.  Maybe you add a few other more common ones plus a catch-all "Other..." entry type or something.
Unless your client is also a fellow developer/designer, they don't want to be adding fields and sections to the backend unless absolutely necessary.
If I were you, I might ask you client: what's different about each report? What's the same? You'll come across some good answers which can help you and your client model this nicely.
That could lead you to use something like Categories instead, where it's very easy to add new ones. If the report types are more like filters, they also will show much nicer in the GUI.
And maybe you do need some report types to hide and show different fields but are otherwise pretty similar. You might consider doing this with, say, the Reasons plugin.
Food for thought!


nesting functionality missing in section type structure after feed-me import i create an new section from type structure.
when i manually add the entries and nest it everything works as aspected.

after importing my entries with feed-me and the option create parents if not exist the nesting is gone and i cant set test as parent in Content-test. when i check the section.yaml its still of type structure.

there is for me no way to get the nesting back.
only option now is to recreate the section.
anyone although having this issue?

Check the sort order dropdown at the top right of the index page to make sure you're on "Structure".


Redactor I icons missing As you can see from the image below, the icons are missing from redactor I. Has anybody else had this issue? Running dev tools in chrome shows no errors.

Bold, for example has the following css selector:

.re-bold:before {
  content: "\e618";
}

I see that the @font-face src is base64 encoded right into the CSS file, so the issue can't be because of a missing font file for the icons can it?

Here is the bold link inspected in dev tools:

As you see there is no mention of .re-icon in the markup, but the only declaration of the font-family: 'RedactorFont' is for the .re-icon selector class. So adding .re-button::before to the selector that declares the font results in this:

...Close but not quite right. I shouldn't be editing these files, but am just doing so to help diagnose this. Presumably this redactor.css file shouldn't be referenced... it should be redactori.css?

It seemed that for some reason my fields said they were Redactor I but were in fact Redactor II.

Reinstalling Redactor I did the trick.


When uploading assets what determines the maximum file size? When I upload an asset I get an alert window stating my file size is to large. I have increased the file size in the general.php config file larger than the file size, however I keep getting a error. We are using AmazonS3. Is Craft limiting the file size, PHP or AmazonS3?

Craft itself, limits the filesize only in the maxUploadFileSize. Default: 16MB

However Craft gets limited by:

PHP: Has a few values which might cause the problem:

memory_limit
max_input_time
upload_max_filesize
post_max_size

AmazonS3: If not limited by a policy value, the default is 5GB.

User: Sometimes it can be just a Browser issue causing the problem.


Pass 'not' category.id to relatedTo in Craft I have a search page that filters with these params:

{% set results = craft.entries({
    section: 'properties',
    price: range,
    search: query.location,
    relatedTo: status,
    order: priceDesc
}) %}

The status variable needs to be set to a 'not' this category (or an array of all the other categories), but I can't seem to phrase my param correctly.

I've tried both the string and array method with category ID's, like this:

relatedTo: ['not', category.id]

And this:

relatedTo: ['or', category1.id, category2.id, ...]

Advice?

You need to exclude the ids in order to achieve your goal. So instead of relatedTo not you need a normal related to but the not statement in your id

I'm not on my computer currently so I'll edit the exact code in about 2h but it's the same like that one
https://craftcms.stackexchange.com/a/22532/5557

id.('and, not ' ~ idsOfEntriesYouWantToExclude|join(', not ')
Is the important part. In order to get them you just select all entries that are related to the thing you want to exclude

Edit
untested but this should do it

{% relatedEntries = craft.entries.relatedTo(status).ids() %}
{# just for debugging to test if the queryString is correct #}
{% set queryString = 'not ' ~ relatedEntries|join(', not ') %}
{% set results = craft.entries({
    id: 'and, ' ~ queryString,
    section: 'properties',
    price: range,
    search: query.location,
    order: priceDesc
}) %}


Using `getPrev` and `getNext` with entries sorted by SuperSort plugin? I applied the superSort plugin function to a list of entries and it works perfectly:

{% set entries = craft.entries.section('sectionName').type('entryType').order('entryTitle')|supersort('natsort') %}

Trying to apply it to an entry page with this code to get the previous and next entry. It does not work:

{% set arrowParams = craft.entries.section('sectionName').type('entryType').order('entryTitle')|supersort ('natsort') %}
{% set prevEntry = entry.getPrev(arrowParams) %}{% set nextEntry = entry.getNext(arrowParams) %}
  {% if prevEntry %}
    {{ prevEntry.title }}
  {% endif %}

  {% if nextEntry %}
    {{ nextEntry.title }}
  {% endif %}

Thanks for helping!

It won't work with getPrev and getNext, as they only work with ElementCriteriaModels and not with an array of Entry models.

But that is what you get returned from the plugin. Supersort converts your craft.entries ElementCriteriaModel into an array of Entry models. This is necessary so that it can do the sorting.

The only workaround I know of would be to get the IDs of your supersorted entries and pass them to the ID param of a new ElementCriteriaModel.

{% set entries = craft.entries.section('sectionName').type('entryType') %}
{% set entriesSorted = entries|supersort('natsortAs', '{title}') %}

{% set entryIds = [] %}
{% for entry in entriesSorted %}
    {% set entryIds = entryIds|merge([entry.id]) %}
{% endfor %}

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

Now you have an ElementCriteriaModel arrowCriteria, prepared to get entries in the desired sort order. So now you can use arrowCriteria with your entry methods.

{% set prevEntry = entry.getPrev(arrowCriteria) %}
{% set nextEntry = entry.getNext(arrowCriteria) %}

{% if prevEntry %}
    {{ prevEntry.title }}
{% endif %}

{% if nextEntry %}
    {{ nextEntry.title }}
{% endif %}


Database Backup Contains Perplexing Number Of Duplicates I recently had a craft update fail when moving from 2.4x to 2.5x. This was probably caused because the linux user craft was using did not have the proper permissions. This is all good and fine. Craft created a DB backup before updating and this is where I am having a very strange issue. This DB backup has tons of duplicates, seemingly on every table. Importing the database always ends in Duplicate entry '1' for key 'PRIMARY'. The dump is also trying to add the same tables multiple times. The database I am importing also into has nothing in it. Has anyone run into this issue?

Here is a partial database dump:
http://pastebin.com/FRgp1FPy

If you for example look at line 100 and 135, you can see that the dump has duplicate primary keys in the table craft_assetfiles. This dump also shows that the craft_assetfiles table is being added twice and with different data each time.

It's because (at least for the one table you posted) your table is missing its foreign keys, which is responsible for maintaining uniqueness on their referenced columns.  For example, the asset_files table should have this as part of its DDL:

CONSTRAINT `craft_assetfiles_folderId_fk` FOREIGN KEY (`folderId`) REFERENCES `craft_assetfolders` (`id`) ON DELETE CASCADE,
CONSTRAINT `craft_assetfiles_id_fk` FOREIGN KEY (`id`) REFERENCES `craft_elements` (`id`) ON DELETE CASCADE,
CONSTRAINT `craft_assetfiles_sourceId_fk` FOREIGN KEY (`sourceId`) REFERENCES `craft_assetsources` (`id`) ON DELETE CASCADE

This can happen if the database was imported to a MySQL box that only had MyISAM (which doesn't support foreign keys) and the keys will silently get dropped.

Or we've seen it happen from a failed import/export whether from a script or a MySQL client.

Regardless, you can use this script to try and help restore the missing foreign keys: https://github.com/pixelandtonic/craft-fixfks

Be aware you still might have to do some manual data cleanup from duplicated/inconsistent data.


Adding admin user accounts I'm lost when it comes to adding a new admin user account. In the dashboard, I go to Settings -> Users, where I'm expecting to find a form where I could input a username, email address, password, etc.  Instead, I'm presented with a blank field layout. So I'm supposed to manually create fields for the username, email address, and password? What fields do I need to add and how do I know what to name the fields? Is there any documentation on this?
Neither the users documentation page nor the user management page offer any help. However, on the User Management page I read this sentence:
  To enable public registration, go to Settings → Users → Settings, and check the "Allow public registration?"

When I go to Settings -> Users -> Settings, all I see is a field to change the User Photo Location and a Save button, nothing else. I'm not trying to enable public registration, but the fact that that option is missing makes me wonder what else is missing.
I don't even know where to begin. Can someone point me in the right direction? Your help is greatly appreciated.

Upon setup, Craft is installed with a free Solo license. This means that the user generated as part of installation is “the only account you will be able to create.” (From the official User Management documentation)
In order to create more users, you’ll have to upgrade your installation to the Pro version through the control panel’s Plugin Store. Pro is free to test and develop with.


"Purify HTML" on plain text fields Recently we've had someone/something trying to perform a XSS attack using a form which saves all data into sessionStorage and then sends it to a custom craft plugin to pair it with a user.

A solution to stop these XSS vulnerabilities from craft docs is to "enable all “Purify HTML?” Rich Text field settings" but I've noticed this option only exists for Rich Text fields.

So my question is, is it somehow possible to activate "Purify HTML" on plain text fields (and other types of input like select and checkboxes)? Or do I need to escape/encode these fields on the client side (and how)?

The reason there is a "Purify HTML?" setting only for Rich Text fields is that Twig will automatically escape the output of every other field by default, mitigating XSS attack vectors.

Rich Text fields, by nature, are designed to store HTML, therefore their output isn't escaped and you have to rely on things like "Purify HTML?" (which uses http://htmlpurifier.org/) to try and remove anything malicious looking.

If you're plugin needs to output data for a Plain Text field in a way that doesn't get escaped (for whatever reason), you can always run HTMLPurifier on it manually.


Plugin not working on PHP 5.3 I written a plugin which doesn't work on PHP 5.3 but does work on 5.4

It doesn't seem to be even routing to the function as if I I add a die("dead") to the controller function I still just get a 500 error if using ajax or a blank page if going straight to the actions URL

The craft requirements say PHP 5.3 and above, is this not the case for plugins?

In theory, all plugins should be 5.3 compatible... but of course, it's up to the plugin developer to decide their own minimum requirements. 99% of publicly available plugins seem to be 5.3 compatible.

The biggest "gotcha" between 5.3 and 5.4 is the simplified array notation. In 5.4, you can declare arrays with simple square brackets ([]), instead of the more verbose array() syntax. That's one of the most notable changes between versions. Although, this doesn't seem to be the problem you're having. You'd at least see the plugin load, and kick up some sort of error message.

I'm guessing that you're testing the 5.3 vs 5.4 requirements on two separate servers? If so, you're probably running into an uppercase/lowercase problem. This actually has nothing to do with the version of PHP... Some servers care about casing, while others don't.

See this thread for a full explanation on casing, and why it might be causing your problem:

  https://craftcms.stackexchange.com/a/1537/45


Displaying content defined by radio button in admin panel I want to let my customer decide if they want a 2 or 3 column page so I made a radio button but now I need to show different content if they select one of them but I cant get the syntax right.

{% if entry.column.contains ('two') %}
   content here for two columns
{% endif %}

{% if entry.column.contains ('three') %}
   content here for three columns
{% endif %}

Close! You can get the selected radio button by its label (what the user sees) or the value you setup in the admin. I'm assuming you're using the value.

{% if entry.column == "two" %}
    {# show 2 column content #}
    2 columns
{% elseif entry.column == "three" %}
    {# show 3 column content #}
    3 columns
{%endif%}

You could also try a switch statement. That gives you a way to fall back to a default option, which might be useful, and a cleaner way to check for more than a couple options (say the client wants a 3 column option with some a special sidebar that doesn't really fit):

{% switch entry.column %}

    {% case "two" %}

       {# show 2 column content #}
       {% include "layouts/_2columns.html" %}

    {% case "three" %}

       {# show 3 column content #}
       {% include "layouts/_3columns.html" %}

    {% case "threespecialsidebar" %}

       {# show 3 column content #}
       {% include "layouts/_3column_sidebar.html" %}

   {% case "default" %}

      {# default to a 1 column layout #}
      {% include "layouts/_default.html" %}

{% endswitch %}

To keep yourself sane, in the switch example, also consider using a include which will bring in a corresponding layout file, depending on which layout you want.  (A stray div for example will drive you crazy.... consider putting your markup in separate files.)

One last thing: from a client standpoint, depending on what you're doing, an entry type might be a better way to handle multiple layouts or if there needs to be additional options/fields in a  certain layout. (In that case, use entry.type instead of entry.column but the rest of the syntax posted above would be exactly the same).


Commerce 'Edit Order' page taking 10 seconds or more to render The individual order view in the CP is taking 10 seconds or more to be displayed, how can we avoid/debug this?

PS. Can ignore the errors in the log (I think) as  they are just mmikkel\cpclearcache\{closure}    Error registering AssetBundle - Unable to find the template “_components/utilities/ClearCaches”.

Just some data for comparison - on our production server, an individual order comes up in a tad less than 2 seconds...(and on local dev it's much the same actually).

Are you up to date with Commerce as there was some work on this I believe: https://github.com/craftcms/commerce/issues/828 (so version 2.1.5 & above should be better).

Or perhaps you have some very expensive custom field stuff attached on your orders??


Is there a way to split the element-api.php file? Is there some way I can split the element-api.php file into separate files and import them all? It's getting quite long and unwieldy.

Sure – the element-api.php config file is just plain ol' PHP, and the functions that make up the individual endpoints (e.g. 'news.json' => function () { ...) doesn't necessarily have to be declared inside that file.

One way to split up the file would be to create one PHP class per element type or section. You could compose these classes however you'd like, but something like the below would work (this is an example file containing two endpoints for the news section, and the example assumes that the file is saved under /config/endpoints/News.php):

<?php

namespace config\endpoints;

use craft\elements\Entry;
use craft\helpers\UrlHelper;

class News {

    public static function index()
    {
        return [
            'elementType' => Entry::class,
            'criteria' => ['section' => 'news'],
            'transformer' => function(Entry $entry) {
                ...
            }
        ];
    }

    public static function view($entryId)
    {
        return [
            'elementType' => Entry::class,
            'criteria' => ['id' => $entryId],
            'one' => true,
            'transformer' => function(Entry $entry) {
                 ...
            }
        ];
    }
}

The next step is to make the file available to the element-api.php config file. One way to do it, is to simply include() it at the top of the element-api.php file:

include __DIR__ . '/endpoints/News.php';

Then, you can add the endpoints from the News endpoint class to the config in element-api.php, i.e.:

<?php

include __DIR__ . '/endpoints/News.php';

use config\endpoints\News;

return [
    'endpoints' => [
        // use an anonymous function to prevent errors when running via cli
        'news.json' => function () {
            return News::index();
        },
        'news/<entryId:\d+>.json' => function ($entryId) {
            return News::view($entryId);
        },
    ],
];

If you want to take this a step further, a much nicer approach than using include() is to have Composer autoload your endpoint classes by adding the below to your composer.json file (again, this assumes that the custom endpoint classes live under /config/endpoints/):

"autoload": {
    "psr-4": {
        "config\\endpoints\\": "config/endpoints"
    }
},

After editing your composer.json file, make sure to regenerate the autoloader by running the following from your command line (root of project, same directory where you keep your composer.json:

composer dump-autoload -o

Then, you can strip out the include() statement(s) in your element-api.php file, because Composer will autoload all the classes under /config/endpoints.

Finally, to make things super clean you could of course create a custom Yii Module (or a Craft plugin) to contain your endpoint classes. This would also avoid having to manually add the classpath to the composer.json file, for the autoloading.


Database issue on upgrade to 2.5 on shared hosting I have a problem with upgrading to Craft 2.5 on a shared hosting platform. I have run the upgrade both automatically and also tried manually. It runs but when I try to update the database I get a fatal error message telling me to contact my server providers.

I believe the problem is the size of the database as there are 20000+ users and related user data. So it's 43mb which I think the shared hosting is having issues with.

As I am limited to what PHP limits I can change with shared hosting I am looking for a workaround.

My first thought is to empty the user tables from the database (which would reduce the size considerably), run the update and then add them back in. However I wanted to check if there were any database changes to the user tables in the upgarde. I'm looking at using version 2.5.2761

I've looked through the change log but can't see anything obvious.

Has anyone else come across this issue or are there any other better solutions?

Cheers

Have you checked craft/storage/runtime/logs to see if there's an error in there related to the update?

In case it is the database: you can disable the database backup during the update by changing https://craftcms.com/docs/config-settings#backupDbOnUpdate to false in general.php

Remember to make a database backup every time you run an update when you change that setting!


Hello World Craft Plugin I am a Joomla developer who has been asked to start developing Craft plugins and I'm afraid my brain is so moulded to the joomla way of doing things that I cannot even see how the template links to the plugin and fires events

I'm especially interested in form processing (being the cornerstone of application functionality) and I've been taking a look at the contact form plugin. In the contact.html template I can see {{ getCsrfInput() }} which is twig syntax for calling a method- but there is no method called getCsrfInput() anywhere in the plugin. However it works, hidden fields are returned with an 'action' pointing to contactForm/sendMessage which (I'm assuming the Craft app decides, because there is no form tag action) fires the actionSendMessage event in the contact form plugin.

I just don't see the sequence! I can program PHP fine, but (perhaps due to ONLY doing things the Joomla way) don't see how plugins are called/included in a page.

It's a silly example, but could someone explain to me how I could get a function to just echo Hello World on a page:

function printHello()
{
echo 'Hello world!'
}

Would this go in the plugin root class? If so, what do I put in the example.html template to call this plugin function?

If I can do that then I can (presumably) use it to do everything else. Just 'including' a PHP function on a page doesn't seem like the Craft way of doing thing- I've read about hooks and events, and they don't make sense to me. Hooks seem to link a plugin to a URI, and it seems to suggest that you don't need to put anything into the template html calling the plugin. The Other, 'Events', is all PHP, so I'm assuming isn't intended to be put into the template files (Any php I put in there is escaped).

So, in short, how can add a hello world output to a page using a plugin (Stupid, but just to get me started)

My thought is that as soon as I can do that I can have a function that grabs form data from a previous page and processes it in order to do some real work.

Thank you so much for your help!

Andy

Apart from reading the docs on plugin development, I would suggest checking out a plugin called Business Logic, which provides a plugin template for creating project specific business logic, with a basic controller, service, and variables file already set up, and doc blocks which explain what the various components do.

For just printing a string I would look into creating a custom variable in your plugins 'variable' file. If the method is more complicated then you can use your variable as a wrapper to call one your service methods defined in your plugin's 'service' file. Here is an example variables file, with a call to a service method:

<?php namespace Craft;

class MypluginVariable
{
    // return the result directly
    public function exampleVariable()
    {
        return 'Anything you want!';
    }
    // call a service method and return the result
    public function exampleServiceMethodWrapper($value)
    {
        return craft()->myPlugin->myServiceMethod($value);
    }

}

You could call these from your template using {{ craft.myplugin.exampleVariable }} and {{ craft.myplugin.exampleServiceMethodWrapper('customValue') }}. These are assuming you want to just print the result of course.

The contactForm plugin that you are looking at is interacting with the plugin through the hidden form field <input type="hidden" name="action" value="contactForm/sendMessage"> which directs craft to submit the form to the contactForm's actionSendMessage() method defined in the plugin's 'controller' file. See controller docs for more info.

Fyi {{ getCsrfInput() }} is a native craft method so won't be in the plugin.


How to delete Matrix fields in front end I created a user profile page with Matrix field with assets, I found this thread and this thread about adding and updating Matrix field in the frontend. Does anyone know how to delete the Matrix field? Moreover, I found that if I update Matrix field through the front end, it doesn't update the S3 bucket. Files are still stored in S3. Does anyone has a solution or give me a hint on delete/modify Matrix asset field? Thanks

I've managed to do this with:

<form method="post" accept-charset="UTF-8">
    {{ csrfInput() }}
    <input type="hidden" name="action" value="users/save-user">
    <input type="hidden" name="userId" value="{{ currentUser.id }}">
    {% include '_partial/wish-list-fields' %}

    <input type="hidden" name="fields[userWishListMatrix][{{ block.id }}][type]" value="null">

    <input type="submit" value="Remove">
</form>

The wish-list-fields partial include hidden inputs showing all the fields already there. e.g.:

<input type="hidden" name="fields[userWishListMatrix][{{ block.id }}][fields][itemProperties][0][col1]" value="{{ row.property }}">

It repeats itself which I know doesn't seem terribly efficient but i dunno :-/ It works!

Please note, I'm on craft3 so things may be a little different (although most likely just the save-user / saveUser action).


How many users can Craft handle? I'm looking to use a Craft3 installation as a bridge app to synch a client's contacts from their CRM server to their Email Service Provider, via respective APIs.

I'll be storing their contacts as users in Craft. They have four contact lists with numbers (there may be some overlap) totaling:

12,000 contacts
55,000 contacts
23,000 contacts
22,000 contacts

Is storing these in Craft as users a realistic option? We'll be editing/adding new users in small batches on a daily basis, slicing them off the full list on the source side by last updated date, and then filtering records to push to the destination using the Craft API.

It depends more on how you are going to create and display them. I had to import 20k elements this weekend and I had to be careful to store them step by step.

Depending on your server/hardware - you can't just insert 10k elements in one request. There is a function App::maxPowerCaptain() to disable the timeout but I still faced overflow errors.

And of course you can't display so many users in one single page without using a pagination or Ajax

Besides that - Craft is able to handle such an amount of elements if you can do it in your code as well


Categories field that allows duplicate values I have a categories field where I would like to be able to include the same category more than once. Any suggestions on how to do this?

I'd probably go with a Matrix field, with one block type containing the Categories field. This would also allow you to include other fields for some extra meta data to distinguish one category assignment from another, otherwise identical one.

To use your playlist example, the Matrix blocks would let you set the order of the tracks as well.


Craft 3: Upload user photo from front end How do I allow logged in users to change their user photo on the front end in Craft 3?

I am creating an "Edit Profile" page and I followed the answer to this question for Craft 2 to create a form updating to Craft 3 syntax where necessary (code below). When I submit the form, the text/textarea fields get updated, but the image does not. Can anyone point me in the direction as to how to get this working?

Thanks in advance!

      <form method="post" enctype="multipart/form-data">
        {{ csrfInput() }}

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

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

                {% for error in errors %}

{{ error }}

                {% endfor %}

        {% endif %}
        {% endmacro %}

        {% from _self import errorList %}

        <input type="hidden" name="userId" value="{{ currentUser.id }}">

        {% if currentUser.getPhoto != '' %}

        {% endif %}
        <input type="file" id="userPhoto" name="userPhoto" value="Upload">

        First Name
        <input id="firstName" name="firstName" value="{{ currentUser.firstName }}">

        Last Name
        <input id="lastName" name="lastName" value="{{ currentUser.lastName }}">

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

        Password
        <input id="password" type="password" name="password">

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

        <input type="submit" value="Save Profile">
    </form>

The field name used for the user photo has changed to photo, so the bare minimum change to make this work is modifying
<input type="file" id="userPhoto" name="userPhoto" value="Upload">
to be
<input type="file" id="userPhoto" name="photo" value="Upload">

You'll probably want to use transforms, when outputting that image, too.

Also, I'd stick with currentUser.photo or currentUser.getPhoto(), instead of using a hybrid currentPhoto.getPhoto, but that might just be me.


Limit entry pagination to 6 pages? I've been given a site and asked to prevent visitors from seeing the news archive beyond page 6.

The navigation has already been done, but if the user manually enters example.com/news/p7 they'll see it.

Here’s my template code:

{% set entries = craft.entries.section('news').limit(3) %}
{% paginate entries as entries %}
    {% for entry in entries %}
        {% include '_elements/_news-entry' %}
    {% endfor %}
    {% include '_elements/_pagination' %}
{% endpaginate %}

The _elements/_pagination include:

{% for page, url in paginate.getPrevUrls(5) %}
    {{ page }}
{% endfor %}

{{ paginate.currentPage }}

{% for page, url in paginate.getNextUrls(5) %}
    {{ page }}
{% endfor %}

I tried adding the following to /craft/config/routes.php, but it doesn't appear to have any effect.

'news/p[^1-6]' => '404',

First, I don’t think your pagination navigation is limiting to just 6 pages like you think it is. The number you pass into paginate.getPrevUrls() and paginate.getNextUrls() will determine how many URLs the functions should return. So if you’re on the 3rd page, calling paginate.getNextUrls(5) will give you the URLs for pages 4-8.

Navigation-wise, what you’re probably better off using is paginate.getRangeUrls(), which accepts explicit first/last page numbers:

{% for page, url in paginate.getRangeUrls(1, 6) %}
    {% if page == paginate.currentPage %}
        {{ page }}
    {% else %}
        {{ page }}
    {% endif %}
{% endfor %}

(You can get a full breakdown of the properties/functions within that paginate variable here: http://buildwithcraft.com/docs/templating/paginate#the-paginate-variable)

Even with that change, you’re not actually enforcing that only 6 pages are available; there’s still nothing stopping a user from manually going to http://example.com/news/p7. The would still get the 7th page of news entries, with an awkward pagination navigation, because it would just show links to pages 1-6 with no indication that you’re on the 7th page.

So back to your original question: how do we enforce a 6-page maximum?

Your idea of setting a route in craft/config/routes.php was a good one, but unfortunately Craft actually removes the “page” part of the URL from its internal path before it starts checking the path for matching routes.

Because of that, your best option here is to enforce it from the actual News template.

You can access the current page using craft.request.getPageNum(), so let’s just check for that at the very top of your template, and if it’s greater than 6, return a 404 using the {% exit %} tag:

{% if craft.request.getPageNum() > 6 %}
    {% exit 404 %}
{% endif %}

To clean things up a bit, you might want to store that maximum number of News entries as a variable within your template, or maybe even as a 'maxNewsPages' custom config variable in craft/config/general.php.

{# Pull the custom 'maxNewsPages' config setting from craft/config/general.php #}
{% set maxPages = craft.config.maxNewsPages %}

{# Enforce it #}
{% if craft.request.getPageNum() > maxPages %}
    {% exit 404 %}
{% endif %}

...

{% for page, url in paginate.getRangeUrls(1, maxPages) %}
    {% if page == paginate.currentPage %}
        {{ page }}
    {% else %}
        {{ page }}
    {% endif %}
{% endfor %}


Redactor migration might fail with allowAdminChanges & useProjectConfigFile false One of the recent Craft updates (something close to 3.1.25) also brought a redactor migration (https://github.com/craftcms/redactor/blob/v2/src/migrations/m190225_003922_split_cleanup_html_settings.php), which fails when those 2 configs are disabled:

'allowAdminChanges' => false,
'useProjectConfigFile' => false,

The reason why it fails is that the migration tries to do something with projectConfig, which is read only when allowAdminChanges is disabled.

According to P&T this is expected behavior. Their solution is to put this in config/app.php:

'components' => [
    'projectConfig' => function() {
        $config = craft\helpers\App::projectConfigConfig();
        $config['readOnly'] = false;
        return Craft::createObject($config);
    },
],

(Thanks Oli, Brandon, Andris!)

Since I do all migration via Craft's console commands, this shorter solution works for me:

'allowAdminChanges' => (php_sapi_name() === 'cli')

It simply enables admin changes when using the console command.


Google Maps plugin - How to trigger an info window I'm migrating Smart Map over to the Google Maps plugin, and I want to open a popup on button click. But it seems there is no JS method available to open an info window.
Here's how it was done in Smart Map:

Trigger Info window in Smart Map using external navigation

How can I do the same thing with the Google Maps plugin?

As of Google Maps 4.0.1, there is a new getInfoWindow method in JavaScript. This makes it easy to retrieve and manipulate existing info windows.
Additionally, I've written a guide for Opening Info Windows...
Hope that helps! :)


How can I retrieve channel data in json format? I've played around with a few implementations but I still don't feel like either is right.

I first came across building the JSON itself. This would be in a file at "craft/templates/entries.json".

[
  {% for entry in craft.entries.section('news').find() %}
    {
      "title": "{{ entry.title | e('js') }}",
      "body": "{{ entry.body | e('js') }}"
    } {% if not loop.last %},{% endif %}
  {% endfor %}
]

This worked but I didn't feel right about writing my own JSON so I came up with this approach instead.

{% set results = [] %}
{% for entry in craft.entries.section('news').find() %}
{%
  set results = results | merge([{
    'title': entry.title,
    'body': entry.body
  }])
%}
{% endfor %}
{{ results | json_encode() | raw }}

This works, the JSON will definitely end up valid and as a bonus it'll be condensed but it's not very reusable and when I add fields I need to adjust it.

What approach should I take to make a reliable way to query data from Craft and return json?

I just threw together a add-on that will provide a Twig filter called prune to allow you to more easily do what you're asking here.

https://github.com/mattstauffer/craftcms-prune

With prune you can now just do the following:

{{ craft.entries.section('news').find() | prune(['title', 'body']) | json_encode() | raw }}

Just pass in an array of the fields you want to pluck out. It's pretty new and could use some love, but it'll get the basics done for sure.


How can I group entries based on a dateTime field? I am getting all entries from a section like this:

// get the parent entry.
{% set author = craft.entries.section('mySection').authorId(currentUser.id).first() %}

// get the child entries from the parent.
{% set entires = craft.entries({
    'section': 'mySection',
    'level': 2,
    'descendantOf': author.id
 })%}

// myDate is a dateTime filed (yyyy-mm-dd)

{% for year, entry in entries|group('myDate') %}

{{ year|date('Y') }}

                {% for entry in entries %}
                    {% if attempt.myDate|date('Y') == year|date('Y') %}

{{ entry.myDate }} > {{ entry.type.name }} - {{ entry.foo }}

                    {% endif %}
                {% endfor %}

        {% endfor %}

What I have is close, however, it's outputting multiple years. For example,

2016
  [entry]

2016
  [entry]

2015
  [entry]

 ...

I'm trying to group all of the child entries by year. For example, if I have 3 entires with the same year (2016) I am trying to show:

2016
  [entry]
  [entry]
  [entry]

2015
  [entry]

2014
  [entry]
  [entry]

...

Thank you for any suggestions!

You're currently grouping on the myDate field, which essentially creates a new array index for each date (e.g. 2016-01-01) which is why you're getting your current output.

To group by year, this should do the trick:

{% for year, entries in entries|group('myDate.year') %}

{{ year }}

        {% for entry in entries %}
            ...
        {% endfor %}

{% endfor %}


Is it possible to group entries by checkbox? We're looking to output a list of entries and group them by their check box values. Here's what we've got so far:

{% for checkbox, entries in craft.entries.section('my_entries').find() | group('checkbox') %}
   {{ checkbox }}
{% endfor %}

This currently returns "Object of class Craft\MultiOptionsFieldData could not be converted to string".

Any ideas? Is this even possible?

What Brad says, plus an example of grouping by selected checkbox:

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

{# get all checkbox options #}
{% set options = entries.first().checkbox.options %}

{% for option in options %}

{{ option }}

    {% for entry in entries if entry.checkbox.contains(option) %}

{{ entry.title }}

    {% endfor %}

{% endfor %}


How to move repeating code into an include template I'm new to Craft and have created some SEO fields similar to this, and the template code appears in all templates as shown below. I don't want to be repeating all that code in every template though, so I thought I'd be better of putting it in an include template (assuming that's how best to handle this in Craft).

But I'm getting an error when I try to do this, so can anyone show me the correct way of doing this please?

Here's my starting code, where I'm repeating the SEO code in every template (see the start and end comments):

{% extends "_layout" %}

{# START OF SEO CODE #}
{% if entry.metaTitle != '' %}
  {% set title = entry.metaTitle %}
{% else %}
  {% set title = entry.title %}
{% endif %}

{% if entry.metaDescription != '' %}
  {% set description = entry.metaDescription %}
{% endif %}

{% if entry.metaKeywords != '' %}
  {% set keywords = entry.metaKeywords %}
{% endif %}
{# END OF SEO CODE #}

{% block content %}

{{ entry.title }}

    {{ entry.body }}

{% endblock %}

And for completeness, I have the following in my _layout template:

{% set metaTitle = globalMetadata.metaTitle %}
{% set metaDescription = globalMetadata.metaDescription %}
{% set metaKeywords = globalMetadata.metaKeywords %}

<title>{% if title is defined %}{{ title }}{% else %}{{ globalMetadata.metaTitle }}{% endif %} | {{ siteName }}</title>
<meta name="description" content="{% if description is defined %}{{ description }}{% else %}{{ globalMetadata.metaDescription }}{% endif %}" />
<meta name="keywords" content="{% if keywords is defined %}{{ keywords }}{% else %}{{ globalMetadata.metaKeywords }}{% endif %}" />

So I've tried moving the SEO code out of the entry template, and into the following include template: _includes/seo_meta:

{# START OF SEO CODE #}
{% if entry.metaTitle != '' %}
  {% set title = entry.metaTitle %}
{% else %}
  {% set title = entry.title %}
{% endif %}

{% if entry.metaDescription != '' %}
  {% set description = entry.metaDescription %}
{% endif %}

{% if entry.metaKeywords != '' %}
  {% set keywords = entry.metaKeywords %}
{% endif %}
{# END OF SEO CODE #}

And am trying to call it from my entry template like this:

{% include "_includes/seo_meta" %}

But I'm getting the following error message, and the error is highlighting my include line:

A template that extends another one cannot have a body.

Thanks in advance for any help, Stephen.

That seo code will need to be in a block of its own.
Create a seo block in your _layout template and then wrap your seo code in your include template with block tags of the same name.


Best Technique for have sections in display in same page with anchor link to each section I'm currently in the process of making a website for a restaurant and using Craft CMS & I'm not sure how to go about making the menu page.

It is a very complete page with a bunch of different categories of food & a bunch of items and pictures for each category. My goal is to have a subnav on the left be Sticky & have them scroll down with anchor links to the corresponding section.

I'm still relatively new with Craft CMS and wanted some opinions/tips on what the best and cleanest way of doing this would be.

Here is a wireframe so I could show you guys what I'm trying to accomplish.

Have the left Nav with anchor links to the corresponding food section.
What is the best technique to create those food category sections & put them into the page.

What I should do is create a category group whish should be filled with your "Food Categories". Once you've done that you could display them in your side menu. (If you show the menu on everypage make sure to include it in your _layout.html or as a new block however you like it.

For your food category section.

You could create a Channel for those. Add all the fields you need and put them in there. Don't forget to create a Category field connected to your food categories group. This way you can link an entry to the category it's supposed to go too.

If you created a couple of entries and connected them to their categories. You can display them in the big section by looping over all the entries in your Food Channel. You can grab the category by looping over the category field you made. This way you can add the coloured banner which belongs to the chosen category.

Here are some links for all this:

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

https://craftcms.com/docs/categories-fields

https://craftcms.com/docs/categories

https://craftcms.com/support/entries-related-to-category

Craft CMS also has a slack community. For more detailed questions you could ask for help there. You can checkout how to join here.

https://craftcms.com/community#slack


Editing error messages and allowing a phone number input in a P&T Contact Form Firstly, thanks very much for the help I've already had from members here. It's been straightforward and easy, even for a newbie like me, to understand.

At the moment, I'm working on editing one of the last pages on a client's site, the Contact Us page and am hoping to be able to use the Pixel & Tonic, Contact Form plugin. But, after some inspection of the Readme and the files that run the plugin, I have been unable to find the following:

1) How do I create/edit the error messages that the form generates?

2) Can I use the form to allow a user to enter their phone number? If so, what should the code look like in the template?

I would like the final form to look like the screenshot below.

Any help that anyone can provide would be most appreciated.

With kind regards,

Mark

EDIT

Thanks to this post, I've realised how easy it is to add a new field for the phone number (and assume I add the code wherever I want the new field to appear(??)), but am still clueless about the error messages.

I found it! It took quite a bit of digging about, but eventually I found the files I needed to edit. In case anyone else is struggling with this same issue, here's what you need to do:

Look in the folder 'craft/app/framework/validators/' for a file called 'CRequiredValidator.php'. Open the file in a text editor and look for the text: 'cannot be blank'.

Part of this line reads: '{attribute} cannot be blank.'

You can change the text 'cannot be blank' to whatever you like and can move '{attribute}' to after the alternative text that you've put in without breaking anything. Save and upload your altered file to the correct location.

Now, look in the folder 'contactform/models/' for a file called 'ContactFormModel.php' (probably the only one there).

By default, it has the following written into it:

    return array(
        'fromName'          => array(AttributeType::String, 'label' => 'Your Name'),
        'fromEmail'         => array(AttributeType::Email,  'required' => true, 'label' => 'Your Email'),
        'message'           => array(AttributeType::String, 'required' => true, 'label' => 'Message'),
        'messageFields'     => array(AttributeType::Mixed),
        'subject'           => array(AttributeType::String, 'label' => 'Subject'),
        'attachment'        => AttributeType::Mixed,
    );

The bits you need to alter to complete the customised error messages are found after 'label' =>

Save and upload your second altered file to the correct location, and check out the new error messages for your form!


Direct relation between templates and PHP Is there a direct relation between code in templates and PHP code inside a controller for example?
I need to translate

{% set relatedProducts = craft.entries.section('products').relatedTo({
                   targetElement: testVariant,
                   field: "productVariants.productSizes"
}) %}

into a controller and im not sure how.

A very similar question has been asked before How can I follow relations in ElementCriteriaModels from plugin code. You would want something like this:

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = 'products';
$criteria->relatedTo = array(
    'targetElement' => $e,
    'field'         => $field
);
$elements = craft()->elements->findElements($criteria);

Where $e is testVariant, and $field is productVariants.productSizes, which can be retrieved using craft()->elements->getElementById(id) and craft()->fields->getFieldById(id) or getFieldByHandle(handle) respectively.

To create a controller see the documentation on Controllers.


Imager plugin for watermarks First time using the Imager plugin and really unsure how to code it. Looking over the documentation I'm not clear on what the 'logo' is referring to to know what to change it to:

{ watermark: { image: logo, width: 80, height: 80, position: { right: 30, bottom: 30 }, opacity: 0.8, blendMode: 'multiply' } }

https://github.com/aelvan/Imager-Craft

My attempt so far:

{% set imageWatermark = [{ watermark: { image: logo, width: 80, height: 80, position: { right: 30, bottom: 30 }, opacity: 0.8, blendMode: 'multiply' } }] %}

{% set transformedImages = craft.imager.transformImage(image, imageWatermark) %}

{# Output image #}
<img src="{{ asset.getUrl('transformedImages') }}">

Have a look a little further down in the Readme and you will see more information regarding Watermark.

From the Readme...

image: The image that is to be used as watermark. Just as the image parameter in the craft.imager.transformImage method, this can be an AssetFileModel, a string to a previously transformed Imager image, or a string to an external image.

{% set logo = craft.assets({ id: 11 }).first() %}
{% set watermarkedImage = craft.imager.transformImage(image, {
    width: 600,
    watermark: { image: logo, width: 80, height: 80, position: { right: 30, bottom: 30 }, opacity: 0.8, blendMode: 'multiply' }
}) %}

Also a link to a Watermark demo https://imager.vaersaagod.no/?img=6&demo=watermarks


How to display a tree view of all assets? I like to display a tree-like view of all files in an asset source:

Folder_X

File_A
File_B
Folder_Y

File_C

Folder_Z

...

I know that I can iterate over all assets in a source ({% for file in craft.assets.sourceId('1') %}) but this gives just an alphabetically sorted list of all files. Maybe we need something like the nav-tag.

Yoursort, my answer was based on the assumption that the AssetsService could be used in templates. Ofcourse, only the variables can be used.

I don't have time to dive into this (now), but I think your best bet is to get all images, use `asset.folder' for each asset and 'rebuild' the hierarchical list of folder and their assets. Again, use cache ;)


Is there a way to change what happens after you save a new entry? I want to remain on the page I just saved so I can view it in the browser and return to continue editing, without having to find the page again in the all pages/entries area.

Is there a way to change the Craft CMS defaults on this?

You can, and it's easy!

The "Save" button contains a dropdown arrow, with alternative options for saving:

You'll notice that "Save and continue editing" is the top option. You may also notice that there's a keyboard shortcut for it... cmd + s on Mac, ctrl + s on PC.


Can entries in a category be reordered? Can entries in a category be reordered in a similar way that entries in a Structure can be reordered? If not, how can entries in a category be reordered manually?

There isn't a builtin way to manually sort the entries as you can in a structure.

When calling the entries in your templates, you can make use of the 'order' parameter to order the entries returned. From the documentation:

  The order the entries should be returned in. Possible values include
  'title', 'id', 'authorId', 'sectionId', 'slug', 'uri', 'postDate',
  'expiryDate', 'dateCreated', and 'dateUpdated', as well as any textual
  custom field handles. If you want the entries to be sorted in
  descending order, add “desc” after the property name (ex: 'postDate
  desc'). The default value is 'postDate desc'.

For example:

{% entries = craft.entries.section('news').order('postDate').limit(10) %}


Matrix -> Super Table - > Matrix I have a matrix field with a Super Table block type. Then I have a matrix field as a field within the Super Table block. I am having trouble filtering by block type from within the child matrix field. Is what I am trying to achieve even possible? Any solution would save me from pulling my hair out any further.

Below is the last attempt I made to filter through before posting here:

{% for block in entry.matrixFieldParent %}

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

        {% for row in superTableBlock %}

            {% for block in row.superTableBlock %}

                {% switch block.type %}

                    {% case "contentBlock1" %}

                       {{ block.contentField }}

                    {% case "contentBlock2" %}

                       {{ block.contentField }}

                {% endswitch %}

            {% endfor %}

        {% endfor %}

    {% endif %}

{% endfor %}

edited to include if statement previously left out by mistake

Firstly, you'll need to change:

{% for row in superTableBlock %} to {% for row in block.superTableBlock %}

So you can reference the Super Table field within your out Matrix field.

You also don't need to loop through {% for block in row.superTableBlock %}

I can't tell if you're looping through the inner Matrix field. Have you tried:

{% for block in entry.matrixFieldParent %}
    {% if block.type == "sectionBuilder" %}
        {% for row in block.sectionBlock %}
            {% for sectionLayout in row.sectionLayout %}
                {% switch sectionLayout.type %}
                    {% case "contentBlock" %}
                       {{ sectionLayout.sectionGrid }}
                    {% case "articlesFeedBlock" %}
                       {{ sectionLayout.sectionBackground }}
                {% endswitch %}
            {% endfor %}
        {% endfor %}
    {% endif %}
{% endfor %}


Add conditional in a for loop I need to add a separator if there are a multiple of types. How can this be done in a for loop?

{% for type in entry.buildType %}{{ type }}{% endfor %}

The outcome is similar to a breadcrumb nav, with an added "/", however the separator should only be placed in between - not for the last.

{% for type in entry.buildType %}
{{ type }}
{% if not loop.last %}/{% endif %}
{% endfor %}

See: https://twig.symfony.com/doc/2.x/tags/for.html#the-loop-variable


When creating a fieldtype how do I provide methods to be used in the templates? I have created a fieldtype that saves a single integer to the database, it has some settings that defines the maximum value that integer can be:

protected function defineSettings()
{
  return array(
    'maxNumber' => array(AttributeType::Number, 'min' => 2, 'default' => 12)
  );
}

What I want to do when outputting my field in the templates is something like this:

The value is {{ entry.myField }} of {{ entry.myField.maxNumber }}

Anyone have any ideas? Do I need to create a data class like the options-based fields use or something? I'm just stabbing around in the dark here...

Like plugins, fieldtypes can have their own settings as you're aware but while you can grab your plugin settings from pretty much anywhere, fieldtypes are a little more contextual.

In any case, like @Bryan pointed out, your fieldtype needs to implement prepValue($value) and ideally return a model containing the value as defined in defineAttributes() and the maxNumber as a property.

This basically means that when Craft calls your fieldtype's prepValue($value) which it does when the value of your field is needed (editing/outputting) you can return a model with the value and maxNumber.

EDIT:

// MyFieldType.php
public function prepValue($value)
{
    $model = new MyFieldModel;

    $model->setAttribute('value', $value);
    $model->setMaxNumber($this->getSettings()->getAttribute('maxNumber'));

    return $model;
}

// MyFieldModel.php
// Explicit getter/setter for $maxNumber rather than defining it as an attribute
protected $maxNumber;

public function setMaxNumber($value)
{
    $this->maxNumber = $value;
}

public function getMaxNumber()
{
    return $this->maxNumber;
}

public function defineAttributes()
{
    return array(
        'value' => AttributeType::Number,
    );
}

// _entry.html or other template name
{{ entry.myFieldHandle.value }}
{{ entry.myFieldHandle.maxNumber }}

@selvinortiz


Sections in local & LIVE out of sync I created a new section (single) on my  local environment.

Then I pushed it to LIVE. There it is not showing up in the entries CP.

But it is showing up in the settings.

So I guess the project.yaml hasn't been applied correctely or something.

If I excecute ./craft project-config/rebuild on LIVE I get the error:

  Exception 'yii\base\InvalidConfigException' with message 'The
  directory does not exist:
  /path/assets'

  in
  /path/vendor/yiisoft/yii2/web/AssetManager.php:213

But this has nothing to do with assets

Also. If I go to said section in the settings and try to save it there is the following error:

  2019-07-15 14:06:43
  [-][1][aaa64a91c1fffdd268c2d774dc31daa4][error][yii\base\Exception]
  yii\base\Exception: Couldn’t save single entry due to validation
  errors on the slug and/or URI in
  /path/vendor/craftcms/cms/src/services/Sections.php:1561

What now?

If I create a folder assets at that location it works. I don't know what this asset folder is about.


$order->dateOrdered returns a string value the first time and DateTime after that. [Order got through event] I am using the Commerce 2 plugin and I am experiencing a very odd issue. Once an order is complete I want to use the dateOrdered property to create a csv which I send through a request endpoint. That worked fine.

BUT! Since recently (somewhere this month), on the first attempt to create and save the .csv, when calling $order->dateOrdered->getTimestamp() I get dateOrdered as a string.

On the second attempt to create and save the .csv I get dateOrdered as a DateTime.

The method which I am calling is the same so I think it has something to do wiht order statuses.

I tried to trace the problem in Commerce's Order.php class but I still have no clue why this occurs or what I am doing wrong.

Any help is more than welcome. Thank you in advance!

The problem was occurring because the order was retrieved through the EVENT_AFTER_ORDER_PAID event. Therefore, the dateOrdered was still not processed (passed through mutations).

What we ended up doing is using $event->sender only to know what order we are looking for and then retrieve the order anew.

I hope this saves someone's life someday! I'll mark this question as solved in 2 days.


Output deprecation error Good Evening,

Please bear with me I'm very new to Craft 3. I'm getting deprecation errors when outputting information.

I'm trying to output a single entry from a section using the following:

{% for entry in craft.entries.section('homepage') %}{{ entry.richText }}{% endfor %}

It is giving me the following error:

  Looping through element queries directly has been deprecated. Use the all() function to fetch the query results before looping over them.

In your example, for entry in craft.entries.section('homepage') is attempting to loop through homepage entries as though they're an array. In Craft CMS 3, this is now deprecated just like the error message is telling you.

That means you need to use .all() when querying entries, meaning...

{% for entry in craft.entries.section('homepage') %}

...becomes...

{% for entry in craft.entries.section('homepage').all() %}

Ryan Irelan produced a nice video about this and it's also covered explicitly in the Craft 3 docs. If you've worked with Craft 2 and you're just getting started with Craft 3, that Changes in Craft 3 guide is an excellent place to start.


Override the postDate for entries so their URL works on the frontend? Is it possible to override/disregard the postDate for all entries in a section so that they are visible on the frontend even if this date is in the future?

I realise I could add a dedicated date field — but keen to avoid this if possible as the fields for this entry are already quite complicated!

You can add status(null) in your ElementQuery in order to fetch all items or you add status(['pending', 'enabled']) to pull all entries, that are not disabled and not expired


How do I pull the first image from the first entry of the first subcategory? I just want to apologize in advance if I'm not quite understanding how the element criteria model works. I know that's the basis of Craft but I learn best by doing and this StackExchange has been an incredible resource. Thank you!
As my question title explains, I'm trying to get an image (image url actually) located in an asset field from the first entry of the first subcategory within a category.
This is what I have so far:
    {% set lastSeg = craft.request.lastSegment %}
    {% for cat in categories.slug(lastSeg) %}
      {{category.title}}
      {{category.catContent}}

        {% set subCategories = craft.categories.descendantOf(category) %}
        {% for subCat in subCategories %}

            {{subCat.title}}

        {% endfor %}

    {% endfor %}

I'd like the image url to replace http://fpoimg.com/280x280 as the img src. I'm getting stuck after looping through the subcategories. I'm not sure how to loop through entries in the subcategory and return the first one, so that I can then loop through the assets and pull the image url I need.
-- edit --
I think I have gotten it to work thanks to Marion's comment, but I would love some input to be certain:
    {% set lastSeg = craft.request.lastSegment %}
    {% for cat in categories.slug(lastSeg) %}
      {{category.title}}
      {{category.catContent}}

        {% set subCategories = craft.categories.descendantOf(category) %}
        {% set products = craft.entries.section('products').relatedTo(subCategories) %}

        {% for subCat in subCategories %}
        {% for entry in products.relatedTo(subCat).limit(1) %}
        {% set image = entry.productImage.first() %}

            {{subCat.title}}

        {% endfor %}

    {% endfor %}

This should work!

This code is to pull the first image, from the first entry of the first sub category given that the 'slug' passed into the first set is your top level category.

    {# Get the category from the slug. This will return one CategoryModel #}
    {% set topCat = craft.categories.slug('someSlug').first() %}

    {# Get the first subcategory under the top level category using the getChildren() method on the category model.  #}
    {% set firstSubCat = topCat.getChildren().first() %}

    {# Grab the first entry under that category using the relatedTo function and appending the .first() method to return only one item. #}
    {% set firstEntry = craft.entries.relatedTo( firstSubCat ).first()  %}

    {# Set your image from your asset field #}
    {% set image = firstEntry.assetField.first() %}


hashing form fields to prevent tampering I have a front end form for entry creation. I have a few options I don't want tampered with. The docs for |hash say "Prefixes the given string with a keyed-hash message authentication code (HMAC), for securely passing data in forms that should not be tampered with."

I've tried a dropdown field:

<input type="hidden" name="fields[businessStatus][]" value="{{ 'created'|hash }}">

When |hash is added the page just reloads instead of going to the correct redirect URL. So I tried a plain text field with |hash and a hashed string is submitted instead of the string before the filter. I'm guessing this is why the page reloads for the dropdown field, what's being submitted doesn't match one of the field's values.

What am I doing wrong? Am I misunderstanding how |hash works?

Also, it says "Prefixes the given string", what if you need to protect a integer?

If you're posting to Craft's EntriesController->saveEntry(), then it doesn't do any hash validation.

You'd need to post to a controller of your own (from a plugin or module if you're on Craft 3), then validate the data yourself like the example in the docs you linked to:

$foo = Craft::$app->request->getPost('foo');
$foo = Craft::$app->security->validateData($foo);

if ($foo !== false) {
    // data is valid
}

Then your controller would manually save the entry similar to how Craft does after your validation.


Custom URI to exclude entries in structure I have a structure where the Entry URI Format is {parent.uri}/{slug} - what I'm looking to do is conditionally not include entry slugs within the uri based on a show/hide setting in the entry.

For example, I might have structure where an entry, sub-page2 has a uri like so page/sub-page/sub-page2 but if there is a setting on sub-page to exclude it, it's uri should be page/sub-page2

This would mean that the conditional to show it should only be considered if it's being called as a parent. sub-page should still be accessible from page/sub-page - trying to find a way to achieve this?

You have the full power of Twig in your template to render the entries Uri so you can conditionally render what you want. This could be your template in your section settings

{% if object.parent.field == true %}{{ object.parent.uri }}{% else %}{{object.parent.slug}}{% endif %}

There are no real limitations since you can do what you are used to in Twig in your frontend


Automatic cache clearing when reordering custom element type I've developed a custom menus plugin which has been working great

https://github.com/familiar-studio/craft-menus

Im trying to get it work with the build in template caching and realizing the reorder actions are not triggering the caches to clear properly?

The template is using the "getNodes(menuHandle)" variable
https://github.com/familiar-studio/craft-menus/blob/master/menus/variables/MenusVariable.php

which just uses standard element criteria? We are also using native structures so is there some way to specifically tell it to clear on reordering as well?

UPDATE: here is the code thats in my _layout that im hoping will clear when i reorder or add new elements

{% cache %}

      {% nav node in craft.menus.getNodes('utilityMenu') %}

                {{ node.title }}

            {% ifchildren %}

                    {% children %}

            {% endifchildren %}

     {% endnav %}

{% endcache %}

UPDATE 2: So on deeper investivation it appears that the issue is only that it doesnt clear the cache when the structure is reordered, editing and saving nodes seems to clear it after all.

So i found an answer, was a little more manual but it works.

I added a call back to the onMoveElement to automatically more manually clear the cache.  This was added to my plugins init() function

craft()->structures->onMoveElement = function(Event $event) {
      $element = $event->params['element'];
      craft()->templateCache->deleteCachesByElementId($element['id']);
};

Was interesting to me that i only had to do this for reordering sturctures while adding/deleting elements automatically cleared the cache with no event code.

Not sure if this was a bug or by design?


Dynamic subject for form notification email Is there a way to have a dynamic notification subject in Sprout Forms via custom fields, eg if I have a field called subject can I use this in the Subject option under Notifications as {{ subject }}?

Yes.  You can use the value of your custom field subject in two ways:

Shorthand Syntax:

{subject}

Object Syntax

{{ object.subject }}

If you want to perform any conditional logic, you will need to use object syntax for the conditional logic:

{% if object.subject != '' %}{{ object.subject }}{% else %}Fallback{% endif %}


How do I set all Assets fields in entry to same directory? I posed this question in the Craft Help Slack channel earlier but still don't have resolve.

Background on my field setup:

Entry
- Matrix
-- Image Block (matrix.imageBlock) (assets)
--- Mobile Image field (mobileField) (assets)

The image block field in the Matrix is using a restricted upload folder {owner.slug}; which is the entry slug (so its saved to /uplaods/entrySlug/). I also have a child asset field added to the image block to add a mobile specific image. Prior to Craft 2.5, using {folder.path} would put those images into the same /uploads/entrySlug/. Now when I "double click" the asset field to add the mobile image, {folder.path} returns This field’s target subfolder path is invalid: {folder.path}.

I was given a few ideas to pursue as it was thought that maybe the dynamic path had not resolved yet, but they didn't work.

I'm thinking that it does indeed revolve around dynamic paths, however, I can't seem to figure it out. All I'm looking to do is save the child asset field files to the same directory that all the other images go to (one image bank, so to speak, for the entire entry).

For long and complicated reasons, in order for this to work after Craft 2.5, your inner Asset field (the one that was restricting uploads to {folder.path}, will need to {folder.path|trim('/')} instead.


Sending activation emails to all pending users I have around 200 hundred users for an intranet setup on the Craft Users section all as pending status. Is there a way to send an activation email en-mass to all pending users? Rather than having to run through each user one at a time.

The system is set to change over and each user will need to verify their account and set their password, but they've been added to the system in advance and need to be sent an activation email out of hours so that they Intranet system changes overnight and they have an email waiting for them the next day they step into the office.

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

Fetch all pending users and send them the mail


New route for entry types I would like to create a route for the entry types of a specific section, pointing to a single template.

Is it possible to do this automatically? So far I haven't had luck, I'm thinking something like this:

route = /{ mysection.type }
template = type/index.twig

Or would I need to create a route for each entry type and all of them pointing to same template?

route 1 = /entryType1
route 2 = /entryType2
route 3 = /entryType3
shared template = type/index.twig

The reason I would like to do it this way, as opposed to how it has been shown before, here; is because I would like to keep all the URL's with a date format, i.e.: example.com/2014/07/11/slug so that I can then implement an archive template. But I still need a way to filter by entry types (a total of 12 types). So that at the end of the day I end up with URLs like these ones:

example.com/2014/01/01/example-entry - URL for Example Entry
example.com/2014/01/01/ - URL for listing entries from day
example.com/2014/01/ - URL for listing entries from month
example.com/2014/ - URL for listing entries from year
example.com/video/ - URL for Video types of entry
example.com/audio/ - URL for Audio types of entry

Any suggestions on how to solve this?

You can have entry type specific templates for your entry pages, see this docs article on how you can do this. And for your archive pages, just set a route for each of them and point it to the corresponding index/listings template.

So basically you end up with something like this for your entries:

media/_entry.html (example.com/2014/01/01/example-entry)
media/_types/audio.html (included in _entry.html if entry type is audio)
media/_types/video.html (included in _entry.html if entry type is video)
...

and this for your archive pages:

media/index.html (example.com/2014/01/01/ etc.)
media/audio/index.html (example.com/audio/)
media/video/index.html (example.com/video/)
...

If you don't want to set new routes for the entry type specific archive pages you can also put the templates in a folder whose index.html template file is called automatically if no route exists (eg. audio/index.html for example.com/audio/).

Additionally I'd make good use of include and extend in these templates to make this as DRY and easy to maintain as possible.


How does one achieve drop-left or drop-right image position? How is one to achieve the layout visualised by Craft's drop-left and drop-right icons?

I feel dumb asking but I don't know of any way to have a floated image stick to the bottom of its sibling text node with text running around it above and to the side, which is what is implied by the icons.

What have I been missing all these years?!

Generally, I'll have a div that picks up on the position's value.

For example:

That renders something like:

Then I'll have a css rule like this:

.image-left img {
    float:left;
}

It's also important to note where you place this element in relation to your text. You many need to put the image call before or after your text.


Locales and links not working as intended I have taken over a project and Im having a small problem with locales.

It is running Craft 2.6.3016

A section has a locale “en” where the english URL format is “en/contact”, and the entry also have the slug “en/contact”…
So, I would expect this URL to be domain.com/en/contact/en/contact, no? But it is not!

When getting the URL with this code:

{{ craft.entries.section( 'contact' ).first().url }}

the url is “domain.com/en/en/contact”, this link does not work, but if I change it to “domain.com/en/contact” as I would expect it to be, it works!!

I have no idea what kind of dark magic that messes around with this, but maybe some of you got any ideas? Nothing seems to make any sense here.
Also note that the “en” folder in the public folder is called “en__” if I change this to “en” the locale stops working.

Any help appreciated!

If your entry's slug is en/contact and you need it to show up when you go to the URL domain.com/en/contact/en/contact, the Section settings for the Entry URL Format should be en/contact/{slug}:

Also, you shouldn't need to use the language code prefix (en/) in Section settings. That should be defined in your config/general.php file. See the Define your site URLs section of the Craft 2 docs on localization.

return array(
    // ...
    'siteUrl' => array(
        'en' => 'http://example.com/en/',
        'no' => 'http://example.com/no/',
    ),
);

Then, if you Section's URL settings are contact/{slug}, these URLs will both work:

http://example.com/en/contact/en/contact
http://example.com/no/contact/en/contact


How do I show errors for a new front end entry form? I'm using a front end form so logged-in users can create a new entry ("post") or edit an existing entry. Here's the controller for figuring out whether it's a new or existing entry:

{# Get the entry being edited from the url parameter #}
{% set entry_id = craft.app.request.getParam('id') %}
{% if entry_id %}
  {% set post = craft.entries({
    id: entry_id,
    status: null
  }).one() %}
{% else %}
  {% set post = null %}
{% endif %}

For the form fields, I'm using Twig partials and with { 'entry' : post }.

This works great for editing a post, and I can create a new post as long as I enter the info that Craft expects. However, there are some required fields, and I want to show error messages when those fields are missing, rather than the post silently failing to be created.

Per the entry form documentation, I'm including the suggested macro and this chunk of code with my required headline field:

{% if entry is defined %}
  {{ errorList(entry.getErrors('headline')) }}
{% endif %}

Desired behavior:
if I try to save a new entry that's missing a headline, I should get the error message for that field.

Actual behavior:
This gives me a runtime error: Impossible to invoke a method ("getErrors") on a null variable.

I've tried setting post = {} for an empty object, but Twig seems to see that as an array and can't invoke getErrors on that either.

How should I go about addressing this?

Thanks to a teammate, got this working!

Needed to change the conditional wrapping my error messages from

{% if entry is defined %}

to

{% if entry is defined and entry is not null %}


Simple category-entry search filter I'm trying to figure what would be the simplest way to do such filtering:

I would like to make it in that way that selecting one of "Specialities" category would limit results from the selected "Plant" category.

Though I want a selection of the second category to be optional, so everyone can browse live and dried i.e. Mint plants or only herbs from all plants if they want.

Also, I would like to implement shipping to/from drop-downs with the same functionality.

Expected result:

How can I start? Any help would be greatly appreciated :-) Thank you.

This article was helpful getting us started when we tackled an advanced search. Though their example uses dropdowns, you'll probably want to use checkboxes for your "Herbs" and "Live Plants" categories.

Combined searches and filters


Breaking one large Craft app into multiple smaller apps Some background information:

We use a Craft app that has several modular components that we've put into separate plugins. IE: a purchase plugin, "logged in" plugin, and so on.

I'm thinking of breaking this very large app into multiple smaller Craft apps which would be able to be deployed independently to AWS instances. This way when we make a change to our Purchase flow we no longer need to redeploy the entire app /remove-headaches.

I've been looking around and haven't found much on terms of people doing this with Craft? The instances would all share the same database instance since we don't store any data in the database anyways so that wouldn't be an issue... but is it just as simple as including the /craft and /public folder on every instance? How would these apps access each other's functions? So if the Purchase Plugin needs to access something from the "Logged in" plugin on the other app it would need to be via HTTP request which would hit the other app's index.php and go from there? I guess we would need to build a gateway for these apps to speak to each other if we need to do cross-app talk?

This is what I was thinking it would look like:

Remove "Purchase plugin" from the original repo.
Create a new repo for purchase app
Plug the "Purchase plugin" into the new app which only has the necessary folders for Craft to run. Ie: craft and public folders with only this one plugin.
Create a gateway for requests coming from "Logged in" app and "Purchase app" to correctly direct to the other app for cross-talk. This would route purchase app requests to logged in app if/when it needs to access something.
These craft instances would point to the same database that has data about all plugins. Or would it be better to each have it's own database? Is this something that would become hectic to maintain for business partners?

Essentially I'd be creating an "API" out of these two apps. They would both be ale to stand independently and the implementation can change for either one so long as it fulfills its contract. This would allow me to deploy them separately and have separate teams maintain them without worrying about something in one app being broken because of something in the other app being deployed.

The instances would all share the same database instance since we don't store any data in the database anyways so that wouldn't be an issue...

Brad or Brandon from P&T is probably going to chime in here with a better answer but it sounds like more trouble than it's worth.

For one thing, Craft relies on the database to determine if plugins are enabled or not. If your plugin is only "enabled" on one instance, the database is going to reflect that state. That sound likes a recipe for disaster.

Even if you make every piece self-contained, with multiple databases for each that "talk" to each via API like JSON or something else, you'll also have the problem of updating Craft's core files in multiple places whenever Craft itself gets updated. Multiple that by how many instances you have to determine what factor of headache you want...

Modularity is a good concept but it reads to me a bigger problem here is your deployment strategy and getting everyone on the same page as to what everyone should be working on, development wise. If one of your developers breaks the API for the other team that's calling it, you're just as screwed as before.

If your team is pushing up code that's broken, you want some way to revert back. That's true of any kind of system, modular or not. Small commits often. You might want to look at DeployBot or Capistrano or something else of that nature.