Namespace issues with binding Javascript I'm building a plugin that relies on Javascript to function correctly. Having tried different methods, I can't get the ID names to remain consistent.

Here's an example of the code that is being output.

<input type="text"
id="fields-slider-output"
name="fields[slider]"
value="539">

<input
id="fields-input"
type="range"
name="fields[slider]"
value="539"  min="0 max="1000" step="0">

The first input is a text input, and displays the ID as you would expect. The span element below only contains "fields-", and leaves out the name of the field. The same happens with the range input, which is the most surprising, as it's a form input with a name.

When using JavaScript, the "fields-" namespace is left out entirely, which means that the Javascript can't bind to an element.

$("#slider-input")[0].oninput = function () {
    $('#slider-value').html(this.value);
};

I'm using this code from the Craft docs.

$id = craft()->templates->formatInputId($name);
$namespacedId = craft()->templates->namespaceInputId($id);

I've also looked into the namespacing HTML docs (http://buildwithcraft.com/docs/apis/templatesservice#namespacing-html) with little success.

Does anyone know a possible solution to this? Bearing in mind this Fieldtype requires Matrix support, so using a class instead of an ID is not an option.

Thanks.

It’s not enough to simply define $namespacedId – you need to actually use it in your Javascript code.

If you’re defining the javascript code in your template, you’ll need to pass the namespaced ID to your template, along with name, id, and value:

return craft()->templates->render("myplugin/my_input_template", array(
    'name'         => $name,
    'id'           => $id,
    'namespacedId' => $namespacedId,
    'value'        => $value
));

Then in your template, use the id variable within id= attributes, and the namespacedId variable within Javascript code:

<input type="text" id="{{ id }}-output" name="{{ name }}" value="{{ value }}">

<input id="{{ id }}-input" type="range" value="{{ value }}" min="0" max="1000" step="0">

{% set js %}
    $("#{{ namespacedId }}-input")[0].oninput = function () {
        $('#{{ namespacedId }}-value').html(this.value);
    };
{% endset %}

{% includeJs js %}

(I’ve cleaned up your HTML a little, besides the formatting – I added a missing quote after min="0, and removed the entire name= attribute from the 3rd input, since the first input seems like it will already take care of that.)


Reverse Relationships Doing my first Craft job and stuck with a reverse related entries thing.
I’ve got a channel of “Sectors” and a channel of “News”. The entries in news have a relationship field back to the “Sectors”.
When I’m viewing a “Sector” entry, I want to show links to entries in News that have a relationship to it.

I’ve tried a few things but essentially I’ve got this…

{% extends "_layout" %}

{% block content %}

{{ entry.title }}

    {{ entry.body }}

    {% for entry in craft.entries.section('news').relatedTo(entry) %}
        {{ entry.title }}
    {% endfor %}
{% endblock %}

But, even though I have a news entry related to a specific Sector entry, the above code doesn't show any related entries.

Oddly, if I do this...

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

Then I get some output but it shows me something from a different channel.

I’m confused. Can someone help?

Update

Schoolboy error alert!

I had the wrong field in my news entries. There was a category field set up which had the same values as the sector names. Once I'd replaced the field with the proper one it all worked as expected!


What are the Pros and Cons to each image transform technique? In Craft you can do two types of image transforms:

1. Control Panel Transforms:

Via: Settings → Assets → Image Transforms

2. Inline Transforms in your Templates

I’m currently using 100% inline transforms as they can be version controlled and seem to work better across different dev environments.

Are there any benefits of using Control Panel Transforms over using Inline Template Transforms in your Templates?

Both methods essentially do exactly the same thing to the image however there are two advantages to pre-defining them in the control panel:

You can just call a transform handle in your templates instead of having to define the whole transform model
They are then available to be used in supported field types e.g. in the Rich Text field type you can select an existing image transform when inserting an image

As you already mentioned the advantages that I can see to defining them in the templates are version control and the lack of needing a database.

I've started defining them all in the templates for the development phase and then when we move to staging I go and add all the ones we're using to the control panel.


Sprout Forms and Multi-site on Craft 3 Is it at all possible to get forms to display per site and not all forms displaying to a site admin user? Also an admin user doesn't seem to be able to run reports on there own site, without being an admin of the entire Craft CMS instance.

https://sprout.barrelstrengthdesign.com/docs/multi-site.html

Looks like multisite support for Sprout Forms is a planned/under review addition


Can't get checkboxfield values to show I'm trying to build a filter and for that I want my client to be able to select a few options, which I use as classes for in my filter.

I chose for a checkbox field and set it up in the backend. Now I'm trying to retrieve the data on the HTML side, but I can only retrieve ALL values, instead of only the selected ones.

This is how my HTML/twig markup looks like

{% for option in entry.offerMinimumPrice.options %}
  {% if option.selected %}
    {{ option }}
  {% endif %}
{% endfor %}

With this code none of the values gets displayed in the front end. When I remove the conditional statement, all values get displayed (instead of only the selected ones).

Can anyone tell me what I'm doing wrong? Thanks!

The problem was that I used this code within an entry, so I had to use the tag of that entry (offer) instead of entry.

The code that works now is:

{% for option in offer.offerMinimumPrice.options %}
  {% if option.selected %}
    {{ option }}
  {% endif %}
{% endfor %}


Returning errors into templates When working with a custom form that posts to a plugin function - what's the best way to return errors that would be displayed like the forgot password code example below

    {% if errors is defined %}

            {% for error in errors %}

{{ error }}

            {% endfor %}

    {% endif %}

I just return the form model object back to the template. Yii has built in validation and error handling within the models themselves. In the example email is the instance of your form's model.

The template:

{% if email is not defined %}
    {% set email = craft.postmaster.email() %}
{% endif %}

{% for error in email.getAllErrors() %}

{{ error }}

{% endfor %}

    To Email

    <input type="text" id="toEmail" name="toEmail" value="{{ email.toEmail }}" />
    {% if email.getError('toEmail') %}
    {{ email.getError('toEmail') }}
    {% endif %}

The controller:

$model = new Postmaster_EmailFormModel(craft()->request->getPost());

if(!$model->validate())
{
    // Prepare a flash error message for the user.
    craft()->userSession->setError(Craft::t('The email could not be sent.'));

    craft()->urlManager->setRouteVariables(array(
        'email' => $model
    ));
}
else
{
    $event = new Event($this, array(
        'email' => $model
    ));

    craft()->postmaster_forms->onEmailFormSend($event);

    $this->redirect(craft()->request->getPost('redirect'));
}


Adding a RESTful, OAuth API on top of Craft I’m currently considering options for a project that will require a standard sales site, commerce features and a user database. The user database will require a web frontend and an API for communication with a mobile app (read and write).

My dilemma is whether it makes sense to consider Craft for all three components, which will give us all the benefits of a unified system, or to split the user database into a separate project where we could take advantage of something like Laravel Passport, which seems like the obvious option for efficiently building a secure API.

The HTTP Messages plugin looks useful but doesn’t appear to deal with authentication at all and preexisting options for Yii/Craft OAuth appear limited to nonexistent. I get the sense that Craft 3/Yii 2 would make life easier, but waiting for a stable Craft 3 release isn’t possible.

Has anyone had any experience developing a secured API on top of Craft? If so, what route did you take and would you do it again?

Short answer: yes I have, I used OAuth 2 and I would absolutely do it again.

I wrote up my experience in general terms here but essentially it boiled down to two plugins, one on each site: one acting as the server and another as the client.

I used league/oauth2-server for the server and then tied in directly to the Dukt OAuth plugin for the client, but in retrospect it would’ve been simpler just using league/oauth2-client for that.

For transforming data like the Element API does I used league/fractal and then to get proper request behaviour I used zendframework/zend-diactoros.

Essentially I think this sort of thing is perfectly feasible in Craft, due to plugins being so flexible you can load whatever libraries you need and go nuts. Craft 3 could simplified things somewhat with Yii Modules as I’m guessing you could package up the whole API code as a module, but it shouldn’t be necessary.

Hope that helps!


Pull random image from entries marked with a certain category I am trying to pull an image from services marked with a category of left. I would only like to display one image. I would also like to randomize the image if possible from all the images marked left.

{# RANDOM IMAGE FROM SERVICES - LEFT #}

    {% for homepage in craft.entries.section('services').limit('1').relatedTo(left).find() %}

{{ homepage.title }}

{{ homepage.description }}

                View Rental Pricing

    {% endfor %}

Welcome to the Craft community @bjyama

{# Step one: pick a random service #}
{% set randomService = craft.entries.section('services').relatedTo(left).order('RAND()').first() %}

{# Step two: pick a random image from the above service #}
{% set randomServiceImage = service.homepageImage.order('RAND()').first() %}

{% if randomServiceImage %}
    <img src="{{ randomServiceImage.getUrl('imageTransformName') }}" alt="">
{% endif %}

For more info, have a look here: https://craftcms.com/docs/templating/craft.entries#order

Let us know how you get on :)


Craft Commerce: How do I handle quantity based discounts on a product level? I'm curious what the best way to handle quantity discounts would be on a product/variant level. For example:

The base price of a variant is $3 each, but if you buy 10-19 they're $2 each, and if you buy more than 20 they're $1 each.

A different variant of the same product could have a base price of $10 each, but if you buy 20-49 they're $8 each, and if you buy over 50 they're $6 each.

Thoughts?

EDIT 2 (added file paths)

Based on the comments by Luke and Andris below, I've implemented an adjuster to handle this. I created a table field with the handle quantityPricing with 3 columns: minQuantity, maxQuantity, price. I then applied this field to the variants on a product.

This way a user can create as many prices for quantity ranges as they want. I then create the adjuster, checking the line items via the following:

craft/plugins/myplugin/Adjusters/Myplugin_Adjustername.php

<?php

namespace Commerce\Adjusters;
use Craft\Commerce_LineItemModel;
use Craft\Commerce_OrderAdjustmentModel;
use Craft\Commerce_OrderModel;

class Myplugin_Adjustername implements Commerce_AdjusterInterface {
public function adjust(Commerce_OrderModel &$order, array $lineItems = [])
{

    if (empty($lineItems))
    {
        return [];
    }

    $updated  = [];
    $amount   = 0;
    $adjuster = new Commerce_OrderAdjustmentModel();

    $adjuster->type        = 'Discount';
    $adjuster->name        = 'Quantity Pricing';
    $adjuster->description = 'The overall price of the cart has been adjsuted based on the number of items you are purchasing.';
    $adjuster->orderId     = $order->id;

    foreach ($lineItems as $lineItem)
    {
        $purchasable = $lineItem->purchasable;
        if (!empty($purchasable->quantityPricing))
        {
            $updated[]     = $lineItem->id;
            $updatedAmount = 0;
            foreach ($purchasable->quantityPricing as $qp)
            {
                if (
                    ($lineItem->qty >= $qp['minQuantity'] && $lineItem->qty <= $qp['maxQuantity'])
                 ||
                    ($lineItem->qty >= $qp['minQuantity'] && empty($qp['maxQuantity']))
                )
                {
                    $lineItem->discount = ($qp['price'] - $lineItem->price) * $lineItem->qty;
                    $updatedAmount      = $lineItem->discount;
                }
            }
            $amount += $updatedAmount;
        }
    }

    $adjuster->amount      = $amount;
    $adjuster->optionsJson = ['lineItemsAffected' => $updated];

    $adjuster->included = false;

    if (empty($updated))
    {
        return[];
    }

    return [$adjuster];
}
}

I was also seemingly able to do this using onPopulateLineItem but based on the advice below changed it. My code for that looked like this:

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

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

            // This method checks for quantity pricing and updates
            // line items costs depending on what it finds.
            if (!empty($purchasable->quantityPricing))
            {
                foreach ($purchasable->quantityPricing as $qp)
                {
                    if (
                        ($lineItem->qty >= $qp['minQuantity'] && $lineItem->qty <= $qp['maxQuantity'])
                     ||
                        ($lineItem->qty >= $qp['minQuantity'] && empty($qp['maxQuantity']))
                    )
                    {
                        $lineItem->price = (float) $qp['price'];
                    }
                }
            }
        });

As mentioned in the comments below, I'm not exactly sure why an Adjuster is the better route to go, because both seem to work.

Please don't hesitate to mention if I did something ridiculously stupid somewhere. It certainly wouldn't be the first time.

Have you looked into building an adjuster for this purpose? You can find the documentation here


Error: min/max value in number fields Is there any reason why min/max value are limited to the following?

[9999999999999]
- Min is too big (maximum is 2147483647)

I need to add ISBN numbers which are 13-digits. Is there a reason for this min/max length, and can it be increased?

Numbers have certain limits in computer systems and storing (as well as working with) exceptionally large ones is cumbersome.

In the database, the int (integer, a whole number) is limited to a range from -2147483648 to 2147483647. A bigint can range from -9223372036854775808 to 9223372036854775807 but is less common. And I don't think Craft uses bigints anywhere.

I know it's purely numerical, but could your ISBN numbers use a text field? Unless you're doing math on it then this should suffice. If you really want you could a new fieldtype that validates an ISBN number but saves as a varchar in the DB.


Cache/ColdCache & checking for ungenerated image transforms This issue is very similar to the following issue, but this goes a little bit further. Cache tag won’t cache in a template

I have a page which is made up of hundreds of lazy loaded images similarly to this:

 <img data-original="{{ image.getUrl(transform) }}" src="/img/placeholder.png" alt="" />

The page takes anywhere between 2 and 5 seconds to load, and yet the server isn't under powered in any way.

The majority of the images on the page aren't transformed within a few page loads. It's quite possible that there are images that no one will ever look at, therefore will never be transformed... Craft will hold off on caching until all the images are transformed; which might never happen.

I could duplicate the template, and turn off lazy loading, and get my client to load that page every time they make changes, but I would prefer not having to ask my client to anything like that.

Apart from loading stuff via ajax when needed, does anyone know of an easy way to get all the images transformed or to get caching working so that it doesn't require all assets to be transformed?

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.


Fatal error in StringHelper.php when using cache block around loop I'm getting a fatal error when wrapping a loop with {% cache %}{% endcache %} tags. The full error is:

  Fatal error: Allowed memory size of 134217728 bytes exhausted (tried
  to allocate 32 bytes) in /craft/app/helpers/StringHelper.php on line
  473

Here's a small code sample of what I'm doing

{!--
  `craft.locationAPI.fetchAllLocations` grabs ~200 entries with related data via custom SQL queries.
  Doing this because craft.entries was throwing memory limit errors.
--}

{% cache %}
  {% for entry in craft.locationAPI.fetchAllLocations() %}
    ...
  {% endfor %}
{% endcache %}

I'm guessing this is because the amount of data getting returned (~13300 lines in "View Source") is too large for the encodeMb4 function in StringHelper.php.

Anything I can do to avoid this?

Increase the amount of memory available to PHP through memory_limit is one option.

Another option is to reduce the amount of data (and therefore memory) you're dealing with in one request.

You don't share what craft.locationAPI.fetchAllLocations() is actually doing, but if you're returning results as Craft models, there is a significant overhead (performance and memory-wise) doing that with large data sets in Craft 2.x.  You could look and return more primitive data structures.

Another alternative is to batch the results and retrieve them over multiple AJAX queries.


How can I incorporate a variable into a string? How can I incorporate a variable into a string, so that the result is a longer string that includes the contents of a given variable?

For example, I have a variable called apple and its value is "Arlington Pippin" (it's a type of apple). I'd like to end up with a phrase that reads:

  There is an Arlington Pippin.

How could I accomplish this?

If you‘ve got a multi-lingual site (or even if you don’t), you can pass variables into strings with the |t filter:

{{ "Welcome back, {name}"|t( {'name': currentUser.name} ) }}

(See http://buildwithcraft.com/help/static-translations for details on how you can use the |t filter to translate your text.)


Overriding BaseFrontEndController in Craft Commerce Is there a clean way to alter the cartArray that is returned when updating the cart through ajax? Which is defined in the BaseFrontEndController Craft Commerce.

For example by using a module? In this question Override a model method via plugin, Yii 2 dependency injection support is mentioned, but I feel like I need someone to point me into the right direction.

Thank you!

The most easiest solution in Your case is to create a custom Controller that extends the default BaseFrontEndController to call that one. The issue for Dependency Injection is the following piece of code:

For example when you do

Craft::$container->set('craft\controllers\EntriesController', [
    'class' => 'prefix\namespace\controllers\FooController'
]);

You would overwrite the default EntriesController with your custom one and the function createControllerByID would do the following

if (is_subclass_of($className, 'yii\base\Controller')) {
    $controller = Yii::createObject($className, [$id, $this]);
    // $controller is now my custom prefix\namespace\controllers\FooController instead of the default

    // but the line below -> get_class($controller) === $className won't match
    return get_class($controller) === $className ? $controller : null;
}

Thus you'll receive an exception, it will work with most other classes/services/components that are created with Yii::createObject but not with Controllers. To change that behavior you would have to replace the createControllerByID in yii\base\Module

Just do as Brad Bell already said and create a custom controller.


Ajax - How to create a Category through actionTrigger I'm trying to create a jQuery/Ajax script to import data from a Wordpress API service and want to import the WP categories and tags into my database. I've managed to import the tags using an Ajax call to /actions/tags/createTag, is there any endpoint that does the same with categories?

Of course there is, otherwise we would not be able to store categories in Craft. The controller that handles categories is called CategoriesController and it contains the function actionSaveCategory so you route will be actions/categories/saveCategory

To create/save a user you have the UsersController.. You may guess the function is actionSaveUser => actions/users/saveUser

It's the same for every element in Craft. EntriesController, actionSaveEntry => actions/entries/saveEntry

But this all has nothing to do with an endpoint or an API, it's just basic Craft code


In the Element API plugin, how can I get only tags that are related to a particular section? I tried to get all tags that are related to an section.
Everything I tried failed. Is there a way to get all assigned tags for a particular element type by using element criteria model.
In this case travelImages? I want to avoid to display not related tags.

'elementType' => 'Tag',
'criteria' => ['relatedto' => 'travelImages']

The relatedTo parameter accepts either a single element ID or model, or an array of element IDs or models. It doesn't accept asset source handles, section handles, or a particular element type constant.

This means that in order to pull all tags related to a specific element type, you'll need to give the relatedTo parameter an array of all IDs for that particular element type.

You're not specific about what travelImages are, but assuming it's an Asset source, something like this should work:

'elementType' => ElementType::Tag,
'criteria' => [
    'relatedTo' => craft()->elements->getCriteria(ElementType::Asset, [
        'limit' => null,
    ])->ids(),
    'limit' => null,
],

Note that if travelImages isn't an Asset source, you'll need to change ElementType::Asset to the appropriate element type (e.g. ElementType::Entry, ElementType::Category etc).


Can Craft easily be hosted across multiple servers? We are looking at Craft as our CMS but would love to be able to scale the installation across multiple Amazon EC2 instances.

Is this possible?

Can all assets uploaded to Craft be pushed to S3?

Is there any other data (eg sessions) that are stored on local storage that would likely cause a problem?

Entirely possible. There is some discussion of having Craft installed in a load-balanced environment here.

You'll want to have CRAFT_STORAGE_PATH point to a shared file system for all servers.

If you have sticky sessions enabled at a load-balancer level, then PHP sessions won't be a problem.  If not, then you'll want to set overridePhpSessionLocation to true and have the PHP session files saved on the same shared file system.


active state macro how to check if segment 2 is empty I'm using a macro to check segment 1 to set an active state on my navigation and all is working correctly. However I would like to change it so that if segment_2 is not empty it doesn't display the active state, with the exception of being pagination in segment-2

so domain.com/photography and domain.com/photography/p2 would get active but domain.com/photography/slug would not be active

my current code is:

macro:

{% macro is_active(segment) %}{% if craft.request.firstSegment == segment %}active{% endif %}{% endmacro %}

and nav:

Home

All Photography

Archives

Not tested, but I think you can test if it is a pagination page. So

{% if (craft.request.getSegment('2') == '') or (craft.request.getPageNum() != 1) %}active{% endif %}


Export database table as .sql before deleting/removing a plugin When you delete/remove a plugin all the database tables related to it will be deleted and I would like to know if there is a way to keep them or store them into a file and force the user to download it.

I made some kind of forum and saved many relevant information in a custom table but if someone deletes/removes the plugin accidentally or to include another row nothing will work anymore.

Is there I function I can use in public function onBeforeUninstall() to save my table?

I know you can go to phpmyadmin/adminer an use the export function by hand but we are all people and we can forget that.

Thank you very much

If your plugin overrides onBeforeUninstall(), then you could call craft()->db->backup();

But that will backup the whole database via PHP code, which might not be what you want.

Since you're in a plugin, I'd probably make sure mysqldump is available to PHP via the command line and use that to execute it and that way you can also specify the exact tables you'd like to dump.


How do you import hierarchical data that uses the adjacency list model into Craft Structures or Categories? Craft makes it nice and easy for us to have hierarchy in Structures or Categories. Many other popular CMS platforms support hierarchical data as well but some support it using a different data model.

Here's an overview of managing hierarchical data in MySQL if anyone's interested:
http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql

In particular, I'm trying to understand the best way to migrate data that uses the Adjacency List Model into Craft which uses the Nested Set model.

Are there any tools to help translate how each item in the table of the adjacency list model refers to a parent to how the nested set model uses lft and rgt to identify how the items in the table are nested?

If there aren't any tools for this, is there any step-by-step process that might make this a bit more accessible?  Or could I just be thinking about it the wrong way?

This looks like a good high-level description of how to go about it.
Also possibly useful: How do you convert a parent-child (adjacency) table to a nested set using PHP and MySQL?.


How to reprocess image transforms that already exist in the database If I import a Craft DB into my local db, and it has references to image transforms that existed in another environment, it won't recreate them in the filesystem when a page is loaded that asks for one of those transforms. Is there a way to tell Craft to recreate these transforms, or is the only option to retrieve the transforms from the other environment and bring them over?

I tried running ./craft index-assets/all in the terminal but that didn't work. Not really sure what that command is meant for.

You can run ./craft clear-caches/transform-indexes to clear your transform indexes.


Unable to retrieve a cookie set by another application on the same domain We have a Laravel app that sets a cookie:

public function make($name, $value, $minutes = 0, $path = null, $domain = null, $secure = false, $httpOnly = true)
{
    list($path, $domain) = $this->getPathAndDomain($path, $domain);

    $time = ($minutes == 0) ? 0 : time() + ($minutes * 60);

    return new Cookie($name, $value, $time, $path, $domain, $secure, $httpOnly);
}

The values passed are as follows:

array (size=7)
    0 => string 'imph_auth' (length=9)
    1 => string 'Russ Back' (length=9)
    2 => int 2628000
    3 => null
    4 => null
    5 => boolean false
    6 => boolean true

I've tried to retrieve that cookie in a Craft template as follows:

craft.request.getCookie('imph_auth')

However I get null when I know that it's been set (I can browse to a Laravel template on the same domain and get the cookie).

I note the JavaScript warning in the Craft docs but this is set in PHP, however I can see the getCookies() method of the CookieCollection class runs each cookie through craft()->security->validateData() and fails validation.

Is there any way I can get around this without resorting to my own PHP in the template or a custom plugin?

Is there any way I can get around this without resorting to my own PHP in the template or a custom plugin?

You can't have PHP is a Twig template, but I think you'd need a real simple plugin for this.

It would just have an init() method that did:

craft()->request->enableCookieValidation = false;

Just be aware that's going to make it much easier for people to potentially tamper with cookie values.


Do something if first entry of a year I'm outputting a timeline for company history and i'd like to add a graphic for the Year before the first entry of each year. My current code is as follows:

{% set companyHistory = craft.entries.section('about').slug('company-history').first() %}

{% for moment in companyHistory.children.type('history') %}
    <li>{{ moment.title }}</li>
{% endfor %}

My date field is simply called 'date'. How might I go about this with the fewest possible DB queries?

I got it using the 'group' filter at : http://buildwithcraft.com/docs/templating/filters#group

Thanks to Steve Abraham for pointing me in the right direction. My code that seems to work is:

{% set companyHistory = craft.entries.section('about').slug('company-history').first() %}
{% set allEntriesByYear = companyHistory.children.type('history') | group('date.year') %}

{% for year, entriesInYear in allEntriesByYear %}

{{ year }}

    {% for moment in entriesInYear %}

{{ moment.title }}

    {% endfor %}
{% endfor %}

Let me know if there is an even better solution.


How to get one random entry from among multiple sections I'm trying to pull a random entry from among an array of sections, but I can't get it to work.

I tried the code below, but I'm just getting errors. I've tried multiple ways of listing the sections -- "section","section" ['section,section'],etc, but none work. Do I need to specify my sections in a different way?

{% set random = craft.entries.section('quotes,didYouKnow').limit(1).order('RAND()').find() %}
{% for content in random %}
...
{% endfor %}

According to the docs, you can pass an array into the "section" parameter:

{% set entries = craft.entries.section(['quotes','didYouKnow']) %}

There are several ways to get a random entry, but the method you've chosen is a very good one, because it randomizes during the initial SQL call:

.order('RAND()')

Lastly, you can cut out some of the extra legwork from your original example by calling first instead of find:

{% set entry = craft.entries.section('mySection').first() %}

When you retrieve your entry using first, you'll get a single entry instead of an array of entries. You can skip the for loop entirely, since you're already dealing with a single entry.

So to put that all together...

{% set randomEntry = craft.entries.section(['quotes','didYouKnow']).order('RAND()').first() %}

<h1>{{ randomEntry.title }}</h1>


Defining elements of a research project as assets or entries? May be over thinking this but I wonder if anyone else has had to deal with a similar issue.

I am building a site which holds my PhD research. The main type of assets I'll be presenting are:

Sketches
Audio files
Videos
Video Links

I'm am going back an forth between 1) creating individual entries for each asset , defining t's type and linking to the file 2) Adding fields to the assets themselves.

The benefit of 2) is I have no need to create unique entries which feels like additional work. The main drawback of 2) is I have no way of managing youtube links (or other links to external files) as an asset as no physical file exists in craft. I would ideally like to manage all these research elements in the same way.

These element can be viewed in various ways in craft through relatedTo. Which will allow sketches to be viewed in a sketchbook as individual sketches to be viewed in relation to a project. It seems that having them as entries (1) would make this easier, but I may be wrong.

Anyone any thoughts on this problem?

I response to Mats:

The plugin you suggest sounds perfect, Thanks.

As a specific example One type of research is a design journal. Each page is made up of a scan of the actual paper journal, Metadata, perhaps a few notes. All of which can be added to the asset. I have 2 options to create the book:

Using a structure:

Book (Entry type of Journal)
--Page 1 (Entry type of Page)
--Page 2 (Entry type of Page)
-- etc

Or, an entry with a matrix

Book (Entry type of Journal)
-- Pages (Matrix field)
---- Page 1 (Matrix block)
---- etc

But, the journal is only useful in that form so it can relate back to a physical copy (which will be handed as evidence). The pages although chronological don't necessarily represent a narrative flow. The narrative comes when I create a separate type of entry, a research project which is a way of pulling together all of the different elements. I would look something like:

-Research Project
-- Overview
-- Related Journal Pages
-- Related Audio recordings
-- Related Articles
-- etc

If the journal were a structure it would be easy to use an entry field in the Research Project, select individual pages and get the name of the journal it's in (it's parent). I'm using ManytoMany plug-in to create a 2-way relationship, so when viewing journal pages you would also see what projects it's mentioned in.

If I went the matrix approach it would be tidier. But, i could't link the Project to the Matrix Block (page) within a journal. I'd instead have to relate it to the original asset. Which would be fine, but instead of a simple parent.title to get the journal name displaying on the Project page. I'd have to run another query to find what journal the asset is related to. Which seem a bit.. unsatisfactory.

I'm not so concerned about not having a unique url for the asset. I'd probably display them from the parent page in 2 ways 1) Thumbnail grid to lightbox slideshow. 2) paginated results.

I'm not sure I've come to any conclusions with this bit or writing. I hoped I would. a) Structure and slightly necessary asset wrapped in an entry or b) asset simplicity and slightly more complicated way of simulating a parent structure ... hmmm.

Actually, there's a brilliant plugin called Embedded Assets, which lets you manage YouTube links and other embeddable media like first rate citizen Assets in Craft. I highly recommend it.

As for the more general question of whether to go with Entries or Assets – it's difficult to give a solid recommendation without knowing more about your project and its requirements, and it'll also probably come down to choice and preference a little bit.

I'm also not totally sure where you're going in regards to relatedTo, but again – Assets are first rate citizens in Craft, and they aren't limited in their capabilities compared to other types of content like Entries or Categories – certainly not when it comes to relations. Assets can be related to Entries, Categories, other Assets – sky's the limit.

Anyway – based on what you're describing, I would probably go for an Assets-only solution, rather than having Entries wrapping Assets. When the actual content is a file, and everything else is basically metadata, this is probably far the more elegant and effective solution.

Depending on your requirements, the only thing you may have to work around is the fact that Assets have no URLs (beyond the actual file URL, of course), nor can Asset sources be assigned a default entry template like e.g. Entries or Categories. For listing templates, search results etc. you can always rely on Craft routing your template filenames as URIs and then just create a craft.assets template query to fetch the Assets you need, but if you need to link to an individual Asset, you'll probably need to create a custom route.


How to display plain text only from redactor without any line break or format Is there a way to display plain text only without any line break or format style. I have an input field using the redactor. I want the result to shows plain text without any formatting for this particular page. How can I modify it?

{% set desc = desc|slice(0,150) %}
{% set _desc = desc|split(' ') %}
{% set __desc = _desc|slice(0,-1) %}
{% set desc = __desc|join(' ') %}
{{desc|raw}}

Thanks.

If you're trying to remove HTML tags from the output completely, you can use Twig's striptags filter: https://twig.symfony.com/doc/2.x/filters/striptags.html.

If you want to retain the tags but show the output without any styling, you're going to have to handle that with your CSS by negating any of the existing styling you don't want.


How to pull all images in [body] Matrix fields I'm working on a basic portfolio site wherein each entry or "project" has a body Matrix field with various blocks for various types of images. I'd like to make an index of all projects showing one slideshow/carousel for each project containing all images within that project.

The problem is that I don't know how to query all images at once = All images, all blocks, in the order they appear in the entry.

Here's my specific code in use. It's almost there but due to the 0 in image[0] it's only pulling in the first image from each instance of each Matrix Block. For example, there are two instances of the block called imageHalf and it pulls the first image from each.

I don't understand how to avoid this integer....

{% for block in entry.body %}

{% switch block.type %}

{% case "imageFull" %}

{% set image = block.image.total() %}

{% case "imageHalf" %}

{% case "imageCouple" %}

{% endswitch %}

{% endfor %}

I think you need to use a {% switch %} statement like the following:

{% switch matrixBlock.type %}

{% case "text" %}

    {{ matrixBlock.textField | markdown }}

{% case "image" %}

    {{ matrixBlock.image[0].getImg() }}

{% default %}

A font walks into a bar.

The bartender says, “Hey, we don’t serve your type in here!”

{% endswitch %}

You can read more here: http://buildwithcraft.com/docs/templating/switch


First Craft website: how to organize different content I am new to Craft and read a lot of arctilces and most of the docs. Most parts are quite easy. Now I plan how to organize all the different parts and pages.

Below is a simple outline. Not every page, but to get the ieda.

Home                            (Single)
- News                          (Section; structure: news)
  - Posts                       (news entry with category post?)
  - Press                       (news entry with category press?)
  - Media                       …
  - Events                      …
- About                         (Section; structure: pages)
  - About us                    (pages entry with defult entry type)
  - History                     (pages entry with defult entry type)
  - Team                        (pages entry with defult entry type)
- People
  - Locations                   (Section; channel: location)
  - Page-A, Page-B, etc…        (? other entry types)
- Members                       (Section; structure: pages)
  - Info                        (pages entry with defult entry type)
  - Jobs                        (?)
  - Listing                     (pages entry with defult entry type)
  - Register/Login              (?)
  - (PROTECTED MEMBERS AREA)    (?)
    - Auth-Group-I
      - Page A, Page B, …
    - Auth-Group-II
      - Page-A, Page-B, …

First:
There are 4 different "sections" (in terms of the content and audience). Would it be possible/a good idea to put alle those into one Craft section, titled pages?
And on those pages, where I need other content, like locations (store locator), I pull data from a dedicated section titled locations. Or on another I query the job listings.
That way I can group most pages, create the hierachy and spearate the content in logical groups/sections.

Second:
Otherwise, would it be better to give each website section its own Craft section.

Third:
What about those "special pages" like my register/login form, the job lsiting page, etc. Do they become a Single?

Fourth:
What is more appropriate for my different news pages: using categories or entry types?

I'll try answer each question as best as I can... Feel free to ask for more information if you still have questions.

First: For your use case, it might indeed by a good idea to put all actual pages in 1 structure, it allows you to better visualise the content structure. You can than pull in the required news, locations, jobs content with corresponding fields.

Second: It depends on how many pages you'll have, if you put it all in one big structure, and you have to many pages in there, you might loose the overview. From what you lined out, I'd put it in 1 structure, and you can still use different entry types if you need different content.

Third: Singles are ment to be one-off pages, mostly with a specific design, but yes, pages for registering, logging in are excellent candidates for singles. Once you'll use the fields or design on it more often, you might be better off putting it as an extra type in a section.

Specifically for Jobs, if those are again their own set of entries (I'd put them in a channel) you can use jobs/index.html as template for your overview page (assuming you specified jobs/_entry as path when registering the section).

Fourth: It all depends on how much the content itself will vary between posts, press and media. IF you'll need a different set of fields, you'll be better off creating different entry types. If however they'll all follow the same set of fields, you can work with categories to differentiate between the different pages.


Editing a tag not reflecting on all records.. kindof We have hundreds of entries with the improperly spelled tag "accessibilty" (the third i is missing). A search for "accessibility" will not find them (spelled correctly).

I edited the tag on a record and it seems all the records have updated (in the control panel). That is, the tag is spelled correctly on all records.

Search however, does not find them. Both in the control panel and using craft.entries.search('accessibility') only return the ONE record that I edited. If I search for the misspelled tag ('accessibilty') I get all the remaining results.

I've emptied all caches.

That's because your search indexes still contain the wrong word. Please go to your utilities section in your CP and rebuild the search indexes

Making changes in the DB directly is sometimes not a good idea if you don't know the consequences it might have. You should have changed the title via CP rather than via DB


Site is "Temporarily Unavailable" I get "Service Unavailable" when I go to my (hosted, not local) test site.

It had been working just fine until I decided to swap databases today.

I deleted the old database and replaced it with the new database.  I kept the database name the same.  I changed the username and password in cPanel and then duplicated those changes in my craft/db.php file... But no dice...  I get the nice little warning:

  Service Unavailable

  Our site is temporarily unavailable.  Please try again later.

I have checked more than once, the path, db name, username and password all check out.  Any suggestions?  ...other than start over

Others have said what the problem is, but in the interest of clarity for future readers...

Cause: The database is expecting a newer version of Craft's filesystem than you have.

Solution: Replace the /app folder with one from a fresh Craft download and visit your admin trigger URL


Contact Form Required Fields Plugin – formEntry error Has anyone experience with the ContactFormRequiredFields plugin? It works fine until the send button is pressed. It brings up an "Undefined variable: formEntry" error. When I look into the plugin I see that "formEntry" is connected to "formId". But what goes wrong?

        ...

        $formId = craft()->request->getPost('formId');
        $formId = craft()->security->validateData($formId);

        /**
         * Get the form entry using the ID
         */
        if ($formId)
        {
            $formEntry = craft()->entries->getEntryById($formId);
        }

        ...

Stack trace:

#0  /var/www/vhosts/tonartmusikschule.at/httpdocs/craft/app/etc/web/WebApp.php(693): CApplication->handleError(8, "Undefined variable: formEntry", "/var/www/vhosts/tonartmusikschule.at/httpdocs/craft/plugins/cont...",
#1  /var/www/vhosts/tonartmusikschule.at/httpdocs/craft/plugins/contactformrequiredfields/ContactFormRequiredFieldsPlugin.php(48): Craft\WebApp->handleError(8, "Undefined variable: formEntry", "/var/www/vhosts/tonartmusikschule.at/httpdocs/craft/plugins/cont...", 48, ...)
#2  /var/www/vhosts/tonartmusikschule.at/httpdocs/craft/app/framework/base/CComponent.php(567): Craft\ContactFormRequiredFieldsPlugin->Craft\{closure}(Craft\ContactFormEvent)
#3  /var/www/vhosts/tonartmusikschule.at/httpdocs/craft/plugins/contactform/services/ContactFormService.php(73): CComponent->raiseEvent("onbeforesend", Craft\ContactFormEvent)
#4  /var/www/vhosts/tonartmusikschule.at/httpdocs/craft/plugins/contactform/controllers/ContactFormController.php(139): Craft\ContactFormService->onBeforeSend(Craft\ContactFormEvent)
#5  /var/www/vhosts/tonartmusikschule.at/httpdocs/craft/app/framework/web/actions/CInlineAction.php(49): Craft\ContactFormController->actionSendMessage()
#6  /var/www/vhosts/tonartmusikschule.at/httpdocs/craft/app/framework/web/CController.php(308): CInlineAction->runWithParams(array("p" => "anmeldung_index"))
#7  /var/www/vhosts/tonartmusikschule.at/httpdocs/craft/app/framework/web/CController.php(286): CController->runAction(CInlineAction)
#8  /var/www/vhosts/tonartmusikschule.at/httpdocs/craft/app/framework/web/CController.php(265): CController->runActionWithFilters(CInlineAction, array())
#9  /var/www/vhosts/tonartmusikschule.at/httpdocs/craft/app/framework/web/CWebApplication.php(282): CController->run("sendMessage")
#10 /var/www/vhosts/tonartmusikschule.at/httpdocs/craft/app/etc/web/WebApp.php(836): CWebApplication->runController("contactForm/sendMessage")
#11 /var/www/vhosts/tonartmusikschule.at/httpdocs/craft/app/etc/web/WebApp.php(287): Craft\WebApp->_processActionRequest()
#12 /var/www/vhosts/tonartmusikschule.at/httpdocs/craft/app/framework/base/CApplication.php(185): Craft\WebApp->processRequest()
#13 /var/www/vhosts/tonartmusikschule.at/httpdocs/craft/app/index.php(62): CApplication->run()
#14 /var/www/vhosts/tonartmusikschule.at/httpdocs/public/index.php(19): require_once("/var/www/vhosts/tonartmusikschule.at/httpdocs/craft/app/index.ph...")

The plugin expects the the ID of the entry you are using to build the form fields to be submitted along with the form so it is available as a request variable.

You should include the ID of the entry you are using to build the form’s fields when you are submitting to the contactForm/sendMessage controller. For example:

{% set form = craft.entries({
    section: 'forms',
    slug: 'contact-form',
}).first() %}

<form method="post" accept-charset="UTF-8">
    <input type="hidden" name="action" value="contactForm/sendMessage">
    <input type="hidden" name="formId" value="{{ form.id|hash }}" />
    ...
    {# Loop through the form fields here #}
    <button type="submit">Send</button>
</form>

The code above assumes you have a section with the handle forms and the slug of the entry you want is contact-form.

If you want a more robust solution that provides the form builder and validation out of the box, you might consider checking out Freeform from Solspace.


Redactor 3 config code I'm trying to get the same features I had in Craft 2 in Craft 3 redactor field.
This is the code I had in config/redactor/standard.json:

{
    "buttons": ["format","bold","lists","link","file"],
    "plugins": ["fullscreen","table","video"],
    "formatting": ["p"],
    formattingAdd: {
        "heading": {
            title: 'Heading',
            args: ['h2']
        },
        "sub-heading": {
            title: 'Sub-Heading',
            args: ['h3']
        },
        "sub-sub-heading": {
            title: 'Sub-sub-Heading',
            args: ['h4']
        },
        "add-attr": {
            title: 'Make a link a button',
            args: ['div', { 'class': 'button' }]
        }
    }
}

The Craft 3 changes page says:
"All strings must use double quotes rather than single quotes" and that "All object properties (the config setting names) must be wrapped in double quotes".
I've tried changing them all and I still get an error. I've looked on the Imperavi Redactor docs pages, but they don't use double quotes and their examples are not in the same format as the craft plugin uses. Some more examples would be useful.

After several iterations I came up with this that works. But still puzzled as when to use [ ] or { }.

{
    "buttons": ["html","undo","format","bold","lists","link","file"],
    "plugins": ["fullscreen","table","video"],
    "formatting": ["p"],
    "formattingAdd": {
        "heading": {
            "title": "Heading",
            "api": "module.block.format",
            "args": {
                "tag": "h2"
            }
        },
        "sub-heading": {
            "title": "Sub-Heading",
            "api": "module.block.format",
            "args": {
                "tag": "h3"
            }
        },
        "sub-sub-heading": {
            "title": "Sub-sub-Heading",
            "api": "module.block.format",
            "args": {
                "tag": "h4"
            }
        },
        "add-attr": {
            "title": "Make a link a button",
            "api": "module.block.format",
            "args": {
                "tag": "div",
                "class": "button"
            }
        }
    }
}


Approaching Google AMP Does anyone have any thoughts on automating the implementation Google's new AMP article markup?

https://www.ampproject.org/docs/get_started/create/basic_markup.html

Also see:
Google will start sending search traffic to fast-loading AMP news articles in February 2016

Thanks!

You're asking kind of a loaded question but as far as Craft is concerned, you're in a good position to spit out exactly what you need as far as markup and styles go. AMP is more or less just a small subset of HTML.
When compared to something like WordPress, Craft is going to give you all the tools necessary to spit out an AMP page just by virtue of it doesn't dictate layout and styling nor include any extra fluff. And it provides easy routing features to make it easy to make different "versions".
Different Versions / Different Routes
Depending on how your site is setup, you'll want different versions of your content—one regular and one for AMP... not unlike the old m dot sites. (Taking it back to the old school WAP era I guess...)
Let's say you have a section called News.  If your entries URL Format looks like: http://site/news/slug/, you might want to have the AMP version look like http://site/news/slug/amp.
One way to do that in Craft is to setup a route. You can do that in Settings -> Routes -> New Route.

That will load the _amp.html template inside a news folder. You'll have to do a little extra work to tell Craft where to pull the entry from since routes only load templates by default. Since we used the slug variable in our routes, we can use that to grab the entry from the news section and also set the entry variable.
{% extends "_layoutamp" %}

{% set entry = craft.entries.section('news').slug(slug)[0] %}

{% block content %}
  ... rest of your content
{% endblock %}

The AMP docs start with a simple skeleton. I used {% extends "_layoutamp" %} in our _amp template so we need to make a  ``_layoutamp.html" file to match inside Craft's templates folder.
   {# _layoutamp.html #}
    <!doctype html>
    <html amp lang="en">
      <head>
        <meta charset="utf-8">
        <title>{{entry.title}}</title>
        <link rel="canonical" href="{{entry.url}}" />
        <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
        <script type="application/ld+json">
          {
            "@context": "http://schema.org",
            "@type": "NewsArticle",
            "headline": "{{entry.title}}",
            "datePublished": "{{entry.dateCreated.iso8601()}}",
            "image": [
              "logo.jpg"
            ]
          }
        </script>
<style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style><noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
        <script async src="https://cdn.ampproject.org/v0.js"></script>
      </head>
      <body>
        {% block content %}
           {# brings in the content from the _amp.html content block #}
        {% endblock %}
      </body>
    </html>

AMP recommends some metadata near the top, in the form of JSON. Easy enough to spit out the required fields in Twig.
"Linking" to an AMP page
You'll notice a <link rel="canonical" href="{{entry.url}}"> in that file as well to tell Google your main version is here.
On your "normal" page, you'll want to add a reference to the AMP page too. (I also like to set the canonical version as well for good measure.
<link rel="canonical" href="{{entry.url}}">
<link rel="amphtml" href="{{entry.url}}/amp">

That will tell Google the AMP version is at the URL.
Anything else?
Pretty much the rest is up to you. AMP is pretty easy to setup but you still need to use their custom tags.
Most notably, things like images and videos need to use custom tags like amp-img and amp-video, so the AMP runtime can intercept the loading of those assets and handle them.
Will be interesting to see how this affects page rank moving forward. Google confirmed it's not a ranking signal (yet) but that doesn't mean it won't be in the future.


How to get second asset? I have an entry with an asset field that has up to 3 assets in it. If I want to load just the second asset in my template code, what's the syntax for this? (can't find any references/examples)

In Craft 3 this should be:
  {% if entry.images | length > 1 %}
    {% set secondImage = entry.images.1 %}
  {% endif %}


How can I repopulate a matrix field on a front-end form? I have a matrix field on my front-end form. Everything is working properly, data is saved correctly etc.

I am testing & trying to break things and I noticed I wasn't repopulating those fields if validation failed.

Here is how I am attempting to repopulate the value(s) in my front-end form:

<input type="hidden" name="fields[myMatrixFieldHandle][new1][type]" value="blockType">
<input type="hidden" name="fields[myMatrixFieldHandle][new1][enabled]" value="1">

...
value="{{ entry.myMatrixFieldHandle.blockType.fieldHandle }}"
...

When I dump the above, I am getting the whole object back. I'm not sure how to get to the actual field's value.

Using the example above, here is how you can re-populate the given matrix field(s). The below is assuming only one matrix field is visible by default [0]. Depending on your use case, you may need to dynamically generate the index number.

...
{%- if entry is defined %} value="{{ entry.myMatrixFieldHandle[0].fieldHandle }}"{% endif -%}
...


How do I create pagination links for my entry index page? So I may be somewhat obtuse here, but I’m trying to discern what I might be doing wrong in this instance. I’m attempting to use a {% paginate %} tag inside my craft.entries loop to return a simple next/previous set of pagination links. I have ensured I have two entries already, so I should be seeing the pagination links, correct?

{% for entry in craft.entries.section('houseRules').limit(1) %}

            {# Content is Here #}

    {% paginate craft.entries as entries %}
        {% if paginate.prevUrl %}Previous Page{% endif %}
        {% if paginate.nextUrl %}Next Page{% endif %}
    {% endpaginate %}
{% endfor %}

You have your {% for %} and {% paginate %} tags in the reverse order. You need to wrap the loop and the pagination URLs with the {% paginate %} tag pair:

{% paginate craft.entries.section('houseRules').limit(1) as entries %}

    {% for entry in entries %}

                {# Content is here #}

    {% endfor %}

    {% if paginate.prevUrl %}Previous Page{% endif %}
    {% if paginate.nextUrl %}Next Page{% endif %}

{% endpaginate %}

Notice how we’re actually looping through entries, rather than a new craft.entries call. That entries variable will be an array of the current page’s entries. All we had to do is define what we wanted that variable to be called (e.g. “entries”).

See http://buildwithcraft.com/docs/templating/tags#paginate for more details on what can be done inside the {% paginate %} tag pair.


How to make fields required on the contact form? When using the Pixel & Tonic contact form (https://github.com/pixelandtonic/ContactForm) how do you make the fromName field required?

When using the form as seen on github, only the message and email field are required.

Thank you!

You could also hand this over to HTML since it supports form validation as of version 5.
Depends on your browser support requirements though. This is what “Can i use” says.


Prevent Redactor from adding site identifier to entry links I have a multi-site setup, and when using Redactor's Link to an entry function, by default, site identifiers are added to the link href:

href="https://mysite/my-page#entry:4223@3:url"

I would like to prevent (or strip out) the @3 site identifier, because I wish to use the current site's base URL, rather than specify a specific site's base URL be used. Is this possible?

I solved this by creating a Redactor plugin that listens for the link.inserted event and strips out the site identifer:

craft/config/redactor/plugins/myplugin.js:

(function($R)
{
    $R.add('plugin', 'myplugin', {
        onlink: {
            inserted: function(link) {
                link.nodes.forEach(node => node.href = node.href.replace(/@\d+/, ''))
             },
        },
    });
})(Redactor);

craft/config/redactor/redactorFieldConfig.json:

{
    "plugins": ["myplugin"]
}


Get full file url, avoiding the siteUrl trailing slash so I'm using an asset field for an OG Image. I need to get the full url for this and I've yet to find a clean way to do this. I figured I could just combine siteUrl and the asset url but I have a weird issue with a double slash.

<meta property="og:image" content="{{siteUrl}}{{entry.ogImage.first().url}}/>

This does what I expect except it adds a slash at the end of {{siteUrl}} and the beginning of the asset so my url is bad, leaving me with a double slash. Short of some programatical removal of the slash, is there another way to do this? Why does my siteUrl have that trailing slash? is something wrong there?

Instead of {{siteUrl}}{{entry.ogImage.first().url}}, try {{entry.ogImage.first().getUrl()}}. getUrl() should return the full image path, including host.


Send an asset from a plugin controller I have a controller which fetches an asset from an entry (this is the service method that provides the asset):

public function findPoster($entryId) {
    $criteria = craft()->elements->getCriteria(ElementType::Entry);
    $criteria->id = $entryId;

    $entry = $criteria->first();

    if ($entry) {
        if ($entry->downloadItem) {
            return $entry->downloadItem->first();
        }
    }

    return null;
}

That works great, however now I need to send the asset to the browser. Having a little poke around in the method listing I see there is a CBaseController::renderFile() which sounds to be what I need, however I can't work out the correct way to build a path to the file. Accessing $url from the asset I've fetched returns a public relative path but obviously I need the path on the filesystem.

So far I've got this working:

$name = strtolower($asset->title) . '.' . $asset->extension;

header('Content-Type: ' . $asset->getMimeType());
header('Content-Disposition: attachment; filename=' . $name);

$path = realpath(craft()->basePath . '/../../public/' . $asset->url);

die(file_get_contents($path));

However this is far from ideal because:

I have to hardcode the public directory which isn't the case at any other point in Craft, so it feels really dirty.
Manually setting the headers seems like something a controller method would be able to take care of properly.

There might be a way to do this with CBaseController::renderFile(), but I'd just use craft()->request->sendFile().

The 3rd parameter is an optional $options array and you can pass a 'forceDownload' => true as one of the key => value pairs to force it to download to the browser.

Instead of hardcoding the the path to your public assets folder, you can do something like:

$path = IOHelper::getFolderName(craft()->request->getScriptFile());

That should get you the path to the folder your public index.php file is executing in and you can tack on your public asset path from there.


Display related entries on a category page filtered by another category field I have a Structure called "Stoves".
Each Entry has two Category fields 'fuelType' and 'output'.

Fuel Type categories = ''Wood Burning','Multi-Fuel','Gas' and 'Electric'.
Output categories = '4kW','6kW','8kW','10kW',

On the category page template the following simple code gives me the correct entries based on the 'fuelType' field...  e.g. when viewing the 'Wood burning' page it shows me Wood Burning stoves.
{% set entries = craft.entries.relatedTo(category).all() %}

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

{% endfor %}

But I now need to also loop through the 'output' category group so I get something like the following:
ALL Wood Burning Stoves
Intro Text
start loop

4kW Stoves

Stove_4kW_No.1

Stove_4kW_No.2

Stove_4kW_No.3

6kW Stoves

Stove_6kW_No.1

Stove_6kW_No.2

8kW Stoves

Stove_8kW_No.1

Stove_8kW_No.2

Stove_8kW_No.3

Stove_8kW_No.4

...and so on....
end loop
Is this even possible?  Alternatively could I pull with individual entry queries using the individual 'output' category slugs?
Many thanks

You'd typically use the group filter for this. Depending on what you need to output, be sure to also use eager loading to improve performance.
{% set groupedEntries = craft.entries.with(['yourOutputCatFieldHandle']).relatedTo(category).all()|group('yourOutputCatFieldHandle[0].title') %}

{% for cat, entries in groupedEntries %}

{{ cat }}

        {% for entry in entries %}

{{ entry.title }}

        {% endfor %}

{% endfor %}

EDIT: alternative answer below to allow for using the correct category ordering as per the control panel's Structure order.
Note: this approach requires the supersort plugin.
{# ======================================
First, fetch entries related to this category,
then group the array by each category's
`lft` structure position, then sort the array
by those keys with supersort's ksort function
========================================= #}

{% set groupedEntries = craft.entries.with([
        'yourOutputCatFieldHandle'
    ])
    .relatedTo(category)
    .all()|group('yourOutputCatFieldHandle[0].lft')|supersort('ksort')
%}

{# ======================================
Next, create a hash map of those categories so we can
match up the `lft` left structure position
with the category's title later.
(google "Nested Sets" if you're really bored)
========================================= #}

{% if groupedEntries|length %}
    {% set catTitlesMap = craft.categories.group('yourOutputCatGROUPHandle').all()|group('lft') %}
{% endif %}

{# ======================================
Finally, loop through the grouped array,
matching up the accessory's `lft` position
with the hash map to get the right title...
========================================= #}

{% for cat, entries in groupedEntries %}

{{ catTitlesMap[cat][0].title }}

        {% for entry in entries %}

{{ entry.title }}

        {% endfor %}

{% endfor %}


FeedMe Change Slug when Importing I asked this question previously before Feedme was acquired by Craft, though I haven't updated Feedme & the code since now.
I'm getting the following error when processing my feeds. I'm trying to change my entries slug when they get imported but only on a certain feed - in this case - a feed with the title of 'merchants'

Argument 1 passed to craft\feedme\Plugin::craft\feedme{closure}()
must be an instance of craft\feedme\FeedProcessEvent, instance of
craft\feedme\events\FeedProcessEvent given - Plugin.php: 67

The code I'm trying to run in Plugin.php
public function init()
{
    parent::init();

    self::$plugin = $this;

    $this->_setPluginComponents();
    $this->_registerCpRoutes();
    $this->_registerTwigExtensions();
    $this->_registerVariables();

    Event::on(
      Process::class,
      Process::EVENT_STEP_BEFORE_ELEMENT_SAVE,
      function(FeedProcessEvent $event) {
        switch($event->feed['name']){
            case 'merchants':
                $element = $event->element;
                $element->slug = ElementHelper::createSlug($element->title.' '.'Coupon Codes & Promo Codes');
                break;
        }
    });
}

I've managed to get it working with great help from Brad Bell and Oli.
The following code changes feedme slugs on Import.
use craft\feedme\events\ElementEvent;
use craft\helpers\ElementHelper;
use craft\elements\Entry;

Adding the following Event with the namespaces above works nicely.
        Event::on(
          Process::class,
          Process::EVENT_STEP_BEFORE_ELEMENT_SAVE,
          function(craft\feedme\events\FeedProcessEvent $event) {
            switch($event->feed['name']){
                case 'merchants':
                    $element = $event->element;
                    $element->slug = ElementHelper::createSlug($element->title.' '.'Whatever you'd like appended!');
                    break;
            }
        });


Merging options to pass with an include I'm trying to pull in the contents of a matrixField block and merge it with some default info —

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

{% for interview in interviews %}

    {% set blocks = interview.thumb %}
    {% for block in blocks %}

        {% set options = block|merge({
            'class': 'episode',
            'more': 'Listen to this interview...',
            'slug': craft.request.firstSegment,
            'linkUrl': interview.url,
        }) %}

        {% include '_includes/blocks/half-block.html' with { options: options } %}

    {% endfor %}
{% endfor %}

I get the error: Key "body" for array with keys "id, enabled, archived, locale, localeEnabled, slug, uri, dateCreated, dateUpdated, root, lft, rgt, level, searchScore, fieldId, ownerId, ownerLocale, typeId, sortOrder, collapsed, class, more, reverse, linkUrl" does not exist

Why am I getting block with the values of the entry instead of that single block of type thumb?

(where thumb has a field called body)

I had tried {% set block = interview.thumb.first() %} instead of {% set blocks = interview.thumb %}{% for block in blocks %} but was trying to be more explicit to see if it made a difference.

I suspect this isn't so much a problem with the strategy as the implementation of the MatrixBlockModel, which is the object type you're trying to merge with a standard Twig "object" or associative array (not sure exactly what Twig uses, behind the scenes).

If you're trying to provide some defaults for various Matrix fields, those ought to be set within the fields, individually.

Otherwise, I think the solution you need is something like this:

{# ... #}
{% set blocks = entry.matrixBlockField %}
{% for block in blocks %}

  {% set options = {
    'class': 'episode',
    'more': 'Listen to this interview...',
    'slug': craft.request.firstSegment,
    'linkUrl': interview.url
  } %}

  {% include '_includes/blocks/half-block.html' with {
    options: options,
    data: block
  } %}
{% endfor %}
{# ... #}

In your partial, you have a bit more work ahead of you, but the special behavior of Twig's ternary operator should help:

{{ data.field ?: options.fallbackField }}

I may be misunderstanding the problem, though— is there something about fetching the MatrixBlockModel elements that appears to be going wrong? As a general rule, I try and avoid using any Twig/Craft reserved words/terms for variable names, but I don't think that's the root of the problem here…


How to setup conditionals within a matrix? In my matrix field, I want to be able to upload my image, and then upload another asset (in this case it would be a document) so that that image I upload links to that document.

I have my Matrix field setup like so:

Image ->
  -Image
  -linkedDocument

How can I set up a conditional where only add in the  tag if I add an asset there?

Here is my relevant code:

% elseif block.type == "image" %}

        {% set image = block.image.first() %}

        {% if image %}

            {% endif %}
        {% endif %}

If you have an image, you want to display it, and if there is also a linkedDocument, you want the image to link to that document. This should handle both cases, without too much code duplication.

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

  {% set image = block.image.first %}

  {% if image %}
    {# set the imgTag, which we will display regardless #}
    {% set imgTag %}
       alt="{{ image.title }}">
    {% endset %}

    {% set linkedDocument = block.linkedDocument.first %}

    {# we may or may not have a linkedDocument. Display the image in either case #}
    {% if linkedDocument %}
      {{imgTag}}
    {% else %}
      {{imgTag}}
    {% endif %}
  {% endif %}

{% endif %}


Can user group permissions be used to override entry section locale settings? I have created a localized site with 9 locales for a client in craft v2.6. They are now requesting us to create a user group for each locale so they can assign editors for each of those regions. When a user creates a new entry they want the new entry to be enabled only for the preferred locale for that user instead of the default enabled locales that are set in the section setting. Is it possible to override a section’s settings based on user group permissions? I know this is a strange request and I don't believe it is doable but wanted to see if anyone had any thoughts on this.

Is it possible to override a section’s settings based on user group permissions?

There's nothing native in Craft that would allow you to do this.

Maybe you could do something like write a plugin that listened to the onBeforeSaveEntry event and simulate it by enabling/disabling it for various locales based on the current user's permissions.


Display X number of characters from an entry I want to display just a short blurb from each blog entry. I dont know how to display my { entry.blogentry } without having all of the text show up.

Is there a way to just show the first 100 characters OR first few lines?

You can use the Twig slice filter do do this, e.g.: entry.text |slice(0, 100)

If you want something that looks a little nicer, and you're using the SEOmatic plugin, you can use the truncateStringOnWord filter, which will truncate to the number of characters you want, but only on word breaks (and it'll add an …).


How to profile Craft CMS I would like to turn on a profiler in Craft CMS so I can see what DB queries are being run and how long they take.

Is this possible?

Yup! Just turn on devMode in your general config:

return array(
    'devMode' => true,
);

And then just open up a console (Firebug, Chrome, etc) and look in the profiling summary report.


Which twig file is being used and how? I have a page in Craft (2.x) that displays several links and I was able to find which twig file had those links by searching the code base of twigs.  Those links point to some Angular code with links like this:

/support/give?source=

By trial and error, I discovered that the Angular code is invoked as part of a twig file in craft/templates/_views/  The original conundrum was there were two "give" files:  give.twig and give-new.twig and I didn't know which one was the actual twig invoked.  By trail and error again, I determined it was using the give-new.twig by changing the template.  But for the life of me, I cannot figure out how THAT twig is being invoked.  I scanned for "give-new" in the code, both craft and Angular and I searched in Settings, Routes and Web Content for any reference to it but I cannot figure out how a URL like /support/give maps to the give-new.twig file.

So the question is: How do I know which twig is invoked by a URL?  I am pretty sure that there isn't any Angular code doing this, the Angular code bundle references are in the twig file, but how that twig is invoked is a mystery.  Where do I start in finding the reference?

You could use this variable to get the template name: {{ _self.getTemplateName() }}

Put it at the top of all your template files:

<!-- {{ _self.getTemplateName() }} -->

And then for every template called it should have the commented out template name.

In Craft 3, there's a nice plugin called "Template Comments" which is great for this... But I don't see a version for Craft 2.


How do I sort entries by two variables? Currently I am sorting the entries by an ID:

{% for gallery in craft.entries.section('Gallery').order('available desc').limit(none) %}

but I would like to show the latest entries on top, currently it shows available first but latest entries ones go to the bottom. How can I mix the above code with something like this?

.order('postDate desc') %}

If you want to order by multiple columns that include custom fields, first make sure you're at least on Craft 2.4.2684, then you'll be able to use this syntax:

{% for gallery in craft.entries.section('Gallery').order('postDate desc, available desc').limit(null) %}

Also note that that you should be using limit(null) instead of limit(none) if you want to result all results.


How to display submission data on a thank you page with sprout forms? How can the thank you page display submitted values? I'd like to give the users the submission id to reference.
I've tried adding a hidden redirect field with a shortcode GET parameter but haven't got the syntax right.

You can grab the last submitted entry on the thank you page. So using the example, you should be able to do lastEntry.id


Sprout Email - output the I've got a notification set up when a user is saved/updated.

I'm trying to add the author/user who made the update

Tried the following to see what returns and nothing:

{author}

{author.email}

{author.firstName}

{{object.author.email}}

The dynamic object passed to a Notification Event depends on which Event is being triggered. In your case, the "When a user is saved" event has access to the User Model.

All of the attributes you are trying to access are on that User Model and are directly associated with the model itself:

{firstName}
{lastName}
{email}

{{ object.firstName }}
{{ object.LastName }}
{{ object.email }}

In your example, you are trying to access the attribute author. However, author is an attribute from the Entry Model. The Entry Model is available to the "When an entry is saved" event and other Entry-specific events.


Conditional to compare segment_1 in the URL with the URI of a specified entry I'm trying to write a conditional that adds a class of 'here' to a navigation menu item if segment_1 of the URL matches the URI of the entry I'm specifying. But it isn't outputting anything, so I'd appreciate any help with this, thanks. Here's my code:

{% set about_entry = craft.entries.id(17).first() %}

{{ about_entry.title }}

This conditional works fine if I change '{{ about_entry.uri }}' for a hard-coded 'about', but I want the URI to be dynamic in case it gets changed in the future/

In Twig you'll never, ever need to nest logic tags, within output tags or visa-versa.

The syntax you're looking for is:

{% set about_entry = craft.entries.id(17).first() %}

{{ about_entry.title }}


Defining fields on a per-entry basis? Consider a site with a very flat hierarchy that has a lot of basic pages. Most pages on the site are extremely similar, so they can all share the same entry type (and thus, fields) without problems.

The problem is, there are a few pages that have wildly unique content layouts. There's special content that will only ever be used on these pages.

From my understanding, there's a few solutions to this:

Use a Matrix field in the Page entry type and add a block for each special page you need. This lets you build the unique pages, but for the dozens of other "normal" pages it becomes very weird and unnatural (plus there's nothing stopping the client from erroneously adding the 'special page' Matrix blocks on non special pages).
Using multiple entry types, but this is also a bit clunky and would mean have to using a Channel or Structure.
Use Global sets (one for each special page). Also a bit of a dirty workaround.

Is there a cleaner way to achieve "one-off" fields that are used only by a specific entry?

Another CMS - Bolt - has a solid solution to this: Template Specific Fields. As another example: using WordPress with ACF, you can assign field layouts on a per-entry basis if required.

I was hoping something similar could be achieved in Craft.

Let's start by saying what you don't want to do...

Don't use Matrix blocks to solve this problem. As you mentioned, the Matrix field would get pretty crazy, and you couldn't prevent people from using the wrong blocks in the wrong places.
Don't use Globals to solve this problem. Global fields get loaded automatically on every page load, so you're bound to add a lot of extra page weight that doesn't need to be there.

To me, it sounds like entry types are the perfect solution. You can have multiple entry types which all share the same fields, but then add extra fields to the entry types which specifically need them. If I'm understanding your problem correctly, it's exactly what entry types were created to solve.

Lastly, you mention needing a Channel or Structure to use entry types. This is 100% true, but it makes me wonder... Are you currently just using Singles? If you're currently using Singles, then this should be a non-issue... each Single is basically a unique entry type anyway.

Hope that helps, let me know if I missed something.


Retrieve entry field value from a different locale? Is it possible to retrieve a field value from an alternate locale? I'm working on a multi-language dictionary website and it would be helpful to display values for an entry in more than one locale (language), while the main content stays in the current locale. Right now I have something setup like this:

{% for word in dictionaryWords %}
    {# returns definition for the word in the current locale #}

{{word.definition}}

{% endfor %}

I'd like to add a secondary definition in another language from a different locale. Something like this, but I'm not sure how to get at the field data from a different locale.

{% for word in dictionaryWords %}

  {# returns definition for the word in the current locale #}

{{word.definition}}

  {# returns definition for the word in a secondary locale #}
  {% if currentLanguageID == "languageID1" %}

{{ word definition in language 2 }}

  {% elseif currentLanguageID == "languageID2" %}

{{ word definition in language 1 }}

  {% endif %}

{% endfor %}

You can just manually fetch the entry in the other locale.  Assuming you already have the first entry, something like:

{% set localeEntry = craft.entries.id(entry.id).locale(languageID1).first() %}

{% if localeEntry %}
    {{ localEntry.otherWordDefinition }}
{% endif %}


Can a plugin force download an asset from third-party source like Amazon S3? I have created a plugin that takes a form post, retrieves an asset id and am trying to have the browser start the download process. Is this possible if using a third party source like AmazonS3?  If so what may be wrong with this plugin controller method?

public function actionDownloadAsset()
{
    $this->requirePostRequest();
    $id = craft()->request->getRequiredPost("id");

    $attributes = array('id' => $id);
    $element = craft()->elements->getCriteria(ElementType::Asset)->limit(1)->find($attributes);

    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename='.basename($element->filename));
    header('Content-Transfer-Encoding: binary');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . $element->filesize);
    readfile($element->url);
}

Everytime I try the plugin from front end I get a page not found.  I have made sure the from is posting to the controller method.

I have found a solution.

public function actionDownloadAsset()
{
  $this->requirePostRequest();
  $id = craft()->request->getRequiredPost("id");
  $attributes = array('id' => $id);
  $element = craft()->elements->getCriteria(ElementType::Asset)->first($attributes);

  $file = $entry->url;
  $name = $entry->filename;

  header('Content-Description: File Transfer');
  header('Content-Type: application/octet-stream');
  header('Content-Disposition: attachment; filename='.basename($name));
  header('Content-Transfer-Encoding: binary');
  header('Expires: 0');
  header('Cache-Control: must-revalidate');
  header('Pragma: public');

  readfile($file);
}

To get access to the file url I had to array_shift the $element returned from getCriteria.  Then I had to exclude the file size header. This was ultimately causing the "this webpage is not available". Not sure the reason.

header('Content-Length: ' . filesize($entry->size))


Filter entries by matching an url segment to Checkboxes Field values I have succsefully managed to filter entries by matching an url segment to a Radio Buttons Field in my entries, like this:
(here category is the field handle of my Radio Buttons field)

{% set filteredEntries = craft.entries.section('news').category(craft.request.getSegment(2)) %}

After having to change the Radio Buttons Field to a Checkboxes Field I tried adapting my code like this:
(here category is the field handle of my Checkboxes Field)

{% set filteredEntries = craft.entries.section('news').category.contains(craft.request.getSegment(2)) %}

But it doesn't work. Any suggestions?

This is just a guess, as I've never used the 'contains' method before, but it's possible that it can't be used directly with an ElementCriteriaModel query. You might have to filter the entries after the fact.

{% set entries = craft.entries.section('news') %}
{% for entry in entries if entry.category.contains(craft.request.getSegment(2)) %}
    {{ entry.title }}
{% endfor %}

This probably defeats the purpose of using it as a psuedo-category selector however.

Update If this answer is any indication it also looks like you could use the search method. Using this method, however, may not be 100% reliable if the search index becomes outdated for whatever reason.

 {% set entries = craft.entries.section('news').search('category:' ~ craft.request.getSegment(2)) %}


Can I store Assets on a Cloud Service like Amazon S3? Is there any way to store Assets on a Cloud Service?

Yes, you could install the Amazon S3 Plugin in order to select & configure that Volume type in your control panel.
After installing that you will get new volume type “Amazon S3” in Settings → Assets → New Volume.

Now you can create new column and using it you can store your assets in Amazon S3 cloud service.


Use Service Worker in Plugin I am currently working on a plugin that uses a service worker which gets registered  on the front-end by some javascript code and the problem is that the service worker scope is restricted to /cpresources/610c42da/ as the Asset Manager only serves the file from there.

Here's the code which I currently use to integrate with the front-end:

Craft::$app->getView()
                   ->hook('cachecraft', function () {
                       // Pass the service worker url to the site
                       Craft::$app->getView()
                                  ->registerScript(
                                      'const CACHECRAFT_SERVICE_WORKER = "' .
                                      Craft::$app->assetManager->getPublishedUrl('@skayo/cachecraft/assetbundles/cachecraft/dist/js/service-worker.js', true) .
                                      '";',
                                      1,
                                      [],
                                      'cachecraft_service_worker'
                                  );

                       // Register asset bundle
                       Craft::$app->getView()
                                  ->registerAssetBundle(CacheCraftAsset::class);
                   });

So what I need is to serve my service worker from the root (https://example.com/service-worker.js) of the website.
Is that possible somehow?
Another possible way is to serve the file normally at https://example.com/cpresources/610c42da/service-worker.js BUT with a Service-Worker-Allowed HTTP Header.
But I don't know how to do that either...

Thanks in advance for any help!

Solved it by just serving the file within a controller action like this:

public function actionCacheCraftServiceWorker () {
    $serviceWorkerFile = Craft::getAlias('@skayo/cachecraft/assetbundles/cachecraft/dist/js/CacheCraftServiceWorker.min.js');

    return Craft::$app->getResponse()->sendFile(
        $serviceWorkerFile,
        'CacheCraftServiceWorker.min.js',
        [
            'mimeType' => 'application/javascript',
            'inline' => true
        ]
    );
}

and using this event to register the front-end url:

Event::on(
    UrlManager::class,
    UrlManager::EVENT_REGISTER_SITE_URL_RULES,
    function (RegisterUrlRulesEvent $event) {
        Craft::debug(
            'UrlManager::EVENT_REGISTER_SITE_URL_RULES',
            __METHOD__
        );
        $event->rules['cache-craft-service-worker'] = [
            'route' => 'cachecraft/frontend/cache-craft-service-worker',
            'suffix' => '.js'
        ];
    }
);

Now I can just access it with https://example.com/cache-craft-service-worker.js which works perfectly fine.


Permissions needed to "edit image"? What permissions do users need in order to access the "edit image" menu in assets?

Some users can't access this, but I can't see a specific permission for this listed under:

Settings > Users > User Groups

Maybe this is what you are looking for

  When the deleteFilesAndFoldersInVolume permission is not set, the user cannot edit the image. And dragging files into other folders result in an error.


How can I call console controllers I have a controller in the console folder. How can I call this controller via ajax please?

I tried to config a route in Routes.php, and then call this route by jquery Get() function. But none of these below work...

'api/v0/hub-loader/<sheet_id:\d+>' => 'craftplugin/import-hubs/test',
'api/v0/hub-loader/<sheet_id:\d+>' => 'craftplugin/console/controllers/import-hubs/test',
'api/v0/hub-loader/<sheet_id:\d+>' => 'craftplugin/console/import-hubs/test',

All these routes return 404 page not found error

I found a way to get around this problem by creating a controller which extends the console controller.
Then I can call the functions in this child controller.

But if anyone knows how to call console controllers directly, please tell me.Thx


Admin-only editable field of entry? I'm have group called "Editors" that can create entries with the text fields but I would like to "Admin" group have lightswitch called "promoted" in same entries or maybe even text field for notes that would be not visible for "Editors" group (and entry owner if he is in "Editors" group) it is possible?

I can't think of a non-terribly hacky way to pull this off in the current version of Craft, unfortunately.

You might want to consider adding a thumbs-up/comment to this feature request that would allow for what you're looking for: https://github.com/craftcms/cms/issues/947


Supporting LongBlob / LongBinary in Craft record ColumnType Why is LongText supported but not LongBlob for Craft records? Is it because of the reliance on Yii? Is there some way I can circumvent that and hard-code that change to the DB, (i.e. changing a field from blob to longblob), without having to change any core Craft code?

Currently my field looks like that:

'data_blob' =>   array(AttributeType::String, 'column' => ColumnType::Binary),

I'd like to be able to have LongBinary (or longblob in mysql) as I'm reaching the max length for blob and my data is getting truncated.

Why is LongText supported but not LongBlob for Craft records?

Support, mainly... and there hasn't been a demand for it (you're the first to ask that I'm aware of).

Currently Craft's PHP based database backup logic chokes on MySQL datatypes that can't be represented as textual data.

For the upcoming Craft 3, we've done away with the AttributeType magic and you've got more direct/exact control over how your want your schema to be defined.

We also plan on updating the backup logic to be able to handle non-textual datatypes.

In the meantime, if you want this in Craft 2, you'll have to move that attribute/column out of an Active Record, create it with a migration and have your service layer use DbCommand to interact with it.


Fetch/Remove all unused assets (by plugin) The title is self-explanatory, but I need to buid a service function to remove unused assets, or at least to fetch those in order to delete found assets after.

Any simple solution?

This should work

//First fetch all ids from elements table
$allIds = craft()->db->createCommand()->select('id')->from('elements')->where([
    'not like', 'type', 'Asset'
])->queryColumn();

// query for all related Assets -> assets that are used somewhere
$usedAssetCriteria = craft()->elements->getCriteria(ElementType::Asset);
$usedAssetCriteria->relatedTo = $allIds;
$usedAssetCriteria->limit = null;
$usedAssets = $usedAssetCriteria->ids();

// query for all assets not in the list of the used one
$unUsedCriteria = craft()->elements->getCriteria(ElementType::Asset);
$unUsedCriteria->id = 'and, not ' . implode(', not ', $usedAssets);
craft()->assets->deleteFiles($unUsedCriteria->ids());


Canonical url for product with multiple categories I'm building a shop using Craft Commerce where a single product can be assigned to multiple categories. The url structure I'm using for the product detail page is: http://domain.com/category/product-url

In an effort to avoid being penalised for duplicate content I would like to set the canonical URL for my product detail page by always pulling the first category as the canonical URL in the meta. I've tried a few things but keep getting stuck - any tips ?

You should be able to use {{ entry.categoryFieldHandle[0].slug }}. The [0] simply grabs the first category in the field.

You will need to make sure there is always at least one category allocated to an entry or you'll get an error.


Verbb Feed Me for Craft 3 - Possible to read assets from local disk? In https://verbb.io/craft-plugins/feed-me/docs/content-mapping/field-types#assets the documentation says yes, but I cannot get it to work.

I also find the documentation confusing: "You should supply the filename only, excluding the full path to the asset". How can it even know where to get the file then?

Files and assets are two different concepts. An asset represents a file already in Craft, and you'll be able to search and browse for it in the Assets section. Whereas in a number of different cases, you'll want to create (upload) an asset from a URL.

If you have an existing asset in Craft already, so you don't want to upload it, then provide just the filename and extension in your feed. This is as per the documentation.

If you want to create an asset from a remote URL, you'll need to tick the "Create asset from URL" checkbox in the mapping screen for Feed Me. If you do this option however, you'll need to provide an absolute URL to the file you want to import into Craft.

So, with the above in mind, the short answer to your question is that Feed Me doesn't support creating assets from a local path, but it does support it from a local URL. You'll need to change the path in your feed to point to a full URL, which you can achieve by moving it to a folder in your project, or setting up a virtual host in your favourite local dev environment.


Craft Commerce Digital Products delete multiples Craft Commerce Digital Products:

Why aren't there checkboxes next to the product names so I can delete multiple items at once?

It exists in regular Craft Commerce Products.

I don't believe there is a technical reason for this, but feel free to make a feature request requesting it: https://github.com/craftcms/digital-products/issues


Craft CMS issue with Composer V2 We have a website built in Craft 3.4.14 and we are moving it to a hosting company with CentOS 7, using Plesk Obsidian 18.0.5.

The hosting company has told us that they have upgraded Composer from version 1 to version 2. On my local machine I have been using version 1.10. However, I try to run Composer on the server and I get these issues: -

craftcms/plugin-installer 1.5.3 requires composer-plugin-api ^1.0 -> found composer-plugin-api[2.0.0] but it does not match your constraint.
craftcms/plugin-installer 1.5.4 requires composer-plugin-api ^1.0 -> found composer-plugin-api[2.0.0] but it does not match your constraint.
craftcms/cms 3.4.14 requires craftcms/plugin-installer ~1.5.3 -> satisfiable by craftcms/plugin-installer[1.5.4, 1.5.3].
Root composer.json requires craftcms/cms 3.4.14 -> satisfiable by craftcms/cms[3.4.14].

Is there a way around these issues so that we can get Craft CMS installed please?

Thank you for your time.

Composer 2 support has been drafted over at craftcms/plugin-installer#4. We’ll merge that in once Composer 2 is officially released.

~~In the meantime, if you really need to get Craft working with Composer 2, follow the instructions at craftcms/plugin-installer#3.~~

UPDATE: craftcms/plugin-installer and yiisoft/yii2-composer have both been updated to support Composer 2.


PHP version issue when installing Craft 3 using Composer Why do I get the error when I try to install Craft 3?

composer create-project craftcms/craft Documents/Development/Project -s beta

The error:

[InvalidArgumentException]
Could not find package craftcms/craft with stability stable
in a version installable using your PHP version 5.6.30.

I am running PHP 7.1.

You are running PHP 5.6.30 on the command line (read the error message), which you can also verify with php -v.

To swap the PHP, you should add the path to your preferred PHP executable to your shell’s configuration file (e.g. ~/.bash_profile, ~/.bashrc, ~/.zshrc).

export PATH="/Applications/MAMP/bin/php/php7.1.1/bin:$PATH"

Another option is to ignore the PHP requirement using --ignore-platform-reqs

composer create-project craftcms/craft . -s beta --ignore-platform-reqs

and then fake the PHP version in the project’s composer.json for later updates

"config": {
  "optimize-autoloader": true,
  "platform": {"php": "7.0"}
},


Styling Subsequent Pages in Craft Pagination I am building my first Craft blog, and can't figure out how to get the CSS styling to apply to pagination beyond the main blog index page. When I click through subsequent blog pages, the URL adds 'p2', 'p3', etc. as expected, and all of the HTML content and links are there and work fine. But no styling beyond the first page. Any ideas? Here is my pagination code in my main blog index.html:

{# Pagination and home page link #}

    {% if pageInfo.prevUrl %}
        Prev
    {% endif %}

    {% if pageInfo.nextUrl %}
        Next
    {% endif %}

    Home

For those who might stumble upon this with a similar issue, the answer ended up being quite simple...

I made sure that my css.main was located in a public directory, in my case /web/css/main.css, and all of the pagination and styling works perfectly.


Show dev mode and Yii toolbar on secondary site I am unclear on how to turn on dev mode as well as the Yii toolbar when viewing a secondary site in Craft.

devMode is a general config setting and it applies to the whole Craft installation (regardless of the site if you're running a multi-site Craft installation.

The Craft debug toolbar is a user account preference to enable and it should work across all sites in a multi-site installation as well.


Can a JS string variable be used in Twig? I've came to the situation where I need to use JS variable string and use it in Twig's variable.

The plan is built on the Guest entries and Ajax form submission. On successful Ajax form submission I'm calling for entry's keys (especially id key) and using these keys to set a cookie names. Those cookie names should be used on next page to get into the entry that just got submitted. Can it be achieved?

As Twig is rendered server side before passed to a browser for JS execution I found out that it can't be done except FOSsRoutingBundle which allows you to expose your routing in your JavaScript code. I don't know if that would be a great idea.

Anyway. I found workaround solution that seems to be working for me.

Here is the Ajax post action with simple window redirection.

// Send it to the server
$.post('/', data, function(response, textStatus, jqXHR) {

  if (response.success) {

    // Request for entry ID key string to be used in HTTP redirect link
    var entryId = response.id

    // HTTP redirect
    window.location.replace("{{ siteUrl }}" + entryId + "/someUri");

    } else {
    // response.error
  }

});

Don't forget Craft's routing!