Headings Not Shown When Adding Custom Source When adding custom sources as per the docs https://craftcms.com/docs/plugins/hooks-reference#modifyEntrySources like so:

foreach($this->regions as $region)
{
    $sources[] = ['heading' => $region['title']];
    $sources['news:'.$region['id']] = [
        'label'    => 'News',
        'criteria' => ['relatedTo' => $region['id'], 'section' => 'news', 'editable' => true],
        'data'     => array('type' => SectionType::Channel, 'handle' => 'news'),
        'defaultSort' => array('postDate', 'desc'),
    ];
    $sources['notifications:'.$region['id']] = [
        'label'    => 'Notifications',
        'criteria' => ['relatedTo' => $region['id'], 'section' => 'notifications', 'editable' => true],
        'data'     => array('type' => SectionType::Channel, 'handle' => 'notifications'),
        'defaultSort' => array('postDate', 'desc'),
    ];
}

the headings are not being shown between the sources. Am I missing something?

UPDATE: Ok, I've managed to figure out that it is to do with ElementIndexSettings. In ElementIndexesService->getSources() is a check for sourceOrder in the settings...

// Should we output the sources in a custom order?
if (isset($settings['sourceOrder']))
...

If I reverse the logic to mimic there being no settings my headings are displayed as expected.

So my question has changed somewhat, firstly is this expected behaviour? If it is I'm only applying these sources for certain users, can I temporarily disable the index settings from within my plugin's init function?

Thanks.

So I have my headings displaying now but this is more of a flawed workaround than an answer.

Basically when the ElementIndexesService->getSources() function finds element index settings it then works through the sources ordering them and applying headings based on the settings.

As my sources are custom ones added by a plugin they don't exist in the settings. Because of this they are shuffled to the end of the list and the headings are removed.

My fix is to add them to the settings in the database. This can be done using...

$elementIndexesService = new ElementIndexesService();
$settings = $elementIndexesService->getSettings(ElementType::Entry);
// and
$elementIndexesService->setSettings(ElementType::Entry, $settings);

$settings consists of two sub arrays containing the sources and their order. By adding my custom sources to these everything appears in the entries index as planned.

The flaws are that I now need to maintain this whenever the entries that effect the sources are created or deleted. Also the index settings modal overwrites the settings in the database so again I have to maintain it if they are changed.


How to temporarily disable entries of one site version within a site group? A client asked me to temporarily disabled all of its entries of one of its Site in a specific language. This entries should not be accessible anymore from their URL.
The quickest and cleanest way to hide them would be to delete this Site version, but this would result in deleting all related entries.
As far as I know, the only way to hide them temporarily is to visit each Entry, then disabled the Enabled for site option, and after that make some changes in menu template to hide this Site version.
As there's a very large number of Entries, this will be very  time consuming. Is there any cleaner or faster way to do that?

I finally ended up with this SQL query, which result to disable all Entries of a site version:
UPDATE `craft_elements_sites` SET `enabled` = '0' WHERE `craft_elements_sites`.`siteId` = 2;

Where 2 is the siteId. After that, don't forget to clear the templates caches.


How do I get the primary site URL? Is there an available variable for the primary site URL in a multi-site CraftCMS setup? I need a variable that I can attach to my logo that will take the user back to the primary site. I could hard code this, however, the URL needs to be environment aware. For example, on my local environment, the link should be https://www.mysite.local and when on development, the link should be https://www.mysite.dev.

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

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

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

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

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

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

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

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


Can I setup multiple sites under one Craft install? I have not used Craft much, but can I setup multiple sites under one Craft install?

If I can, which version of Craft is needed?

Thanks.

you definitely can, both in Craft 2 and Craft 3. I would recommend using Craft 3 (3.1 beta if you can) so you use the latest improvements available.

On Craft 3 you can set different Groups for different pages and then different sites within each group for the different languages.

I recommend this video, it helps a lot with the set-up and understanding how it works.

Anyway, I am not sure if you might need different license type for setting more than one site on production.


Mute NotFoundHttpException from logs I'm getting a lot of noise in the logs from requests that are auto generated from browsers and spiders (like favico.ico, robots.txt, /home /news etc) that doesn't actually have any endpoints.

These get caught by index.php and throws

[yii\web\HttpException:404] yii\web\NotFoundHttpException: Template not found: new in /app/vendor/craftcms/cms/src/controllers/TemplatesController.php:93"

Which is causing a tremendous amount of noise. I would never consider a 404 a real error, so I would like to not log this at all in Craft (I can use access log aggregation for this).

However, I'm not sure how to go about it. I have already created a custom log component, to remove the logging of all server variables on error, and send outputs to stderr (because of docker), with yii2-streamlog.

My log config is as follows:

    'components' => [
        'log' => function() {
            return Craft::createObject([
                'class' => yii\log\Dispatcher::class,
                'targets' => [
                    [
                        'class' => codemix\streamlog\Target::class,
                        'url' => 'php://stderr',
                        'levels' => Logger::LEVEL_ERROR | Logger::LEVEL_WARNING,
                        'logVars' => []
                    ],

                ]
            ]);
        }
    ],

Those should not be logged in web.log when running Craft 3.x, but rather in the web404s.log -- assuming you don't have devMode on (which it shouldn't be on for production...)

Vide: Zen and the Art of Craft CMS Log File Reading

Also should you really want to customize things, it's not hard to do with Craft CMS, check out: Creating a Custom Logger for Craft CMS


Override admin template with own template How can I override the following admin template in Craft 2?

craft/app/templates/users/_edit.html

I've tried placing the template in my own template directory, like:

templates/users/_edit.html

but this doesn't override Craft's own template.

For that path, Craft would look for the following template files, and use the first one that exists:

craft/app/templates/users/_edit
craft/app/templates/users/_edit.html
craft/app/templates/users/_edit.twig
craft/app/templates/users/_edit/index.html
craft/app/templates/users/_edit/index.twig
craft/plugins/users/templates/_edit
craft/plugins/users/templates/_edit.html
craft/plugins/users/templates/_edit.twig
craft/plugins/users/templates/_edit/index.html
craft/plugins/users/templates/_edit/index.twig

[source]

As the users/_edit.html template in craft/app/templates will always exist, it will always find that first and use it.


Return to default error handling In my plugin, I'd like to catch errors when they appear in the control panel, so I can handle them differently. However, from the front-end, I'd like to keep the default Craft-style handling of error messages.

try
{
    // Some code which might produce an error
}
catch (\Exception $e)
{
    if (craft()->request->isCpRequest()) {
        // Do something with $e->getMessage()
    } else {
        // Use default Craft error handling
    }
}

All of that is working for me, just trying to sort out how to do this part...

// Use default Craft error handling

How can I get my error handling to just go back to what Craft was doing by default? I want to make sure my errors still appear in devMode per usual.

Just re-throw the exception and pretend like nothing ever happened...

try
{
    // Some code which might produce an error
}
catch (\Exception $e)
{
    if (craft()->request->isCpRequest()) {
        // Do something with $e->getMessage()
    } else {
        // Nothing to see here...
        throw $e;
    }
}


Using Element API to output Super Table fields I am building a feed using Element API. I am currently looping through Matrix blocks to get various data (based on the help from this post). One of the matrix blocks contains a Super Table field, with various fields inside of that. Here is the relevant section of my Element API config file.

'transformer' => function(Entry $entry) {
  $contentBlocksArray = [];

     foreach ($entry->contentBlocks as $block){
       switch($block->type->handle) {

         case 'introText':
           $contentBlocksArray[] = [
             'introText' => [
               'body' => $block->body,
             ]
            ];
            break;

          case 'twoColumnText':
             $contentBlocksArray[] = [
               'twoColumnText' => [
                  'columnTextBlocks' => [
                      'icon' => $block->icon,
                      'text' => $block->text
                  ]
                ]
              ];
              break;

The first case in this switch works as expected. 'introText' is the Matrix box and 'body' is a plaintext field inside that block. The second case is where I'm having trouble. 'twoColumnText' is the Matrix block and 'columnTextBlocks' is a Super Table field with two plaintext fields. The api returns a response, but both 'icon' and 'text' = null.

I have also tried calling some of the functions as demonstrated in Super Tables docs here but no luck. I am by no means a php / laravel / etc developer, so I might be missing something that would be obvious to such a developer.

I suspect it's something similar to retrieving images where I have to loop through the Super Table fields, but I don't know what that syntax would look like.

Here is a solution I found. Define an empty array, then loop over it, providing whatever keys you want to return from the Super Table fields. Simply by looping over $block->columnTextBlocks (the handle of my Super Table field), Element API returns the information for the fields within the Super Table.

 case 'twoColumnText':

    $SuperTableRows = [];

    foreach ($block->columnTextBlocks as $row){
        $SuperTableRows[] = [
            'fieldHandle1' => $row->fieldHandle1,
            'fieldHandle2' => $row->fieldHandle2,
            'fieldHandle3' => $row->fieldHandle3
        ];
    }

    $contentBlocksArray[] = [
        'twoColumnText' => [
            'columnTextBlocks' => $SuperTableRows,
        ]
    ];

break;

If you need additional information about the Super Table fields, such as Placeholder text, field id's, etc. you can add a generic call to the Super Table field like so (using the same names as my previous code example):

$contentBlocksArray[] = [
    'twoColumnText' => [
        'generic' => $block->columnTextBlocks,
        'columnTextBlocks' => $SuperTableRows,
    ]
];

Now in Element API, the "generic" object includes a customFields array for each field within the Super Table. This only becomes available when you loop over the Super Table field, otherwise it would be null.

Here are some pictures of what the data from Element API looks like.

Here is a simplified version:

'transformer' => function(Entry $entry) {
   $SuperTableRows = [];

   foreach ($entry->superTableFieldHandle as $row){
     $SuperTableRows[] = [
       'fieldHandle1' => $row->fieldHandle1,
       'fieldHandle2' => $row->fieldHandle2
     ];
   }

   return [
     'SuperTableRows' => $SuperTableRows
   ];
 },


Can craft omit default locales from generated paths? My bilingual site works fine, but it is not optimal from a url and SEO perspective because Craft is outputting duplicate content on different paths.

My default locale is en and the secondary locale is cy, this means many English pages can be reached by omitting the local from the path (which is the behaviour I want).

The problem is that certain pages craft generates via the {{ entry.url }} parameter contains the locale in the path even for the default one. i.e., Craft is spitting out paths like http://mysite.com/en/section/entry-title when I'd prefer it to be http://mysite.com/section/entry-title. It's actually accessible from both URLs, which is a bad thing for SEO. I only want the locale parameter added into the path when it's actually needed (i.e., for when we switch to cy).

Is this possible? If not, is there a work-around?

In your config file you will want to define the locales such that en points to the root directory.

'siteUrl' => array(
    'en' => 'http://craft.dev/',
    'cy' => 'http://craft.dev/cy/'
 ),

And your public html folder should not include an 'en' folder:

/craft
/html
    /cy
        /.htaccess
        /index.php
    /.htaccess
    /index.php


How can I perform an HTTP Request? I'm new to the Craft and I just want to ask if how am I able to perform an HTTP request in Craft just like AJAX. Where should I perform it? What should be the flow?

I have used the placid plugin to achieve this in the past.
Is this what you are looking for?

https://github.com/olivierbon/Placid/wiki/Making-requests


Upload user profile image from custom plugin controller Im trying to upload a profile image from a front end form via a controller function

this is what i have but the $image keeps returning null?

<form name="updateProfile" method="post" enctype="multipart/form-data">
     <input type="hidden" name="action" value="salesforce/saveContact">
     <input type="file" name="photo" id="avatarUpload">
     <input type="submit"/>
</form>

and my controller action is

public function actionSaveContact()
{

    $this->requirePostRequest();

    $userPhoto = craft()->request->getPost('photo');

    $user = craft()->userSession->getUser();

    craft()->users->saveUserPhoto('test.jpg',$userPhoto, $user);

}

Not sure what im doing wrong?

The image data is not going to be in POST variable. You should be using

$userPhoto = UploadedFile::getInstanceByName('userPhoto');


Modify how the html fields are outputted by Redactor Is there a way to modify how the html fields are outputted by Redactor? I'm creating an email template and I'm trying to add inline styles to Redactor's list items, links, etc.

To add inline styles to HTML tags generated by Redactor such as <li>, install the Retcon plugin and add the following to your template. For example:

{{ entry.body | retconAttr('li', { style: 'color: red;' }) }}

For more info, consult the retconAttr filter documentation.


Invalid path after Craft update I updated to the latest Craft version.

This error shows under the field in entries (backend):

This field’s target subfolder path is invalid: {slug}

I checked the field and there is no {slug} tag at all.

Fronted shows images fine, but with that error I cannot update my entries.

In whatever Section you're getting that error in, you've got an Assets field inside of Matrix (or possibly SuperTable) and that Assets field has “Restrict uploads to a single folder” set and you've got a dynamic subfolder path setup for it.

In that dynamic path, you're using {slug} when you should be using {owner.slug}.

From the docs:

  Note that if you are creating the Assets field within a Matrix field, the source element is going to be the actual Matrix block, not the element that the Matrix field is being created on. So if your Matrix field is attached to an entry, and you want to output the entry ID in your dynamic subfolder path, you would type {owner.id} not just {id}.


Output currency symbols Is there a way to output the currency symbols for each accepted payment currency in a Craft Commerce site?

Consider the following simplified example;

{% set currencies = craft.commerce.paymentCurrencies %}
{% if currencies|length > 1 %}
<select name="paymentCurrency">
    {% for currency in currencies %}
        <option>{{ currency.iso }}</option>
    {% endfor %}
</select>
{% endif %}

Instead of the currency ISO code being output in the option, I also want to show the symbol. I can't find a method for doing so.

You don't need to create your own symbol map - it exists as a yii translation:

{% set localeData = craft.i18n.getLocaleData() %}
{% set currencyIso = 'USD' %}

{{ localeData.getCurrencySymbol(currencyIso)  }}


Multiple backends on CraftCMS 3 - Problem with cpresources We've got a AWS setup with an ELB in front, 2 varnish cache servers and 2 Craft CMS backends, with Redis for php sessions and Craft cache shared amongst the backend servers.

We do not have sticky sessions, so each request can end up on a different server.

Problem is with cpresources and the generated files. First request generates files on server 1, but as each request can end up on a different server, the other servers will not have the same files.

What is the best approach here? What alternatives do we have?

We would like to avoid sharing cpresources amongst the servers if possible (via mount), as it slightly complicates setup and its "one more thing that may break".

-- Edit

We have been experimenting with AWS EFS (Elastic File Storage) to share disks between servers, but unfortunately its too slow.

We noticed that in Craft CMS 2, static files were served through index.php, which allows php to create the files, should they not exist, which would solve this particular issue. However, in Craft CMS 3, this changed and they are served directly. It would be great if someone official in Craft CMS could verify this change and comment why it was designed the way it is in Craft CMS 3 and also comment on how that change is beneficial in a multi-backend-setup.

We are now looking into an EC2 instance to serve the purpose of an NFS share, but doing this we are introducing a single point of failure in an architecture that was suppose to eliminate that exact thing.

Running into the same issue here!

For the uploaded files I have solved it by creating a NFS share on all backends (15 servers). Not ideal but it's working for now. Maybe mounting the cpresources to NFS share would also do the job, but I haven't tested it.


Meta are moved to body I am getting some global entries from the CMS that I want to use as meta-tags content.

When I load the page I see in the inspection that the meta-tags are moved inside the body.  When I remove the dynamic meta-tags and use only the hardcoded, everything is ok.

I have something like that in the head:

{% set metadata = craft.globals.getSetByHandle('metadata') %}

<title>{{ metadata.title }}</title>
<meta name="description" content="{{ metadata.description }}">
<meta name="keywords" content="{{ metadata.keywords}}">

Why the meta-tags are moved? How can I fix that? Is it a Craft issue or a Twig issue or my mistake?

So the problem was caused by a secret character, the character was not visible in code but it was noticed in the w3c validator for html.

So after removing that character issue solved.


Redirect and locale issues when using Valet / Caddy Server I'm trying to setup our Craft CMS dev environment with Valet which is just a wrapper for Caddy Server and dnsmasq.

I seem to be running into some redirect/locale issues that's preventing these pages from loading. The rest of the site and the CMS admin itself is working fine.

I've previously had things setup on apache and have followed the localization guides but I'm thinking it has to do with the fact that caddy server doesn't honor .htaccess files so I need to add some rewrite rules in my Caddyfile for the various locales.

When trying to load the regional sites it's just giving me a 404.

Has anyone else got this working?

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


POS integration with Craft Commerce My client has an online store that we are building with 10 or so products. They will also have a high street store which sells the exact same products.

Is it possible to integrate Craft Commerce with POS (Squareup or iZettle ) software so the stock levels are kept up to date?

It's totally possible. However, since there is no existing plugins for this that is readily available, you'd have to create a custom plugin to do it.

If you have the necessary coding chops, you can get a flying start by generating the boilerplate over at pluginfactory.io.

If not, you can hire a programmer in the Craft community to do this for you. Posting in the Craft slack channel #jobs should get you started.


date in database -1 day as on frond-end We just found out that in the database birthday field, all dates has 1-day difference than what is shown on the front-end.

On the front-end, it is the correct date by the way.

Question: Is it a bug and if not, why is this?

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

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


Saving matrix field of a duplicate of an entry not working I'm creating a cron job to automatically import new entries (vacancies).
I have an entry that I use as a template with some standard data fields and matrix fields. If it's an entry that has not been imported before I create a new entry as a duplicate of the template entry.
$entry = Craft::$app->getElements()->duplicateElement($entryTemplate);

The template already has the matrix blocks but only placeholder data that I want to overwrite like this:
// existing matrix fields (already created or from template)
$matrixBlocks = $entry->myMatrixBlock;

/** @var MatrixBlock $matrixBlock */
foreach($matrixBlocks as $matrixBlock) {
    $matrixBlock->setFieldValues(['contactText' => 'random text']);

    $success = Craft::$app->elements->saveElement($matrixBlock);
}

The strange thing is that the ownerId of the matrixBlock isn't the value of the $entry->id nor is it the value of the template id. It generated a new ownerId.
It works correctly when I import it a second time because the owner id is now correct.

This sounds suspiciously like a bug that was fixed in today's Craft 3.6.10 release.

Fixed a bug where entries could return the wrong Matrix/Neo/Super Table blocks if the blocks were queried immediately after the entry was created via craft\services\Elements::duplicateElement().

My guess is if you update to that release, it'll behave like you expect now.


Change posts url without losing SEO positioning I migrated a site with over 500 posts from Wordpress to Craft 2.6 recently but came across this problem: the WP site used to set post's urls as https://mysite.com/{slug} while the new blog is (correctly) saving them to https://mysite.com/blog/{slug}.

The problem is, a lot of the post entries have great SEO positiong and I don't want to lose that, what is the best way to achieve this?

Migrating Redirects should not be thought of as a one-time event but a process that includes a step where you make sure Redirects are in place and working.

A rough redirect strategy

Take a snapshot of where your old website stands. This can be a combination of using tools like Google Analytics, Screaming Frog, moz.com, raventools.com, or one of many other services that do similar things. The main goal of this step is to understand where your current website ranks and what errors your current website has. Whatever you do in this step, you're going to do it again after you launch and by understanding your baseline before you make significant changes you'll have a better picture of what may need correcting after you launch the new site.
Identify all the URLs that are changing and decide which ones you want to redirect. Often this is all of them. Sometimes, you might choose to clean things up or just focus on key pages. Redirects can be managed in various places. The easiest place to manage them may be via a plugin like Sprout SEO or Retour however managing them via the .htaccess file or some other lower level configuration is also an option.  A good way to consider which URLs need redirected is to look at your analytics data. You can filter Google Analytics data and get a list of all pages that have been visited in the past year ordered by page views to get a fairly accurate list of what's important that you should be caring about.
Get redirects in place. If you have a few redirects, adding them manually may be fairly straightforward. If you have lots, consider using regex patterns in your redirects. If a group of pages changes their URLs in the same way, you can likely write a single rule to match all of their URL patterns and forward those old pages to the new ones. I've given a more specific example of this below.
Once you go live, be sure to test your redirects (see notes below) and take another snapshot of your site and monitor the site for unexpected behavior. Google Search Console and various tools like the ones mentioned above can help you monitor the site for errors and make sure no big issues were accidentally introduced. Sprout SEO can help you capture all 404 Redirects and an admin can convert any pages that were missed into 301 Redirects. When you do find issues, be sure to address them as quickly as you can. The longer you let them sit, the more likely search engines will think they are the norm.

A few additional notes on redirects

There are different types of redirects. If you set a redirect to be a 301 redirect, that rule will get cached in your user's browsers. If you happen to make a mistake and try to change your redirect, the only way a user that hit your last redirect will get rid of it is if they clear their browser cache. For this reason, I recommend starting out with 302 redirects and testing all redirects as 302s. If the redirects work as expected, you can then update them to 301 redirects to signal to search engines that your changes are permanent and reduce the change that you create a scenario where incorrect rules get accidentally cached in user's browsers.

If you have several redirects that follow the same pattern, you can use regexes to simplify the number of redirects you need. The following example is an .htaccess redirect that will match all incoming article/{slug} URLs and redirect them to a new blog section (the term used in regexes for matching patterns within parentheses is Capturing Groups).

RewriteRule ^/article/(.*)$ /blog/$1 [R=301,L]

In your case, since the previous URL was very broad {slug} it may be challenging to find a pattern that matches your old URLs that doesn't also match all of your new URLS or new pages on your site. In this case, you may need to be more explicit in which URLs you are redirecting

If you do need to import 500 URLs, Sprout SEO Redirects can be converted from CSV and imported via Sprout Import.


Migrating Craft site to another server --- throws 404 for all pages but homepage I've been asked to migrate a Craft site from one server to another.  The new server setup is the same as the server I'm migrating from.  I moved all the files in the webroot directory over to the new server and imported the database.  The homepage works just fine, just all links go to an Apache 404 and so does the admin panel.  Ideas?  Nothing is different from the other server.

99% chance that it is because the .htaccess file did not come over when you copied the files, as it is a hidden file. Copy that over to your new webroot and those interior pages should properly work.


Is it possible to force Craft to recheck available sever modules? One of our servers hosting a Craft site has recently had ImageMagick installed on it, as we noticed that transformed animated GIFs weren't animating.

The 'Requirement Report' at /admin/utils/serverinfo is still reporting a 'warning' against ImageMagick (as it was before it was installed), and Craft seems to still be using GD as the freshly transformed animated GIFs still aren't animating.

Is there a way to force Craft to 'recheck' the available modules on the server (and so in my case, for it to recognise that it can now use ImageMagick)?

Craft will re-run the requirement checks simply by loading that admin/utils/serverinfo page.  The results aren't cached.

It sounds like your box may have had the ImageMagic library installed, but not the PHP wrapper for it.  You can check by going to admin/utils/phpinfo and searching for imagick and if there are no results, it's not installed.

Alternatively maybe it is installed, but you're explicitly setting the imageDriver config setting to 'gd'.  Be default, it's set to null which means Craft will automatically use Imagick if it sees its available.


How do you output the Image Caption on an asset? When you double-click an asset you can set the Image Caption:

How do you structure the query to output this Image Caption "field?"

You should give a try:

{{ craft.assets.filename('refresh1.png').one().imageCaption }}

Where imageCaption is the handle of your Image Caption field (imageCaption is an example, you should check this value).

More informations about how to fetch assets: https://docs.craftcms.com/v3/dev/element-queries/asset-queries.html


How do I iterate over a categories field in an entry I'm using the Scout plugin to sync my entry data to an Algolia search index. In the transformer for the scout.php config file, I need to iterate over all of the categories in a category field on each entry.

How would I do this to output the category at each level like so:

"categories": {
    "lvl0": ["Rigging", "Film Lighting"],
    "lvl1": ["Rigging > Rigging Support", "Film Lighting > Stands"],
    "lvl2": ["Rigging > Rigging Support > Stands"]
}

Here is where i'm at with the transformer:

'transformer' => static function (craft\base\Element $entry) {
    return [
        'entryTitle' => $entry->title,
        'id' => $entry->id,
        'url' => $entry->url,
        'title' => $entry->equipmentFriendlyName,
        'manufacturer' => $entry->equipmentManufacturer,
        'modelNumber' => $entry->equipmentModelNumber,
        'description' => $entry->equipmentDescription,
        'categories' => $entry->equipmentCategory->all(),
    ];
}

Try this approach:

<?php
return [
    'transformer' => function(craft\base\Element $entry) {
        $level1Categories = [];
        $level2Categories = [];
        $level3Categories = [];

        foreach ($entry->equipmentCategory->level(1)->all() as $category) {
            /** @var $category \craft\elements\Category */
            $level1Categories[] = $category->title;
            $children           = $category->getChildren()->level(2)->all();

            foreach ($children as $child) {
                /** @var $child \craft\elements\Category */
                $crumb      = [
                    $category->title,
                    $child->title,
                ];

                $level2Categories[] = implode(' > ', $crumb);

                foreach ($child->getChildren()->level(3)->all() as $subChild) {
                    /** @var $subChild \craft\elements\Category */
                    $crumb      = [
                        $category->title,
                        $child->title,
                        $subChild->title
                    ];

                    $level3Categories[] = implode(' > ', $crumb);
                }
            }
        }

        return [
            'entryTitle'   => $entry->title,
            'id'           => $entry->id,
            'url'          => $entry->url,
            'title'        => $entry->equipmentFriendlyName,
            'manufacturer' => $entry->equipmentManufacturer,
            'modelNumber'  => $entry->equipmentModelNumber,
            'description'  => $entry->equipmentDescription,
            'thumbnail'    => !empty($entry->equipmentImages->one()) ? (string)('https://acsweb.com' . $entry->equipmentImages->one()->getUrl()) : '',
            'categories'   => [
                'lvl0' => $level1Categories,
                'lvl1' => $level2Categories,
                'lvl2' => $level3Categories,

            ],
        ];
    },
];```


How to check for an non empty element field? Which one of the following is the correct of way of checking if an element field like images, entries or category is not empty?

{% if entry.fieldHandle.one() %}
{% if entry.fieldHandle.all() %}
{% if entry.fieldHandle.count() %}
{% if entry.fieldHandle | length %}
{% if entry.fieldHandle.exists() %}
{% if entry.fieldHandle %}

They'll all work except for the last one:

entry.fieldHandle.one()
entry.fieldHandle.all()
entry.fieldHandle.count()
entry.fieldHandle | length
entry.fieldHandle.exists()


Installing Craft without installer screens Is it possible to install Craft from the command line or without going through the installer screens?

is it as simple as using bootstrap.php and then calling craft()->install->run($inputs); with valid inputs?

Would this be something? Craft CLI Installer


Assets (in assets folder) failing to load locally [Craft 2] I'm trying to get my Craft 2 site running locally again (it worked at one point but now does not).
I have gotten all the db related issues (seemingly) done and dusted and the admin loads fine, but it seems that anything linked to Amazon S3 (or perhaps the {{ craft.config.rootUrl }}?) seems to be failing.
The devtools console has a lot of :
Failed to load resource: the server responded with a status of 404 (Not Found)
The local set up is using docker inside a virtual machine and is brought up using vagrant. I have all the code locally tied to lvh.me (on a specific port) and when the site loads, some external services (such as Imager) are still working – just nothing relating to aws / S3 for some reason.
Has anyone encountered this before? Have I forgotten to set something up re: Multi Environment variables or perhaps did Google change a policy that requires me to add permissions to the IAM user to allow for local access?
Thanks in advance for any steers.
Really at an impasse here. Can anyone help?
edit:
After helpful comments, I am getting the impression that since the path to the root of the Assets folder is something that is controlled by the general.php file and the files that aren't loading seem to be directly inside there (and local, as opposed to on S3), that maybe this isn't an S3 issue (yet). It seems that the local path to the Assets folder is least part of the problem.
Here's what my set up in general.php looks like:
// $protocol = isset($_SERVER['CRAFT_PROTOCOL']) ? $_SERVER['CRAFT_PROTOCOL'] : 'https';
$protocol = $_ENV['CRAFT_PROTOCOL'];
// force http on local environment
if ($_SERVER['REMOTE_ADDR'] == '127.0.0.1' ) {
    $protocol = 'http';
}

return array(
    '*' => array(
        'devMode' => false,
        'omitScriptNameInUrls' => true,
        'preserveImageColorProfiles' => true,
        'backupDbOnUpdate' => false,
        'generateTransformsBeforePageLoad' => true,
        'maxUploadFileSize' => 33554432,
        'environmentVariables' => array(
            'baseUrl' => $protocol.'://'.$_ENV['SITE_URL'].'/',
            'basePath' => $_ENV['DOCUMENT_ROOT'].'/',
            'assetsUrl' => $protocol.'://'.$_ENV['SITE_URL'].'/'
        ),
        'rootUrl' => $protocol.'://'.$_ENV['SITE_URL'],
        'siteUrl' => array(
            'en_gb' => $protocol.'://'.$_ENV['HTTP_HOST'].'/',
            'ja_jp' => $protocol.'://'.$_ENV['HTTP_HOST'].'/'
        ),
    ),
);

Anything look out of place to anyone? The assets that won't load locally, via lvh.me, are in the *public > assets > folder (e.g. public> assets > js > app.js). They load fine in the staging environment, but just not locally.  It feels like either a Docker / CI issue relating to the Sandbox or just a config issue with the settings above.
The error is a 404 not found and that URL is reading:
http://lvh.me/assets/js/app.js?v=14
What do you think?

My guess is that your bucket doesn't have the right permissions. Try adding this permission to your bucket (use with caution since this will make the S3 100% public):
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::bucketname/*"
        }
    ]
}

Replace bucketname with your actual bucket name. You can add this policy via the AWS UI console. In S3 > YourBucket > Permissions > Bucket Policy.
If by doing this you actually manage to get URLs that resolve, then your problem are permissions. I would still delete this bucket policy and set the correct permissions for your use case.


How can I restore Matrix content after accidentally changing its field type? We accidentally deleted all our body text on all our pages, how do I redo my website to a older version. (24 hours ago)
We changed matrix to assets and after that every body text disappeared.

As John mentioned, restoring a database backup is your best bet.

If you don’t have a recent backup, you may still be able to get your Matrix content back, thanks to semi-bug where Craft doesn’t actually delete Matrix block content, when a Matrix field is converted to something else.

Here’s what you can try:

Enable the Project Config file for your site, if you don’t already have it enabled.
Figure out what your field’s uid is by looking up its row in your database’s fields table.
Find the most recent project config backup in storage/config-backups/ where your field was still a Matrix field. The most recent backup will be called project.yaml, the second most recent will be called project.yaml.1, and so on. For each file, search for <field-uid>: (replace <field-uid> with the UID from step 2). If the nested type property is set to craft\fields\Matrix, you’ve found the right file. It will look something like this:

8823155c-e84a-4a38-af30-2cb88b705e7b:
  name: Body
  handle: body
  instructions: ''
  searchable: true
  translationMethod: none
  translationKeyFormat: null
  type: craft\fields\Matrix
  settings:
    maxBlocks: '3'
    localizeBlocks: false
    contentTable: '{{%matrixcontent_testimonials}}'
  fieldGroup: d58a1faa-0bf6-46b2-b880-b0c14bebca75
  contentColumnType: string

Find the same field definition in your current config/project.yaml file, and replace it with the field definition from the backup you found in step 3.
As a sanity check, you may want to compare the config backup from step 3 with the subsequent backup (so if you found your matrix field in project.yaml.10, compare it with project.yaml.9), using a diff tool like FileMerge (comes with macOS) or Kaleidoscope. If there are any other significant changes that happened at the same time, you may want to revert those changes as well in config/project.yaml.
Now access your Control Panel and click the button to sync your new project.yaml changes. When that’s done, if all goes well, your field should be a Matrix field again, and your content will be restored.


Is there any way to code multiple lines in a twig file? Instead of using:
{% ... %}
{% ... %}
{% ... %}

For each line, i'd like to know if there is a way to do something like:
{%

...
...
...

%}

You can't execute multiple statements inside of a single {% %} block.
You can have a single statement that is multi-line.
See here for more info: https://stackoverflow.com/questions/31111516/does-twig-support-executing-multiple-statements-inside-a-single-block


How to add an alpha ordered list option in Redactor? In addition to a bulleted unordered list and a numbered ordered list, I'd like to add an option to format text as an ordered list with upper-alpha letters, like this:

A.

B.

C.

D.

Can I add this to the list formatting menu somehow? If now, how would I create a custom formatting option that creates an ol?

EDIT 9/4

I am able to add custom formatting (with formattingAdd) to create

, but I haven't found a way to allow li elements to be created inside it.

I ended up making a custom redactor plugin for this. Code at https://github.com/FosterCommerce/redactor-alphalist (repo is currently private but should be published soon).


Programatically Changing Entry Types? I have a people channel that historically has used another field to decide if they're a "featured" person or not.

The field set for "featured" people has now diverged from what a normal person has, so I'm wanting to create a new entry type in the people channel (featuredPeople) and programatically shift these people to the new entry type.

The field set is additive to the old one, so I'm hoping due to there being no field/structural changes this isn't too hard?

I've got the bones of a script together to do this, but I'm struggling to find any info on how to actually change the entry type on the entry.

# Get all people
$peopleCrit = Entry::find();
$peopleCrit->section = "people";
$people = $peopleCrit->all() ?? [];

foreach ($people as $person) {

    # If this was a "featured" person, shift to new featuredPeople entry type.
    if (historical "is featured" check) {

        # Move to featuredPeople entry type
        ???

    }

}

Any help would be greatly appreciated.

Something like this should work. I've also cleaned up the code a bit to be correct PHP syntax as my assumption is that you''ll be doing this in a module/plugin.

// Get all people entries
$entries = Entry::find()->section('people')->all();

foreach ($entries as $entry) {
    // If this was a "featured" historical person
    if ($entry->historical == 'featured') {
        // Change to featuredPeople entry type
        $entry->typeId = $featuredPeopleEntryTypeId;

        // Save entry
        Craft::$app->elements->saveElement($entry);
    }
}


I can't get Dukt Videos working in a Matrix field? I have the plugin Dukt Videos installed to latest version 1.0.31.  I setup a Matrix block field with these settings:

Field handle: videos
Matrix Block handle: videoBlock
Matrix Video Field: videoURL

For some reason this will not work:

{% for video in entry.videos %}

title: {{ video.title }}

url: {{ video.url }}

embed: {{ video.embed({ width: 300, height: 200 }) }}

{% endfor %}

I get this error: Craft\MatrixBlockModel and its behaviors do not have a method or closure named "embed".

When I try this it also does not work:

{% for blockMedia in entry.videos %}
    {{ blockMedia.videoUrl }}
{% endfor %}

I get this error: Internal Server Error. Object of class Craft\Videos_VideoModel could not be converted to string

What am I doing wrong with this Dukt Videos Plugin?

I'm sure the documentation could be better, but this has nothing to do with Duct Video, it's simply a user error. Although a common one, when accessing things inside a matrix, assets field, or similar.

When you do:

{% for video in entry.videos %}

video is a matrix block. Not the field you've created inside that matrix blocktype. When accessing video.videoUrl, you get the an object of type Videos_VideoModel, same as when you add this field directly to an entry type. The correct way to do this (disregarding that videoUrl is a bad name for the video field) would be:

{% for block in entry.videos %}
  {% set video = block.videoUrl %}

title: {{ video.title }}

url: {{ video.url }}

embed: {{ video.embed({ width: 300, height: 200 }) }}

{% endfor %}


How can I set up tiered volume discounts without enacting a waterfall effect of multiple discounts being applied? Trying to set up tiered volume discounts and can't figure out how to not have multiple discounts get applied when the cart total meets minimum criteria for more than one discount.

So the simple discounts I'm trying to have applied are here:

I understand why Craft is applying both: Because the order meets the criteria for both Purchase Quantities. Is there a way I can specify a range, or other workaround?

Currently at Craft Commerce 1.1 this is not possible with the current discount engine.

We would need to implement features like a min qty AND a max qty for the discount rules. It is on our radar.

Fee free to vote for extended discount conditions features here: http://feedback.craftcms.com/forums/295386-commerce/filters/top


Set Default Entry Types for elements in a Structure Section I have a Structure Section controlling my Nav and page contents
So I have

Home

About Us

History
List item
List item

Services

Service 1
Service 2
Service 3

In the Control Panel when I add items to this structure I have 3 different Entry Types.
Is it possible to set it so that when I add a Child to the Services structure item a specific entry type can be set as default as opposed to the first one?

Or should create a different structure section for each one and have its own entry type?

I'm not sure if you can set a default entry type within Craft.

But a reasonably workaround would be to go to Settings > Sections, then click 'Edit entry types' for the section you need to apply this to. Next, drag the entry type you would like to be used by default to the top of the entry-type list.

That way, when a new entry is added to the Section, the default entry type will be whichever type is the top of the list.

Hope this helps, but as I say there may be some other answers that offer a cleaner approach.


Pages for each entry from an entry type? Let's say I have an entry type named "Designers", and I have:

A title field "Full Name"
A categories field "Specialty"
Another categories field "Location"

Now I want each designer (that is, each entry) from the "Designers" entry type to link to a another page showing blog entries on which this designer's work is featured.

I'm sorry if I'm not being clear enough... Basically, it's a basic directory what I want to build. People can find designers by specialty and location (not sure if categories is the right way to do it...any suggestions?).

My question is how can I create that page showing the entries. Maybe this can't be done with entry types and I need a separated channel?!

What about using a category group for your designers as well?

Add your "Specialty" and "Locations" category fields to a "Designers" category's field layout and then use a "Designers" category field on your blog entries to assign the designer.

Sorry for the confusion with my other answer, after re-reading your question today I noticed that I headed in the wrong direction. A "Designers" category would probably be the right way to do it, even if you had the ability to add a second channel section.


is it posible to have dynamic Title for my article image grid? I have an image grid for my articles, and its sorted by the type of articles. So all the articles of a certain type is all put in the same item grid, but I want to sort it after the brand aswell by having my image grid sort under a logo of the brand. So if I have 2 different brands of 1 type of article, I want 2 image grids on the same page, neatly sorted under their respective logo.

This is what I have so far:

    {% for entry in entry.children %}
    {% if entry.type=="lift" and entry.liftMerke=="nifty" %}

        {% for entry in entry.children %}
        {% if entry.type=="lift" and entry.liftMerke=="nifty" %}

                {% set bilde = entry.bilde.one() %}
                {% if bilde %}

                {% endif %}

{{ entry.title }}

Arbeidshøyde: {{ entry.arbeidshoyde }}

{{ entry.title }} | {{ entry.arbeidshoyde }}

       {% endif %}
       {% endfor %}

    {% endif %}
    {% endfor %}

So this gives me just a whole bunch of logos whitch is not what I want. Is there something I can do to make it search through the entry.children articles, and do something only once(print logo) if something is true for either one of the articles? Really appreciate any help!

EDIT:

So I have been playing around with this abit now, but I cant really get it to work. I forgott to mention something inportant in my post aswell, I am using craft3 beta.

So I am abit unsure if the errors I am encountering are me not really understanding what I am doing or if it is related to differences between craft 2 and 3.

I created a catogory group(liftmerker) and two catogories(denka, nifty). I added a image field(image field is called "bilde") to the catogories where I uploaded the logos.

This is what the code looks like at the monent:

    {% set entries = entry.children | group( 'entryCategory.one().title' ) %}
    {% set brands = craft.categories.group( 'liftmerker' ).titles %}
    {% for brand in brands %}
        {% set brandEntries = entries[ '' ~ category ] | default( [] ) %}
        {% if brandEntries | length %}

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

        {% endif %}

    {% endfor %}

This gives me an error that I dont really understand:

TypeError
Argument 1 passed to craft\web\twig\Extension::groupFilter() must be of the type array, object given, called in /home/vagrant/Code/Gantic/Gantic3/storage/runtime/compiled_templates/c3/c383e9d48f1c478076ea5c1b97037f5aa9b4242fb3b6dcb877a0488b0b8b32b7.php on line 114

Any suggestions for what I can do different or what line in the code is causing the error?

I hope I got your issue right. For the brand I'd use a category. So each article can be assigned to a category brand.

You can then group your entries by category:

{# Save entries, group by category #}
{% set entries = entry.children | group( 'entryCategory.first().title' ) %}

{# Get all category logos for the category group "yourEntryCategoryHandle" #}
{% set brands = craft.categories.group( 'yourBrandCategoryHandle' ).titles %}

{# Loop through the category title array #}
{% for brand in brands %}

    {# Get the entries grouped under the current brand title #}
    {% set brandEntries = entries[ '' ~ category ] | default( [] ) %}

    {# Print the category title and entries #}
    {% if brandEntries | length %}

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

    {% endif %}

{% endfor %}

This is a modification from this issue: How Do I group entries by Category and retain fixed Category Order?


SuperTable Field returning null I am performing a query from within a plugin like so:

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = $journeyTitle;
$response = $criteria->find();
$attributes = $response[0]->getContent()->getAttributes();
var_dump($attributes);

The dump gives me the following:

array(7) {
  ["id"]=>
  string(1) "3"
  ["elementId"]=>
  string(1) "3"
  ["locale"]=>
  string(5) "en_us"
  ["title"]=>
  string(7) "Armenia"
  ["lifeBeforeColumnOne"]=>
  NULL
  ["lifeBeforeColumnTwo"]=>
  NULL
  ["tester"]=>
  string(12) "fdsfsdfdsfsd"
}

Has anyone ever used Super Table Before, and know why this would be showing up null? I would REALLY like to use this on my project, but am not really sure on how to proceed with this.

For reference, here is a screenshot of the entry that you see outputted within the dump:

The reason the attribute for your Super Table is null is because the field is an element, which doesn't have 'simple' content. You'll find this is the exact same case for any other element like an Entries field, or a Matrix field.

I believe the reason for this is that this simply fetches the content from the actual craft_content table. Being complex (relational) data, there's technically nothing in the content table. Getting the content is a little more complex.

In the case of Super Table (and other elements), when querying the field's content on an attached element, you'll get an ElementCriteriaModel (for Craft 2) returned, which allows you to do all sorts of things when outputting the content of a Super Table (limit, order, etc).

To illustrate, you can do:

var_dump($response[0]->lifeBeforeColumnOne);

Which will output the ElementCriteriaModel, which will be not overly useful for actual content output. In addition, you'll want to call find() on the criteria (just like you're doing above in your code to fetch the entries) to return an array of SuperTable_BlockModel's.

$blocks = $response[0]->lifeBeforeColumnOne->find();

foreach ($blocks as $block) {
    var_dump($block->featuredImage);
    var_dump($block->textContent);
    var_dump($block->source);
}

You can then output the content by targeting the inner fields'.

You might also find this slightly related conversation useful - Getting all content, including Matrix fields from an EntryModel

There's also an example of this sort of functionality on the docs - https://verbb.io/craft-plugins/super-table/docs/guides/developer-examples#fetching-content-from-a-super-table-field


Monitor PHP memory usage I'd like to examine the memory usage per-page on my website using Craft CMS. Is there a configuration option to enable memory logging or to display memory usage at the bottom of the page?

If you enable devMode, then memory usage, along with tons of other debugging information (# of database queries, query profiles, execution timestamps, etc.) will be output to your browser's console.


How does Craft automatically wrap `fields[]` around name attributes? When you use a form macro to generate an input in the CP, you'll end up with something like this...

<input type="text" id="fields-myField" name="fields[myField]">

Oddly, it looks like "myField" is generally passed around the code as a single name value.

What code in Craft core is responsible for automatically appending the fields- to the id attribute, and wrapping fields[] around the name attribute?

I've scoured the Craft core code and just can't find it. That magic doesn't seem to be happening in a Twig macro or JavaScript.

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

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

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

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

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

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

Which would produce the equivalent, rendered HTML of:

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

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

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

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

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

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


Craft Commerce: Variable "product" does not exist My shop has one product. As such there isn't much point in me having a page displaying all products.

When I paste in my template code for my single product into Cart Commerce's main index template I get the error Variable "product" does not exist on the following code:

{% for purchasable in product.variants %}

    <option {% if purchasable.stock <= 0 and purchasable.unlimitedStock == false %}disabled {% endif %} value="{{ purchasable.purchasableId }}">{{ purchasable.description }} {{ purchasable.price|currency(cart.currency) }}</option>

{% endfor %}

Why is this being thrown up and how do I remedy this?

product will only be available by default if you're viewing the template set in the CP under that products type settings:

If you want to display your product elsewhere on your site you will need to set it to a variable like so:

{% set myProduct = craft.commerce.products.first() %}

you can then loop through this product's variants

{% for purchasable in myProduct.variants %}

    <option {% if purchasable.stock <= 0 and purchasable.unlimitedStock == false %}disabled {% endif %} value="{{ purchasable.purchasableId }}">{{ purchasable.description }} {{ purchasable.price|currency(cart.currency) }}</option>

{% endfor %}


Is there a way to eager-load fields in a global set? I use a header global set to store various thing about my site header, including the company's logo.
I use it in my template like this:
{{ header.globalSetsHeaderLogo.one()logo.getImg() }}

Any idea on how I could eager-load this?

Do you mean lazy load or eager load?
Usually you lazy load images via JS to speed up site loading but not I'm not sure doing it to one image across multiple pages is all that beneficial?
After the initial load, the browser should cache that image and "reuse" it. However, querying the global set certainly has a cost on the database.
As far as eager loading, not sure it'll make a huge difference here and it looks like you're not outputting any transforms but you might consider using, say, {% cache globally %} tag on your header. That'll save you some db queries that can have an affect on performance.


How to display the featured image on a Commerce product: How do I display the featured image on a Commerce product:

A good approach is always to check if the element even has a related asset or not, otherwhise you'll receive exceptions.

{% set asset = entry.featuredImage.one() %}
{% if asset is not null %}

{% endif %}


Evenly dividing up table items in columns I'm building out my first Craft site and learning a whole lot so far. Coming from ExpressionEngine, this really seems like what EE should have been.

Anyway, I'm trying to find a way divide up content from a table field into three even columns. For example, if I have content in 9 rows in a table, I would like to have 3 items per column. Is this possible with Twig?  Here is the HTML.  Thank you!

item

item

item

item

item

item

item

item

item

It's actually quite simple! What you're looking for is Twig's batch filter... Ironically, the example given on that page is nearly identical to what you are requesting.

I've adapted the example to more closely match what you're looking for:

{% set myData = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] %}

{% for column in myData|batch(3, 'No item') %}

            {% for item in column %}

{{ item }}

            {% endfor %}

{% endfor %}


How can I automatically generate responsive images from a single hi-res asset? I want to be able to upload a single high resolution image, and output a <picture> element that outputs it with a few different sizes and resolutions automatically (using Picturefill to sort out which one actually shows up to the browsers). How can I do that?

You can do this using image transforms.

There are a couple things you’re going to need to consider though:

Not every image will necessarily be high-res (e.g. a computer screenshot taken on a non-retina screen)
You probably don’t want to output images that are larger than their original size

For #1, we need some way of identifying images that are 1X vs. 2X. You could do this a couple different ways:

Give your assets a Lightswitch field that identifies if it’s a 2X image
Use a consistent naming convention for 2X image filenames, e.g. “filename@2x.ext” (to borrow Retina.js’s convention)

I personally prefer the second. (That’s what we do on buildwithcraft.com, except we use “.2x” instead of “@2x”.)

We can tackle #2 with some logic in the template that only uses a transform when the resulting size is going to be smaller than the original image.

It’s the combination of these two problems where things get interesting: You need to figure out the image’s CSS pixel size (based on whether it’s 1X or 2X) before you start determining whether it needs a transform, and how big to make the transform, etc.

Here’s what we came up with for Craft’s documentation (such as the image on the asset transforms page):

Create a macro called srcset() which will be responsible for outputting a <source> or <img> tag’s srcset= attribute and value, and optionally the width= and height= attributes as well. It should accept the following arguments:

image - an AssetFileModel
maxCssWidth - the maximum “CSS pixel” width that we want to output the image at
includeDimensions - whether the macro should also output the width= and height= attributes.

Create a <picture> element with nested <source> and <img> elements per the Picture spec, using our new srcset() macro to write out the srcset= attributes.

Here’s what the macro looks like:

{% macro srcset(image, maxCssWidth, includeDimensions) %}
    {%- spaceless %}
        {# Is this a 2X image? #}
        {% set is2x = image.filename matches '/@2x\\.\\w+$/' %}

        {# Determine the CSS width for the image, if it were output at 100% #}
        {% set cssWidth = (is2x ? round(image.width / 2) : image.width) %}

        {# Determine the image size that 1X screens should get #}
        {% set width = (cssWidth > maxCssWidth ? maxCssWidth : cssWidth) %}

        {# Determine the image size that 2X screens should get #}
        {% set width2x = (width * 2) > image.width ? image.width : (width * 2) %}

        {# Output the srcset= attribute value #}
        srcset="{{ image.getUrl(image.width != width ? { width: width }) }}, {{ image.getUrl(image.width != width2x ? { width: width2x }) }} 2x"

        {#- Output the width= and height= attributes if needed #}
        {%- if includeDimensions %} width="{{ width }}" height="{{ image.getHeight({ width: width }) }}"{% endif %}
    {% endspaceless -%}
{% endmacro %}

Adjust that {% set is2x = ... line based on however you’re identifying 2X images. For example if you’re going the Lightswitch route instead, it could be as simple as:

{% set is2x = image.is2x %}

Note that each of the image.getUrl() calls on the {{ output }} line are making sure that the width is different than the actual image width before passing the { width: X } object into getUrl() - that way we’re not having Craft go through the trouble of generating a transform unless we actually need to.

With that macro in place, now we just need to import it in our template, and start using it.

{% from _self import srcset %}

{# ... #}

{% for image in entry.myAssetsField %}
    <picture>
        <!--[if IE 9]><video style="display: none;"><![endif]-->
        <source media="(min-width: 1000px)" {{ srcset(image, 1000) }}>
        <source media="(min-width: 800px)" {{ srcset(image, 800) }}>
        <source media="(max-width: 320px)" {{ srcset(image, 320) }}>
        <!--[if IE 9]></video><![endif]-->
        <img {{ srcset(image, 600, true) }} alt="{{ image.title }}">
    </picture>
{% endfor %}

If you placed the macro in a different template, replace _self with the path to that template, e.g. "_macros".


Converting array of entries to an array of ids If I've got an array of entries, is there a less long winded approach to convert that to an array of ids so I can use it in another lookup.

{# Look up authors that match the entered query.
{% set authorEntries = craft.users.search('fullName:*' ~ query ~ '*')|default([]) %}

{% set authorIds = [] %}
{% for author in authorEntries %}
    {% set authorIds = authorIds|merge([author.id]) %}
{% endfor %}

Thanks!

Simply append .ids() to your initial query...

{% set authorIds = craft.users.search('fullName:*' ~ query ~ '*').ids() %}

Without the .ids() method, you're actually working with an Element Criteria Model.

The behavior that you're seeing is the default... it's as if you had appended .find() to your initial query.

  [.find()] will be called automatically as soon as the ElementCriteriaModel is treated like an array (that is, as soon as you...  start looping through the elements)

So instead of allowing the default behavior to kick in, just apply .ids() to the initial query, and get a batch of entry IDs instead of a full array of entries


Suppress HttpException.404 for bad URLs Requests for non-existent templates/pages (404s) result in an uncaught HttpException.404 being thrown, though the correct 404 template is displayed. Is there some way to suppress or handle this exception? It's flooding my error reporting tool. For reference, here's the stack trace from the log:

2016/12/07 17:29:07 [error] [exception.Craft\HttpException.404] exception 'Craft\HttpException' in /project/craft/app/controllers/TemplatesController.php:59
Stack trace:
#0 [internal function]: Craft\TemplatesController->actionRender('page-no-existy', Array)
#1 /project/craft/app/framework/web/actions/CAction.php(109): ReflectionMethod->invokeArgs(Object(Craft\TemplatesController), Array)
#2 /project/craft/app/framework/web/actions/CInlineAction.php(47): CAction->runWithParamsInternal(Object(Craft\TemplatesController), Object(ReflectionMethod), Array)
#3 /project/craft/app/framework/web/CController.php(308): CInlineAction->runWithParams(Array)
#4 /project/craft/app/framework/web/CController.php(286): CController->runAction(Object(CInlineAction))
#5 /project/craft/app/framework/web/CController.php(265): CController->runActionWithFilters(Object(CInlineAction), Array)
#6 /project/craft/app/framework/web/CWebApplication.php(282): CController->run('render')
#7 /project/craft/app/framework/web/CWebApplication.php(141): CWebApplication->runController('templates/rende...')
#8 /project/craft/app/etc/web/WebApp.php(290): CWebApplication->processRequest()
#9 /project/craft/app/framework/base/CApplication.php(185): Craft\WebApp->processRequest()
#10 /project/craft/app/index.php(62): CApplication->run()
#11 /project/src/static/index.php(21): require_once('/project...')
#12 {main}
REQUEST_URI=/page-no-existy

The good news in the upcoming Craft 3 this isn't an issue.  404's get logged to their own separate log files and won't clutter up the main Craft log files specifically for this reason.

In Craft 2, I think you'd have to do something like write a plugin that listens for Yii's onException event, makes sure it's a 404 status code, then go through Yii's CLogger to get the full list of log entries and remove the last one.


Javascript loads before iframes I have a couple of youtube iframes loaded into a channel entry. I also have a script running that resizes those iframes. It appears the script fires on window load but it appears that it fires before the iframes load in from craft. Is there any quick fix to this issue and if so how do I fix it?

This seems more like a jquery issue then a craft issue. You might look into jquery's load method. Doing a quick google search I came up with this possible solution, which you would need to adapt.

function callIframe(url, callback) {
    $(document.body).append('<iframe id="myId" ...>');
    $('iframe#myId').attr('src', url);

    $('iframe#myId').load(function() {
        callback(this);
    });
}


Route that should be matching numbers not matching a zero? I have the following in my routes.php file:

return array(
    'articles/(?P<sectionId>\d+)/(?P<offset>\d+)' => 'articles/index'
);

And while localhost/articles/4/1, for example, routes properly to the template, localhost/articles/4/0 does not and I instead get a 404.

Is there an issue with zeros being picked up as valid URI segments?

An easy fix could be to define an additional route without the offset parameter:

return array(
    'articles/(?P<sectionId>\d+)' => 'articles/index',
    'articles/(?P<sectionId>\d+)/(?P<offset>\d+)' => 'articles/index',
);

In your template, you'd need to check if the offset parameter is defined, and if not, set it to 0:

{{ offset | default( 0 ) }}

or

{% set offset = offset is defined ? offset : 0 %}

EDIT:

Another way to solve this is by making the offset segment capturing group optional, as per @carlcs' answer to this question – in my opinion this is a bit more elegant than having two different routes:

return array(
    'articles/(?P<sectionId>\d+)(/(?P<offset>\d+))?' => 'articles/index',
);

The trick here is wrapping the last segment in parentheses, appending a question mark at the end.


Accessing global sets from Element API Is there an easy way to access global sets from an Element API endpoint, so its content can be included in the JSON response?

Since Global Sets are elements just like entries, users, etc., you can create API endpoints that are all about them:

'globals/<handle:\w+>' => function($handle) {
    return [
        'elementType' => 'GlobalSet',
        'criteria' => ['handle' => $handle],
        'first' => true,
        'transformer' => function(\Craft\GlobalSetModel $globalSet) {
            return [
                'foo' => $globalSet->foo,
                'bar' => $globalSet->bar,
            ];
        }
    ];
}

You can also manually query for Global Sets, to include their data in an endpoint that’s tied to another element type:

'my/other/endpoint' => [
    'elementType' => 'Entry',
    // ...
    'transformer' => function(\Craft\EntryModel $globalSet) {
        // ...

        // Fetch a global set
        $criteria = craft()->elements->getCriteria(ElementType::GlobalSet);
        $criteria->handle = 'myHandle';
        $myGlobalSet = $criteria->first();

        // Include the global set content in the response data
        return [
            // ...
            'foo' => $myGlobalSet->foo,
            'bar' => $myGlobalSet->bar,
        ]
    }
]

Craft also provides a couple methods for fetching Global Sets by ID or handle, so if that happens to be exactly what you need, feel free to use those:

craft()->globals->getSetById()
craft()->globals->getSetByHandle()


How do I import existing products into Craft Commerce with the FeedMe or Import plugins? I get it that there are hooks, but i can't get enough inside the differences between entries and product, and actually hack together an extension for either of those plugins.

Feed Me only supports Entries at this stage. Its on the short-term roadmap in allow importing into all Elements, including Commerce Products. This cannot be achieved through hooks at the moment. Keep an eye on the plugin page.

Update: FeedMe 2.0 now supports multiple entry types, including Commerce Products: http://sgroup.com.au/plugins/feedme/getting-started/introduction


Dynamically load either standard res or hi-res background image I am currently dynamically loading a background image using the style tag:

<li style="background-image: url({{ project.portfolioImage.first().url }})">

I want to add support for retina screens, so I want to also upload a hi-res version as well as the standard one and serve whichever is applicable.

Can I use {% includeHiResCss %} to do that?

This is actually a difficult problem, and there are many possible solutions, none of which are optimal (until img srcsets are better supported).

The way I would probably go about doing this, depends on a couple of factors.

If it is important to show something on load, you need to include an initial image in the markup, like you have already. If that is not an issue, I would include the two different resolutions in data-attributes on the
, and then add the appropriate one with Javascript.

It would probably go a little like this:

markup:

....

js: (not tested, probably needs tweaking to work)

$(function() {
    var windowWidth = window.innerWidth || $(window).width();
    var threshold = 600;
    $('.js-resp-bg-img').each(function(idx, elem) {
        var bgImageUrl = $(elem).attr('data-low-res');
        if (windowWidth > threshold) {
            bgImageUrl = $(elem).attr('data-high-res');
        }
        $(elem).css({
            backgroundImage: 'url(' + bgImageUrl + ')'
        });
    });
});

If you need something to display on load, you put the low res image in the style tag, and switch it out only when appropriate. Downside with this is you'll load the asset twice.

Also, in my example I'm only testing for window width, if you need to you can do additional tests, for example testing for retina with this method.


Multiple image transforms of same image in template I'm getting odd results when trying to apply multiple image transforms to the same image. Here's my code:

{% for photo in photos %}
    {% set thumb = photo.image.first().setTransform({ mode: 'crop', width: 300, height: 300 }) %}
    {% set large = photo.image.first().setTransform({ width: 600 }) %}

{% endfor %}

The above code renders an image that is 600px wide for BOTH "thumb" and "large" even though the criteria for each is different and I'm setting unique variables.

Is it possible to have multiple transforms on the same image? Is there another approach I should try?

EDIT

Same results with these two code variations:

{% set photos = craft.entries.section('photo').find() %}
{% set thumbTransform = { mode: 'crop', width: 300, height: 300 } %}
{% set largeTransform = { width: 600 } %}
{% for photo in photos %}
    {% set p = photo.image.first() %}
    {% set thumb = p.setTransform(thumbTransform) %}
    {% set large = p.setTransform(largeTransform) %}

{% endfor %}

AND

{% set photos = craft.entries.section('photo').find() %}
{% for photo in photos %}
    {% set thumbImage = photo.image.first() %}
    {% set largeImage = photo.image.first() %}
    {% set thumb = thumbImage.setTransform({ mode: 'crop', position: 'center-center', width: 300, height: 300 }) %}
    {% set large = largeImage.setTransform({ width: 600 }) %}

{% endfor %}

You might consider setting a variable for the image, then one for each transform type.

{% set thumb = { mode: 'crop', width: 300, height: 300 } %}
{% set large = { width: 600 } %}

{% for photo in photos %}
    {% set p = photo.image.first() %}

{% endfor %}


Accessing relation data in an on save entry event I have a front end form that saves an entry with a relation field based on an ID.

<input type="hidden" name="items[{{ index }}][finish]" value="{{ finish.id }}">

When the entry is saved this ID saves the field with the correct category relation.

I then have a plugin which triggers on entry save that sends an email and attaches the $entry.

craft()->on( 'entries.saveEntry', function( Event $event ){
    $entry = $event->params['entry'];
    if( !$event->params['isNewEntry'] || $entry->section->handle != 'sampleOrders' )
    {
        return;
    }
    //die(Craft::dump($entry->samplesOrder[0]->finish->find()));
    $email = new EmailModel();
    $email->toEmail = 'luke@ten4design.co.uk';
    $email->subject = 'Order Received';
    $email->body = '';
    $email->htmlBody = craft()->templates->render( 'pentagonemailservice/_emails/order', array(
        'entry' => $entry
    ) );
    try{
        craft()->email->sendEmail( $email );
    }
    catch( Exception $e ){
        Craft::log( 'Could not send email.', LogLevel::Error );
    }
} );

For some reason in my email template I cannot access the finish field with the following code. The other fields print correctly. The finish field is a category relation.

{% for item in entry.samplesOrder %}
    {% set appr = craft.entries.section( 'appearances' ).apprId( item.appearance ).first() %}

{{ appr.apprId }} - {{ appr.displayName }} - {{ appr.pentagonRange[0].title }}

Material

{{ appr.material }}

Finish

    {#
{{ finish.title }}
#}

Quantity

{{ item.quantity }}

{% endfor %}

How do I access the finish field in my email template?

Related elements, such as categories, are stored by Craft as arrays, even if there is only a single element to be stored.

In your entry form, you don't appear to be storing an array, but only the id of the selected category:

<input type="hidden" name="items[{{ index }}][finish]" value="{{ finish.id }}">

This seems to be borne out by what you see when you dump the item variable in your email template. item[finish] should be an array, even if only a single category is assigned to it.

Try using the following in your entry form to see if that helps, which should store the category id as an array:

<input type="hidden" name="items[{{ index }}][finish][]" value="{{ finish.id }}">

You should then be able to access the correct value for the category title using the code in @carlcs answer.


Is it possible to show commerce product id's in the control panel? For entries you can show the ID in control panel listings.

I can't find a way to show craft commerce product ID's in a similar way in the control panel.
Commerce 3

No, it does not seem to be possible to select the ID as column to be shown in product overviews when clicking on the cogwheel on the left side.
You could use this extension https://plugins.craftcms.com/preparse-field to create a custom field into which you can "preparse" the product's ID. This field will then be available for selection.


Correct way of showing errors when editing profile via front-end form? I've been looking at the following resources:

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

Allow user to change or delete their photo for their profile from the front end

Front end edit: entry doesn’t get saved

Front end registration form, no errors

To try and put together a profile editing page that returns errors once submitted, but can't seem to get it.

user is equal to either the currentUser or craft.users.id(craft.request.getSegment(3)).first()

<form method="post" accept-charset="UTF-8" enctype="multipart/form-data">

{{ getCsrfInput() }}
<input type="hidden" name="action" value="users/saveUser">
<input type="hidden" name="redirect" value="partners/view/{{ user.id }}">
<input type="hidden" name="userId" value="{{ user.id }}">

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

            {% for error in errors %}

{{ error }}

            {% endfor %}

    {% endif %}
{% endmacro %}

{% from _self import errorList %}

{{ dump(user.getErrors) }}

        First Name:
        <input id="firstName" name="firstName" autocomplete="off" type="text" data-parsley-required="true" value="{{ user.firstName }}">
        {{ errorList(user.getErrors('firstName')) }}

        Last Name:
        <input id="lastName" name="lastName" autocomplete="off" type="text" data-parsley-required="true" value="{{ user.lastName }}">
        {{ errorList(user.getErrors('lastName')) }}

        Email:
        <input id="email" name="email" autocomplete="off" type="email" data-parsley-required="true" data-parsley-type="email" value="{{ user.email }}">
        {{ errorList(user.getErrors('email')) }}

        User Photo:
        {% if user.photoUrl %}

            <input type="hidden" name="deleteUserPhoto" id="deleteUserPhotoInput" value="">
        {% else %}

        {% endif %}
            <input id="profilePhoto" type="file" accept="image/*" capture="camera" name="userPhoto" value="{{ (user.photoUrl ? 'Change Photo' : 'Upload') }}">
        {% if user.photoUrl %}
            Delete
        {% endif %}

        User Description
        <textarea id="userDescription" name="fields[userDescription]" autocomplete="off" data-parsley-required="true" value="{{ user.userDescription }}"></textarea>

<button type="submit" class="btn btn-solid">Save</button>

</form>

Could anyone point out where I'm going wrong, or provide a working example?

Many thanks!

Not sure what validation error you're expecting from the template code.

Both firstName and lastName are non-required fields that will basically accept any input.

photoUrl could return a validation error if, for example, you tried to upload a .txt file to but you're not calling the errorList() macro on that field.

Not sure if userDescription is required or not, but the errorList() macro isn't being called there, either.

Finally, the variable that Craft returns back to the template when there are validation errors is called account.

So you'd want to do something similar to what the User Registration Form example doc does:

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


Show shipping rate on Cart screen in Craft Commerce How can I show the shipping rate on the cart screen? At the moment this defaults to 0.00 - I assume as we don;t know the customers location so no shipping method can be applied. Ideally I want to show the standard shipping rate based on UK and then allow the user to click and change location to apply a different shipping rate. Ideally I want to do this in the Cart screen so users can see the full total before logging in or checkout out as a guest. I want to eliminate the shipping selection page. Any ideas on how to go about this?

I've not tried this so early in the checkout process, but how about adding the following to your Add To Cart forms? Replace the # with the correct value obviously.

<input type="hidden" name="shippingAddress[countryId]" value="#">
<input type="hidden" name="shippingMethod" value="#">

That way, as soon as people arrive on the Cart page a country has been added already as a shipping address, which, I think, should be enough for shipping to be calculated.


How can I get all child categories - of a child category based on url segment? I am missing something very obvious I think. I am trying to get all child categories based on url segment.

For example: "mysite.com/foo"

I have a category Group called Sections Within Sections I have a category called Foo.

Categories:

Sections  <-- Category Group
    |- Foo
        |- One
        |- Two
        |- Three

Using this url as an example: www.mysite.com/foo

twig

{% set categoryGroup = craft.categories.group('Sections').level(1).slug(craft.request.getSegment(1)).first() %}
{% set categories = craft.categories.ancestorOf(categoryGroup) %}

Doing this:
Group: {{ categoryGroup }}

Renders this: Group: Foo

Great!

{% if categories|length %}
    {% for cat in categories %}
        {{ cat.title }}
    {% endfor %}
{% else %}
    NOTHING
{% endif %}

I am always getting back my NOTHING statement. When I navigate to mysite.com/foo, I would like to show One Two Three

There are a couple of things I would do differently here. The first is to check the Categories in this group have their own URLs box in the Category Group settings. Set the url to {slug}, and you will have category defined in the template without needing:

  {% set categoryGroup = craft.categories.group('Sections')
  .level(1)
  .slug(craft.request.getSegment(1))
  .first() %}

The second problem is that once you have your category, what you want are the children, not the ancestors:

{% set theChildren = category.children %}

{% if theChildren|length %}
  {% for cat in theChildren %}
    {{ cat.title }}
  {% endfor %}
{% else %}
  NOTHING
{% endif %}


Is it possible to loop through locales? Is it possible to loop through locales? For example:

{% locale in craft.locales %}
    {# get link for each locale available #}
    {{ locale.title }}
{% endfor %}

You can try to use the following code to loop through the locales:

{% set locales = craft.i18n.getSiteLocaleIds()%}

{% for locale in locales %}
    {% set localeEntry = craft.entries.id(entry.id).locale(locale).first %}
    {{ localeEntry.title }}
{% endfor %}

A full solution for a language switcher is described under How can I build a language switcher?


How to limit sources for Entries field set up via migration I'm seeting up all of my project's fields using migrations.
This works really well, but I haven't been able to figure out how to limit the sources (sections) for an entry selection field.

I've based my work on this migrations example, which contains the following code:

new \craft\fields\Entries([
    "name" => "Questions",
    "handle" => "questions",
    "instructions" => "Choose one or more questions",
    "sources" => ["section:" . $questionsSection->id],
    "limit" => 10,
    "required" => false,
    "selectionLabel" => "Select Questions",
]),

However, I don't get how I can add multiple sections as allowed sources… can anybody clarify how to do this?

After getting some feedback from Craft support it turns out one has to use uid instead of id for this to work:

"sources" => ["section:" . $questionsSection->uid],

Since I had a lot of places in my migration where I needed to specify sources, I included a couple small functions:

/* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

protected function _section_id($sectionHandle)
{
    return Craft::$app->sections->getSectionByHandle($sectionHandle)->uid;

} // _section_id()

/* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

protected function _source($handle, $kind = 'section')
{
    $source = $kind . ':' . $this->_section_id($handle);
    return $source;

} // _source()

/* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */

You can then limit the entries field sources like so:

"source" => null,
"sources" => [
    $this->_source("sectionA"),
    $this->_source("sectionB"),
],

(Note that I'm additionally setting "source" => null as per a plugin-created migration I analyzed, but not sure if it's required.)


Multi-Environment Config Database Credentials Being driven to distraction trying to setup multiple environments with Craft. I have Craft running (and working) locally without issue. I have created a staging server with Digital Ocean and setup the appropriate database. I'm using DeployBot to push changes from Github.

However upon trying to access the remote server, I get the following errors:

  Service Unavailable

  Our site is temporarily unavailable. Please try again later.

and

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

I'm sure there is an obvious solution to why this isn't working, but I'm yet to find it.

Here are my db.php and general.php files with sensitive data redacted:

db.php

return array(
  '*' => array(
    'database' => '******',
    'tablePrefix' => 'craft',
  ),

  'localhost' => array(
    'server' => 'localhost',
    'user' => 'root',
    'password' => 'root',
  ),

  // Use IP of your droplet and MySQL credentials of a user you created
  '000.000.000.000' => array(
    'server' => '000.000.000.000',
    'user' => 'root',
    'password' => '***********',
  )
);

config.php

<?php

return array(
    '*' => array(
        'omitScriptNameInUrls' => true,
        'devMode' => true,
        'loginPath' => 'users/login',
        'postLoginRedirect' => 'commerce/customer',
        'setPasswordPath' => 'users/setpassword',
        'enableCsrfProtection' => true,
    ),

    '000.000.000.000' => array(
      'siteUrl' => 'http://000.000.000.000/',
      'environmentVariables' => array(
        'basePath' => '/var/www/html/',
        'baseUrl' => 'http://000.000.000.000/',
      )
    ),

);

Also index.php file for good measure

<?php

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

// Do not edit below this line
$path = rtrim($craftPath, '/').'/app/index.php';

if (!is_file($path))
{
    if (function_exists('http_response_code'))
    {
        http_response_code(503);
    }

    exit('Could not find your craft/ folder. Please ensure that $craftPath is set correctly in '.__FILE__);
}

require_once $path;

Help needed and much appreciated!

Here is what my configuration looks like. Ideally, I'd like to swap out the hard-coded baseUrl with something like I have for basePath. That way the other members on my team can call/put the site wherever they want and it won't break anything.

I don't make any changes to index.php.

Hope this helps!

db.php

return array(
'*' => array(
    'tablePrefix' => ''
),
'.dev' => array(
    'server' => 'localhost',
    'user' => 'username',
    'password' => 'password',
    'database' => 'dbname'
),
'mysite.stagingdomain.com' => array(
    'server' => '12.345.67.890',
    'user' => 'username',
    'password' => 'password',
    'database' => 'dbname'
),
'mysite.com' => array(
    'server' => '12.345.67.890',
    'user' => 'username',
    'password' => 'password',
    'database' => 'dbname'
)

);

general.php

return array(
    '*' => array(
    'cpTrigger' => 'admin',  // whatever you want
    'omitScriptNameInUrls' => true,
    'enableCsrfProtection' => true
),
'.dev' => array(
    'devMode' => true,
    'siteUrl' => 'http://mysite.dev/',
    'environmentVariables' => array(
        'basePath' => $_SERVER['DOCUMENT_ROOT'] . '/',
        'baseUrl' => 'http://mysite.dev/',
    )
),
'mysite.stagingdomain.com' => array(
    'devMode' => true,
    'siteUrl' => 'http://mysite.stagingdomain.com/',
    'environmentVariables' => array(
        'basePath' => $_SERVER['DOCUMENT_ROOT'] . '/',
        'baseUrl' => 'http://mysite.stagingdomain.com/'
    )
),
'mysite.com' => array(
    'siteUrl' => 'http://www.mysite.com/',
    'environmentVariables' => array(
        'basePath' => $_SERVER['DOCUMENT_ROOT'] . '/',
        'baseUrl' => 'http://www.mysite.com/'
        )
    )
);


"Fatal Error 'OAuth\Common\Storage\Session' not found" when trying to connect to connect to Google or Vimeo I purchased the Dukt Videos plugin and when trying to connect with one of the services (Google or Vimeo) I'm met with the following fatal error:

( ! ) Fatal error: Class 'OAuth\Common\Storage\Session' not found in /home/forge/website.com/craft/plugins/oauth/providers/BaseOAuthProviderSource.php on line 51
Call Stack
#   Time    Memory  Function    Location
1   0.0001  242088  {main}( )   ../index.php:0
2   0.0002  243000  require_once( '/home/forge/website.com/craft/app/index.php' )   ../index.php:36
3   0.0392  3729440 CApplication->run( )    ../index.php:62
4   0.0392  3731160 Craft\WebApp->processRequest( ) ../CApplication.php:180
5   0.0617  4905776 Craft\WebApp->_processActionRequest( )  ../WebApp.php:263
6   0.0617  4906040 CWebApplication->runController( )   ../WebApp.php:756
7   0.0623  5054240 CController->run( ) ../CWebApplication.php:282
8   0.0625  5080680 CController->runActionWithFilters( )    ../CController.php:265
9   0.0625  5080792 CController->runAction( )   ../CController.php:286
10  0.0626  5081528 CInlineAction->runWithParams( ) ../CController.php:308
11  0.0626  5083200 Craft\OauthController->actionConnect( ) ../CInlineAction.php:49
12  0.0765  5789632 OAuthProviderSources\BaseOAuthProviderSource->initializeService( )  ../OauthController.php:120
13  0.0765  5789672 OAuthProviderSources\BaseOAuthProviderSource->getStorage( ) ../BaseOAuthProviderSource.php:124

This aspect of the plugin works on my dev env but when testing this on another separate install on my webserver this error keeps coming up.

Anyone have an idea how this can be fixed? Assuming it's not a plugin bug.

I have contacted the plugin developer about the issue but I'm concerned that I won't get a reply as I've asked him about another issue I encountered with the plugin about 2 weeks ago (with a follow up last week) and I did not get any reply. I've also seen that another member of this community had an issue with a plugin from the same developer and received no reply from the developer either. If this was a free plug in I wouldn't be expecting support but when you consider that the plugin costs €49, it's quite disappointing that there isn't a reply.

Thanks in advance!

Hey Daniel and sorry for the lack of response. Please get in touch at ben@dukt.net and I'll be happy to offer you the license hoping you'll accept my apologies for the huge delay in my reply.

Regarding your issue, it looks like some classes haven't been loaded (OAuth\Common\Storage\Session). Can you please check if Session.php file is present in OAuth plugin's folder under oauth/vendor/lusitanian/oauth/src/OAuth/Common/Storage.

Also, you might consider get a fresh copy of the latest release of the OAuth plugin and try to unzip/re-upload the files, I'm thinking you may just have some missing files and that could fix the problem, otherwise we'll dig further.


Removing whitespace from {{ tag.name }} I'm using tags to do some Javascripting.

Is there any way that I can tell Craft to remove whitespace from {{ tag.name }} if the tag.name has spaces (for example 'apples and carrots'), and add dashes ('apples-and-carrots') ?

There are multiple ways to solve this:

Native:

Twigs url_encode filter:

{{ "apples and carrots"|url_encode }}
{# outputs "apples%20and%20carrots" #}

Twigs replace filter:

{{ "apples and carrots"|replace(' ', '-') }}
{# outputs "apples-and-carrots" #}

Plugins:

Twig PCRE Filters - Plugin:

{{ "apples and carrots"|preg_replace('/ /', '-') }}
{# outputs "apples-and-carrots" #}

Low Regex - Plugin:

{{ "apples and carrots"|regex('/ /', '-') }}
{# outputs "apples-and-carrots" #}

Slugify - Plugin:

{{ "apples and carrots"|slugify }}
{# outputs "apples-and-carrots" #}


Draft from front-end form with limited field set I have a front-end form which sends a limited selection of the fields to the action entryRevisions/saveDraft (actually a custom plugin action, but in the it end up there). I expected it to take the already published entry's data and creates a new draft based on the data of the published one overriden with the posted data. But it seems this is not the case. Now I have drafts with only the few fields from the front-end form.

Of course I can get the entry data of the published entry before saving the draft and overwrite it with the post data, but maybe you guys know a simpler/better solution?

Too bad no one could help me, but found a solution in the meantime. Inspired by others on Github and Stackoverflow (https://craftcms.stackexchange.com/a/14158/3937). Maybe my solution helps someone else with the same problem.

I created a method in my controller which gathers all values from the fields and prepares an array of it, which has exactly the same format as the CP in the browser sends when saving a new draft. I use this array to feed the method setContentFromPost on the EntryDraftModel, together with the incoming POST data from craft()->request->getParam('fields').

public function getFieldValuesFromEntry(BaseElementModel $entry, $fields = null)
{
    foreach ($entry->fieldLayout->fields as $fieldLayoutField) {
        $fieldHandle = $fieldLayoutField->field->handle;
        if ($fields === null || in_array($fieldHandle, $fields)) {

            $fieldValue = $entry->getFieldValue($fieldHandle);

            if ($fieldValue instanceof RichTextData)
            {
                $value = $fieldValue->getRawContent();
            }
            elseif ($fieldValue instanceof ElementCriteriaModel)
            {
                $value = $fieldValue->ids();
            }
            elseif ($fieldValue instanceof SingleOptionFieldData)
            {
                $value = $fieldValue->value;
            }
            else
            {
                $value = $fieldValue;
            }

            $field[$fieldHandle] = $value;
        }
    }

    return $field;
}

And this is the snippet where I feed it into the draft ($entryFields is here the output of the method above):

$draftFields = craft()->request->getParam('fields');
$draft->setContentFromPost(array_merge($entryFields, $draftFields));

If anybody has a more efficient solution to fix my problem, please let me now. Cheers!


Search Matrix and Smartmap I'm trying to search through a set of results inside a Matrix field. Craft is giving me this error message: Craft\EntryModel and its behaviors do not have a method or closure named "avdelinger".

When I searched the information without the Matrix field it worked but now it's not. I'm using the smart map plugin to find the nearest office added in my Matrix field. Here's my code:

{% block content %}

<form action="">
    <input type="search" name="sted" placeholder="Search">
    <input type="submit" value="Go">
</form>

{% for block in entry.avdelinger %}

{{ block.navn }}

        {{ block.sted.street1 }}

        {{ block.sted.city }}, {{ block.sted.zip }}

        Latitude: {{ block.sted.lat }}

        Longitude: {{ block.sted.lng }}

{% endfor %}

{% set target = craft.request.getParam('sted') %}
{% set params = {
    target: target,
    range: 1000,
    units: "kilometers"
} %}

{% set blocks = entry.avdelinger(params).order('distance').find() %}

Showing results for "{{ target }}"

{% for block in blocks %}

        {{ block.sted.street1 }}

        {{ block.sted.city }}, {{ block.sted.zip }}

        {{ block.sted.distance | number_format(2) }} kilometers away

{% else %}

No results found

{% endfor %}

{% endblock %}

Thanks!

The syntax to set a custom field parameter on a Matrix Block element criteria model is like so:

{% set blocks = entry.myMatrixField.mySmartMapField(params) %}


Creating a switch based on entry handle I'm trying to create a switch statement for a single entry event template that has various entry fields associated with it (description, contact, location, etc.) from an Events Channel I have. Rather than using a bunch of IF's to display only those fields that have been populated, I'm trying to use a switch statement instead, but I can't get this to work when I based the switch on the 'entry.type." I'm trying to something like this, but it's not working. Any help would be appreciated!

{% switch entry.type %}
{% case 'contact' %}
    {{ entry.contact }}
{% case 'location' %}
    {{ entry.location }}
{% endswitch %}

It's a little unclear what you need to achieve here –

If your entries' entry type handles actually are 'contact' and 'location', the above code should work; which means that you've got an error somewhere that isn't really possible to figure out based on your description – e.g. the entry type handle is actually contacts, and not contact, or something like that.

One thing you might try, is to simply print the entry.type variable in a template, to see if it contains what you expect it to contain:

{{ entry.type }}

On the other hand, if your issue is simply that some entries have a contact field populated and others have a location field populated, you can't really use a {% switch %} statement in any sensible manner for that – though a plain old {% if %} would do it:

{% if entry.contact %}
    {{ entry.contact }}
{% elseif entry.location %}
    {{ entry.location }}
{% endif %}