Asset indexing failing with large asset source I've got an asset folder where i need to bring over about 20Gb of assets, obviously trying to update asset indexes from the Craft Cpanel is causing a serious failure.

Other than adding my assets in smaller chunks is there any other option to make it less memory intensive?

If the assets were on S3 rather than local, would it be less intense?

I've done this before with a combination of a Craft console command that replicates the indexing process, and a external way that processes each row.

<?php
namespace Craft;

class BusinessLogicCommand extends BaseCommand
{
    /**
    * ./craft/app/etc/console/yiic businesslogic --offset=x --sourceId=y --sessionId=z
    */
    public function actionIndex ($offset = '', $sourceId = '', $sessionId = '')
    {
        if ( $offset ) {
            $index = craft()->assetIndexing->processIndexForSource($sessionId, $offset, $sourceId);

            if ( $index ) {
                echo sprintf("Processed offset: %s for source %s", $offset, $sourceId);

                return 1;
            }
        }

        return 0;
    }

    /**
    * ./craft/app/etc/console/yiic businesslogic getIndexOverview
    */
    public function actionGetIndexOverview ($sourceIds = '')
    {

        // Get batches
        $batches   = array();
        $sessionId = craft()->assetIndexing->getIndexingSessionId();

        // Selection of sources or all sources?
        if ( $sourceIds ) {
            $sourceIds = explode(',', $sourceIds);
        }
        else {
            $sourceIds = craft()->assetSources->getViewableSourceIds();
        }

        $missingFolders = array();
        $grandTotal     = 0;

        foreach ($sourceIds as $sourceId) {
            // Get the indexing list
            $indexList = craft()->assetIndexing->getIndexListForSource($sessionId, $sourceId);

            if ( !empty($indexList['error']) ) {
                echo json_encode($indexList);

                return 0;
            }

            if ( isset($indexList['missingFolders']) ) {
                $missingFolders += $indexList['missingFolders'];
            }

            $batch = array();

            for ($i = 0; $i < $indexList['total']; $i++) {
                $batch[] = [
                    'sessionId' => $sessionId,
                    'sourceId'  => $sourceId,
                    'total'     => $indexList['total'],
                    'offset'    => $i,
                    'process'   => 1,
                ];
            }

            $batches[] = $batch;
        }

        // Overview

        $assetsSourcesBeingIndexed = $sourceIds;
        $assetsMissingFolders      = $missingFolders;

        $job = [
            'batches' => $batches,
            'total'   => $grandTotal,
        ];

        echo json_encode($job);

    }

    public function actionCleanUpIndex ()
    {
        // Get overview
        $sourceIds      = $assetsSourcesBeingIndexed;
        $missingFiles   = craft()->assetIndexing->getMissingFiles($sourceIds, $sessionId);
        $missingFolders = $assetsMissingFolders;

        $responseArray = array();

        if ( !empty($missingFiles) || !empty($missingFolders) ) {
            $responseArray['confirm'] = craft()->templates->render('assets/_missing_items', array( 'missingFiles' => $missingFiles, 'missingFolders' => $missingFolders ));
            $responseArray['params']  = array( 'finish' => 1 );
        }
        // Clean up stale indexing data (all sessions that have all recordIds set)
        $sessionsInProgress = craft()->db->createCommand()
                                        ->select('sessionId')
                                        ->from('assetindexdata')
                                        ->where('recordId IS NULL')
                                        ->group('sessionId')
                                        ->queryScalar();

        if ( empty($sessionsInProgress) ) {
            craft()->db->createCommand()->delete('assetindexdata');
        }
        else {
            craft()->db->createCommand()->delete('assetindexdata', array( 'not in', 'sessionId', $sessionsInProgress ));
        }

    }

}

This is done in 3 steps:

Trigger getIndexOverview, which returns an JSON object string that lists all your index rows.
Use the JSON object in some way, and create a job for each row, which should trigger step #3.
Trigger the index command with the parameters  --offset=x --sourceId=y --sessionId=z

I have used Laravel + Queue backed by Redis for this. If you have huge files, or a lot of data to process, think about spinning up a big VPS somewhere.

That way you can run 10-12 jobs in parallel, export your database/file structure, and tear the VPS down after. With hourly pricing, you'd end up paying a few $.


Values from fields in templates I have categories in my cms.

How do I gets a list of these value into my templates?

Thanks.

This is all covered in the Craft CMS documentation:

{% for option in entry.<FieldHandle> %}
    Label: {{ option.label }}
    Value: {{ option }} or {{ option.value }}
{% endfor %}


Any problems installing Craft on CentOS with SELinux enabled? Seriously considering installing Craft on CentOS w/SELinux.  I currently have it running on Ubuntu.  Anyone have any problems with that type of install?

thanks,

Chip

Someone with more CentOS experience will probably want to chime in—like you I'm more familiar with Debian/Ubuntu—but I can't imagine it wouldn't work, assuming you configure SELinux correctly and you're using at least CentOS 6, preferably the latest.

Basically, SELinux is an kernel level gatekeeper, preventing or allowing certain processes from reading/writing to parts of the file system.

In terms of how that affects Craft, you'll need to make sure it knows that Apache/PHP is allowed to write to /craft/app, craft/config and craft/storage and whatever upload directories you have setup.

Just perusing the SELinux docs and problems people have had with Yii and WordPress, assuming your Craft install is at /var/www/craft/ running something like:

cd /var/www/craft/
chcon -R -v -t public_content_rw_t app/ config/ storage/

... should open up the permissions. There's more to it than that obviously.

If you run PHP as an FPM pool/CGI, as I do, that's going to affect permissions as well.

This article is based around setting up permissions for WordPress but it's still applicable for Craft.


Can a structure have multiple parents? Can entries of type structure have multiple parents?

https://docs.craftcms.com/v3/sections-and-entries.html#sections says that they can be hierarchical, but the UX doesn't seem to let me have more than one parent for any given child structure.

Not sure if that is a hard limit or just something misconfigured on my end.

I searched around a bit and saw this answer: Structure entry connected to multiple parent entries which implies that the way to do this is to use relations, not structures, but wanted to confirm.

Short answer is "no, you can't have more than one parent."

Using relationships is probably the best answer. It's unfortunate that Luke didn't expand on his comments and add an official answer (in that other thread), but he was on the right track.

If you create a relationship field, you can relate your entry to as many other entries as you need.


How do I add meta data and a page title through ajax? I have looked a lot through this StackExchange but I guess I am not too advanced in using AJAX/Json.

My aim is to have page transitions using Ajax. This was rather easy to accomplish following this article:
https://designbycosmic.com/journal/craft-cms-ajax-page-transitions-with-history-pushstate

Now what this article is missing out is the updating of the page title and meta tags. I have done a lot of searches and from what I understand I need to build json files for each page/entry.

So I installed ElementAPI and tried to get the basics working

    <?php
namespace Craft;

return [
    'endpoints' => [
        'news.json' => [
            'elementType' => 'Entry',
            'criteria' => ['section' => 'news'],
            'transformer' => function(EntryModel $entry) {
                return [
                    'title' => $entry->title,
                    'url' => $entry->url,
                    'jsonUrl' => UrlHelper::getUrl("news/{$entry->id}.json")
                ];
            },
        ]
    ]
];

But I am getting stuck at this point.
I know that I can get the jquery through

  $.ajax({
      type: 'get',
      url: 'news.json',
      data: {
        format: 'json'
      },
      success: function(result){
        $main.html(result);
      },
      error: function(){
        console.log("error.");
        location.reload();
      }
    });

But if I do that I am getting an empty body that loads nothing.

I kind of am stuck here as my knowledge ends.

I would be very grateful for any information on how to progress. I am really looking to understand how this works but without having at least a working model it's hard for me to analyze and reverse-engineer the code.

You almost certainly don't have to update the meta tags when you use AJAX to load pages like this.

Meta tags are not exposed to the end user; they're there for search engine crawlers and social media embedding (e.g. Facebook) etc. Crawlers will read the meta tag values from the original HTML at the URL being crawled or shared, not whatever values you update to using JavaScript in an AJAX callback.

On the other hand, updating the page/document title can be a good idea, as users will see this value in their browser.

You can update the document title simply by setting

document.title = "Who let the dogs out?"

somewhere in your JavaScript. A good place to do this in regards to the tutorial script you're using would be inside the ajaxLoad() method, i.e.

ajaxLoad = function(html) {
    init();

    /* ----- Here you could maybe add logic to set the HTML title to the new page title ----- */
    document.title = "Who let the dogs out?";

    ...
},

Of course, you'll want to set the document title to something relevant – preferably the "real" page title for that URL. You certainly could use the ElementAPI plugin to pull your entry's title, but that would mean a ton of work and an additional AJAX request. A much simpler way to do it is to set a data-attribute somewhere in the markup returned by the original AJAX call, e.g.:

<div class="js-ajax-wrapper" data-title="{{ siteName }}: {{ entry.title }}">
    {{ entry.body }}
    ...
</div>

And then do something like this in your ajaxLoad() method:

ajaxLoad = function(html) {
    ...
    document.title = $('<div />').append(html).children('.js-ajax-wrapper').data('title');
    ...
},

Note that the designbycosmic.com script has a small bug – in order for the above to work you'll have to change the call to ajaxLoad() inside the success callback for the loadPage() method to ajaxLoad(result); – alternatively, you can ignore the ajaxLoad() method and just change the document title inside the success callback:

success: function(result){
    ...
    document.title = $('.js-main .js-ajax-wrapper').data('title');
    /* ----- Bring In New Content ----- */
    ...
},

Finally, as an aside your issue with the ElementAPI plugin is that you're returning a JSON payload (containing only the title, url and jsonUrl for the entry), yet you're attempting to inject that data into the DOM as HTML (i.e. $main.html(result);.


302 redirect when updating the cart via Ajax using Craft Commerce 2 I'm working on a site that has recently migrated from Craft v2 with Commerce v1 to Craft v3 with Commerce v2.

Using Commerce v1 I was able to update the cart via Ajax and get a data object with the state of the cart as a response.

After updating to Craft Commerce v2 the ajax requests fail, returning Status 302 - Redirect instead of the data object, although the changes to the cart are successful.

I can add one or more products or change their quantity via Ajax, however, I need the data object in order to properly update the state of the cart without reloading the page.

I'm running Craft v3.0.10.2 with Craft Commerce from dev-develop commit 1db58f6 on a machine running PHP v7.1.12
The action I'm using is commerce/cart/update-cart
The method of all requests is POST
Any form data should to be ok since the cart updates succesfully
All requests are sent with the following headers:

Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest

I'm I missing anything new in CC2? Any help would be much appreciated.

The function contains this

if ($request->getAcceptsJson()) {

Thus you'll need to set the dataType in your ajax request to json or text/json in order to not get redirected. If you didn't set it correctly Craft will treat it as a normal post request instead of an ajax request


Can I add custom JS to Sprout Form? I'd like to be able to attach custom JS to a Sprout Form which can be managed in the form builder. I need to add logic that will switch the email address of the recipient based on a choice from a select menu. For example, "Website Issues" goes to "websupport@mywebsite.com", and "Information" goes to "info@mywebsite.com".

Ideally this JS would be managed at the form builder level so it only loads for that specific form.

I'm in the testing phase of Sprout Forms, so I apologize if I'm missing something obvious.

You can do this with the default Email Dropdown field (no JS needed!). The Email Dropdown field lets you create a mapping between an item in the dropdown and an email:

Website Issues: websupport@mywebsite.com
Information: info@mywebsite.com

The Email Dropdown field obscures those emails in your template. And when you set up your Notification Email, you can reference your Email Dropdown field by its handle in your Recipients setting: {emailDropdownFieldHandle}

In the case you ever did wish to add JS to your templates, the best way to add it to your template is to use Template Overrides.


How do you use the Element API plugin to output Matrix blocks for an entry? I am having a hard time trying to figure out how to pull matrix blocks within an entry into the single entry's endpoint with the Element API plugin.

Is this possible? Or do I need to output the blockId's and then create another API endpoint to query by the matrix block id?

Totally possible. Just loop through the blocks and add whatever data you want from them to the response array:

'transformer' => function(EntryModel $entry) {
    // Create an array of all the "Body" Matrix field's blocks
    $bodyBlocks = [];
    foreach ($entry->body as $block) {
        switch ($block->type->handle) {
            case 'text':
                $bodyBlocks[] = [
                    'text' => $block->myRichTextField->getParsedContent(),
                ];
                break;
            case 'image':
                $image = $block->myAssetsField->first();
                $bodyBlocks[] = [
                    'image' => $image ? $image->getUrl(['width' => 500]),
                    'caption' => $block->myPlainTextField,
                ];
                break;
        }
    }

    return [
        'title' => $entry->title,
        'url' => $entry->url,
        'description' => (string) $entry->description,
        'body' => $bodyBlocks
    ];
},

Each of the elements in that sub-array will be MatrixBlockModel objects.


Getting blank screen at domain.com/admin when installing I'm trying to install Craft for the first time, I've used Ben Croker's requirements check and everything passes, and I'm pretty sure everything else is set up properly, but when I access domain.com/admin to run the install, I just get a blank screen - no errors, warnings or messages.

I've tried installing in a subdomain (my preference) as well as in the root, with the craft dir both above and below the root, but get the same result no matter what the config.

I've checked the logs (craft.log) and it gets this far (see below). There is no phperrors.log file. Does anyone have any ideas where I should check next?

2014/08/20 11:49:16 [info] [application] $_GET=array (
  'p' => 'admin',
)

$_SERVER=array (
  'DOCUMENT_ROOT' => '/xxx/xxx/public_html',
  'GATEWAY_INTERFACE' => 'CGI/1.1',
  'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
  'HTTP_ACCEPT_ENCODING' => 'gzip,deflate,sdch',
  'HTTP_ACCEPT_LANGUAGE' => 'en-US,en;q=0.8,es;q=0.6,fr;q=0.4,it;q=0.2,ja;q=0.2,pl;q=0.2,ru;q=0.2',
  'HTTP_HOST' => 'xxx.xx.xx',
  'HTTP_PROXY_CONNECTION' => 'keep-alive',
  'HTTP_USER_AGENT' => 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36',
  'PATH' => '/bin:/usr/bin',
  'QUERY_STRING' => 'p=admin',
  'REDIRECT_QUERY_STRING' => 'p=admin',
  'REDIRECT_STATUS' => '200',
  'REDIRECT_UNIQUE_ID' => 'U-SLOlmRTRcABtAqnnkAAAAx',
  'REDIRECT_URL' => '/admin',
  'REMOTE_ADDR' => 'xx.xx.xx.xx',
  'REMOTE_PORT' => '62291',
  'REQUEST_METHOD' => 'GET',
  'REQUEST_URI' => '/admin',
  'SCRIPT_FILENAME' => '/xxx/xxx/public_html/index.php',
  'SCRIPT_NAME' => '/index.php',
  'SERVER_ADDR' => 'xx.xx.xx.xx',
  'SERVER_ADMIN' => 'xxxxx',
  'SERVER_NAME' => 'xxxxxx',
  'SERVER_PORT' => '80',
  'SERVER_PROTOCOL' => 'HTTP/1.1',
  'SERVER_SIGNATURE' => '',
  'SERVER_SOFTWARE' => 'Apache',
  'UNIQUE_ID' => 'U-SLOlmRTRcABtAqnnkAAAAx',
  'PHP_SELF' => '/index.php',
  'REQUEST_TIME_FLOAT' => 1408535356.3350970745086669921875,
  'REQUEST_TIME' => 1408535356,
)
2014/08/20 11:49:16 [trace] [system.CModule] Loading "db" application component
in /xxx/xxx/xxx/craft/app/etc/web/WebApp.php (642)
in /xxx/xxx/xxx/craft/app/etc/behaviors/AppBehavior.php (69)
in /xxx/xxx/xxx/craft/app/etc/web/WebApp.php (799)

I'm documenting this here in case it helps someone else. My white screen during installation was caused by a missing comma between array items in my general.php and db.php config files. Once I added it, the install page loaded correctly.


Is there a way to find out if images (assets) are landscape or portrait? In a current project we will list entries in a masonry-style grid view where the entry’s respective cover image should be styled differently based on their image format. Landscape vs. portrait and -- of course -- square.

I haven’t found anything on here or in the docs pointing to a possible way of doing this.

How about just using the getHeight() and getWidth() methods available on the AssetFileModel? Something like this:

{% set myImage = entry.imagesField.first %}

{% if myImage.getWidth() < myImage.getHeight() %}
  {# portrait #}
{% elseif myImage.getWidth() > myImage.getHeight() %}
  {# landscape #}
{% else %}
  {# square #}
{% endif %}


Show Disabled Entries I have a page on one of my sites which requires entries to show even if the entry is disabled, but just greyed out. Is there a way I can disable an entry and make it still show up on my webpage?

I have tried using {% if not entry.enabled %} but it doesn't show up either way. Also I'd rather it showed up in the order its laid out in the admin, not before or after.

The field I am trying to display is an entries field which is taking data from another Structure and is disabled in that Structure, not the one which it is being called into.

Anyway of doing so?

You need to include a status(null) to the ElementCriteriaModel to search for disabled entries.

{% set enties = craft.entries.status(null).find() %}

If you have a RelationField you would just add it before you fetch the entries

{% set relatedEntries = entry.myAwesomeField.status(null).find() %}


Check if entry has a descendant with a certain field enabled Whew, complicated thing to described in a short subject line! :)

Okay, so I have a structure like this:

Asia

Peking

weekend ( field howLongWillYouBeGoing == 'shortStay' )
long weekend ( field howLongWillYouBeGoing == 'mediumStay' )
week ( field howLongWillYouBeGoing == 'longStay' )

Europe

Peking

weekend ( field howLongWillYouBeGoing == 'shortStay' )

South America
(no subpages)

I have a navigation bar that just lists the continents and turns them into a link as soon as it has descendants. When it doesn't have descendants, it just shows the continent name as a non-clickable text.

Now this is the thing. I have used the following code, but it doesn't work. It still shows Europe in this example as a link, even though I believe the conditions are not met. I would LOVE love love any input because I've been staring myself blind on this the last few hours :)

{# loop through continents #}
{% for entry in craft.entries.section('destinations').type('continent').find() %}
    {# only show links to continent pages if it has any travelguides #}
    {% if entry.hasDescendants(3) %}

        {% set mediumStay = 0 %}
        {% for subPage in entry.getDescendants(2) %}
            {% if subPage.howLongWillYouBeGoing == 'mediumStay' %}
                {% set mediumStay = 1 %}
            {% endif %}
        {% endfor %}

        {% if mediumStay == 1 %}
            {# if subpage is marked as mediumstay, show a link to it #}

{{ entry.title }}

        {% endif %}
    {% else %}

{{ entry.title }}

    {% endif %}
{% endfor %}

Wow - thanks for listening ;-)

I solved it like this:

{# loop through continents #}
{% for entry in craft.entries.section('destinations').type('continent').find() %}
    {# only show links to continent pages if it has any travelguides #}
    {% if entry.hasDescendants() %}
        {% set continentID = entry.id %}
        {% if entry.howLongWillYouBeGoing == 'mediumStay' in craft.entries.section('destinations').descendantOf(continentID) %}
            {# if subpage is marked as mediumstay, show a link to it #}

{{ entry.title }}

        {% else %}
            {# if it's not a mediumStay, just show the text #}

{{ entry.title }}

        {% endif %}
    {% else %}

{{ entry.title }}

    {% endif %}
{% endfor %}


Is it possible to output month names in my native language? I'm doing this:

{# Get events from `events` section in desired sort order #}
{% set allEvents = craft.entries.section('events').order('eventsDate asc') %}

{# Loop through `allEvents` and print the list #}
{% for event in allEvents %}
    <li>{{ event.title }} - {{ event.eventsDate|date('j F, Y') }}</li>
{% endfor %}

I guess I can do something with this: http://php.net/manual/en/datetime.formats.date.php, but I need to display months in my native language, which is slightly different from how Craft outputs it.

For example I'd like it to say "7 des", not "07 dec", "15 mai", not "15th may" and so on.

Yes, the date() filter you use (see Twig docs) allows you to format dates with the same formating characters as the php date function takes. All language dependent parts are returned in the language of the current locale. I don't know if you can change that primary locale in the control panel, but you could do that in the DB.

As you noted in the comments to your question, you want the CP to be in english. This is possible even if you set the site's locale to another language; the site's locale and the user language for the CP are different things.


Need somebody to help us with our existing Craft web page Our developer has disappeared and we need some help in changing and adding a few things on our website (www.fincarosablanca.com)? Would like to have somebody in Costa Rica but it doesn't really matter.

Sorry to hear about your disappearing developer.

Stack Exchange as a Q&A site usually isn't the best place to find a developer, unless you'd like to post to Stack Overflow Jobs (https://stackoverflow.com/jobs).

For Craft specific developers, there are a couple of places you could look:

https://craftcms.com/partners
https://www.workwithcraft.com/
https://straightupcraft.com/jobs
The Craft Slack #jobs channel: https://craftcms.com/community#slack


Exclude entry based on segment I am trying to exclude the current entry in a "Recommended Reading" section which works at level 1 with the ID tag, but I also need it to do the same at level 2 (children).

 `{% for entry in craft.entries.section('Thunder').level(1).id('not '~entry.id).limit(3).order('RAND()') %}`

The level 1 entry is the Article and the level 2's are the Chapters. The recommended reading section displays other Articles and should therefor exclude the level(1) article also when viewing the Chapters.

Should I use craft.request.getSegment(2) to exclude the current entry, but how do you write that conditional statement?

Url structures are:

/site/article
/site/article/chapter

Section: Structure

No matter how many levels there are in your structure ancestorOf will fetch level one entry. entry.parent could be used but covers only one level up.

{% set excludeEntry = entry %}
{% if entry.level > 1 %}
    {% set excludeEntry = craft.entries.ancestorOf(entry).level(1).first() %}
{% endif %}

{% for entry in craft.entries.section('Thunder').level(1).id('not '~excludeEntry.id).limit(3).order('RAND()') %}
...
{% endfor %}


Change password messaging per site? I have several sites running under one Craft install. Two of them are for our internal use, and one is public-facing. On the public-facing site, I need to provide a reset password function. When the email is generated to the user, it looks like this:

{Name of primary site} info@primarysite.com
Wed 2/24/2021 1:13 PM
Hey Ben,
To reset your {name of primary site} password, click on this link:
https://public-facing-site.edu/admin/set-password?code=nwKE16ULcdBfj30IDhfZWz4IOjlhkkjlf8hi75fi87aw5f8o75of757i8

Is it possible to customize this email to reflect the site which the user has accessed? Note that the domain name part of the password reset URL is the correct public-facing one. I see the area Utilities > System Messages where I can customize this, but the email still includes reference to the primary site.

You can do this by overriding fromName and fromEmail in the mailer component config based on your site handle (or language).
You would do this in your config/app.php like so:
'components' => [
    'mailer' => function() {
        // Fetch the site the user is on
        $currentSiteLanguage = Craft::$app->getSites()->currentSite->handle;

        // Fetch the stored email settings
        $settings = craft\helpers\App::mailSettings();

        // Define the name and email address based on language. Change `public` to match your own site handle
        $fromName = $currentSiteLanguage == 'public' ? 'From your public site' : 'Default from name';

        $fromEmail = $currentSiteLanguage == 'public' ? 'email@public.site' : 'default@email.address';

        // Apply the name to existing settings
        $settings->fromName = $fromName;

        // Apply the name to existing settings
        $settings->fromEmail = $fromEmail;

        // Create a Mailer component config with these settings
        $config = craft\helpers\App::mailerConfig($settings);

        // Instantiate and return it
        return Craft::createObject($config);
    },
],


Is it possible to use the ElementType Modal UI for a custom Field Type Plugin? So I'm writing a plugin to try and create a relationship between two entry sections that is a two way street (Many to Many).

I would love to co-opt the UI and functionality of the ElementType modal for a predefined section ID and then do my own saving logic.

In other words, I would just like to use the front end form functionality and handle the backend logic myself. Is this possible?

Thanks!

Yep, you can do that with Craft.createElementSelectorModal():

var myModal = Craft.createElementSelectorModal('Entry', {
    resizable:          true,
    storageKey:         'someUniqueID',
    sources:            ['section:1', 'seciton:2'],
    criteria:           { status: null },
    multiSelect:        true,
    disabledElementIds: [1, 2, 3],
    disableOnSelect:    true,
    onCancel:           function(){},
    onSelect:           function(entries){}
});

The first argument specifies what type of element you want to be selecting (Entry, Asset, etc.), and the second argument defines the settings.

All of those settings are optional except for onSelect. Here’s what they do:

resizable (bool) – Whether the modal should be user-resizable. (Defaults to true)
storageKey (string) – The storage key prefix that the modal will use to save its state in the browser’s localStorage, including things like which source was selected. (Defaults to null)
sources (array) – Which sources should be shown in the modal’s sidebar. If omitted, all sources will be shown. (Defaults to null)
criteria (object) – The params that will be used to determine which elements will be shown. See the craft.entries documentation for available params when selecting entries. (Defaults to null)
multiSelect (bool) – Whether multiple elements should be able to be selected at once. (Defaults to false)
disabledElementIds (array) – A list of element IDs that should be disabled (unselectable). Pass any elements that are already selected in here, so they can’t be double-selected. (Defaults to an empty array)
disableOnSelect (bool) – Whether the modal should automatically disable elements when they are selected. (Defaults to false)
onCancel (function) – A function that should get called when the modal is cancelled without selecting anything.
onSelect (function) – A function that should get called when elements have been selected.

The onSelect function will get passed an array that contains info about each of the selected elements. Each item in the array will have the following properties:

id – The element’s ID
label – The element’s label (the Title if it’s an entry)
status – The element’s status
url – The element’s front-end URL, if it has one
hasThumb – Whether the element has a thumbnail
$element – A jQuery object for the element, which you can append to your field input

Once you’ve created your modal, it will automatically be shown. It will also be automatically closed when it is cancelled out of, or elements are selected.

You can re-open it later by calling myModal.show().


Unable to manage robots.txt in Craft I would like my robots.txt file to be generated by Craft. Things that I have tried that don't work:

a craft/templates/robots.txt template
a craft/templates/robots.txt.twig template
a route for robots.txt that points to a robots.twig template

Both of these work fine for a foo.txt file. The error I get is 404,  not the Craft 404, but the system one - nginx.

You can simply create a 'robots.txt' file in your templates folder and populate it using twig (templates do not need to end in .twig). Not sure what you're trying to control exactly, but something like this should technically work.

User-agent: *
{% set entries = craft.entries.limit(null) %}
{% for entry in entries %}
    Disallow: {{ entry.uri }}
{% endfor %}

Terrible example but you get the idea. Then just delete the robots.txt file that is in your public folder.


Assign user group to group of entries In the CP, is it possible to assign a user group to selected entries within a section.

For example, say I have a section called Events. Within that section I have a fieldType called company.

Can I create a user group called Company 1 where users within it can only see/edit entries within Events section that has its company field selected as Company 1?

Trying to ascertain if its possible to allow users from multiple companies access to the CP, but heavily restrict what they can access.

Thanks!

Nope. It isn't possible to set permissions for individual entries (based on a field value, entry type or any other criteria).


Contact Form plugin email is not being received, not clear if it is being sent I am using the Pixel & Tonic Contact Form plugin.  I set it up using the Mijingo tutorial.  Everything appears to be working ...

I hit submit, redirects to thank you, no message received.  Setup looks good.  Hidden input fields appear good.  Error messages working when required inputs (fromEmail and message) left blank.  Redirects to thank you.  Honeypot setup looks good.   But, no message received.  And I don't know how to confirm it is really being sent.  What might I try? Thanks

I am in dev mode

There's a good article here for troubleshooting email errors and well as email deliverability issues: https://craftcms.com/support/troubleshooting-email-errors

TL/DR: Don't use PHP's mail/sendmail methods in production and even in development, you aren't guaranteed email deliverability with those.


Enable client to add users to user group but not set permissions I need my client (typical editor account in CMS) to be able to add/modify/delete users in the CP. I don't want him to have access to groups/permissions for users, but I need to put every user he creates into the same group (Site Users).

The existing plugin - https://github.com/lindseydiloreto/craft-autoassignusergroup - doesn't work if the client doesn't have the "Assign user groups and permissions" checked.

Is there a way to force every new user created in the CP by the client into a default group? Or a way to give him "Assign user groups" but not "and permissions"?

doesn't work if the client doesn't have the "Assign user groups and permissions" checked.

That's not a limitation of the plugin, but a requirement of Craft.

  Is there a way to force every new user created in the CP by the client into a default group?

Yes, that's what the previously linked plugin will do, with the caveat that the currently logged in user has to have assignUserPermissions permissions.

The only way I can think of to do what you're trying to accomplish is build the user administration stuff for your client on the front-end of the site.  That way - though a plugin - you've got complete control over the user management business logic.


Importing Craft CMS Locally I've inherited an existing website created using CraftCMS and hosted on Fortrabbit.

I'm fairly new to CraftCMS but anxious to get started on a couple of updates. The site currently exists on Fortrabbit. I have SSH and SFTP access and can see the files and have a fresh version of CraftCMS locally installed but unsure how to bring in the files. I'm aware it's built on the server so just not sure what parts I need to bring locally.

I have already grabbed and imported the DB to the MySQL content but just need this last step.

Many thanks.

So having tried bringing it locally and getting a multitude of errors, I realized the live site was version 2 and I was installing version 3.

Following the upgrade guide solved it for me (among some minor plugin tweaks).


Purging inactive carts in Craft Commerce I've a Commerce store with orders dating back to September and have the following in my config:

'purgeInactiveCarts' => true,
'purgeInactiveCartsDuration' => 'P1M',

The docs say that the purging should be triggered by me visiting the Inactive carts area of the Commerce order section, but it isn't. Does anyone know if:

The trigger is time limited, e.g. is only called once a day?
There are any known issues with the purging of inactive carts?
Anything else I could look at?

The mistake was not reading the docs properly and putting the config values in general.php. Instead, I needed to create a commerce.php config file and put the values in that. As soon as I did, the orders were purged.


When using .limit on matrix blocks they don't show in live preview I have a Matrix field setup and working perfectly except for one problem.

In my template I'm using .limit to only pull the first two items from the matrix field (I can't use max in the field settings as I'm using the same field on other pages that allow more than two blocks to show).

Using the following line to pull the Matrix blocks works fine in the live preview.

{% for serviceBlock in entry.serviceBlocks %}

But adding the limit stops Craft showing the blocks in the live preview. Though the rest of the template loads and updates perfectly.

{% for serviceBlock in entry.serviceBlocks.limit(2) %}

I'm not getting any errors, and if I save the page and reload the live preview it will render the blocks perfectly, but not update the content live.

Has anyone encountered this problem, or have an idea that might help?

I noticed the same issue with live preview, but using the type property on the Matrix field: Issue with Matrix type property and Live Preview? According to Brandon's answer this is a current bug / limitation of the Matrix field that you have to find a workaround for.

In this case this is rather easy, get all the blocks and use the slice filter to loop over a subset:

{% for serviceBlock in entry.serviceBlocks|slice(0, 2) %}


Element API: PHP Error: Fatal error: Allowed memory size of 33554432 bytes exhausted Trying to get this json api to work for us and keep running into issues. Here, when trying to list all items, it throws the following PHP error:

  Fatal error:  Allowed memory size of 33554432 bytes exhausted (tried to allocate 65552 bytes) in /home/accesstrucks/craft/app/framework/YiiBase.php on line 618

There are only 100 listings currently, but this is just for testing. Which is nothing compared to how many listings there will be when live.

Here's my code:

return [
  'endpoints' => [
    'alltrucks.json' => [
      'elementType' => 'Entry',
      'criteria' => ['section' => 'trucks'],
      'paginate' => false,
      'transformer' => function(EntryModel $entry) {
        return [
          $entry->year.' '.$entry->manufacturer.' '.$entry->model,
          (string)$entry->author,
          !empty((string)$entry->category[0]) ? (string)$entry->category[0] : null,
          !empty($entry->listingPhotos[0]->url) ? str_replace('/images/uploads/listings/', '', $entry->listingPhotos[0]->url) : null,
          ($entry->saleType=='new') ? '0' : '1',
          (string)$entry->featured,
          ($entry->saleType->label=='new') ? '0' : '1',
          $entry->transmission,
          (string)$entry->dateUpdated,
          $entry->mileage,
          $entry->price

Your php.ini file's memory_limit setting is set to 32M.

You'll want to bump that up to something higher like 256M.


Sprout Form Not Saving Entries We have a Sprout Forms form being used for gated content access. The form appears to work correctly but none of the entries are appearing in the database/CMS.

Here is an example URL with the form: http://thisisbeyond.co.uk/blog/feel-good-brands-report-2015/

Below is a CMS screenshot of the form settings.

Below is the template code we are using to generate the form:

{% if craft.request.getParam('message') == 'success' %}

Thank you for your message, we'll get back to you as soon as possible.

{% else %}

{% macro errorList(errors) %}
{% if errors %}
{% for error in errors %}
{{ error }}
{% endfor %}
{% endif %}
{% endmacro %}

{% from _self import errorList %}

<form method="post" action="" accept-charset="UTF-8">
{{ getCsrfInput() }}
<input type="hidden" name="action" value="sproutForms/entries/saveEntry">
<input type="hidden" name="handle" value="gatedForm">
{% set gated = entry.gatedDocument.first() %}
<input type="hidden" name="redirect" value="{{ gated.url }}">

    Full Name *
    <input type="text" name="fields[fullName]" id="fields-fullName" class="form-control" value="{% if gatedForm.fullName is defined %}{{ gatedForm.fullName }}{% endif %}" required/>
    {% if gatedForm is defined %}{{ errorList(gatedForm.getErrors('fullName')) }}{% endif %}

    Company Name *
    <input type="text" name="fields[companyName]" id="fields-companyName" class="form-control" value="{% if gatedForm.companyName is defined %}{{ gatedForm.companyName }}{% endif %}" required/>
    {% if gatedForm is defined %}{{ errorList(gatedForm.getErrors('companyName')) }}{% endif %}

    Email *
    <input type="text" name="fields[email]" id="fields-email" class="form-control" value="{% if gatedForm.email is defined %}{{ gatedForm.email }}{% endif %}" required/>
    {% if gatedForm is defined %}{{ errorList(gatedForm.getErrors('email')) }}{% endif %}

    <button type="submit" class="btn btn-primary">Submit</button>

</form>

{% endif %}

UPDATE: re-installing the Sprout Invisible Captcha plugin and including the following line before the closing  tag got it working:

{{ craft.sproutInvisibleCaptcha.protect() }}

Re-installing the Sprout Invisible Captcha plugin and including the following line before the closing tag got it working:

{{ craft.sproutInvisibleCaptcha.protect() }}


Are there any poll plugins for Craft CMS? Since many of us are coming from EE, I will reference these EE addons as examples:
- channel polls
- vwm polls

I found this question but it didn't help much:
How to deal with client input your site?

Also there is UPVOTE plugin but it's not really polls.
https://www.doublesecretagency.com/plugins/upvote

It is important that it works like field type and that you can add as many options as you need.

Thank you

The only public listing of plugins that I'm aware of is on the straightupcraft site — so if nothing is there that meets your requirements then probably not. New plugins are getting added all the time though.

Depending on your requirements, developing a custom solution would probably not be too difficult though. If you want to give it a shot and have questions feel free to ask.


Why does asset creation not work for hidden images? Im creating a gallery for Fancybox and only wish to show the first image. The rest are hidden in a container and only referenced so that Fancybox can call on these latter. I've tried two approaches: anchor tag with and without the image tag.

I am sure that this is a recent change as I have been using this technique on earlier craft versions and gettting good results.

The image is generated but it looks like in a temporary location "...cpresources/transforms..." to which Fancybox doesn't recognise.

Set generateTransformsBeforePageLoad in your config/general.php file.

'generateTransformsBeforePageLoad' => true,

  Configures Craft to generate new image transforms right when getUrl()
  is called, rather than when the browser first requests the image.


All categories selected by default for an entry Is it possible to create an entry, and have all the categories added by default ?

Let's say I have a category called 'materials', with values like 'gold', 'silver', 'copper'... They should all be added to the entry by default, with the possibility to remove them afterwards

Is this possible in Craft ?

There's not a native way to do this, but you could probably pull it off in a plugin that utilized the cp.entries.edit template hook and modified the field data directly (selecting whatever categories you want) before returning it to the template.


Rich Text - Redactor doesn't allow iframe even when in allowedTags config setting I've updated my craft/config/redactor/UserContent.json settings with allowedTags containing iframe but iframe tags are stripped on save.

Other added allowedTags seem fine and iframe works on paste and initial editing, just not after saving.

Running Craft Pro 2.4.2679

I see there were issues with this for older versions of Redactor but they seem to be resolved. Any ideas about how to fix this?

Here's my UserContent.json:

{
    toolbarFixed: true,
    buttons: ['html', 'formatting', 'bold', 'italic', 'underline', 'deleted', 'horizontalrule',
              'unorderedlist', 'orderedlist', 'alignment', 'indent', 'outdent',
              'link', 'image', 'video', 'table'],
    removeEmpty: ['p','strong','em','span','a'],
    cleanStyleOnEnter: true,
    plugins: ['video', 'table'],
    allowedTags: ['a', 'abbr', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'blockquote', 'br', 'button', 'canvas', 'caption', 'cite', 'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'div', 'dl', 'dt', 'em', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'kbd', 'keygen', 'label', 'legend', 'li', 'map', 'mark', 'menu', 'nav', 'ol', 'optgroup', 'option', 'p', 'picture', 'pre', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'small', 'source', 'span', 'strong', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'time', 'title', 'tr', 'track', 'u', 'ul', 'var', 'video', 'wbr'],
}

If you can, update to the latest Craft build. There was a Redactor update in Craft 2.4.2682 back in July that updated Redactor and fixed issues with iFrames.


siteUrl in Twig templates not working I've got a problem where siteURL wasn't working for a localized version of my site. I have a site in two languages — Russian and English, with Russian exposed under www.mysite.com and English under www.mysite.com/en/.

My problem was that siteUrl variable was always giving me a non localized version of the site URL (www.mysite.com instead of www.mysite.com/en/) on the pages in English, even though other localized features were working fine (strings were translated into English, correct entries output etc.). See below for the solution.

The answer to this is that in the general.php I had a setup which somehow was giving trouble when setting siteUrl. Things were like this:

return array(
    '*' => array(
        'omitScriptNameInUrls' => true,
    ),
    'siteUrl' => array(
        'ru' => 'http://www.mysite.com/',
        'en_us' => 'http://www.mysite.com/en/'
    )
);

While seemingly correct, in this setup siteUrl should be moved into '*' block, otherwise there comes the problem that I described earlier. So the correct version is this:

return array(
    '*' => array(
        'omitScriptNameInUrls' => true,
        'siteUrl' => array(
            'ru' => 'http://www.issuesinlinguistics.ru/',
            'en_us' => 'http://www.issuesinlinguistics.ru/en/'
        )
    )
);


How to add attachments to emails with sprout forms I am trying to add file attachments on the notification emails sent out by sprout forms plugin. Looking in the docs it looks like I need to add hidden config setting within the plugin.

I have created a config.php file in the plugin directory and put the following code in it:

<?php

return array(

'sproutForms' => 'enableFileAttachments',

);

However, when I receive a notification email it still doesn't have the attachment. Can anyone suggest what I'm doing wrong?

It looks like your on the right track but there may be a couple issues that we need to address:

The hidden config setting should be set in the craft/config/general.php file
The enableFileAttachments config setting should also be within an array and set to true:

return array(
  'sproutForms' => array(
    'enableFileAttachments' => true,
  )
);

Note: As of this posting, we handle this functionality as a hidden config setting because we are still refining it's behavior. At some point, this will likely be easier to do directly from the Control Panel.


Is there a tool to migrate Joomla/K2 entries into Craft? I have a Joomla site with K2 installed, and a couple of thousands of articles (no custom fields) and corresponding images.

Is there a script to help migrate those into Craft? Or will I have to manually write something custom to move the content?

Thanks in advance

I'm not sure there is anything specifically for importing from Joomla, but you could try the Import plugin. Depending on the data format, you may also be able to use the Feed Me plugin.

Edit: Alternatively, a popular Craft CMS plugin maker (Barrel Strength Design) offers a commercial service to migrate/import data from Joomla -> Craft CMS. It's called The Great Migration. (NOTE: I'm nothing to do with the service, I just had it bookmarked for future reference)


Asset thumbnail size in Entries Is there a quick an easy way to change the asset thumbnail size when it's attached to an entry?

By default this is quite small and restrictive and would like to show a more representative version of the image when add/editing each entry.

I would have thought this is possible using a transform but how would this be tied back to the entry form?

No, you currently can't do that. But it's on The List! :)

See discussions in g+ here:

https://plus.google.com/110899911634334728373/posts/Q4Vi5d1y8Ry
https://plus.google.com/114292096121951987560/posts/PdXYBMxqbzb


Blog/_entry breaking all assets globals like header & footer logos When templating my Craft site, I have run into an issue with on both my Local & Server environments on the latest version of Craft. I am running a LAMP stack and I think I have been able to narrow down the issue to being a file directory issue or section config mistake.
My Blog/Index page functions perfectly and will include all asset fields without issue, yet when I click on a blog post to navigate to a blog/_entry, all assets stop functioning. Below is the twig code that I use. I have only one volume titled "images" sitting within the web/ folder.

{% for image in entry.featureImage %}
  <img src="{{ image.url }}" alt="{{ image.title }}" data-holder-rendered="true"/>
{% endfor %}

So the funky thing is that the {{ image.title }} entry seems to work perfectly and will call the image, but will not display it. Maybe this could be an issue with file organization? The same problem occurs with my global assets (logos).
Here's a screenshot of what this looks like in action.
Any direction is much appreciated! New to development & not the brightest crayon in the shed so I'm having difficulty  figuring out how to approach this problem, although I didn't seem to locate any issues among the config/ files.

If the entry is in a subdirectory, the image path will be incorrect. If the images are in a folder called "assets" in your home folder:
image.url for your main page would be "assets/imagename.jpg"
image.url for your entries in "blog" SHOULD be "../assets/imagename.jpg" BUT it will still return just "assets/imagename.jpg" instead of jumping up a directory to get the assets directory. Therefore, no image found at blog/assets/imagename.jpg.
Depending on your setup you might try img src="{{ siteUrl }}/{{ image.url }}". This will fetch the full site path to the image every time no matter what where it's called from.


Matrix: Hide preview Is it possible to hide the preview shown by default when Matrix blocks are collapsed?

  You can collapse Matrix blocks by clicking the “Collapse” menu option,
  or by double-clicking on a block’s title bar. When a block is
  collapsed, its title bar will show a preview of its content, so you
  can still identify which block it is.

It's useful to just be able to see the content outline made up by block types clear and simple. A lot of the time in my case the preview is irrelevant so it would be great to turn this off across the board by default.

There is no out-of-the-box way to do this, but you can make use of a plugin like Lindsey Diloreto's CPCSS to set display: none on the body.ltr .matrixblock > .titlebar > .preview class.


Site Headers Showing x-robots-tag: none I am having issues with search engines picking up my Craft site. I'm seeing x-robots-tag: none when reviewing my site's headers - which is shorthand for "no-index and no-follow".

The following is commented out in my nginx file as advised:
location = /robots.txt  { access_log off; log_not_found off; }
I have restarted nginx and the problem persists.
Robots.txt exists and works - I am using the SEOmatic plugin which generates the robots.txt file.
I have checked I'm using the live environment - which enables indexing.

How do I fix indexing at the header level?

Solved

There is an environment override in SEOmatic's settings. This was set to local instead of live.


Craft CMS usage of punycode Our malware scanner detected punycode as malware in /vendor/bower-asset/punycode/...

In light of punycode being used to mask some IDNs like wikipedia.org etc. I would like to know what the usage of punycode is in Craft installations.

I saw that punycode is listed under the devDependencies in /vendor/craftcms/cms/package.json however it was not installed on all of our Craft installations.

The file that's being marked as malware is:

/vendor/bower-asset/punycode/tests/data.js

I can't say officially (since I had nothing to do with building it), but it looks like the Punycode library specifically does this:

  This library converts a Unicode encoded domain name to a IDNA ASCII form and vice-versa.

I'm not sure why it's getting flagged as malware, it seems like a pretty harmless little library. If you're still concerned about it, I'd either reach out to Pixel & Tonic directly (support@craftcms.com) or post an issue on the Punycode repo.


Entries order postDate not working I'm trying to get prev/next entry using positionedAfter and positionedBefore filters but getting weird order on results because order('postDate desc') seems to be ignored.

{% set prevSibling = craft.entries.positionedAfter(entry).order('postDate desc').first() %}

{% set nextSibling = craft.entries.positionedBefore(entry).order('postDate desc').first() %}

Can anyone help?

positionedAfter only applies to entries within a structure section (https://craftcms.com/docs/templating/craft.entries#positionedAfter). See this answer for how to get next and previous entries.


Flash message in control panel In short, I've got an extra background process running that syncs content for a given section to an external application as well whenever an entry in that section is saved and a certain toggle is set on that entry.

The background process itself runs smoothly, no problems at all there.

However I get a lot of questions from the end users saying they'd like to see some visual clue (besides the added job in the background processes queue) at the bottom of the sidebar. So I thought I'd show them a notice like you see when you save an entry (small blue bar at the top of the screen) indication when the external sync is triggered.

However I can't seem to find out how I can trigger such a message.

So I've got an Event::On block that does all the needed checks and triggers the jobs, and I'd like to expand that so it also shows a message.

I think setNotice is what you're after;

Craft::$app->getSession()->setNotice('Your message');


Craft CMS throws Internal Server Error 500 I got given a Craft CMS project build with composer and npm. Pointed valet to the correct folder, installed all the dependencies and started the app with npm run watch.
http://localhost:3000 just gives me an "Internal Server Error" though...

There is nothing in the logs apart from sth inside storage/logs/web.log which does not sound like a showstopper:
2020-12-07 06:59:06 [-][-][-][error][yii\base\ErrorException:8192] yii\base\ErrorException: Method ReflectionParameter::isArray() is deprecated in /vendor/yiisoft/yii2/web/Controller.php:133 Stack trace:
Error 500 bugs are really hard to track down, any hints would be appreciated!

Based on the error message and this: https://php.watch/versions/8.0/deprecated-reflectionparameter-methods, it sounds like you're running PHP 8, which Craft isn't compatible with, yet.
The soon-to-be-released Craft 3.6 adds PHP 8 compatibility, so you'll want to downgrade to PHP 7.4 until that's out.


How can you display entries filtered by localisation/localization? Supposing you have a structure of products but you only want some to be available to certain localities?

I am sure you could add a field to the entries E.g (Available in: eng | fr) and then test the local in the template before listing the entires. However, I'm not sure this is the best way of approaching this.

Initially, it may be that the category the product is within dictates its availability in a country but this is not guaranteed in the future.

Any ideas appreciated.

Yeah, a simple checkboxes field with a list of the countries would be a good approach to realize this.

Another idea is to make use of the localization feature, which comes with a Craft Pro license. Then you'd add a new structure entry (in your case the product) in one locale (e.g. "fr"), save it, and all entered content is copied over to the other locales (e.g. "en" and "de").

After that you can switch over to another locale's version of that entry, and make individual edits for it (e.g. change "10 EUR" to "8 GBP"). To disable an entry completely for one locale, use the status lightswitch available for each locale separately at the top right of the info panel.

Don't read this as if this "localization feature" solution is the right one. Consider if you really need to translate entry fields (product infos etc.) into other languages1, if not I'd definitely do it like you initially intended.

And there's also a chance that you want to use both of these features combined: if you want to list all entry pages translated for each locale and additionally show the visitors where these products are available.

--

1. "Craft Personal and Craft Client store content on a per-locale basis too, so down the road if you want your site to cater to a second locale, Craft is already set up for it."


Is there a way to require the Expiration date I can't find a way for a section (a channel in this case) to require the use to enter an expiration date.

I know I could add a new field and require that field, but that would get rid of the default functionality of entry/expire date fields.

You could do this with a little custom plugin. All you need to do is to listen to onBeforeSaveEntry events
and check if there's an expiryDate submitted.

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

    if($entry->section['handle'] == 'news' && $entry->type['handle'] == 'news')
    {
        if ($entry->expiryDate === null)
        {
            $event->params['entry']->addError('expiryDate', Craft::t('Expiration Date cannot be blank.'));
            $event->performAction = false;
        }
    }
});


Adding `www` causing it to have index.php I am trying to get pretty urls

In my general.php file I have

'omitScriptNameInUrls' => true,

which works fine and removes the index.php

BUT

When I try to force a www in the htaccess the index.php comes back and I can't seem to remove this.

This is what I have in my htaccess

RewriteEngine on
RewriteCond %{HTTP_HOST} ^example\.com [NC]
RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301,NC]

Any thoughts?

Your .htaccess is basically saying "Redirect example.com to www.example.com".

OK, that's cool. so you want to add www to any request that a comes in. I'm guessing you put this after Craft's code?

This actually needs to come before you send the request to Craft.

So, your example should look like this:

<IfModule mod_rewrite.c>

  #Make sure the rewrite engine is on
  RewriteEngine On

  # Redirect non-www requests to www
  RewriteCond %{HTTP_HOST} ^example\.com [NC]
  RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301,NC]

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


Using an IP address in config/db.php I'm trying to set up multi-environment configs.

I have specific db settings I want to change depending on environment. I am using localhost and my Digital Ocean server IP address in my db.php file.

<?php

return array(

'*' => array(
    'tablePrefix' => 'craft',
),
'localhost' => array(
        'server' => 'localhost',
        'user' => 'root',
        'password' => 'root',
        'database' => 'something',
),
'xxx.xxx.xxx.xxx' => array(
            'server' => 'localhost',
            'user' => 'some_user',
            'password' => 'some_password',
            'database' => 'somethingelse',
    ),
);

I've tried switching the order, that did not work.

Do I need to use a domain name rather than a IP address here?

The short answer is yes — you need to use a domain names.

You might also want to have a look at this multi-environment configuration method defined on the craft cookbook website that creates a global php variable called CRAFT_ENVIRONMENT in your main index.php.

I generally use that in combination with Ben Parizek technique as described in this answer.


Trimming lastSegment from a URI trims that PLUS the last number of the previous segment I am fairly new to twig and templating with Craft (and I have inherited this code, so that makes it even more fun).

I have a calendar page that lets you filter the events in the calendar based on a venti group (using the Venti Calendar plugin to create those groups).

How it currently works is that whatever group filter is selected, the url updates to have that group ID as the last segment.

Filter Names and their IDs: Cinema = 1, Theatre = 2, Events = 3, Education = 4

If a user is looking at the events for the month of December 2017 with no filters, the url looks like this:

example.com/month/2017/12

If a user is looking at the events for the same date, but has a filter applied (in this case, the "Cinema" filter), the url looks like this:

example.com/month/2017/12/1 Cinema has group ID of 1 so 1 is the last segment.

In order to change the applied filter without resetting the date, I want to trim the last segment from the url, and replace with the new ID as the last segment. Doing this works completely as expected unless the last segment and the last character of the previous segment are the same number (e.g., example.com/month/2017/12/2).

In this case, if I am currently on this URL, and I want to change to a different filter (in this example we change to use Cinema Filter = 1), the following happens.

example.com/month/2017/1/1 where it should actually be example.com/month/2017/12/1

So what is happening is that it is trimming the 2 from the last segment and the segment before the last segment.

Here's the code for the filter buttons:

    {% set groups = craft.venti.groups() %}
    {% for group in groups %}
        <a class="button" href="
            {% spaceless %}
            {% if craft.request.getLastSegment() in ['1','2','3','4'] %}
                {{url(craft.request.path)|trim('/' ~
                craft.request.getLastSegment())}}/{{group.id}}
            {% else %}
                {{url(craft.request.path)}}/{{group.id}}
            {% endif %}
            {% endspaceless %}">
            {{ group }}
        </a>
    {% endfor %}

If I remove '/' ~ from this:
{{url(craft.request.path)|trim('/' ~ craft.request.getLastSegment())}}/{{group.id}}

It actually works perfectly, save for the fact that the new url looks like this: example.com/month/2017/12//1 With the addition of that second backslash.

Can anyone see what I am doing wrong here, or provide any help? If you need more of my code, please let me know.

Thank you!

Twig's |trim filter is just a wrapper for PHP's trim() method, which says:

  Strip whitespace (or other characters) from the beginning and end of a string

So in your example, you're telling it to strip all / and 2 from the beginning and end of the given string, which explains the output you're seeing.

I think you'll be better off by installing something like the Twig PCRE plugin, which gives Twig full access to the PHP preg_ regex methods.

Then you'd just do a preg_match to target exactly what you're looking for and replacing it with new values as necessary.


After migrating, I am getting this error for several of my buttons and menus on Craft 2.6 Internal Server Error
Craft\MatrixBlockModel and its behaviors do not have a method or closure named "header".

Apache Version  2.4.37
PHP Version 7.1.24
MySQL Version   5.7.24
Architecture    x86_64
Operating System    Linux Cent OS

This error indicates that you don't have a matrix block, called header, setup in the CMS, but your template is expecting one.

The solution is to create a new matrix field;

settings > fields > new field.

The field type should be “matrix” and it's handle needs to be “header”.


error in production when using redis for cache and session I've added this to the array that is returned in config/app.php:
'components' => [
        'redis' => [
            'class' => yii\redis\Connection::class,
            'hostname' => App::env('REDIS_HOST'),
            'port' => APP::env('REDIS_PORT'),
            'password' => ''
        ],
        'cache' => [
            'class' => yii\redis\Cache::class,
            'defaultDuration' => 86400,
            'keyPrefix' => App::env('APP_ID') ?: 'CraftCMS',
        ],

        'session' => function() {
            // Get the default component config
            $config = App::sessionConfig();

            // Override the class to use Redis' session class
            $config['class'] = yii\redis\Session::class;

            // Instantiate and return it
            return Craft::createObject($config);
        },

    ]

This all works find when my environment is in dev and devMode is on.
When I switch to production, I get an internal server error. I don't know what the issue is because it doesn't give me the full logs.

Luckily, someone else had this problem: https://github.com/craftcms/cms/issues/7617#issuecomment-786715807
The issue was because of leaving the password blank. devMode did not care, but production did. Had to remove the password entirely


Issue Devmode is still enable in multi-environment config file I have an issue with a site I have just put live. devMode is still enabled even though the config site sets it as false for .com.

Code snippet:

'*' => array(
        'devMode' => 'false',
        'siteName' => 'sitename',
        'omitScriptNameInUrls' => true,
        'maxUploadFileSize' => 33554432,
        'defaultSearchTermOptions' => array(
            'subLeft' => true,
            'subRight' => true,
        ),
        ),
    '.com' => array(
        'devMode' => 'false',
        'env' => 'live',

I did have a .dev option as well but removed this to see if it would make any difference but it hasn't.

Next I cleared all caches and still no joy devMode is still active. How can I clear this for the the live site has it logged it in the DB somewhere and it's not removing it?

You’re setting the devMode setting to the string 'false', which seems to be evaluated to true. You need to set it to a boolean.

'*' => array(
    'devMode' => false,
),
'.dev' => array(
    'devMode' => true,
),


orderBy title, but remove the word "The" from titles If I have a huge list of TV shows and Movies, many of them have "The" in the title, meaning they all get grouped together if you order by title.
Is it possible to "filter out" a word in entry titles when using orderBy?
{% set entries = craft.entries().section('media').orderby('title asc').limit(24).all() %}

{% set entries = craft.entries().section('media').orderBy("(CASE WHEN `title` LIKE 'The %' THEN SUBSTRING(`title`, 5) WHEN `title` LIKE 'A %' THEN SUBSTRING(`title`, 3) ELSE `title` END) asc").limit(24).all() %}
worked.


Best practices of converting an already created site into Craft CMS? We have various clients who already have websites but would like us to optimize them a little bit and set them up on craft.

Is there a more efficient way to do this than just hand coding all of the PHP and blocks for every page to align to be editable on craft?

If you're not already on a CMS, I'd recommend migrating to Craft sooner rather than later. Sounds like you're definitely planning on migrating to Craft, so I see no valuable reason to delay.

Pros of migrating now:

Awesome Craft features, like Matrix
Plugins
Twig

Cons of migrating later:

More legacy code to port
More legacy data to restructure

You'll notice that both of those lists reinforce the idea of migrating now. ;)


How can I manually update Craft? If one wished to manually update for any reason, would one need to change anything outside of the the app folder, or be concerned with anything else?

Only the /app folder matters.

No other files are relevant to the Craft core operations. Make sure you replace the folder entirely, don't let the new files get merged with the old files.

Nothing else will be changed. If the update would trigger any database changes, those will be handled automatically by migrations (located in the app/migrations folder).

For more information, see the documentation on Manually Updating.


Root domain config overriding subdomain config My question is similar to Subdomain database configuration picking up root domain config, but I don't have any custom database variables.

I have a staging site and a (forthcoming) production site on the same remote shared hosting server. The staging site is at a staging subdomain and the production site will be at the root.

The staging site seems to be using the config variables from the root domain in general.php and db.php. I had to take the production site out of db.php to get the staging site to work at all, and anywhere I'm using environment variables (like my asset paths), they're coming from the production config instead.

This is my general.php:

return array(
  '*' => array(
    'omitScriptNameInUrls' => true,
    'generateTransformsBeforePageLoad' => true,
    'loginPath' => 'admin',
  ),
  'localhost' => array(
    'server' => 'localhost',
    'devMode' => true,
    'environmentVariables' => array(
      'basePath' => 'C:\wamp\www\craftcms',
      'baseUrl'  => 'localhost/craftcms/',
    )
  ),
  'staging.safs.msu.edu' => array(
        'server' => '35.8.12.67',
    'devMode' => true,
    'environmentVariables' => array(
      'basePath' => 'staging',
      'baseUrl'  => 'http://staging.safs.msu.edu',
    ),
  ),
  'safs.msu.edu' => array(
    'server' => '35.8.12.67',
    'devMode' => false,
    'environmentVariables' => array(
      'basePath' => '',
      'baseUrl'  => 'http://safs.msu.edu',
    ),
  ),
);

How do I get my config files to recognize the staging subdomain's settings?

Craft looks for partial matches to apply config settings (both general.php and db.php which means you can do things like:

'.dev' => array(
..

'.com' => array(
..

Craft applies these settings for each match from the top of the file to the bottom. So in your case because you have the the production domain after your subdomain config it matches and overrides your subdomain settings.

Simply swap your config variables over and it'll work.

return array(
  '*' => array(
    'omitScriptNameInUrls' => true,
    'generateTransformsBeforePageLoad' => true,
    'loginPath' => 'admin',
  ),
  'localhost' => array(
    'server' => 'localhost',
    'devMode' => true,
    'environmentVariables' => array(
      'basePath' => 'C:\wamp\www\craftcms',
      'baseUrl'  => 'localhost/craftcms/',
    )
  ),
  'safs.msu.edu' => array(
    'server' => '35.8.12.67',
    'devMode' => false,
    'environmentVariables' => array(
      'basePath' => '',
      'baseUrl'  => 'http://safs.msu.edu',
    ),
  ),
  'staging.safs.msu.edu' => array(
    'server' => '35.8.12.67',
    'devMode' => true,
    'environmentVariables' => array(
      'basePath' => 'staging',
      'baseUrl'  => 'http://staging.safs.msu.edu',
    ),
  ),
);


How to include a section name in the page title? I can get Craft to generate page titles for entries and individual pages using:

{% set title = entry.title %}

and

{% set title = "News and Insights" %}

But I need to be able to generate a full page title for an entry, that includes the section name, for example:

News Item | News and Insights | Company Name

Can anyone please explain how...?

Many thanks!

{{ entry.section }} - {{ entry.title }}

Here are a list of properties you can get from the Entry model:

https://craftcms.com/docs/templating/entrymodel

So you could do

{% set title = "#{entry.section} | #{entry.title}" %}


Users fields on front end form Is it possible to include a Users Fields Type on a front end form? I'd like to allow people to choose existing users on a front end form rather than giving them access to the admin area of the Craft site.

Sure is!  You'll want to bookmark this ridiculously handy page, but if you look under "Relations" you'll see the syntax you're looking for:

<select multiple name="fields[fieldHandle][]">
    <option value="13">Username One</option>
    <option value="42">Username Two</option>
    <option value="144">Username Three</option>
</select>


Possible to override Garnish.Modal? [Plugin] Is there a way to override Garnish.Modal?

For example, I have a custom modal which uses a custom form but I want to be able to use the built in forms.elementSelect to select from a user list. When I select a user and press "select" it closes both my custom modal and my user select window.

Can I override this to just close the most recent modal?

This is in reference to Custom Modals inside Plugins: How can my plugin generate a generic modal window in the Control Panel?

Edit: It looks as if Garnish hides any other modals before loading a new one.

By default, Garnish.Modal will automatically close other modals when show() is called (which happens automatically when you first create it).

That behavior can be overridden by setting the closeOtherModals setting to false, though:

var myModal = new Garnish.Modal($container, {
    closeOtherModals: false
});


Multilinugual Import I am currently using an import plugin to import csv data into a channel section and it works just fine. Now I want to import the entries in a second language. Does anyone have any experiences with this?
Since the import works great, I could set up a new channel for the second language, but I wonder if there's a chance to import translations for existing entries.

We recently built our first multi lingual site on craft and used FeedMe to import our entries. What we did was to set up fields such as enDesc, deDesc, svDesc. Then when we imported our entries into craft mapping all of our multi lingual content to be spread across these fields in a single locale. Once this was done we then ran a script across the database to copy the content from deDesc into enDesc on the entry with the locale set to de, and then the same for sv also. Here is the script we built to get this job done. We ran this script from a program called CodeRunner on Mac, but you could equally FTP this up to the server and navigate your browser to it to run the script.

<?php
$servername = "XX.XXX.XXX.XXX";
$username = "db_username";
$password = "db_password";
$dbname = "db_name";
date_default_timezone_set('GMT');

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);

// Check connection
if ($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}
echo "Connected successfully";
$fieldName = "Desc";
$failed = 0;
$result = $conn->query("SELECT * FROM craft_content WHERE field_de".$fieldName." <> '' AND locale = 'en';");
while($row = $result->fetch_assoc()) {
    $elementId = $row['elementId'];
    $desc = $row['field_de'.$fieldName];
    if ($conn->query("UPDATE craft_content SET field_en".$fieldName."='".$desc."', field_de".$fieldName."=NULL WHERE elementId='".$elementId."' AND locale = 'de';") === TRUE) {
        echo "Updated ".$row['title']." - de";
    } else {
        echo "Failed ".$row['title']." - de";
        $failed++;
    }
}
$result = $conn->query("SELECT * FROM craft_content WHERE field_swe".$fieldName." <> '' AND locale = 'en';");
while($row = $result->fetch_assoc()) {
    $elementId = $row['elementId'];
    $desc = $row['field_swe'.$fieldName];
    if ($conn->query("UPDATE craft_content SET field_en".$fieldName."='".$desc."', field_swe".$fieldName."=NULL WHERE elementId='".$elementId."' AND locale = 'sv';") === TRUE) {
        echo "Updated ".$row['title']." - swe";
    } else {
        echo "Failed ".$row['title']." - swe";
        $failed++;
    }
}
if ($failed == 0) {
    if ($conn->query("UPDATE craft_content SET field_de".$fieldName."=NULL, field_swe".$fieldName."=NULL;") === TRUE) {
        echo "Cleanup Complete";
    } else {
        echo "Cleanup Failed";
    }
}
?>

Once this had completed, the values from deDesc and svDesc should have copied into enDesc on both the German and Swedish locale entries. The values for deDesc and svDesc will also be removed if there were no errors. All you need to do now is rename your field from enDesc to desc and delete the deDesc and svDesc fields from craft. Rinse and repeat this process for each field and cleanup the fields afterwards and that should sort out your multilingual import for you.

Just make sure to take database backups frequently in case there are any errors though.


Extra spaces appearing in Rich Text fields after 2.5 update In addition to the inability to resize images in the rich text fields (mentioned elsewhere), I'm having issues with rich text fields, particularly in Matrix blocks, inserting extra spaces between paragraphs.

While an entry may be rendering normal on the frontend, opening up the entry will show the paragraphs with large spaces between them. Looking into the HTML, these appear as a series of tags like

Strangely, when switching back and forth between the normal and HTML view, more and more of these spaces are inserted between the paragraphs. Do I have the option to rollback to the earlier version of Redactor? Any help or suggestions are appreciated!

The fix is in!

Running Redactor “I” in Craft 2.5

Just used this on one of my problem upgrades and it worked seamlessly - now they get to be in on the 2.5 party too :)


FreeForm: Accessing a fields customAttributes Is it possible to access customAttributes on a FreeForm field?

Currently attempting to do this via:

{% for row in form %}
  {% for field in row %}
    {{ dump(field.customAttributes) }}
  {% endfor %}
{% endfor %}

Where form is a FreeForm object.

Currently I'm getting an error that indicates that attribute does not exist or I can't access it.

You'll need to access the properties individually like this, assuming you've set them on the Form object:

{{ form.customAttributes.rowClass }}
{{ form.customAttributes.columnClass }}
{{ form.customAttributes.inputClass }}
Etc...

https://solspace.com/craft/freeform/docs/form/#prop-custom-attributes


Plugin development: Forms I'm embarking on my first plugin build.

The docs are OK, but lacking in some areas or maybe I'm just looking in the wrong place.

The settings page allows you to define any settings and when rending out the template view, pass through those settings.
http://buildwithcraft.com/docs/plugins/plugin-settings

It makes sense that all of the settings are going to be form fields. Where's the documentation for form helpers?

Looking around at other plugins I can see an include to Craft's form templates.

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

Where's the docs on how to use these form fields? Is this a Twig thing and I should be looking at those docs? Any help would be appreciated.

There currently aren't any docs for _includes/forms... you'll need to backwards engineer it. You'll notice some common patterns as you dig in there, which gives great insight into the overall Craft structure.

That file (or batch of files) is one of the most commonly backwards engineered parts of the core code. You may be able to find other posts (on Stack Exchange or blog posts) which describe it in some detail, but you'll still want to investigate on your own.


Blog Integration or Creation? I'm working on a website for a school and need to create a system where students can login, check assignments and upload homework that the teacher can then view easily and give feedback on. I am only a front and programmer so I am hoping there is some form of pre-built plugin for Craft that I can use and then modify to suit our needs.

Currently we use Blogger and it does an alright job for what we need. But we would prefer to have all the interactions for students to be done through own website and not a third party.

Because it's a complicated question here is a very basic outline of what I am trying to achieve:

It's certainly doable, but I think there will be some significant plugin and templating work needed, even when starting with something like the the Guest Entries plugin that Jamie mentioned.


'onDeleteEntry' Event is not triggered when an Entry is deleted? I have the following code:

namespace Craft;

class AffiliatesExportPlugin extends BasePlugin
{
  //All other functions

  public function init() {
    craft()->on('entries.onDeleteEntry', function(Event $event) {
      Craft::log(" on delete ######\n\n", LogLevel::Info, true);
    });
  }
}

I added this as a plugin activated the plugin, but when I delete an entry, it doesn't seem to get triggered. What am I doing wrong?

Bulk actions do not trigger their respective events. When you delete an entry (or multiple entries) via the checkboxes, you are performing a bulk action.

As a workaround, you can listen to the onBeforePerformAction or onPerformAction events, check to see if the action parameter to see if it's the action you're interested in and perform  your logic as necessary. *

  * Much of this answer was copied from my & Brad's answers on this similar thread...


Set a lineItem option from within a plugin? I’m trying to set a specific lineItem option. Here is the gist of my attempt:

craft()->on('commerce_lineItems.onPopulateLineItem', function($event){

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

    if (something == true) {
        $lineItem->options['optionKey'] = 'newValue';
    }

});

This returns an error:

  Indirect modification of overloaded property…

What’s the correct way to do this?

I'm guessing you're doing this in a plugin and not the front end using an input for a reason?

I struggled with this recently and had luck using the following:

// Get the line item from the event
$item = $event->params['lineItem'];

// We get all the options from the post request
$options = craft()->request->getPost('options', []);

// Add the new value
$options['optionKey'] = 'newValue';

// Save the options to the line item
$item->options = $options;

If somebody can suggest an improvement to this I'd be grateful.


Dealing with existing data in a separate database I'm creating a site with Craft that needs to communicate with an existing database, which is separate from the database Craft will be installed on. My client is already using an existing online database to manage a bunch of their internal work, but I need to fetch some of that data for public display on the site. I don't need any relational queries between the two databases, so it's fine that they're separate.

My plan is to create a plugin that will create a new Record. Because BaseRecord extends Yii's CActiveRecord class, I should be able to override the getDbConnection() method to return a new CDbConnection object, which will connect to the external database.

So my first question is: Will that work, in theory? Or will Craft try to use my site's table prefix in this external database (which wouldn't work)?

My second concern is that Craft will associate the table returned by getTableName() in my new record as a table specific to this plugin, and will delete that table if the plugin ever gets uninstalled. Obviously since I'm dealing with an external database, I don't want that to happen. Is there any way around that?

EDIT:

I just came across this question: Query table in a different database, and the solution there seems like it's a simpler option for me. I am still interested in learning the answers to my above questions though.

I haven't tested, but I'm about 90% confident that Yii's CActiveRecord is directly coupled to the underlying craft()->db connection and there isn't a way to change that at runtime.

You're going to be better off going with the method in the answer you linked to and use QueryBuilder.


Can the Freeform Plugin be used with headless mode in Craft? Anyone know if the Freeform plugin is compatible with Craft's headless state. Or if there are any other form plugins that are?

Broadly speaking, any Form plugin that implements Forms using Elements can probably be used headlessly using Craft's Element API plugin.

I'll give an example using the Sprout Forms plugin.

Install the Element API plugin
Add a config/element-api.php file to your project's config folder
Build your API

The following example creates two endpoints.

The first returns a Form Element that can be used by your front-end framework to output the form. You can use the Default Form Templates as an example of how the HTML needs to be built for submission and remember to submit the form using a CSRF token. This example returns the field data and the field folder name which can be used as a unique identifier when determining which field template to display on the front-end.

The second returns a list of unread Form Entry Elements. You can customize the query however you'd like, just like any Element Query.

<?php

use barrelstrength\sproutforms\elements\Form;
use barrelstrength\sproutforms\elements\Entry;

return [
    'endpoints' => [
        'api/sproutforms/<formId:\d+>.json' => function($formId) {
            return [
                'elementType' => Form::class,
                'criteria' => ['id' => $formId],
                'one' => true,
                'transformer' => function(Form $form) {
                    foreach ($form->getFieldLayout()->getTabs() as $tab) {
                        foreach ($tab->getFields() as $field) {
                            $fields[] = [
                                'field' => $field,
                                'folder' => $field->getFieldInputFolder()
                            ];
                        }

                        $tabs[] = [
                            'title' => $tab->name,
                            'fields' => $fields
                        ];
                    }

                    return [
                        'handle' => $form->handle,
                        'tabs' => $tabs
                    ];
                },
            ];
        },
        'api/sproutforms/<formId:\d+>/entries.json' => function($formId) {
            return [
                'elementType' => Entry::class,
                'criteria' => [
                    'formId' => $formId,
                    'status' => 'unread'
                ],
                'paginate' => true,
                'transformer' => function(Entry $entry) {
                    return [
                        'id' => $entry->id,
                        'dateCreated' => $entry->dateCreated,
                        'title' => $entry->title,
                        'customField' => $entry->customField,
                    ];
                },
            ];
        }
    ]
];


How do I insert a special entry into a sections list? I want to apologize if I'm not asking the question correctly, but basically this is what I want to do:

I have this craft.entries:

{% paginate craft.entries.section('example').limit(10) as entriesOnPage %}
  {% for entry in entriesOnPage %}

{{ entry.title }}

  {% endfor %}
{% endpaginate %}

How do I insert another list-item with a different class that has to always stay in same position. For this example in the 3rd spot, to look something like this:

I'm a title

I'm a title

I'm am different

I'm a title

....

Once again, I apologize if I'm not using the right terms, but hopefully the code can explain it.

Thanks!

There's a special loop variable available in for loops which provides info about the iteration.
In your case you'd just insert that list item after the 2nd iteration:

{% for entry in entriesOnPage %}

{{ entry.title }}

    {% if loop.index == 2 %}

I'm am different

    {% endif %}
{% endfor %}

If you want to do this only on select pagination pages, you'd additionally compare  against the paginate variable available in between paginate tags:

{% if loop.index == 2 and paginate.currentPage == 12 %}


Individual persistent property per item in stock This is more advanced: We want to sell activation keys for digital products. We know that in Craft a variant has a stock. So every single item "in" the stock needs a unique activation key. When we sell one item of the stock we sell a activation key. Of course, an activation key can only be sold once. For each product we will have a limited number of activation keys, so this will be reflected by the stock number itself.

We know that this feature requires some customization. Question is: is this achievable in an easy or hard way via Craft Commerce? How would an elegant approach look like?

You can use the beforeGenerateLicenseKey event and query for a custom key in your custom table and set the license key

Event::on(License::class, License::EVENT_GENERATE_LICENSE_KEY, function(GenerateKeyEvent $e) {
    $licenseKey = (new Query())
                      ->select(['mykey'])
                      ->from('{{%mytable}}')
                      ->where(['used' => false])
                      ->scalar();

    $e->licenseKey = $licenseKey;
});

And when you insert new keys in your custom DB table, you can change the stock of your variant accordingly

$variant = //grab the variant you need for your product
$variant->stock = (new Query())->from('mytable')->count();
// store the variant


How do you page through child entries in a structure? I am trying to figure out how to page through only the children of the top level section entry being displayed, I have looked at this question but as I say I am after only the children not the siblings.

Is there a prevChild() and nextChild() or something similar I can't see them in the docs.

Response to Bryan

So I would do something like:

{% set prevDatabyteSeries = entry.getChildren().first().getPrevSibling() %}
{% set nextDatabyteSeries = entry.getChildren().first().getNextSibling() %}

{% if prevDatabyteSeries %}

{% endif %}

{% if nextDatabyteSeries %}

{% endif %}

getPrev, getNext, getPrevSibling, getNextSibling all specify an entry relative to the current one. prevChild and nextChild if they existed would somehow specify an entry relative to a child of the current entry. They don't exist.

What you can do is paginate through the children. Here I use .limit(1) to page through them one at a time, but you could fetch more.

{% set prePaginatedEntries = entry.getChildren().limit(1) %}
{% paginate prePaginatedEntries as entries %}
  {% for oneChild in entries %}
    {# do whatever with oneChild #}
  {% endfor %}
  {# pagination links #}
  {% if paginate.prevUrl %}
    Previous Page
  {% endif %}

  {% if paginate.nextUrl %}
    Next Page
  {% endif %}
{% endpaginate %}


What's the recommended way to include vendor library dependencies in your plugins? My plugin requires vendor library dependencies and api keys set. What is the recommended way to register an external library? I would also like to configure the public api keys separately for stage and production environments — is there a way to set these in craft/config with the rest of the multi-environment configuration? Or is it better to create a plugin config file of some kind?

Currently I am having to include these in each of my service methods (and something similar again in my javascript files):

private function _saveStripeCustomer($account, $token = NULL)
{
    require_once(CRAFT_PLUGINS_PATH . 'businesslogic/vendor/stripe/lib/Stripe.php');
    \Stripe::setApiKey("sk_test_xxxxxxxxxxxxxxxxxx");

    // ...
}

I'm not familiar with composer. I don't know if that can perhaps help here.

Composer!

There's already a package for Stripe: https://packagist.org/packages/stripe/stripe-php

Install composer.
Add a composer.json file in your plugin's root folder.
Add this to the composer.json file:

{
    "require": {
        "stripe/stripe-php": "1.17.2"
    }
}
Run php composer.phar update from your plugin's root folder.
The library will be installed in a /vendor folder in your plugin.
Add an init() method to your main plugin's class file with this in it:

require CRAFT_PLUGINS_PATH.'/pluginhandle/vendor/autoload.php';

And you're done.

Composer will handle autoloading all of the class files, so you don't need to worry about it.

If you ever want to update the Stripe library to a newer release, grab the version number from the packagist site, update your composer.json file with it and run php composer.phar update again.


Craft 3 Ubuntu installation error via composer setup After running composer and then initiating craft setup I keep getting this error:

Username: [admin]
Email: abc@test.com
Password:
Confirm:
Site name: test
Site URL: test.com
Site language: [en-US]
Installing Craft...

Exception 'craft\errors\MigrationException' with message 'An error occurred while executing the "craft\migrations\Install migration: Error while sending QUERY packet. PID=25472'

in /vendor/craftcms/cms/src/db/MigrationManager.php:267

My MySQL version is 5.7.18-0ubuntu0.16.04.1.

[SOLVED] By upping wait_timeout from 10 to 100 in my.cnf - seems to have fixed the issue.

Initial google searches for "Error while sending QUERY packet" led me to increase max_allowed_packet size, but this didn't fix the problem alone.
Note, I'm not sure if both timeout and packet size need to be increased or just timeout nevertheless I have increased both and it works now.

Another side note on my server setup, the server I had problem with was a default Vesta CP ubuntu/mysql configuration. I had no problem installing Craft 3 on a different ubuntu 16 configured by Serverpilot.io.


How to route short tag to external web site I am writing a plugin to that will map http://short.com/e9DG to http:/longdomainname.com/longsubpagename

I assume I need to use the config/routes.php but am having struggling to understand how how to set this up. I keep getting 404 as it cannot resolve the url.

As a test I have the foloing code

return array(
    'e9DG' => array('action' => '/cocktailrecipes/ingredients/new'),
);

With the registerSiteRoutes hook you can route http://short.com/e9DG requests to any template.

public function registerSiteRoutes()
{
    return array(
        'e9DG' => '/mysection/mytemplate.html',
    );
}

With getUrl and redirect accessible via craft()->request you can set up server redirects:

$url = craft()->request->getUrl();

if ($url == 'http://short.com/e9DG')
{
    craft()->request->redirect('http:/longdomainname.com/longsubpagename', true, 301);
}


Get label from value in radio buttons list fieldtype Ok I know how to list radio buttons and use it to display a particular value:

{% set newsType = craft.fields.getFieldbyHandle('newsType') %}
{% for option in newsType.settings.options %}
    {% if option.value == 'newsValue' %}

{{  option.label }}

    {% endif %}
{% endfor %}

(I am not in an existing entry context.)
So I would like to know if there is a shortcut to directly get this label from the value? Like that syntax :

{% set newsTypeLabel = craft.fields.getFieldbyHandle('newsType').option('newsValue').label) %}

You could make a macro and use that as a "shortcut":

{% macro optionLabel(fieldHandle, optionValue) %}

    {%- set field = craft.fields.getFieldbyHandle(fieldHandle) %}
    {%- for option in field.settings.options %}
        {%- if option.value == optionValue %}
            {{- option.label }}
        {%- endif %}
    {%- endfor %}

{%- endmacro %}
{% import _self as macros %}

<h3>{{ macros.optionLabel('newsType', 'newsValue') }}</h3>


Undefined index: siteSettings when updating entry types I'm receiving an Undefined index: siteSettings when trying to save changes to entry types (both new and existing). Of course, this is only occurring on a production server - local server with up-to-date copies of the DB is working as expected. Also, we're not using project config.

yii\base\ErrorException: Undefined index: siteSettings in /chroot/home/sitename/vendor/craftcms/cms/src/services/Sections.php:608
Stack trace:
#0 /chroot/home/sitename/vendor/craftcms/cms/src/web/ErrorHandler.php(80): yii\base\ErrorHandler->handleError(8, 'Undefined index...', '/chroot/home/ly...', 608)
#1 /chroot/home/sitename/vendor/craftcms/cms/src/services/Sections.php(608): craft\web\ErrorHandler->handleError(8, 'Undefined index...', '/chroot/home/ly...', 608, Array)
#2 /chroot/home/sitename/vendor/craftcms/cms/src/services/ProjectConfig.php(872): craft\services\Sections->handleChangedSection(Object(craft\events\ConfigEvent))
#3 [internal function]: craft\services\ProjectConfig->craft\services\{closure}(Object(craft\events\ConfigEvent))
#4 /chroot/home/sitename/vendor/yiisoft/yii2/base/Component.php(627): call_user_func(Object(Closure), Object(craft\events\ConfigEvent))
#5 /chroot/home/sitename/vendor/craftcms/cms/src/services/ProjectConfig.php(551): yii\base\Component->trigger('addItem', Object(craft\events\ConfigEvent))
#6 /chroot/home/sitename/vendor/craftcms/cms/src/services/ProjectConfig.php(866): craft\services\ProjectConfig->processConfigChanges('sections.0ad0be...')
#7 [internal function]: craft\services\ProjectConfig->craft\services\{closure}(Object(craft\events\ConfigEvent))
#8 /chroot/home/sitename/vendor/yiisoft/yii2/base/Component.php(627): call_user_func(Object(Closure), Object(craft\events\ConfigEvent))
#9 /chroot/home/sitename/vendor/craftcms/cms/src/services/ProjectConfig.php(551): yii\base\Component->trigger('addItem', Object(craft\events\ConfigEvent))
#10 /chroot/home/sitename/vendor/craftcms/cms/src/services/ProjectConfig.php(395): craft\services\ProjectConfig->processConfigChanges('sections.0ad0be...', true)
#11 /chroot/home/sitename/vendor/craftcms/cms/src/services/Sections.php(1174): craft\services\ProjectConfig->set('sections.0ad0be...', Array)
#12 /chroot/home/sitename/vendor/craftcms/cms/src/controllers/SectionsController.php(374): craft\services\Sections->saveEntryType(Object(craft\models\EntryType))
#13 [internal function]: craft\controllers\SectionsController->actionSaveEntryType()
#14 /chroot/home/sitename/vendor/yiisoft/yii2/base/InlineAction.php(57): call_user_func_array(Array, Array)
#15 /chroot/home/sitename/vendor/yiisoft/yii2/base/Controller.php(157): yii\base\InlineAction->runWithParams(Array)
#16 /chroot/home/sitename/vendor/craftcms/cms/src/web/Controller.php(187): yii\base\Controller->runAction('save-entry-type', Array)
#17 /chroot/home/sitename/vendor/yiisoft/yii2/base/Module.php(528): craft\web\Controller->runAction('save-entry-type', Array)
#18 /chroot/home/sitename/vendor/craftcms/cms/src/web/Application.php(299): yii\base\Module->runAction('sections/save-e...', Array)
#19 /chroot/home/sitename/vendor/craftcms/cms/src/web/Application.php(565): craft\web\Application->runAction('sections/save-e...', Array)
#20 /chroot/home/sitename/vendor/craftcms/cms/src/web/Application.php(278): craft\web\Application->_processActionRequest(Object(craft\web\Request))
#21 /chroot/home/sitename/vendor/yiisoft/yii2/base/Application.php(386): craft\web\Application->handleRequest(Object(craft\web\Request))
#22 /chroot/home/sitename/html/index.php(23): yii\base\Application->run()
#23 {main}

Application Info

PHP version: 7.1.33
OS version: Linux 2.6.32-754.18.2.el6.x86_64
Database driver & version: MySQL 5.6.43
Image driver & version: Imagick 3.4.3RC1 (ImageMagick 6.7.2-7)
Craft edition & version: Craft Pro 3.3.19
Yii version: 2.0.31
Twig version: 2.12.3
Guzzle version: 6.5.1
Imagine version: 1.2.3-dev

Even with 'useProjectConfigFile' => false, it is still active under the hood.

Could you run ./craft project-config/rebuild and see if that fixes the issue?