Huge Latency In Pre-prod Environment Hello Craft community,

My team and I have built a site for a client and it looks great.  The site runs just fine in my developers local environment and we're all very happy.  I have the site now set up on my preproduction Red Hat environment and when I access it there is about 30 seconds of latency, every single time.  I cannot figure out where this latency happens, perhaps there is a configuration somewhere I am missing?

I can access images, js files, etc. without any issue - but once I hit a php file in the Craft environment, things are super slow.

I tried turning the devMode flag to false in the general configurations and that didn't seem to help.

This has nothing to do with my browser - I've tried a straight CURL to the URL and I see the same amount of lag.  Perhaps there's some server-side caching I need to enable?  Like I said - this is not just with my site, it was slow during the install as well as when I just access the admin tool to look at/change configurations.  Please help!

I've just ran into this myself this morning. It looks to be related to the SmartMaps plugin doing an IP > Geo lookup using an external service.

Specifically it looks like it's using this api :https://geoip.maxmind.com/geoip/v2.0/ which is hanging.

Disabling the plugin fixed my loading issues.


Specifics on ImageMagick and animated GIFs I've looked through several StackExchange threads without specifics on how ImageMagick is tied into Craft. Web host says the binary is installed on server but not the module. Is the PHP module required?

  we looked into this further, and found that we do not have the ImageMagick PHP module installed, but we do have the binary. I'm not sure if Craft needs the PHP module, but if it does, that would be the reason for this not working.

For Craft to use it, yes the ImageMagick PHP extension is required because Craft uses PHP's bindings in the library they're using.

Depending on the host's OS, it should be a package manager update away. Any decent host should be able get it working incident free.


How can I rename an asset file on upload when an entry is saved (Craft 3)? I have an entry type that includes an Assets field. When this entry is created/saved via the CP or a front-end form, I want to rename the Asset file as follows:

Entry's author id. E.g: 148
01, 02, 03 based on how many entries the author has already submitted.

So files would look like: 148-01.jpg 148-02.jpg, 148-03.jpg.

At some point, I would also like to add the value of a custom field.

Also, I would like to limit this to entry for a certain type in a certain section: Section name: "Competitions", Entry type: "Submission".

Screenshot: https://cl.ly/a526f40c6d58

So far In my Craft 3 Module I have this. I can get the Asset id, but I can't get the Entry's Author Id:

Event::on(
    Elements::class,
    Elements::EVENT_AFTER_SAVE_ELEMENT,
    function (ElementEvent $event) {
        $asset = $event->element;
        $id = $event->element->getId();
        if ($event->isNew && $asset instanceof craft\elements\Asset) {
            $newFileName = "new-file-name-" . $id . ".jpg";
            Craft::$app->assets->moveAsset($asset, $asset->getFolder(), $newFileName);
        }
    }
);

I found this answer https://craftcms.stackexchange.com/a/13199/298, but it's for Craft 2:

craft()->on('entries.beforeSaveEntry', function(Event $event)
{
    $entry = $event->params['entry'];

    if (($entry->section['handle'] == 'friends') && ($entry->type['handle'] == 'friends'))
    {
        $title = $entry->slug;
        $assets = $entry->imgdir;

        if (count($assets) != 1)
        {
            $event->params['entry']->addError('imgdir', Craft::t('Exactly 1 asset has to be selected.'));
            $event->performAction = false;
        }
        else
        {
            $filename = $title.'.'.$assets[0]->getExtension();

            craft()->assets->renameFile($assets[0], $filename);
            craft()->assets->storeFile($assets[0]);
        }
    }
});

How can I do this in Craft 3?

The code below is working for me so far. The answer at https://craftcms.stackexchange.com/a/28168/298 helped me figure things out for Craft 3.

Event::on(
    Entry::class,
    Entry::EVENT_AFTER_SAVE,
    function(ModelEvent $event) {
        /** @var Entry $entry */
        $entry = $event->sender;
        //Set entry's author ID
        $authorId = $entry->authorId;
        //Set value of custom field
        $imageOrder = $entry->myCustomField;

        if ($entry->enabled && $entry->section->handle === 'mySectionHandle' && $entry->type->handle === 'myEntryTypeHandle') {
            /** @var Asset $asset */
            foreach ($entry->myAssetField as $asset) {
                $newFileName = "0" . $imageOrder . "-" . $authorId . "-" . date('YmdHis') . "." . $asset->getExtension();
                Craft::$app->assets->moveAsset($asset, $asset->getFolder(), $newFileName);
            }
        }
    }
);

Can it be improved? For e.g., can I do without the foreach loop? Let me know and I'll update this answer and then mark it as accepted.


What's the simplest way of automatically activating/verifying user accounts? I'd like to have my users automatically verified/activated so they can immediately login after registration. Normally this would be done through the automatic emailer, but I'd like to skip that.

Are there any easy changes to do this, or will I have to write a plugin?

If you have Craft Pro edition installed, in the control panel you can go to Settings->Users->Settings and uncheck "Verify email addresses?" and check "Allow public registration?".

Use a front-end registration for similar to this and it should do what you're looking for.


Checking submission from the Contact Form plugin I've potentially have had some messages not come through to email. I've seen the user has reached my thank you page but I don't always receive a message. Are these stored anywhere in the Database to check?

Based on that code I see on github (I'm assuming you're referring to this plugin) I'm afraid they're not saved to the database.

However craft logs each mail succesfully sent with its internal mailer so you could check your log files to see if any are missing.

The log messages look like

  Successfully sent email with subject: xyz

That should give you an indication of how many are missing, as for the actual content, there I'm afraid you're out of luck as far as I know.


Manual update without database backup I’m trying to update Craft Pro 2.0.2543 to the latest build but the site’s database is in excess of 2Gb. When hitting ‘Finish up’ in the CP after a manual update, by the time the database has backed up I’m logged out, or the process has timed out. Is there a way I can ‘Finish up’ without the backup running first?

It is indeed possible. Craft has a handy general configuration option for this exact situation.

return array(

    'backupDbOnUpdate' => false

);

Just add that to config/general.php and that should do the trick!


Change the name of 'CraftSessionId' from HTTP header requests? I am running a Nginx server and tried to hide the 'Set-Cookie' parameter from the HTTP header output when using curl -I hostname.com - I applied the Nginx configuration using:

proxy_hide_header Set-Cookie;

Using this worked as intended - until I noticed that any request to login to the control panel simply resulted in reloading the admin login page.

Is there a way to change or hide this that still allows users to login to the control panel?

I'm not sure I'm understanding 100% what you're trying to do, but by preventing the Set-Cookie header, aren't you essentially blocking any cookies from being set in your browser?

All of Craft's authentication is cookie based, so it's not surprising that trying to login to the control panel doesn't work.


Where exactly are my element type custom statuses stored and used? I have custom statuses working on the control panel for my plugin. However, there are a few issues I have with custom statues.

Looking through the database, I am unable to figure out exactly where the custom status is stored. I have my table 'craft_pluginName' with my records. My field layouts exist and so does everything else needed for my element type.

However, I still can't find the custom status. Browsing through the 'craft_content' table I see the content, related to my element type. Yet I still don't see anything related to a status.

Is the assumption that my table 'craft_pluginName' is supposed to contain a column named 'pluginNameStatus' and I then have to hook that into the element type (for a lack of better term)?

Edit:
More research uncovered that 'craft_elements' has id, type, enabled and the typical time stamps. The column 'enabled' is a boolean so it can be only 0 or 1. Updating that value manually in the database updates the 'status' on my element type index view..

I feel that this 'status', which is shown when your element type has 'hasStatus' set to true. I do not feel that this really allows us to use custom statuses as you are more than likely going to have more than two options for a custom status. In my case: 'pending', 'approved' and 'denied'.

So I am still at a loss on how we actually use custom statuses in our element types, as the default right now is either on or off...

For starters I'd classify statuses in two groups - static statuses and dynamic statuses:

Static statuses are set explicitly
Dynamic statuses change according to other circumstances (other attribute values, lunar phases, whatever)

For static statuses you'd go with the approach Lindsey outlined and just define a column for that where to store everything, however, things get more interesting when you start tackling dynamic statuses.

For that, you should look at the Entry element type.

/app/elementtypes/EntryElementType.php
/app/models/EntryModel.php

You'll want to look at the EntryElementType::getElementQueryStatusCondition() method - adding this method to your Element type will allow you to use "status" criteria when searching for elements. As a nice side-effect, this will also make the status filter in the Element index work nicely.

Another method worth looking at is the EntryModel::getStatus() method - implementing this method ensures that your Element type actually returns the correct dynamic status when asked for it.


Laravel Forge not honoring Craft 3 maxUploadFileSize config setting I have a Craft 3 site deployed to a Digital Ocean droplet via Laravel Forge. I have the maxUploadFileSize set to 256B (268435456 in bytes) in my config/general.php like so:

<?php

return [
  // Global settings
  '*' => [
    'omitScriptNameInUrls' => true,
    'securityKey' => getenv('SECURITY_KEY'),
    'maxUploadFileSize'=> 268435456,
    'useProjectConfigFile' => true,
    'defaultSearchTermOptions' => array(
      'subLeft' => true,
      'subRight' => true,
    ),
  ],
  'dev' => [
    'devMode' => true,
    'rememberedUserSessionDuration' => 'P1Y',
    'userSessionDuration' => 'P1Y',
  ],
  'production' => [
    'allowAdminChanges' => false,
  ],
];

When I go to upload a file larger than 8mb I get this error:

  The file “.mp3” could not be uploaded, because it exceeds the maximum upload size of 8.0 MB.

My php.ini has upload_max_filesize set to 256M. I can't figure out what exactly is blocking uploads. Nothing in my .env file or my nginx.conf appears to be hindering the upload size.

Any help you can provide would be greatly appreciated!

After doing some digging, this article helped solve my issue: https://stackoverflow.com/questions/36582004/increase-upload-max-filesize-via-forge.

By increasing the post_max_size in the PHP FPM Configuration and the PHP CLI Configuration I was able to resolve the issue and increase my upload limit to 256M.


Updating user profile matrix block with plugin I've written a plugin to update some user profile fields via ajax. It works great for normal text fields like this 'myWooly' field, ex:

<?php
namespace Craft;

class ProfileUpdateController extends BaseController
{
    protected $allowAnonymous = true;

    /**
     * updateWooly
     */
    public function actionUpdateWooly()
    {
        $this->requireAjaxRequest();

        $post = craft()->request->getPost();

        // get current user's profile info
        $currentUser = craft()->userSession->getUser();
        $profile = $currentUser->getContent();

        $currentUser->getContent()->myWooly = $post['myWooly'];

        if (craft()->users->saveUser($currentUser)) {
            $response = 'success';
        }
        else {
            $response = 'error';
        }

        $this->returnJson($response);
    }

I've created a Matrix field with each block having its own Wooly, ex:

Kids (Matrix field)
 - kid (block type)
  + firstName
  + wooly
 - kid
  + firstName
  + wooly
 - etc.

...and now I need for users to update the 'wooly' within each Matrix block.

I've updated my AJAX call to POST a Matrix Block ID and updated my actionUpdateWooly() action to the following:

    public function actionUpdateWooly()
    {
        $this->requireAjaxRequest();

        $post = craft()->request->getPost();

        // get current user's profile info
        $currentUser = craft()->userSession->getUser();
        $profile = $currentUser->getContent();

        // SAVE WOOLY IN KIDS MATRIX FIELD
        if (isset($post['kidId'])) {

            $kidsMatrix = craft()->fields->getFieldByHandle("kids");

            $kidsMatrixBlocks = craft()->matrix->getBlockTypesByFieldId($kidsMatrix->id);
            foreach ($kidsMatrixBlocks as $key => $data) {
                if ($data->handle === "kid") {
                    $kidBlock = $data;
                    break;
                };
            };

            $block = new MatrixBlockModel($post['kidId']);
            $block->fieldId    = $kidsMatrix->id; // Matrix field's ID, 'Kids'
            $block->ownerId    = $currentUser->id; // ID of entry the block should be added to
            $block->typeId     = $kidBlock->id; // ID of block type, 'kid'
            $block->getContent()->setAttributes(array(
                'wooly' => $post['myWooly'],
            ));

            $response = craft()->matrix->saveBlock($block);

        }

        // WOOLY STORED AT TOP-LEVEL OF ACCOUNT
        else {
            $currentUser->getContent()->myWooly = $post['myWooly'];
        }

        if (craft()->users->saveUser($currentUser)) {
            $response = 'success';
        }
        else {
            $response = 'error';
        }

        $this->returnJson($response);
    }

This is successfully CREATING NEW matrix blocks in the correct field, but it's not UPDATING the one I'm expecting.

I would expect this to get the Matrix block by ID but apparently it's not:

$block = new MatrixBlockModel($post['kidId']);

Yes, I've made sure the Matrix Block ID

Can anybody spot what I should be doing differently to get a specific matrix block and updated it within a user profile?

I believe this is the correct way to get an existing Matrix block. Found this gem after digging around in the Google group.

$block = craft()->matrix->getBlockById(blockId);

I updated my plugin code above to this and it seems to work properly.

// THIS DOESN'T WORK
// $block = new MatrixBlockModel($post['kidId']);

// THIS WORKS
$block = craft()->matrix->getBlockById($post['kidId']);

$block->fieldId    = $kidsMatrix->id; // Matrix field's ID, 'Kids'
$block->ownerId    = $currentUser->id; // ID of entry the block should be added to
$block->typeId     = $kidBlock->id; // ID of block type, 'kid'
$block->getContent()->setAttributes(array(
    'wooly' => $post['myWooly'],
));

$response = craft()->matrix->saveBlock($block);


Element API, query entries where relationship field ':empty:' AND the same relationship field with specified entry ID Element API, query entries where relationship field ':empty:' AND the same relationship field with specified entry ID.
Can't seem to figure out how to do this without performing two separate queries and merging the objects together. However I don't see a way to perform this within the Element API.
The answer to this other question seems like an approach? Option 1 or Option 2? Not quite sure as this looks all foreign to me with sparse documentation, and it's not specific to my issue.
How can I query entries based on a Matrix Block Type?
Seeing as you can't use ':empty:' with relatedTo, I'm stuck here.
return [
    'criteria' => [
        'section' => 'mySection',
        /* this is the myRelatedField entries field relating to other Section Entry ID */
        'relatedTo' => (['targetElement' => $otherSectionEntryId]),
        /* unable to use :empty: with the relatedTo, incorporating myRelatedField :empty: below will return zero results */
        /* cannot use this below */
        'myRelatedField' => ':empty:'
    ],
    'transformer' => function(Entry $entry) {
        return [
            'title' => $entry->title
        ];
    }
];

UPDATE with further testing. Various tests used below in trying to use simple relations with :empty:. It looks as though ':empty:' is ignored when utilized in an array.
// results returned where relationship field is empty
'relatedDrinks' => ':empty:'

// no results returned where relationship field is empty
'relatedDrinks' => [':empty:']

// results related to drink ID returned
'relatedDrinks' => [$myDrinkId]

// results returned for drink ID, no results returned with empty
'relatedDrinks' => [':empty:', $myDrinkId]

Craft will include this functionality in their next release.
https://github.com/craftcms/cms/issues/7256#issuecomment-744644568


About customer address When i use lastUsedShippingAddress it populates the last customer order address. However when the order is complete, database create new customer address (same info but with different ids).

Is this how it suppose to work?

When the order is completed, duplicates of the the shipping and billing addresses that were used during checkout are created, and then related only to the Order. This means that editing the address from the order edit screen does not edit the address in the customer address book.

The address IDs that the customer selected (before address duplication) when checking out are the ones saved as the lastBillingAddress and lastShippingAddress on the customer. This enables you to set them as defaults for the next time the user checks out.

The lastBillingAddress and lastShippingAddress have no use for guest checkouts as a new customer will be created for the guest.


Twig search function doesn't work after upgrading to Craft 3 My client's Craft 2 site includes several templates which use search functions to return a product entry by an ID, like so:
{% set product = craft.entries.section('Product')
    .search('externalidentifier::' ~ craft.request.getParam('eid'))
    .one() %}

This has been working without issue.
They just upgraded to Craft 3 however, and now these search functions don't work. As a troubleshooting step, it works for me if I manually loop through all entries and grab the matching item as shown here:
              {% set eid = craft.request.getParam('eid') %}
              {% for prod in craft.entries.section('Product').all() %}
                  {% if prod.extenralidentifier == eid %}
                  {%     set product = prod %}
                  {% endif %}
              {% endfor %}

...but that only illustrates that the matching entries do exist and should be found with the search function. Any ideas why the search function would stop working after an upgrade to Craft 3?

The search parameter relies on the internal search index (whereas your other approach does not).
It's possible that something got tripped up during a migration to Craft 3, perhaps when the new drafts & revisions system was introduced.
Try rebuilding your search index. It might take a long time to run, but should hopefully solve your problem.


Get data of user after login (but not with craft()->userSession->getUser()) Can I directly get the data of the user that I just logged in with craft()->userSession->login($username, $password) ? (not from a method that uses the SESSION like craft()->userSession->getUser() though)

If you have the any identifying information about the user (user ID, email, username, UID), you can use one of the UsersService's methods:

craft()->users->getUserById()

craft()->users->getUserByUsernameOrEmail()

craft()->users->getUserByUid()

craft()->users->getUserByEmail()

They will each return a UserModel object to interact with.


Why does my custom element type error around locale being missing on the element types' model? I have made numerous elementTypes in my plugin that all work perfectly but for some reason one elementType keeps having an error when trying to view the Model's content or custom fields.

This is the error:

Property "Craft\Myplugin_OrderModel.locale" is not defined.

Everything looks exactly the same as all the other models that are elementTypes in my plugin.

All my plugins elementType models are using

public function isLocalized()
{
    return false;
}

but the issue still persists with that one Model.

That's interesting Luke, I had the exact same issue and spent WAY too long on it.

Even though I used a diff tool to see the difference between working elementType models and the one with the error I just did not catch the silly difference:

protected function defineAttributes()
{
    return array(

vs the working:

protected function defineAttributes()
{
    return array_merge(parent::defineAttributes(), array(

you need to add the parent attributes that includes attributes like locale :)

I knew that all along, but just didn't catch it on multiple re-reviewing of the Model.


How to load entries with a certain category only? I am trying to load entries from a section which have a category field with multiple values. Based on that, I want to show specific entries filtered by category.

Example: I have a news section and I want to load sports and entertainment news only.

Help me on this, please.

You could use this, note: this is untested maybe you have to remove the first() or use targetElement: category1.id

{% set category1 = craft.categories.id(yourId).one() %}
{% set category2 = craft.categories.id(yourId2).one() %}
{% set news = craft.entries.all({
    section: 'news',
    relatedTo: [
        'and',
        { targetElement: category1.id },
        { targetElement: category2.id }
    ]
}) %}

You should read about that topic here click


Multi language site not working on sub domain I have an odd situation on a multi-lingual site I am building. I have the site set up on my local dev server and it works fine switching between languages. I have now added the site to an external server to show the client on a subdomain so test-dev.mydomain.com. Everything is exactly the same and the config file has been set up to target this domain. However now switching to another language only brings up the English version of the site when navigating past the home page. Any ideas what is happening here? Could this be because it is sitting on a subdomain?

Config snippet:

'test-dev.mydomain.com' => array(
    'devMode' => 'true',
    'env' => 'dev',
    'environmentVariables' => array(
        'siteStore' => '/assets',
        'sitePath'  => 'http://test-dev.mydomain.com/',
    ),
    'siteUrl' => array(
        'en_gb' => 'http://test-dev.mydomain.com/',
        'de_de' => 'http://test-dev.mydomain.com/de/',
        'pl_pl' => 'http://test-dev.mydomain.com/pl/',
        ),
)

Ok after several weeks of head scratching. I worked out the solution. So hopefully this will help someone else.

Each locale has it's own folder on the root. So to enable you to view the pages on a subdomain you need to edit the .htaccess file within the locale folder and add a RewriteBase /fr or whatever the folder name of the locale you are targeting is.

This will then resolve the problem.

Hope this helps someone else.


Researching Craft CMS but we are a .NET Shop I am involved with researching various CMS solutions and Craft CMS is one of the options for our organization as an Enterprise soluton, so not just for development use cases. When it comes to development we are mostly a Microsoft shop when it comes to the front-end so my question is, and I apologize for my ignorance on this, can I have an ASP.NET web application pull content from Craft? From what I can tell it looks like Twig is the development language, which again as I understand it is a language that generates PHP. We are not a PHP shop by any means so just wondering if there is some sort of plug-in or API that I could make calls to from an ASP.NET web application to pull out content from Craft. Is there anyone doing anything like this?

Again, I apologize for my ignorance but just trying to clear up some of the high level questions being brought up.

Thanks!

Craft can definitely work as a "headless" CMS that you can put whatever want in front of. The go-to solution for such setups is the first-party Element API plugin.

For more info, Mijingo just released a free lesson on Element API and using Craft as a headless CMS.

It's also worth mentioning that Craft 3 (currently in dev preview; public beta ETA early 2017) is expected to add a RESTful API implementation to Craft core (either on release or after).


renderTemplate in a plugin for front end request using front end template I want to be able to render a template in the main 'templates' directory from within a plugin controller.

Basically the controller gets the url request, does some work and then renders a template saved in the 'craft/templates' directory instead of the 'plugin/templates' directory.

I have tried the plugin path trick mentioned on this page https://craftcms.com/docs/plugins/templates without any success.

Any ideas?

Craft will only serve templates from craft/templates/ by default if it’s a front-end site request.

To explicitly tell Craft to serve templates from there, you can use PathService::setTemplatesPath():

$path = craft()->path->getSiteTemplatesPath();
craft()->path->setTemplatesPath($path);

$this->renderTemplate('path/to/template', $variables);


Multi-environment configs and running sites on different ports In my studio, we have successfully used multi-environment config files to allow several machines on our local network to use local MAMP installs as well as designate dev and production environments at our web host.

Locally we run sites on separate ports, so for instance to look at my site I point my browser to http://10.0.1.2:8081/. To look at what’s going on on each other’s machines in the studio, we just change the ip address.

But now we are looking to run both a stable “trunk” version and a “branch” version for developing new features of our site on each local machine. And I can’t see how to make that work in the general.php and db.php files.

The following is what I’ve had in general.php for running a single instance of the site on my server:

'10.0.1.2' => array(
    'userSessionDuration' => false,

    'environmentVariables' => array(
        'siteUrl'        => 'http://10.0.1.2:8081/',
        'fileSystemPath' => ‘/path/to/trunk/files/‘,
    ),
),

I feel that what I’d like to do is something like the following to differentiate between the two sites running on 10.0.1.2:

'10.0.1.2:8081’ => array(
    'userSessionDuration' => false,

    'environmentVariables' => array(
        'siteUrl'        => 'http://10.0.1.2:8081/',
        'fileSystemPath' => ‘/path/to/trunk/files/‘,
    ),
),

'10.0.1.2:8082’ => array(
    'userSessionDuration' => false,

    'environmentVariables' => array(
        'siteUrl'        => 'http://10.0.1.2:8082/',
        'fileSystemPath' => ‘/path/to/branch/files/‘,
    ),
),

Similarly, in the db.php file, currently I’ve got:

'10.0.1.2' => array(
    'server' => 'localhost',
    'user' => 'root',
    'password' => 'root',
    'database' => 'trunk.database’
),

Which I thought I’d change to:

'10.0.1.2:8081’ => array(
    'server' => 'localhost',
    'user' => 'root',
    'password' => 'root',
    'database' => 'trunk.database’
),

'10.0.1.2:8082’ => array(
    'server' => 'localhost',
    'user' => 'root',
    'password' => 'root',
    'database' => ‘branch.database’
),

But alas these kick off this error:

An exception has been thrown during the rendering of a template ("Craft canâ€™t connect to the database with the credentials in craft/config/db.php.") in "_layout" at line 15.

Am I trying to do something impossible, or can anyone point me in the right direction?

Thank you much,
Willhaus

You can define CRAFT_ENVIRONMENT in your index.php like so:

switch ($_SERVER['SERVER_PORT']) {
  case "8081":
    define('CRAFT_ENVIRONMENT', 'TRUNK');
    break;
  case "8082":
    define('CRAFT_ENVIRONMENT', 'BRANCH');
    break;
}

And then in general.php and db.php you can:

return array(
  '*' => array(
    ...
  ),
  'TRUNK' => array(
    ...
  ),
  'BRANCH' => array(
    ...
  )
);


Problem with mailer plugin My problem is that the Mailer plugin (version 0.5) does not work with Craft Pro 2.3.2620. Unfortunately, I get no error message - it still does not send e-mail (the log is empty). Craft in general is able to send e-mails.

Has someone else the same problem?

While this question is a bit old, for the sake of completeness I'll echo what Brad mentioned in the comment above.

Plugin bugs are best handled by notifying the developer directly. This plugin happens to be on Github and it appears that the developer has responded to all open issues and closed them out.

Additionally, the convention for tagging Stack Exchange posts that are related to plugins is to prefix the plugin's name with the word plugin. In this case, a good tag may be plugin-craftmailer or plugin-mailer.


What is the best way to include an Element's content? I'm creating a HTTP RESTful API plugin for Craft. In this case, I'm trying to return Elements (based on criteria), and include their content (via $element->getContent()).

By default, if I return just the Elements collection returned by craft()->elements->getCriteria($type)->find(), the content is not included.

I'm also running each Element through a Transformer which uses ModelHelper::packageAttributeValue($value), and converts attributes to their proper PHP type using attribute configs.

I'm not sure the best way to go about including content in my responses dynamically. Suggestions?

Edit:

I've just found out that $element->getContent() returns fields that aren't even associated with that particular element. Weird. Anybody know anything about this? I've instead resorted to using:

$fields = array_map(function (FieldLayoutFieldModel $model) {
    return $model->getField();
}, $element->getFieldLayout()->getFields());

Not sure what's best here.

I've determined what I think to be the best way to dynamically add Element's field content values to my responses.

First off, the reason why field content values are being returned using $element->getContent() regardless of the Element relationship with the fields, is because the content table has field values as columns themselves. So when a Content model is populated, all fields are included. If I setup a field for an Entry, it will appear as a field for a User when using this method.

My solution:

$entries = array();

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

foreach ($results as $model) {
    $entry = array();

    $attributes = $model->getAttributes();

    foreach ($attributes as $name => $value) {
        $entry[$name] = $value; // Do some transformation here (type casting, etc.)
    }

    $content = $model->getContent(); // No extra DB queries here - Model is already populated with content values

    $fields = array_map(function (FieldLayoutFieldModel $model) {
        return $model->getField();
    }, $model->getFieldLayout()->getFields());

    foreach ($fields as $field) {
        $entry[$field->handle] = $content->{$field->handle};
    }

    $entries[] = $entry;
}

return $this->returnJson(array(
    'entries' => $entries,
));

In my particular development, I've separated a lot of the above logic into services, which I'm using like Transformers.

This helps me deliver field content values through my API. I spent hours pouring through source code, and I'm pretty confident this is the best solution based on efficiency, best practices, and similarity with logic concepts found throughout built-in services and models. Let me know what you guys think.


Twig Templating If statement (Unexpected tag name error) Sorry if this is a really obvious question, I'm new to Twig and Craft. I'm getting the following error:
Unexpected tag name "offset" (expecting closing tag for the "if" tag defined near line 54)

Can anyone tell me what is wrong with my code?

{% set offset = true %}
{% if offset %}

    {% set caseHero = entry.heroImage.first() %}

{{entry.title}}

{{entry.description}}

    {% offset = false %}
{% else %}

    {% set caseHero = entry.heroImage.first() %}

{{entry.title}}

{{entry.description}}

    {% offset = true %}
{% endif %}

It seems like you want to set offset to false after your first section.

To do this correctly you would need to use set like this:

{% set offset = false %}

Checkout the documentation to set a variable


How to set Home page menu as active when slug is not defined in admin panel? Is their is any way to set active class to a page when slug is not define?

craft.request is useful for setting an "active" class based on URL segments without slug.
In your template you can set a slug in twig and then you can run if statement to check what the segment is. Check below example for that.

    {% set slug = craft.app.request.getSegment(1) %}
    {% for entry in entries %}
        {% set destination = entry.linkDestination.one() %}

            {{ entry.linkText }}

    {% endfor %}


Template not found: $PRIMARY_SITE_URL/$PRIMARY_SITE_URL/blog/this-is-my-blog Very new to craft CMS, recently just installed XAMPP with php 7 and craft 3 and followed the getting started tutorial from Craft CMS. Then when I try to preview or open the page created from the tutorial, it gives me a 404 template not found error.
The error is as follows:
yii\web\NotFoundHttpException: Template not found: $PRIMARY_SITE_URL/$PRIMARY_SITE_URL/blog/this-is-my-blog in C:\xampp\htdocs\craft\vendor\craftcms\cms\src\controllers\TemplatesController.php:92
Stack trace:
#0 [internal function]: craft\controllers\TemplatesController->actionRender('$PRIMARY_SITE_U...', Array)
#1 C:\xampp\htdocs\craft\vendor\yiisoft\yii2\base\InlineAction.php(57): call_user_func_array(Array, Array)
#2 C:\xampp\htdocs\craft\vendor\yiisoft\yii2\base\Controller.php(181): yii\base\InlineAction->runWithParams(Array)
#3 C:\xampp\htdocs\craft\vendor\craftcms\cms\src\web\Controller.php(190): yii\base\Controller->runAction('render', Array)
#4 C:\xampp\htdocs\craft\vendor\yiisoft\yii2\base\Module.php(534): craft\web\Controller->runAction('render', Array)
#5 C:\xampp\htdocs\craft\vendor\craftcms\cms\src\web\Application.php(274): yii\base\Module->runAction('templates/rende...', Array)
#6 C:\xampp\htdocs\craft\vendor\yiisoft\yii2\web\Application.php(104): craft\web\Application->runAction('templates/rende...', Array)
#7 C:\xampp\htdocs\craft\vendor\craftcms\cms\src\web\Application.php(259): yii\web\Application->handleRequest(Object(craft\web\Request))
#8 C:\xampp\htdocs\craft\vendor\yiisoft\yii2\base\Application.php(392): craft\web\Application->handleRequest(Object(craft\web\Request))
#9 C:\xampp\htdocs\craft\web\index.php(23): yii\base\Application->run()
#10 {main}

and it looks like this:

I have followed all the instructions in the tutorial, and have created the _entry.twig in my templates/blog folder. Any help would be much appreciated

You have to go to your Admin Dashboard > Settings > Sites > Your site and delete Base URL field, then save it and try to navigate.


How to find out which assets are being used I want to be able to delete assets that are not linked to. I have adapted the following code from previous examples of this kind of thing, but it doesn't seem to pick up all the related entries, just some of them. Some photos do not show a related entry but if I go to the entry where I think it might have been used it is still in use. Am I missing something in matching the entries to the assets?

{% set photos = craft.assets.kind('image') %}
{% for photo in photos %}

{{ photo.filename }} / {{ photo.folderId }}

        {# Loop throught entries related to this asset #}
        {% for entry in craft.entries.relatedTo(photo).order('title') %}

{{ entry.title }}

        {% endfor %}

{% endfor %}

I have tried using the assetusage plugin but it doesn't seem to work with non images and I also wanted to test if it was working properly.
I also looked at the Asset-Use plugin but that is beta and only does images.

Create this function in your plugins variable:

public function getAllIds(){
    return craft()->db->createCommand()->select('id')->from('elements')->where([
        'not like', 'type', 'Asset'
    ])->queryColumn();
}

You'll fetch all ids in Craft, then you can to this:

{% set allIds = craft.your-plugin-handle.getAllIds() %}

{% set usedAssets = craft.assets({
    relatedTo: allIds,
    limit: null,
}).ids() %}

{% set unusedAssets = craft.assets({
    id: 'and, not ' ~ usedAssets|join(', not '),
    limit: null
}) %}

To be honest I'm not sure what the error is in your code. You should get all entries related to the asset, even if they are in a matrix block. Maybe you related to asset to a category and this category to an entry and you assume to get the entry(?)


Manual update to 2.6.2931 After uploading the app-new folder to my server, renaming it and logging in to the admin area. The website responds with a 'System not available message' (in Dutch) for both front and admin end.

Resetting the app-old as the default app folder again does not solve the error message. I've cleared the storage/runtime/cache and storage/runtime/compiled_templates folder.

What actions are needed to restore the site to working order first, before going into the update again?

Replace the /app folder, per the Manual Update instructions. It sounds like you may have already done this, but rolled it back.

Once the new /app folder is in place, you must visit the admin section. This will run any necessary migrations.

That's it!


Is there a way to send offsite backups of the whole site to Amazon S3? I used to use a plugin for ExpressionEngine called "Backup Pro" (http://devot-ee.com/add-ons/backup-pro) that would allow me to backup the entire file system and database to an offsite location like Rackspace or Amazon S3.

Is this functionality built into Craft anywhere or does a similar plugin exist?

You're in luck... Backup Pro for Craft was released just this week:

  https://mithra62.com/projects/view/backup-pro


How to search against a specific field/s, and not every field related to an element? I have the below. I want to only show results that contain the query in the the username or fullName attributes.

Because currently if I search for say Tom the search results will return users without a username or full name containing the query Tom, but will show a person if the email contains it. I don't want this as emails are not publicly shown and therefore may cause confusion to the user searching.

How would I exclude email from the search criteria or only allow searching from the username or fullName attribute?

The same happens when searching entries - how do I narrow the search to only use the title field for example otherwise the search results can be too broad which is bad for UX.

{% set users = craft.users()
    .search(query)
    .group('creatives')
    .all() %}

{% if users|length %}

{{users|length }} results:

        {% for user in users %}

{{ user.username }}

        {% endfor %}

{% else %}

Your search for {{ query }} didn&#39t return any users.

{% endif %}

You can just limit your search to those specific user fields.
It should go something like:
{% set users = craft.users()
    .search('fullName:' ~ query ~ ' OR username:' ~ query)
    .group('creatives')
    .all() %}

More info on searching here: https://docs.craftcms.com/v3/searching.html#supported-syntaxes
Top tip: You can test your search query directly in the search bar within Craft's admin. e.g. See if fullName:Tom OR username:Tom pulls the intended results.


Translating checkbox labels I'm trying to translate the labels for a global checkbox field in my front-end templates like in this post: Is there a way to have checkbox field labels translatable?.
This looked promising but I can't seem to get it working (maybe it's Craft2 and things have changed in 3)

Basically it's using namespacing in the translations file e.g for a French translation file

return [
  'field.fruits.option.apple.label' => 'pomme',
  'field.fruits.option.lemon.label' => 'citron',
];

But no translations showing in the template when I try

{% for fruit in myGlobalSet.fruits %}
    {{ fruit.label|t }}
{% endfor %}

Any ideas? I'm sure it must be syntax related or wrong namespacing but I'm not getting any errors.

In order to do the namespaced trick in Craft 3, you'd do it like this:

Create your folder structure like this for your locale with one file for the Control Panel and one for the front-end of the site:

Contents of files:

Settings for Checkbox field:

Template code:

Front-end results:

Edit entry results:


Commerce 2: Custom product fields not showing up in order I've created a dropdown field for my users to select from on each of my products, but if the user was to select an option from the dropdown and click 'add to cart' , it doesn't show up in their order once it's all gone through.

What I currently have on my products page is:

<form method="POST" name="main">
    <input type="hidden" name="action" value="commerce/cart/update-cart">
    <input type="hidden" name="paymentCurrency" value="{{ currency }}">

    {{ redirectInput('cart') }}
    <input type="hidden" name="qty" value="1">
    {{ csrfInput() }}

    {% set max = product.max %}
    {% set i = 0 %}

    <select name="options[max]">
        {% for i in 1..max %}
            <option value="{{ i }}">{{ i }}</option>
        {% endfor %}
    </select>

    {%- for purchasable in product.getVariants() -%}
        {% if purchasable.isAvailable %}
            <input type="hidden" name="purchasables[0][id]" value="{{ purchasable.id }}" />
            <input type="hidden" name="purchasables[0][qty]" value="1" />
        {% endif %}
    {%- endfor -%}

    {%- for purchasable in product.getVariants() -%}
        {{ purchasable|currencySalePrice('' ~ currency ~ '') }}
    {%- endfor -%}

    <input type="submit" value="{{ "Add to cart"|t }}" class="button"/>
</form>

Any reason why 'add to cart' wouldn't update this info and show it in the customers order?

First you need to figure out which one you are using.

LineItem Options:
Here is the doc for it.
https://docs.craftcms.com/commerce/v2/adding-to-and-updating-the-cart.html#line-item-options-and-notes

One thing worth to mention is that options store in lineItem, which is one set of options for each purchasable/variant. So in your form you should put the options in your for loop of the product.getVariants().
And have the loop index in front just like the purchasable. e.g.

<select name="options[0][max]">
        {% for i in 1..max %}
            <option value="{{ i }}">{{ i }}</option>
        {% endfor %}
</select>

Same with your "qty" it needs to have loop index in front as well.
See the documentation link for example:
https://docs.craftcms.com/commerce/v2/adding-to-and-updating-the-cart.html#adding-multiple-purchasables-to-the-cart

Order Field:
Didn't find documentation for it in craft CMS commerce 2 docs.
Order field stores with order object. One order has one value for a unique field handle.
You can use <input type="your-choice" name="fields[customFieldHandle]"/> in "commerce/cart/update-cart" action.
You can retrieve it by calling order.customFieldHandle.

Before you use one custom field in the twig template you need to go your control panel and create a custom field first. "http://your-site.com/admin/commerce/settings/ordersettings". Find the "order fields" (name maybe different due to the version of craft, I don't think P&T have ever changed it since beginning.) tab, and create a field just like you would create a field for entry.

Try this form:

<form method="POST" name="main">
    <input type="hidden" name="action" value="commerce/cart/update-cart">
    <input type="hidden" name="paymentCurrency" value="{{ currency }}">

    {{ redirectInput('cart') }}
    {{ csrfInput() }}

    {% set max = product.max %}

    {%- for purchasable in product.getVariants() -%}
        {% if purchasable.isAvailable %}
            <input type="hidden" name="purchasables[{{loop.index}}][id]" value="{{ purchasable.id }}" />
            <select name="options[{{loop.index}}][max]">
             {% for i in 1..max %}
                <option value="{{ i }}">{{ i }}</option>
             {% endfor %}
            </select>
            <input type="hidden" name="purchasables[{{loop.index}}][qty]" value="1"/>
        {% endif %}
    {%- endfor -%}

    {%- for purchasable in product.getVariants() -%}
        {{ purchasable|currencySalePrice('' ~ currency ~ '') }}
    {%- endfor -%}

    <input type="submit" value="{{ "Add to cart"|t }}" class="button"/>
</form>

If you want customer to choose one options and apply for all the purchasables.

Just put a hidden input in the for loop and then use JavaScript function to update options in the loop on change.


Schedule a draft to auto publish? Is there a way to schedule a draft of a entry to go live?

If the entry is not already published, just set the Post Date to a date in the future.

That will set the entry to what Craft calls Pending. On the entry's index, the status indicator will be orange (instead of green).

If the entry is already currently published, no. That'd be a feature request. I agree, it would be great to be able to "publish over" the current edition (say for a contest or what not). If you set a draft's entry to a future date, Craft will un-publish the entry and set the status to pending.

You could work around this in Twig though. Say you want to have the entry change on 11/10. Set up a new Draft, name it Will Go Live on 11/10 (or whatever). Then in your template:

{% if now|date('U') > "2015-11-10"|date('U') %}

{% set theDrafts = craft.entryRevisions.getDraftsByEntryId(entry.id) %}

{# keep the "old" entry around just in case #}
{% set oldEntry = entry %}

        {%for i in theDrafts %}

            {# look for the specific draft and set if it exists #}

            {% if i.name == "Will Go Live on 11/10" %}
                {% set entry = i %}
            {% endif %}

        {% endfor %}

{% endif %}

{# template as normal #}
 ...


Uploaded assets not saving in specified local folder I have a local asset folder defined with name 'Local storage' file system path ../public/cms/images/, and URL /cms/images/.

I create an Assets field named 'Hero image', not restricted to a single folder, with source 'Local storage', and default upload location 'Local storage' with path heroes/{slug}/.

I'd expect uploads for Hero image to land in the /public/cms/images/heroes/{slug} folder. When I do upload an asset, this folder is created, yet the asset lands in the root /public/cms/images folder.

Why might this be?

This answer really belongs to Brad, as he mentioned it to me. But he doesn't really need the points, does he ;)

What you want in that slot is {owner.slug}, and then the proper sub-path will ensue.

The explanation is deep in the doc page at: http://buildwithcraft.com/docs/assets-fields

To wit,

  "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}."


Filter products by variants' tags I want to set up a product filter system based on variants' tags. I encounter two difficulties.

1. Outputting all variants' tags from a group of products.

{% set products = craft.commerce.products.type('Custom').find() %}
{% set variants = craft.commerce.variants.relatedTo(products) %}

{% for pattern in craft.tags.group('patternSwatch').relatedTo(variants) %}
    {{ pattern.name }}
{% endfor %}

{% for pattern in craft.tags.group('patternSwatch').relatedTo(craft.commerce.variants) %}
    {{ pattern.name }}
{% endfor %}

2. Filter product based on the multiple variants' tags

{% set pattern = craft.request.getParam('pattern') %}
{% set tag = craft.tags.group('patternSwatch').title(pattern).first() %}
{% set variants = craft.commerce.variants.relatedTo(tag) %}

{% for v in variants %}
    {{ v.product.slug }}
{% endfor %}

Personally I would use categories for a 'facetted search' filter you describe, as categories are less likely to get out of control. e.g. If tags are seldom re-used then a search for a tag may only produce a single result.

This plugin may help you: https://github.com/iainurquhart/FacetedNav_CraftPlugin

If you're going to use tags then I suggest making use of Craft's search functionality as this will allow you to submit the tag as a search term and also display any entries which contain the word/tag in ANY field of the entries within Craft.


How can I reference images in a rich text field? I need to reference an image in a rich text field separately to the text.

So I can't just use {{entry.body}} I need to be able to do {{entry.body.image}} or something comparable.

How can I do something like this?

Hopefully my question makes sense, I am new to Craft.

Thanks!

Sounds like you are coming from something like WordPress. In Craft there are asset fields where you can relate assets to your text. Together with matrix fields you can create a powerful layout rather than inserting everything into one huge wysiwyg.

If you really want to fetch images in html editors you'll need a plugin for that. It's not possible in Craft per default because it's not really the intended way


How does Craft regard a Lightswitch field when it's set to Required in the Fields layout? If I set a Lightswitch field as required, does that require it to be On? Is that valid at all?

(Context: I'm using a Lightswitch in User fields to capture "I agree to the Terms & Conditions...", and building a front-end user registration form.)

Thanks!

Currently it has no affect on the Lightswitch field at all, which I think is the right call.

However, you do have a valid use-case for either making a setting on the field that forced it to be "on" if required is set or maybe even a separate "Require On" field type all-together.

Regardless, probably worth putting up on http://feedback.buildwithcraft.com


Define record start ID Is there a way to define my plugins Record start ID? Now it start with ID 1, and for various reasons I would like to define a starting number.

Not the most direct way, but you could do something like this from your plugin's record:

public function createTable()
{
    // Let the base class do the actual work
    parent::createTable();

    // Change the PK auto-increment starting point.
    craft()->db->createCommand()->setText('ALTER TABLE myTable AUTO_INCREMENT=9999')->execute();

}


Making a DB on a remote server I need to make a database on a remote server, and since I have been using craftman installer which uses Docker to install Craft CMS and DB locally I have no idea how does the DB actually looks like. How can I check and see what is DB like, and export the sql file so that I can import it on the remote server?
I have tried to connect to it using these settings:

Host: 127.0.0.1
Username: root
Password:
Database: craft
Port: 3306

I have also tried with changing the Db name from craft to the name of my project, but that didn't work either, not sure where I can find the right settings and how to connect to DB?

Never used craftman before, but it looks like the database name it creates is called craft and it's pulling the database user and password from some environment variables named CRAFT_DB_USER and CRAFT_DB_PASSWORD you could check for.


Front End Asset Upload to Custom Element Type not working I have a custom Element Type to which I can add several custom fields.  I can create a front end form with most of those custom fields and the submitted data saves just fine.  However, I'm getting some odd behavior with the Assets field.

I can save Assets fields from the front end of Craft to Craft sections just fine.  And I can edit one of the Entries for my custom Element types on the backend and upload an Asset just fine there as well.

But when I submit an Asset from the front-end for a new Entry with this custom Element type, I don't get the right behavior.

What does happen (as far as I can tell):

The asset uploads and appears in the target upload folder
A new row in the craft_relations table is created correctly
identifying the asset and the element that it is related to.

What doesn't happen:

The uploaded asset doesn't appear in the Asset index.  Even if I reindex assets for this particular folder, it never shows up in the Assets file manager.
When I visit the individual entry page in the CP, the Asset never appears. (But if I upload the asset directly from this CP page, the asset then does appear on this same page)

I'm struggling to know where to look to troubleshoot this.  What would cause an Asset not to display properly when it's uploaded from the front end but to work fine when it's uploaded from the back end?  Could I be missing some data on the front end submission?  My form uses enctype="multipart/form-data" and the asset field is as simple as it gets (and I've tried several variations (<input type="file" name="fields[uploadfield]" >)

I looked into this extensively and the one thing I found is that if your element type uses a custom content table, the save procedure will be done properly but when Craft needs to display the asset in the index, inside an asset selection modal, or an asset field, it simply won't look in the right place and unless you copy your asset's locale and title to the Craft content table from your custom content table, it won't show up.

I've made @Brad aware of this but they haven't fix it yet, at least not in the last release that I can tell.


How can I get all entries that are equal to, but not after a date? Some of the products on my page are time sensitive (events). Currently I am getting them all like this:

{% set events = craft.commerce.products.type('event').order('eventStartDate desc') %}

I can't use the expiryDate as the end date for my event, as I am keeping an archive that I want users to be able to click though. But, I don't want to include these "expired" events in my "upcoming events" list.

I am reading through this SO thread which I think is doing the same thing I am. It's painfully obvious that I don't know what I am doing though.

{% set today = now %}
{% set events = craft.commerce.products.type('event').eventEndDate('>= today') %}

: Call to a member function getTimestamp() on boolean

eventEndDate is a dateTime field type.

I am trying (and failing) to get all events that have an end date that is equal to, or before today. Once the event is over eventEndDate is after today, I do not want to show it in my list.

Thank you for any suggestions!

I think the only issue is that you're adding "today" to the query as a string, not the variable you've created. try:

{% set today = now %}
{% set events = craft.commerce.products.type('event').eventEndDate('>=' ~ today) %}

The code in the answer you referred to had the same error, I've fixed it.


How to structure this multiple relation? So I have these sections and fields that I'm dealing with:

candidates

Name
Pic
Bio

answers

relatedQuestion
Body
relatedCandidate

questions

title
body

candidateGroup

title

I'm outputting a single page using the question:

Question and Info

Candidate Group Name

Candidate

Answer

Candidate

Answer

... Repeats ...

So my current setup looks like this:

{# Get the answers that are related to the question entry #}
{% set relatedAnswers = craft.entries.section('answers').relatedTo(entry) %}

{# Loop through categories #}
{% for category in craft.categories.group('candidateGroup') %}

  {{ category.title }}

  {# Get me the candidates that belong to this category and have an answer related to this question entry #}
  {% set candidateAnswers = craft.entries.section('candidates').relatedTo('and',
    category,
    relatedAnswers
  ) %}
  {% for candidateAnswer in candidateAnswers %}

    {# Output the candidate's info and their answer #}

  {% endfor %}
{% endfor %}

I feel like this is right and it seems to be working locally but when I get it live on the site it's having issues recognizing what "entry" it's a part of. No matter what entry I go to via url, it outputs the same answers.

I tried to do a simple loop to see what relatedAnswers outputs, and it's the right information. It's just getting lost in that inner loop somehow.

Update:
I believe it is working locally just fine. But for some reason, on my Media Temple hosted site, it's not outputting in the same manner. I double and triple checked all the fields and couldn't find any differences?

Update 2:
I can't figure this out for the life of me. It works fine on local, just not on production. I checked the database to see if there anything out of the ordinary and it looked fine to me. I installed the introvert plugin to see if the relations were working properly and they seem to be just fine. Kind of lost at this point.

Updated 3
I tried it another way:

  {% for category in craft.categories.group('candidateGroup') %}

{{ category.title }}

      {% for answerEntry in craft.entries.section('answers').relatedTo('and',category,entry) %}

              {% set relatedCandidate = craft.entries.section('candidates').relatedTo(answerEntry).first() %}
              {% set asset = relatedCandidate.avatar.first() %}

{{ relatedCandidate.title }}

                {% set categoryCandidate = relatedCandidate.group.group('candidateGroup').first() %}
                {{ categoryCandidate.title }}

            {{ answerEntry.body }}

      {% else %}

          There are no answers from candidates in this group yet.

      {% endfor %}

  {% endfor %}

Unlike the other solution, my problem on the server is that it doesn't return any entries at all. I'm assuming it has something to do with that 'relatedTo(entry)'. It's like it doesn't recognize that at all. In the first case it just ignores it and  in this case it's like it can't read it.

There could be corrupt data in your remote database. I tried to answer a similar case some weeks ago: "Entries related to Users", where the code was right, but Craft returned the wrong entries.

I'd check if it helps to clear the database and do a fresh import from you local environment.


Adding multiple slashes after the site URL breaks the current entry, but still loads the template I've come across an issue where typing the URL e.g www.sitename.com///about will still load the about template, but not fill the page with the content. Is this an issue for google finding the appropriate pages in google searches? And how can I get these pages to no longer exist or result in a redirect to the correct URL www.sitename.com/about?

Thanks for any assistance

Are you getting the About template or the layout template it extends?

In a test with a local site I have running, I was able to trigger a 404 for any bad requests by putting

{%  redirect 404 %}

inside the main block in the _layout template.

This works in my case because that block is overridden on every request. If it's not, something has gone wrong and I need to exit out since the layout template should never render on its own.


Forcing destruction of httpSession variables on logout I would like to store some data in the user's session specifically for when they're logged in. When logged out, I would like the session to destruct. Trawling through the code, it seems that session destruction is forced to false on logout.

yiilite framework:

public function logout($destroySession=true)

Craft UsersController:

 public function actionLogout()
 {
            craft()->userSession->logout(false);
....

I'm using the following in Craft config to force logouts and expiration after a certain amount of time, but the session doesn't get destroyed until the browser is closed.

'userSessionDuration'=>'PT20M',
'rememberedUserSessionDuration' => false,

Is there something I'm missing here, or do I have to override the event and clear the session variables myself?

Currently when you manually click the logout button in Craft, it will destroy your authenticated session information (to be logged into the control panel), but keep your existing PHP session (represented by the CraftSessionId cookie) so anything stored in PHP's session will remain.

If that's not the behavior you're looking for, you can make a feature request to expose this behavior via a config setting and/or write a simple plugin that listens for the userSession.onLogout event and manually destroy PHP session.


Twitter API request for images with DUKT twitter I am using DUKT's Twitter 1.0.32 but am fresh at reading APIs, so would like a little help.
I would like to request tweets with image only from our main ID.

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

This works fine, but even an attempt to play around with the other parameters within user_timeline baffles me.

Could I ask for some examples to display tweet text & image, plus some other relevant parameters?

I have used it like this. You can find the documentation for most fields on Twitter. Truth be told, the DUKT documentation is not too transparent.

{% set tweets = craft.twitter.get('statuses/user_timeline', { user_id:'', count: 10, trim_user: false }) %}
{% if tweets %}

        {% for tweet in tweets %}

{{tweet.text|autoLinkTweet}}

           {{ tweet.created_at | twitterTimeAgo )}

        {% endfor %}

{% endif %}

Update

You have several entities in the data you get back from Twitter API (as described by Twitter):  media, urls, user_mentions, hashtags, and symbols. The DUKT plugin, however only gives back urls, user_mentions, hashtags, and symbols as far as I see in the error messages they provide.

 {{tweet.entities}}


Craft not Downloading Auto Update - HttpException on OS X PHP56 I have a development system running OS X / nginx / php-fpm 5.6 and I've pulled down a version of my site from my git repository. The site is currently running an out of date version of craft, however it appears to have issue connecting to the craft update server when I check for an update, simply saying ‘You’re up to date!' (which it isn't).

This only happens on the testing system so I'm guessing it's a configuration issue in php, but having reconfigured php several times I still have this issue. It also causes plugins like the Directory plugin and DUKT's Videos plugin to return errors like 'Couldn't retrieve account' when querying apis.

Looking at the logs turns up a HttpException, although I'm not entirely sure what would cause this issue? Craft hasn't said anything is wrong with my environment but clearly something is failing somewhere...

2014/10/27 23:42:04 [warning] [application] 404 -
in craft/app/etc/errors/HttpException.php (29)
in craft/app/controllers/TemplatesController.php (59)
in craft/app/etc/web/WebApp.php (293)
2014/10/27 23:42:04 [error] [exception.Craft\HttpException.404] exception     'Craft\HttpException' in craft/app/controllers/TemplatesController.php:59

I installed PHP through homebrew with the command:

brew install php56 --with-homebrew-curl --with-homebrew-libxslt --with-homebrew-openssl --without-snmp --without-apache --with-fpm --with-mysql php56

So the issue appears to be with php56: after uninstalling 56 and installing 55 craft works as expected.


Why is the Craft without filter not working correctly and how to debug? I am using the Dukt Follow plugin to return 2 arrays which both hold User objects, I am then using the without filter to remove users from the array which are considered friends. Friends are determined by using the intersect filter on the 2 arrays.

Everything works apart from the second without filter which does not work, and returns objects that are in the friends array.

{# Friends, Followers & Following #}
{% set userFollowing = craft.follow.getFollowing(user.id) %}
{% set userFollowers = craft.follow.getFollowers(user.id) %}

{% set friends = userFollowing|length and userFollowers|length ? userFollowing|intersect(userFollowers) : null %}
{% set following = userFollowing|without(friends) %}
{% set followers = userFollowers|without(friends) %}

Is there an obvious reason why this might not be working?
How is best to debug something like this?

I have checked the output of all the arrays and objects and they do appear to hold the data that they should.

Basic data stored in each array:

User Following:
Array: ["Craft\\UserModel: bencallaway","Craft\\UserModel: davidwearn","Craft\\UserModel: shorn"]

User Followers:
Array: ["Craft\\UserModel: bencallaway","Craft\\UserModel: davidwearn"]

Friends:
Array: ["Craft\\UserModel: bencallaway","Craft\\UserModel: davidwearn"]

Following:
Array: {"2":"Craft\\UserModel: shorn"}

Followers:
Array: ["Craft\\UserModel: bencallaway","Craft\\UserModel: davidwearn"]

Full variable output can be accessed here: http://cl.ly/2o292X3O2r0M

Try using |without based on arrays of user IDs, not entire UserModel objects. Behind the scenes, it's just using PHP's in_array method, which works much better on simple primitives like ints, strings, etc. instead of complex objects like Models (that has magic methods, other objects, primitives, etc.).  in_array probably doesn't know how deep of a comparison to make on those objects.


What is the best way to have an entry for top-level categories? I'm currently working on an eCommerce project with categories for products:

- Category 1
    - Sub-category 1
    - Sub-category 2
    - Sub-category 3
- Category 2
    - Sub-category 1
    - Sub-category 2
    - Sub-category 3

What I am hoping to achieve, is to give each top-level category its own entry in Craft, so I can apply my site-wide SEO, matrix content and utility fields.

I am aware you can apply fields to categories, but the whole double-clicking on a category and managing the content from the small modal window approach isn't ideal, especially with category pages that are a bit heavy on the content side.

These categories do have their own URL, and creating an entry with the same slug results in incrementation: example-category-1, which is to be expected.

Is there any way in Craft I can get round this? I guess if there is no other way I can apply fields to the category, but I wanted to see if anyone had any other ideas.

After a little more consideration, I decided it was best instead not to use categories for this.

I have instead created a 'Product Categories' structure, and the relationships are handled through an entry field.


Advanced Search with tags and categories Been scratching my head for the past day on how to implement search with multiple categories.

At the moment, I have product categories as a select dropdown which only allows to search in one category at a time. This is passing the value as a parameter. How do I go about searching with multiple categories (checkboxes) at once? Here's what I have so far.

Any ideas?

search.html

<form action="{{ url('food-suppliers/results') }}">
    <input type="search" name="query" placeholder="What are you looking for?" style="width: 100%;">

    <select name="supplier">
      <option value="">All Markets</option>
      {% set suppliers = craft.categories.group('suppliers') %}
      {% for supplier in suppliers %}
      <option value="{{ supplier.slug }}">{{ supplier.title }}</option>
      {% endfor %}
    </select>

    <select name="product">
      <option value="">All Products</option>
      {% set products = craft.categories.group('product') %}
      {% for product in products %}
      <option value="{{ product.slug }}">{{ product.title }}</option>
      {% endfor %}
    </select>

    <select name="delivery">
      <option value="">All Delivery</option>
      {% set deliveries = craft.categories.group('delivery') %}
      {% for delivery in deliveries %}
      <option value="{{ delivery.slug }}">{{ delivery.title }}</option>
      {% endfor %}
    </select>

      <input type="checkbox" name="homeGrown" value="true">Home Grown

      <input type="checkbox" name="preparedProduce" value="true">Prepared Produce

      <input type="checkbox" name="redTractor" value="true">Red Tractor

      <input type="submit" value="Search">

</form>

results.html

{% set query = craft.request.getParam('q') %}
{% set supplier = craft.request.getParam('supplier') %}
{% set product = craft.request.getParam('product') %}
{% set delivery = craft.request.getParam('delivery') %}

{% set homeGrownParam = craft.request.getParam('homeGrown') %}
{% set preparedProduceParam = craft.request.getParam('preparedProduce') %}
{% set redTractorParam = craft.request.getParam('redTractor') %}

{% set supplierCat = craft.categories.group('supplier').slug(supplier).first %}
{% set productCat = craft.categories.group('product').slug(product).first %}
{% set deliveryCat = craft.categories.group('delivery').slug(delivery).first %}

{% set supplierParam = supplier ? {targetElement: supplierCat} : '' %}
{% set productParam = product ? {targetElement: productCat} : '' %}
{% set deliveryParam = delivery ? {targetElement: deliveryCat} : '' %}

{% set entries = craft.entries.section('suppliers').relatedTo(productParam).relatedTo(deliveryParam).search(query).homeGrown(homeGrownParam).preparedProduce(preparedProduceParam).redTractor(redTractorParam) %}

Before I answer your main question, I'm seeing a couple issues with what you’re currently doing that are worth correcting.

First, this code:

{% set supplierCat = craft.categories.group('supplier').slug(supplier).first %}
{% set productCat = craft.categories.group('product').slug(product).first %}
{% set deliveryCat = craft.categories.group('delivery').slug(delivery).first %}

should be replaced with:

{% set supplierCat = supplier ? craft.categories.group('supplier').slug(supplier).first %}
{% set productCat = product ? craft.categories.group('product').slug(product).first %}
{% set deliveryCat = delivery ? craft.categories.group('delivery').slug(delivery).first %}

in case any of the supplier/product/delivery params are blank.

Next, this code:

{% set supplierParam = supplier ? {targetElement: supplierCat} : '' %}
{% set productParam = product ? {targetElement: productCat} : '' %}
{% set deliveryParam = delivery ? {targetElement: deliveryCat} : '' %}

should be replaced with:

{% set supplierParam = supplierCat ? {targetElement: supplierCat} %}
{% set productParam = productCat ? {targetElement: productCat} %}
{% set deliveryParam = deliveryCat ? {targetElement: deliveryCat} %}

That way you will avoid unexpected behavior if a supplier/product/delivery was posted, but it had an invalid slug, and yielded no results. Also, the : ''s at the end are just not really necessary unless your really wanted them to be strings by default (no reason in this case though), as Twig will default the values to null, which is just as good.

Also, you can’t chain multiple relatedTo params together like this:

.relatedTo(productParam).relatedTo(deliveryParam)

When you do that, the second relatedTo param will just override the 1st one.

Instead you’d need to do something like:

{% set relationParams = [supplierParam, productParam, deliveryParam]|filter %}

{% set entries = craft.entries({
    section: 'suppliers',
    relatedTo: relationParams ? ['and']|merge(relationParams) : null,
    search: query,
    homeGrown: homeGrownParam,
    preparedProduce: preparedProduceParam,
    redTractor: redTractorParam
}) %}

(I’m using the {p1: v1, p2: v2} syntax for setting the criteria params here for clarity, but you can use the p1(v1).p2(v2) chaining syntax instead if you prefer it.)

With that out of the way…

To support searching for entries that are related to multiple suppliers/products/deliveries at the same time, the first thing you’ll need to do is update your search form. I know you said you want to go with checkboxes, but for simplicity’s sake I’ll demonstrate with multi-select boxes, since that’s closer to your original code and produces the same request param data.

For each of your <select>s, just append a [] to the input name and add the multiple attribute:

<select name="supplier[]" multiple>
...
<select name="product[]" multiple>
...
<select name="delivery[]" multiple>
...

In your search results template, change .first to .find() when fetching the categories:

{% set supplierCat = supplier ? craft.categories.group('supplier').slug(supplier).find() %}
{% set productCat = product ? craft.categories.group('product').slug(product).find() %}
{% set deliveryCat = delivery ? craft.categories.group('delivery').slug(delivery).find() %}

And assuming you want this to be an inclusive search (where only results with all of the selected suppliers should be included, etc.), you’ll need to prepend 'and' to each of the targetElement arrays:

{% set supplierParam = supplierCat ? {targetElement: ['and']|merge(supplierCat)}l %}
{% set productParam = productCat ? {targetElement: ['and']|merge(productCat)} %}
{% set deliveryParam = deliveryCat ? {targetElement: ['and']|merge(deliveryCat)} %}

That’s it. The rest can stay the same.


Possible to paginate product variants in Craft Commerce 2? I am currently in the process of building a commerce 2 site with a very detailed level of nesting in the product options so we're looking to list all variants for a product. (Sounds silly, but it works in this case!)

However, while trying to use paginate, I'm getting the following error:

Impossible to invoke a method ("limit") on an array.

Here is my markup:

{% paginate variants.limit(12) as pageInfo, pageEntries %}

Is it even possible to paginate variants?

Thanks

EDIT

We are getting all the product variants as follows:

{% set variants = product.variants %}

But if we use the limit here outside of the pagination, won't that mean we will always get the same first 12 items. Whereas we need to limit it within the paginator so we get the first 12, the next 12 etc etc.

Cheers

product.variants returns the variants for the product as an array only. It is not like a element relationship field which returns an element query.

If you want to use a element query of variants for a particular product you can do:

craft.variants.product(product).all


How to create different template for specific page? I have added a "newsletter" page under Admin > Entries > Page [New Entry]
And the page is opening fine on the url xyz.com/newsletter
But I want to assign a different template to this url, how can I do that?
I tried creating a folder at /templates/newsletter/index.twig but that is not working at all.

Entry templates are assigned on a per-section basis, and each section can only have a single entry template per site.
The workaround is to create a "proxy" template and use that as your section's entry template. The only responsibility for the proxy template is to {% include %} another template (the actual entry template), based on some conditions.
Here's how that proxy template could look in your case:
{% if entry.slug == 'newsletter' %}

    {# Use a special template for the "Newsletter" entry #}
    {% include 'newsletter/index' %}

{% else %}

    {# All other entries use a default "page" template #}
    {% include 'pages/page' %}

{% endif %}

Note: Using entry.slug (or entry.id, entry.title etc) for something like this is a bit fragile, because your content editor can easily change the slug and at that point the conditional will fail and the wrong template would be loaded.
A better approach is to add multiple entry types to your section (e.g. a "Newsletter" entry type and a "Page" entry type), and change the conditional to use that:
{% if entry.type.handle == 'newsletter' %}

    {% include 'newsletter/index' %}

{% else %}

    ...

Using different entry types also enables you to have different fields for different kinds of entries within the same section (which you'd typically want, when you're loading completely different templates for those entries).


Getting Page Not Found error for my custom subdomain setup I want to setup a new custom subdomain (va.domain.com) within the project of my existing domain (craft.domain.com) using homestead.

So I referred to this this answer on craftexchange and followed all the steps.

I now have a separate folder at the root level called public_va. Inside that I have my index.phpwith this define statement that is supposed to change the path:

define('CRAFT_TEMPLATES_PATH', realpath(dirname(__FILE__) . "/../templates_va").'/');

Inside of the craftfolder I have created a folder called templates_va that is a sibling of the existing templates folder. And I put in a simple index.html file in just for testing.

Now when I point my browser to va.domain.com, it just shows me:

Page Not Found

The requested URL was not found on this server.

I also tried creating a new (single) section called va_homepage in the CP backend but I get the same error.

What am I doing wrong? How do I fix this? My error logs inside my vagrant box show nothing. The domain itself has been setup correctly via homestead. I verified by routing request to a static file.

This is now fixed. The dynamic path to the new templates folder was wrong:

define('CRAFT_TEMPLATES_PATH', realpath(dirname(__FILE__) . "/../templates_va").'/');


Using static translations for the primary site / site.php being ignored I'm having trouble outputting static translations for the primary site, and only the primary site.
Translations structure:

translations

en-US

site.php

site.php
<?php

return [
  'UNIQUE_KEY_NAME' => `This is the string I'd like to appear.`,
];

Template
{{ 'UNIQUE_KEY_NAME' | t }}

Output
UNIQUE_KEY_NAME

Is there a way to make this pattern work?
The advantage of storing microcopy and site furniture in a single location is that it is much easier to update and share with copywriters.
If there is a second site, then it appears the site.php for that language will be respected, but when there is just one site, the primary site, its corresponding site.php translation file appears to be ignored. Is this intended?
Thanks

I think the error is to do with the fact that you are using backticks (slanted quote) instead of single/double quote marks.
Copy/paste the below and it should work for you
<?php

return [
  'UNIQUE_KEY_NAME' => 'This should now work',
];


Change the URL of nav child entry conditionally I want to change the URL of a li from a nav menu conditionally (using a custom field where the user sets the URL), but I don't see how to use conditionals with {% ifchildren %}?

{% nav entry in entries %}

        {{ entry.title }}

        {% if entry.id in craft.entries.descendantOf(4).ids() %}
            **change the url of all child entries**
        {% endif %}

        {% ifchildren %}

                {% children %}

        {% endifchildren %}

{% endnav %}

ID 4's children is the entry which I want to display custom URLs.

Instead of using {% ifchildren %} use {% if entry.hasDescendants %}. It allows for more flexibility in your nav templating.


Showing/Hiding children of a Structure based on categories I'm a newbie, so please excuse this if its a super simple question. I have a structure set up like so:

• Parent Section 1
  - Child 1A (category: pro-users)
  - Child 1B (category: pro-users)
  - Child 1c

• Parent Section 2
  - Child 2A
  - Child 2B

I am wanting to output a navigation/landing page with the children viewable or not based on what category they are set to. So for example, on a specific page, I just want items with category "pro-users" (two entries specified above) to show up, with their parent title, and not any of the others. I also don't want the parent titles of sections that don't contain matching elements (Parent Section 2) to show. So, in this example where I just want the children with category "power-users" to show up, it would only show me:

PARENT SECTION 1
   Child 1A
   Child 1B

And nothing else. Please ask for more specifics if this doesn't make sense. I just can't figure out how to a) only show the children that are matching the categories I specify (in this case "pro-users") and to also not show the subsequent parent title if there are no matching children (as is the case for Parent Section 2).

Thanks in advance for your help, I really really appreciate it!

Something like this should do the trick! You want to get all the section parent entries, then search for child entries that are related to the category you want.

{% set parents = craft.entries.section('your_structure_handle').level(1) %}

{% for parent in parents %}
    {% set children = craft.entries.decendantOf(parent).relatedTo(category) %}
    {% if children|length %}

{{parent.title}}

        {% for child in children %}

{{child.title}}

        {% endfor %}

    {% endif %}
{% endfor %}


How automatic slug generator could replace accentuated letters? When typing in the title, the automatic slug generator doesn't filter or replace accentuated letters such as (ő, ú, á, ű). Is there a way to replace these letters to the unaccented one (like ő -> o, ű -> u, etc..)?

It actually used to work this way when Craft first launched, but we had feedback where it was desired behavior to allow accented characters and even multi-byte characters in slugs, because they are perfectly valid in the URI.  e.g. http://domain.com/會意字

However, enough people have brought it up where they would like the old behavior that we're going to add a config setting for Craft 2.2 where you can choose which you prefer.

Update:

This was added as a limitAutoSlugToAscii config setting that defaults to true in Craft 2.2.


How to show entires from past 12 months? I need to display entries from the past 12 months. I'd like to create an entry query and set the timeframe of the entries I need.

I used the after parameter in my query.

{% set query = craft.entries({
    after: now|date_modify('5:00 -12 months')
}).all() %}

I'm grabbing todays date, then modifying with the date_modify filter. The 5:00 string makes sure it changes at the same time everyday.

I got the usage of date_modify from carlcs's answer here: How to only show entries older than 12 months


Cannot find control panel after installation After installing craft on apache server, when I try to access control panel using web/admin, serwer throws 404 error.
I didnt changed cpTrigger setting. Default craft template that displays after installation is displayed correctly.

.htaccess file in web directory was not modified in any way, its contents are default:

<IfModule mod_rewrite.c>
    RewriteEngine On

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

Web is the public web folder if you followed the recommended install location, so the link to login is just /admin, i.e.

http://your-domain/admin


Dropdown menu out of entry types There is the one way to build it, I could know, but It's complicated for maintenance, because I may add some new entry by time.

I'm trying to figure out a better way to have entry types related to a section and all sections in dropdown menu. Namely, sections have some same, some different entry types. So, when I click at any entry type at current section page, I get all those related entries to the click. It's more like filter feature, but except filtering on current page, you get redirected to a page with selected entry type's option.

Better to visualize it:

(http://www.dev.craft/ = all entry's types from all sections) = all entries from all sections and entry's types.

(http://www.dev.craft/entryTypeHandle = entryTypeHandle from all sections) = entries from all sections and entryTypeHandel.

(http://www.dev.craft/sectionHandle/entryTypeHandle) = entries from sectionHandle and entryTypeHandle

It is hard to read. You're welcome for question's comments, if anything unclear.

The only thing I can think of off the top of my head is create custom routes in a plugin dynamically generated from your entryTypes, sectionHandles, and sectionHandle/entryTypes and then point them all to the same template, which would then either display the entries directly (via twig) or dynamically include a corresponding template, based on the handle.

Something like the following perhaps? Completely untested.

public function registerSiteRoutes() {

    // array to store routes
    $routes = [];

    // get all section and entryType handles
    foreach(craft()->sections->getAllSections() as $section)
    {
        // add '/sectionHandle' routes
        $sectionHandle = $section->handle;
        $routes[$sectionHandle] = array('_dynamicTemplates/routeHandler.html');

        foreach($section->getEntryTypes() as $entryType)
        {
            // add '/entryTypeHandle' routes
            $entryTypeHandle = $entryType->handle;
            $routes[$entryTypeHandle] = array('_dynamicTemplates/routeHandler.html');

            // add '/sectionHandle/entryTypeHandle' routes
            $routes[$sectionHandle.'/'.$entryTypeHandle] = array('_dynamicTemplates/routeHandler.html');
        }
    }

    return $routes;

}

The one thing I don't know is if 'registerSiteRoutes()' gets called on every request, or only once when the plugin gets installed. If not, then you may also need to call it directly from an 'init()' method (or maybe just anytime an entry is saved - so it doesn't get fired on every request).

public function init() {
    parent::init();
    self::registerSiteRoutes();
}

The template would then grab the segments, perform an ECM search, and display results (or include a dynamic template based on the segments). Note: you might need to add an 'all' (or something else) to the solo 'entryTypeHandle' routes if there is any chance that your sectionHandle and entryType handles are the same. (i.e. '/all/entryTypeHandle').

In theory anyway — the whole thing might not work also. Be interested to hear how it goes.

Note: there also may be some problems with my routes array. I've never tried creating a dynamic route to a template in this way (might need to explicitly add '/templates/'). If anyone sees a problem please feel free to edit the answer or leave a comment. Thanks.

Update: I see a potential problem. See this answer for possible solution. Not sure how to integrate it as part of the answer though. Perhaps send all requests to a controller action, and render the template from there. May have to leave it to you to try and resolve for now — sorry about that.


How can I use tag slugs in URLs? This question is a summary of my working with tags yesterday, I'm posting my findings to SE so other people can benefit.

For the purposes of this question, I'm going to be using a tag with the title 'Two Words'.

I'm trying to add a tags listing and filtering system to a blog. As tags don't have a 'slug' property, I've been having issues using them in URLs. If I use the following links:

{% for tag in tags %}
    {{ tag.title }}
{% endfor %}

Then you get unfriendly urls such as http://craft.dev/news/tags/Two%20Words. If I use :

{% set tag = craft.tags.search(craft.request.getSegment(3)) %}
{% for entry in craft.entries.relatedTo(tag) %}

Then I get a list of articles that may contain the term "two words", but aren't actually tagged with Two Words.

I want to list articles related to the tag in the URL, so how can I pull the specific tag from the url, making sure it stays 'url-friendly'?

The key to this is to use the |kebab filter and the relatedTo params.

Listing:

{% for tag in relatedTags %}

{{ tag.title }}

{% endfor %}

Fetch related articles

{% set tag = craft.tags.search(craft.request.getSegment(4)) %}

{% for entry in craft.entries.relatedTo({ targetElement: tag[0], field: tagField }) %}

The tag[0] is necessary, as {{ craft.tags.search() }} will return an array (even if there's only one tag returned).

This finds entries that are specifically related to Two Words (a tag object, pulled from the URL), and searches in the tagField specified.

The alternative to the above is to use {{ tag.id }} and {{ craft.tags.id() }}, but that isn't URL/SEO friendly.


What's the correct syntax for recipients in Sprout Email? I've got a form creating an entry in a Bookings channel which contains two fields, an Entries field (eventBooking) and a Users field (userBooking).

I'm trying to get Sprout Email to send an email to the user selected in userBooking. Can anyone help me with the correct syntax please?

I've tried the following which don't seem to work:

{{ userBooking.first().email }}
{{ object.userBooking.first().email }}
{{ entry.userBooking.first().email }}
{ object.userBooking.first().email }

This should work:
{{ object.userBooking.first().email }}

I would check if the problem is with something else.


Plugin RegisterUrlRulesEvent - cannot find Controller aciton -> 404 The error I'm getting:

HTTP 404 – Not Found – yii\web\NotFoundHttpException
Page not found.
↵
Caused by: Invalid Route – yii\base\InvalidRouteException
Unable to resolve the request "Expedweather/forecast-panel".

The plugin's base was made through https://pluginfactory.io, I've simply added to it.

Below are the relevant code excerpts which for some reason do not seem to work as intended.

// ./src/Expedweather.php::init
$map_page = 'data\/<range:\w+>\/<peak:\w+>\/<view:\w+>\/<parameter:\w+>';
$event->rules[$map_page] = 'expedweather/forecast-panel';
// ./src/controllers/DefaultController
protected $allowAnonymous = ['index', 'forecast-panel'];
public function actionForecastPanel() {...}

Any ideas and/or potential solutions?
The Regex routing seems to work fine, but it cannot find the DefaultController's Action.

This is on CraftCMS Version 3.3.0.1

Found a Solution
Context:
When I created my plugin-frame through https://pluginfactory.io the DefaultController was still a thing -> routing to /pluginname/default-controller-action-name worked as it defaulted to search in the... default-controller. But it seems that is no more, so what I had to do instead to get it to find the action is add a section referring to the controller.
this is the new/fixed code:
// ./src/Expedweather.php::init
$map_page = 'data\/<range:\w+>\/<peak:\w+>\/<view:\w+>\/<parameter:\w+>';
$event->rules[$map_page] = 'expedweather/default/forecast-panel'; // <-- changed!!
// ./src/controllers/DefaultController
protected $allowAnonymous = ['index', 'forecast-panel'];
public function actionForecastPanel() {...}

The only row that changed is the $event->rules one which now has /default/ before the action -> this refers to the DefaultController.


Channel with URLs based on entry type Example: I have content which could be separated into Big News and Small News.

The Big News has much text (which would need a link to its own entry). The Small News has only one text block (so it wouldn't need a separate page for each news).

Whats the best way of handling this? Two separate channels?

One channel with two entry types and a template with a conditional:

{% if entry.type == 'SmallNews' %}{% exit 404 %}{% endif %}

How do you handle this? I guess it is not possible to add These entries have their own URLs based on entry types, right?

I would make this decision based on what makes the most sense for the client. You can realize both solutions on a technical level, so it's really just a question about the preferable CP user experience.

For me this sounds like "Big News" and "Small News" are quite similar, so I'd probably like to have them combined in a single channel. And your template conditional is a good way to handle the manually (accidential?) typed in URLs.

You could even add a dedicated source for the entry index views by making use of the modifyEntrySources hook and some lines of custom plugin code. See this Stack Exchange Q&A for how to do this: Filter entries by entry type in the CP?


404s on custom sections and entries I have created a section called "Services" and an entry within called "seo".  When I click to view that entry in the admin area, it takes me to domain.com/services/seo, as expected, but that 404s.

Is there anything else required to use channels?

I have .htaccess in place working properly and the shipped sections ('News', and the home page) all load fine.

You'll need to create a template, and add the path to that template to the Entry Template field in your "Services" section's settings.

For instance, if you create a template called /craft/templates/services/_entry.html, you'd use the path services/_entry for your section's Entry Template field.

With this setup, you could also add an index.html file to the /craft/templates/services folder. That template would render when the user visits the URL domain.com/services, enabling you to create a listing/index view for your "Services" section.

For more info, I'd suggest looking at the excellent official docs on templating in Craft.


Display related entries on the entry page they are related to I have a number of 'blog' channel entries related to various 'fayre' entries
I want to display all the blog entries related to the fayre entry page they are related to (Entry field is 'fayreBlog'), but not ones which are not related to that entry, so far I can only display only one blog entry and not more (even though there are more related to the entry I am relating to) not sure where my code is wrong? it resides in the fayres _entry.twig template:

{% set relatedBlogs = craft.entries.section('blog').relatedTo(entry).all() %}

{% for post in relatedBlogs %}
    <p>{{ post.title }} </p>
{% endfor %}

Argh! this code works! I had duplicate entries and looking at the wrong entry! User erroooor!


How to query with relatedTo of a Relationship Field in a Matrix Field block I have structures called Instrument and Person. On the person structure, I have a Matrix field called Roles. Roles has a block called Musician. And That block type has a Relationship Field called Instrument.

This allows someone to be a musician and to be assigned an instrument.

In my template I need to output each Instrument as a section, and all of the musicians that play that instrument.

I think this issue has something to do with the relationship being added in a Matrix block rather than on the entry itself.

Unfortunately there are many roles (block types) that a person can have, each with different fields. I tried to solve this by swapping to Instruments as categories but that doesn't seem to be working either. Here's some sample code I've been playing with:

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

{{ instrument.instrumentName }}

          {% for person in craft.entries.section('person').relatedTo( instrument ) %}

{{ person.personName }}

          {% endfor %}
        {% endfor %}

You were right about the issue being that the relationship is made within a Matrix field. Because of this, you have to explicitly pass the Matrix field's handle to the relatedTo parameter.

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

{{ instrument.instrumentName }}

      {% set people = craft.entries.section('person').relatedTo({
         targetElement: instrument,
         field: 'roles.instrument'
      }) %}
      {% if people|length %}
         {% for person in people %}

{{ person.personName }}

         {% endfor %}
      {% else %}

Nobody plays {{ instrument.instrumentName }} :(

      {% endif %}
{% endfor %}

Note: Using a dot notation to specify the sub-field is only necessary if you have multiple relational fields within a Matrix, but it can't hurt.


get post data after submitting User Profile Form for success message After a logged-in user updates their profile on the front end, I'd like to redirect them to the same page but show a success message. I believe I can do this with craft.request.getPost() but it's not working for me.  Code below:

<input type="hidden" name="test" value="xyz">

and then

{% set success = craft.request.getPost('test') %}
{% if success %}
    Success message
{% endif %}

I can see "test" in my dev tools network tab but can't seem to access it.

Not possible – any input values added to your profile editing form (such as test in your case) will be included in the POST request to the users/saveUser controller action, but they won't actually be included in the redirect request back to the page (or to whatever URL is in your form's hidden redirect input).

As a workaround you can always check for the Flash notice that the UsersController sets after the user is successfully saved:

{% if craft.session.getFlash('notice') == 'User saved.'|t %}

Success message!

{% endif %}