Get ancestor at a specific level? I can grab a top/bottom level ancestor with something like entry.ancestors.first/last.title.

But, say I'm at level 6, is it possible to grab an ancestor at a particular level, like entry.ancestors.level(3).title? Or would you have to grab all the ancestors and loop through them to accomplish this?

New to deep structures and just want to confirm I'm not missing something that would allow me to sidestep a loop. Thanks!

entry.ancestors returns an ElementCriteriaModel (→ getAncestors() in the Craft docs) prepped to return the entry's ancestors.

entry.ancestors.level(3) makes it return only entry ancestors which are at 3rd level of the structure.

As you well pointed out in the comments, an entry can only have one ancestor on a particular structure level. So you can now use the first() method to get this one entry. Keep in mind that if there's no ancestor at that level, the method won't return anything (null).

{% set ancestorL3 = entry.ancestors.level(3).first() %}

{% if ancestorL3 %}
    {{ ancestorL3.title }}
{% endif %}


Redactor 2 - Can a text alignment button be added? Left, Center, Right -- Can the text alignment button be added to Redactor 2, and if so, how?

You can use the formattingAdd config setting to add custom formatting to the "Format" dropdown.

formattingAdd: {
  "align-left": {
    "title": "Align left",
    "args": ["p","class","align-left"],
  },
  "align-right": {
    "title": "Align right",
    "args": ["p","class","align-right"],
  },
  "align-center": {
    "title": "Align center",
    "args": ["p","class","align-center"],
  },
  "align-justify": {
    "title": "Justify",
    "args": ["p","class","align-justify"],
  },
},

If you want to have a separate dropdown or individual buttons in the toolbar for this functionality, have a look at my plugin Redactor Inline Styles.


How to get parent categories from an entry? I have a pretty standard type entry page (_entry.html) which displays the details of an entry having navigated to it through 2 levels of categories. On this page I'd like to be able to query the two immediate category parents of this entry (sub-cat & cat) for use in a breadcrumb and page title variables.

I'm not sure how to approach this, or what the correct dot syntax is - I'm just getting up-to-speed with Craft CMS.

Any tips/references?

Assuming you have a Categories field associated with the entry, you can get all of the related categories in your template via entry.myCategoriesField (replace with the actual Categories field handle).

So here’s how you would loop through all of them:

{% for category in entry.myCategoriesField %}

{{ category.title }}

{% endfor %}

If you just want the last 2 categories, you can use Twig’s slice filter:

normal syntax:
{% for category in entry.myCategoriesField|slice(-2) %}

shortcut syntax:
{% for category in entry.myCategoriesField[-2:] %}

If you want to set these categories to their own variables, so they can be referenced later on in your template, you could do this instead:

{% set parentCategory = entry.myCategoriesField.last() %}
{% set grandparentCategory = parentCategory.parent() %}


Enable CORS on ElementAPI I was wondering if there is way to enable CORS for the ElementAPI plugin? I want to be able to call the API from the website and not allow external client to access the API

Not really anything to do with Craft or the ElementAPI plugin, but you can enable CORS at the Apache/.htaccess level easy enough.


Manual Plugin installation on Craft 3 I'm trying to manually install a plugin Pic Puller for Craft 3 Beta.

My shared hosting won't allow enabling of allow_url_fopen so it can't be done via the plugin store within the dashboard.

Any docs I checked are telling me to add the plugin files to /craft/plugins/ but I'm not seeing this directory in Craft 3.

I tried adding it to the /modules/ directory but this didn't work for me.

Thanks!

You have to create the folder where you want to include your plugins by yourself. There are no requirements how you name it. Let's say you want to create the folder plugins in your Craft folder, then you have to include the plugin in your composer.json like this

"require": {
   "php": ">=7.0.0",
   ....
   "namespace/pluginhandle": "your version",
   "secondred/form-builder": "^1.0" (<--- example how it could look like)
},
"repositories": [
{
  "type": "path",
  "url": "plugins/yourPluginFolderName"
},
{
  "type": "path",
  "url": "plugins/form-builder" (<--- example how it could look like)
},
....

Then you'll need access to your server via ssh and do composer update


Where do you all host your CratCMS sites? I'm very curious to know what are the most popular hosting services chosen by CratCMS developers. Perhaps I'm missing out in some gems!

Please let me know what you love about your favorite hosting service and at least one thing you dislike about it.

Anything that you can config and auto-deploy through using https://forge.laravel.com/ (Digital Ocean, Rackspace, Amazon).


Adding section in breadcrumbs My Entry URL Format looks like this: {section}/{slug} and I am using the standard breadcrumbs code;

   {% if entry.level > 1 %}

        {% for crumb in entry.getAncestors() %}

{{ crumb.getLink() }}

        {% endfor %}

{% endif %}

This will parse:

Home > article > entry-title

how can you add the {section} in as:

Home > section name > article > entry-title

I don't believe there's a more "magic" way than just hard coding the first list item/link, i.e. something like this:

{% if entry.level > 1 %}

            {{ entry.section.name }}

        {% for crumb in entry.getAncestors() %}

{{ crumb.getLink() }}

        {% endfor %}

{% endif %}


What variables are available to redirectToPostedUrl? Craft's Web Controller has a redirectToPostedUrl method. Copied here for the sake of discussion:

public function redirectToPostedUrl($object = null, string $default = null): YiiResponse
{
    $url = Craft::$app->getRequest()->getValidatedBodyParam('redirect');
    if ($url === null) {
        if ($default !== null) {
            $url = $default;
        } else {
            $url = Craft::$app->getRequest()->getPathInfo();
        }
    }
    if ($object) {
        $url = Craft::$app->getView()->renderObjectTemplate($url, $object);
    }
    return $this->redirect($url);
}

We can call this method from our plugin controllers to redirect to the posted URL in the redirect input field and use a dynamic {siteUrl} variable. In my template, I have a redirect value that uses {siteUrl}:

<input type="hidden" name="redirect" value="6026760a62b9c6007a4b5695a65acbabG2540f8cb3727b998a1c78da45db863f{siteUrl}?id={id}">

And in my Controller, I receive that value and redirect to that location:

return $this->redirectToPostedUrl($object);

That all works fine. I can pass my custom $object to this method and the {id} or any other part of the model I wish to process can appear in the URL.

My question is, where is {siteUrl} being made available to the redirectToPostedUrl method? In looking closer at renderObjectTemplate it never appears to specifically make global variables available. And, if I try other global variables such as {currentUser.id} nothing gets rendered. In Craft 2 I believe this method made environmentalVariables available for parsing but those are no longer supported in Craft 3.

So why and how does {siteUrl} work? Are there other variables that are available to be used in the redirect URLs too that we don't explicitly make available by passing them in via the $object argument?

When you take a deeper look into redirectToPostedUrl you'll see these lines. All they do is convert the Object into an array, so they fetch every property of the object and pass those to the template to use them directly. You have everything the Object has.

You can access those attributes via short syntax {title} which is the same as {{ object.title }}.

For example if you have an yii/model/MyFancyModel with the following attributes

[
    'id' => 4,
    'title' => 'foo',
    'someRelation => ['foo' => 'bar']
]

Craft will merge this array with ['object' => $object] and you have access to { id }, { title }, { someRelation.foo } as well as {{ object.id }} (and all others) as well as all other variables passed via variables the third attribute of the function, since redirectToPostedUrl doesn't pass a third argument these additional attributes are an empty array.

In your case { siteUrl } is nothing else than {{ object.siteUrl }} which is basically {{ entry.siteUrl }} that means the siteUrl of your Element. When you do { type.handle } (with an Entry)  it will render the handle of your EntryType. When your Object is a user you can do { email } to display his/her email.

One more note: The attributes of the Model are fetched via Arrayable Trait if it has it. So it grabs all fields and extraFields gets those attributes. I can provide further explanations about fields and how they work exactly in detail if you like


update via CLI with error! I'm trying an update on the CLI and get the following error.

If I do it again afterwards I get told that everything is up to date.
If I want to install a plugin then I still get the message that I should update to the current version.

Who can tell me what I am doing wrong or where the mistake lies?

$ php-7.2-cli -d allow_url_fopen=1 craft update all
Fetching available updates ... done
Performing one update:

    - craft 3.1.25 => 3.1.28

Backup the database? (yes|no) [yes]:yes
Backing up the database ... done
Performing update with Composer ... done
Applying new migrations ... error: The command "'/home/lichtebs/CraftCMS-ALL/craft' 'migrate/all' '--no-content'" failed.

Exit Code: 255(Unknown error)

Working directory: /home/lichtebs/CraftCMS-ALL

Output:
================
Content-type: text/html

Warning:  Unexpected character in input:  '' (ASCII=92) state=1 in /home/lichtebs/CraftCMS-ALL/craft on line 16

Parse error:  syntax error, unexpected T_STRING in /home/lichtebs/CraftCMS-ALL/craft on line 16

Restore the database backup? (yes|no) [yes]:yes
Restoring the database backup ... done
Revert the Composer changes? (yes|no) [yes]:yes
Reverting Composer changes ... error: The command "'/home/lichtebs/CraftCMS-ALL/craft' 'update/composer-install'" failed.

Exit Code: 255(Unknown error)

Working directory: /home/lichtebs/CraftCMS-ALL

Output:
================
Content-type: text/html

Warning:  Unexpected character in input:  '\' (ASCII=92) state=1 in /home/lichtebs/CraftCMS-ALL/craft on line 16

Parse error:  syntax error, unexpected T_STRING in /home/lichtebs/CraftCMS-ALL/craft on line 16

It looks like you need to have php-7.2-cli -d allow_url_fopen=1 in front of your craft commands. When you run craft update all, Craft then tries to run migrations (craft migrate/all) but without your php-7.2-cli... declaration it seems to fails.

If you have access to composer, you could try to update 'manually' instead of running craft update.

run composer update
then php-7.2-cli -d allow_url_fopen=1 craft migrate/all


I do not have the /craft/storage/runtime/logs/ folder I am trying to set up SMTP emails using Microsoft 365 and the settings are not working so I need to dig into the logs to find out why.

When I go to find the folder it is not there. Instead I have a /craft/storage/logs/ folder but this does not seem to contain the file containing email test logs - [exception.Craft\EmailTestException]

I have tried turning dev mode on to see if that changed the logs I was getting, and it does, but I am still not getting the logs I need.

Looks like that article needs to be updated for Craft 3.

In Craft 3, the logs folder is at storage/logs and you can search for [error] and find the one related to email sending.


Plug-ins for static hosting? Our local dev environment allows us to run a CMS like Craft but our (government) host is static only. We currently accomplish things with movable type 4, but would like something more modern. MT 7 costs $1000 a year, so that is right out.

Is there a plug-in for Craft that can export static html we can upload to our host?

Perhaps you could have a local/internal Craft install and then regularly run a script that crawls the site and saves all the pages as static HTML. Tools like HTTrack already do a pretty good job of this.

Or there are static cache plugins like Blitz that you might be able to utilise. They’re designed for caching, but if you warm the cache you might be able to export the static files for uploading to your host.

UPDATE: Blitz 3 makes this possible. Read the announcement at:
https://putyourlightson.com/articles/blitz-3-embracing-the-jamstack


Get Random Set of Entries I'm trying to create a "Hack Job" version of Similar Entries, I'm using the following code but it seems to be getting the same entries over and over again. I know shuffle function does this, but I thought it'd be shuffling through the entire array of Entries?

{% set nextEntries = shuffle(craft.entries.section('merchants').id('not ' ~ entry.id).limit(15)) %}

I'm looking to make it grab a random 15 entries from the merchants section, which I will then cache.

Any help would be great.

You're always getting the same set because the entries are first fetched, then shuffled. To achieve what you want, you could do:

{# get all your entries ids #}
{% set allIds = craft.entries().section('yourSection').ids() %}
{# Shuffle all and slice to just 15 #}
{% set shuffledIds = shuffle(allIds) | slice(0,15) %}
{# Fetch your random entries #}
{% set entries = craft.entries.id(shuffledIds).all() %}

Or

{# get all your entries ids #}
{% set allIds = craft.entries().section('yourSection').ids() %}
{# Fetch your random entries #}
{% set entries = craft.entries().id(shuffle(allIds) | slice(0,15)).all() %}

In response to your comment then you could do something like the below:

{# set a random offset #}
{% set offset = random(0, 6000)%}

{# set a random sort #}
{% set orderBy = random(['postDate', 'id', 'title']) %}

{# set a random direction #}
{% set direction = random(['ASC', 'DESC']) %}

{# get 500 ids #}
{% set allIds = craft
            .entries()
            .section('posts')
            .offset(offset)
            .orderBy(orderBy ~ ' ' ~ direction)
            .limit(500)
            .ids() %}

{# Fetch your random entries #}
{% set entries = craft.entries().id(shuffle(allIds) | slice(0,15)).all() %}

With this, you only fetch 500 entries with a random offset and sorting, shuffle that pool and pick 15. This might not be as random but I doubt you'd notice it.


'devMode' enabled on the frontend yet its set to false I have recently migrated a website to the live server.

In the craft/config/general.php my 'devMode' is set to false.

In the backend of the website I am not seeing the yellow and black banner to say its in dev mode but on the frontend each meta title is starting with [devmode].

Regards,

Reece

Probably you are using SEOmatic; it has its own setting for the local environment you're using; check out this docs here: https://github.com/nystudio107/craft-seomatic/tree/develop#plugin-settings


phpdotenv with multi-lang Craft setup on MAMP I inherited a Craft site which uses phpdotenv (which I'm unfamiliar with) and which I now have to make multi-lingual (https://craftcms.com/docs/localization-guide) with an added es and fr locale on top of the english language site.
The question is regarding the setup on MAMP which seems to never find the .env file.
On my production server in /es/index.php this works:

// Composer autoload
require_once('../../vendor/autoload.php');

// DotEnv
try {
    $dotenv = new Dotenv\Dotenv('../../');
    $dotenv->required(['DB_HOST', 'DB_NAME', 'DB_USER', 'DB_PASS']);
} catch (Exception $e) {
    exit('Could not find a .env file.');
}

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

// Tell Craft to serve the spanish content
define('CRAFT_LOCALE', 'es');

However, the same code on my local MAMP install will not find the .env file no matter what path I enter into the new dotenv statement....
Anyone have any idea or suggestion? Truly stumped here.

Some troubleshooting steps:

Make sure a vendor/ folder exists two levels up from es/. If not, you need to run composer install in your terminal from the directory that contains a composer.json file. (If you don’t have Composer installed, see its installation instructions.)
Make sure a .env file exists two levels up from es/. It probably won’t, as you’re not supposed to include your .env file in the Git repo. You can copy it from production, or from .env.example if that exists. Then fill it in with working credentials for your local environment.

Matt Stauffer wrote a great article explaining how to get phpdotenv running with Craft 2: https://mattstauffer.com/blog/environment-specific-configuration-for-craftcms-using-phpdotenv/ Probably a good idea to read through that just to get an idea of how it’s all supposed to work (and what the advantages are).


syntax error, expecting variable (T_VARIABLE) in Search Plus Custom Mapping I’m looking for a little help with Custom Mapping for the Search Plus plugin. I think(?) I'm getting pretty close, but stuck on something (and I do front end web design, so this is just over my head) I’m using https://transition.topshelfcraft.com/software/craft/searchplus/usage/hooks-events as a reference and used https://pluginfactory.io to create the plugin.

Per the instructions in the documentation above, I’ve added this to the bottom of the plugin :

public function searchPlus_addAlgoliaMapping()
{
    $ret = [];
    $ret['name'] = 'GHCC Staff Mapping2';
    $ret['handle'] = 'GHCC_Staff2';
    $ret['description'] = 'Mapping for Staff Page';
    $ret['method'] = 'example.testMapping';
    return $ret;
}

public function testMapping(element)
{
    $ret = [];

    $ret['objectID'] = $entry->id;
    $ret['title'] = $entry->title;
    $ret['activityId'] = $entry->id;
    $ret['id'] = $entry->id;
    $ret['slug'] = $entry->slug;
    $ret['url'] = $entry->url;
    $ret['uri'] = '/' . $entry->uri;

return $ret;
}

But am getting an error: syntax error, unexpected ')', expecting variable (T_VARIABLE) referencing line 186  public function testMapping(element)

Was wondering if anyone had any tips

Thanks!

That is a typo in the plugin's documentation.

public function testMapping(element)

should be

public function testMapping($element)

since $element is a PHP variable.


How do I set up event listing & detail pages with entry post dates that are in the future? I'm struggling to set up a listing template and a detail template which will display "event" entries with post date set in the future. I keep getting a 404 error on the detail page. How do I set up Craft & templates to show future dated entries on a listing and detail page?

STEP ONE:
Create an "Events" section in Craft and uncheck "Entries in this section have their own URLS".

STEP TWO:
Create your listing page and use ".status('pending')" to have CRAFT return only future dated entries. Also use ".order('postDate')" to have Craft order entries so that the next future dated entry is the first in the list:

{% set entries = craft.entries.section("events").order('postDate').status('pending') %}

STEP THREE:
In the listing template, you need to manually build the URL to the event's detail page:

{{ entry.title }}

STEP FOUR:
Set up a custom Route to tell Craft which template to load for the URL pattern you're using in STEP THREE.

STEP FIVE:
Code your event's detail page template to grab the entry's slug from the URL and query the DB to get the right entry.

{% set slug = craft.request.getSegment(2) %}
{% set entry = craft.entries.section("events").slug(slug).status('live', 'pending', 'expired').find()%}
{% for entry in entry %}

{{ entry.title }}

{% endfor %}

NOTE: I've set the code sample in STEP FIVE to use .status('live', 'pending', 'expired') to show return these types of entries on my event detail page. You can use .status(null) to return ANY/ALL entries on the event detail page... or you can use .status('pending') if you only want future dated events to show and all others to return a 404. This is 100% up to you and based on your project requirements.


Are caches saved per locale by default? Or do we need to set a specific key that includes something unique?

I assume you're referring to template caches with the {% cache %} tag.

If so, then yes, the {% cache %} tag by default will cache it's contents on a per URL and per locale basis.

If you use the globally parameter, then it will just be on a per locale basis.


Populating TAG page when using the kebab filter I have a page that displays entries based on a specific tag. It works well until I apply the kebab filter.
Here's my link to the page:
{% for tag in tag %}

{{ tag.title }}

{% endfor %}

and my tags/tag.html page looks like this:
{% set tag = craft.tags.name(tag).first() %}
{% set entries = craft.entries.relatedTo(tag).order('title') %}
{% if entries | length %}
   {% for entry in entries %}
       Code here
    {% endfor %}
{% endif %}

The page populates all entries regardless of the tag once I apply the kebab filter. How can I fix that?
Thanks in advance.

For your link, change {{ tag.title | kebab}} to {{ tag.slug }}

Then on your tag.html page change your tag variable to this:

{% set tag = craft.tags.slug( craft.request.segment(2) ).first() %}

This is how I have it set up and works fine.

Edit: Forgot the route needed: Add this to your routes.php: 'tags/{slug}' => 'tags/tag',


How to use required fields on localised entries? I'm building a multi-lingual site and have found Craft's locales / translatable fields useful for setting up structures where each page will have a translated version. However, for at least one of the Channel sections it would make more sense to have separate entries for each locale, rather than having each entry being translatable and appearing in all locales.

This seems doable by disabling all but one of the locales on each entry in the section, but the problem I'm having is that if an entry has required fields, I can't save it if these fields are empty, even if they're only empty in a locale that I'm trying to disable. (eg. I want to have a Spanish-only post, but when I try to disable the English version I can't save the post because the English version has required fields that aren't filled in...)

It seems I either have to make my required fields non-required, or fill them with spurious stuff in the locale I want to disable. I'm sure there must be a way of making required fields work with multi-lingual posts, but I can't figure out quite how... I'd be grateful for any pointers here!

I don't know if you re-use the fields you're using in that channel in other sections and if you do, my suggestion might not work for you, but here's what you could do:

Set all fields to be "not translatable" and if content is entered in one locale it will get synced to all locales. Thereby all required fields will always be filled out and disabling individual "dummy versions" is no problem any more.


Deleting user data from the database I'm using Craft 3.6.4.1 and I need to delete a whole tranche of users from the database (that has derived from another Craft instance).
I've been deleting by hand via the CMS but note that loads of user related rows remain in the database:

The CMS is reporting only the 4 users which I want to retain, but craft_users still has 10,706 rows in it.

From which tables should I clean out rows that pertain to users I want to delete?
I note the additional following tables which seem relevant in ways I'm unsure of:
craft_usergroups_users
craft_userpermissions
craft_userpermissions_usergroups
craft_userpermissions_users
craft_userpreferences

After deleting the users from the UI they are only soft-deleted. If you look at the user id and find the matching element in your elements table, you will see that this element has a populated dateDeleted.
Run garbage collection (./craft gc) to clean up and completely remove everything.


Performance of a categories list with post count Let's say I'm outputting a list/nav of categories, with the count of entries in each category, as described in other questions:

{% nav category in craft.categories.group('...') %}
   {% set entryCount = craft.entries.relatedTo(category).total() %}
   {{ category.title}} ({{ entryCount }})
{% endnav %}

On a site with plenty of categories (more than 100 in this case), that seems like a lot of relatedTo queries. Is there a way I could accomplish the same thing with fewer queries / better performance?

I don't think you'll be able to avoid the database queries, but you'll definitely want to use cacheing here, and set a high cache time if possible.

Wrap your code in {% cache %} tags like below:

{% cache globally for 1 month %}
{% nav category in craft.categories.group('...') %}
   {% set entryCount = craft.entries.relatedTo(category).total() %}
   {{ category.title}} ({{ entryCount }})
{% endnav %}
{% endcache %}

If this navigation appears on every page, use the "globally" tag.


External URL with image I want to have the option to have social media icons that will link to different URLs. I currently have it set up so the user can click which icons will display on the page, but how would I have it so they can change the link to what URL they want?

Sounds like you're on the right path. Create a Global matrix field containing an asset field for Social Icon, a text field for Social Url, and a lightswitch field for Enabled/Disabled. Then the user can add new social media icons as needed and manipulate the url.


Entries not visible on Production I have a Structure called Pages which works great on my localhost. When it comes to deploying the website i'm not sure what the issue is.

Before I deploy; I am running ./craft settings/rebuild. If I check my config/project.yml file it contains this:

sections:
  21e80bf5-5bf0-4acd-89fa-e108f377f367:
    name: Pages
    handle: Pages
    type: structure
    enableVersioning: true
    propagationMethod: all
    siteSettings:
      0bbf44af-5493-45e6-a8fd-711fbf205c27:
        enabledByDefault: true
        hasUrls: true
        uriFormat: '{parent.uri}/{slug}'
        template: pages/page
      62a954cf-14e6-4afc-a4ee-721a1fa504ce:
        enabledByDefault: true
        hasUrls: true
        uriFormat: '{parent.uri}/{slug}'
        template: pages/page
      b24e91d9-c16e-4418-a2be-f784c1a5db73:
        enabledByDefault: true
        hasUrls: true
        uriFormat: '{parent.uri}/{slug}'
        template: pages/page
      dcd40638-52ee-4f8e-944b-be8663f015d6:
        enabledByDefault: true
        hasUrls: true
        uriFormat: '{parent.uri}/{slug}'
        template: pages/page
    structure:
      uid: 3051f9fb-d940-42a7-a2bf-1a4dcfbf0bfe
      maxLevels: null
    entryTypes:
      33ed925f-348c-4c9d-bf8e-a18f36ffa2f9:
        name: Homepage
        handle: homepage
        hasTitleField: true
        titleLabel: Title
        titleFormat: ''
        sortOrder: 2
        fieldLayouts:
          b04b3c2b-b371-4c33-8813-5dd41ba38143:
            tabs:
              -
                name: Content
                sortOrder: 1
                fields:
                  7dfc068b-dcde-47e8-92ab-17054e23cd28:
                    required: false
                    sortOrder: 2
      96020cb2-dbdb-42c7-bcae-66762fd7b98c:
        name: Page
        handle: page
        hasTitleField: true
        titleLabel: Title
        titleFormat: ''
        sortOrder: 1
        fieldLayouts:
          63ce77f0-af11-4304-b21d-c1bc6d0c8bb6:
            tabs:
              -
                name: Content
                sortOrder: 1
                fields:
                  0556df33-f19f-4a6e-a26b-73be1b719674:
                    required: false
                    sortOrder: 1
                  7dfc068b-dcde-47e8-92ab-17054e23cd28:
                    required: false
                    sortOrder: 2

When I deploy my changes and run ./craft project-config/sync the Entries section isn't showing up in Admin.

Am I doing something wrong here?

Is it a problem with the URLs maybe?

Notice you got
handle: Pages

And in code below
template: pages/page

A lucky guess would be, your local is not case sensitive. As you might running it on a windows machine with a virtual host.
However, your server ,if its a Linux server, it is likely to be case sensitive.
So I will suggest you change your handle: Pages to handle: pages


Twig templating within  tag I think I might be missing something here but it seems twig tags aren't parsed within  tags? Is there any way they can be, e.g.:

<script>
var homepageStandfirstAnchors = [<% for anchor in homepage.homepageStandfirstAnchors %>[{{ anchor.text }},{{ anchor.section.handle }},{{ anchor.anchorLink }}],<% endfor %>];
</script>

doesn't work as expected.

It appears to be due to the angle brackets. Try:

<script>
    var homepageStandfirstAnchors = [{% for anchor in homepage.homepageStandfirstAnchors %}[{{ anchor.text }},{{ anchor.section.handle }},{{ anchor.anchorLink }}],{% endfor %}];
</script>


Set a Variable inside a conditional I'm building my first Craft site and need to set a variable if a field has an image and then use that variable elsewhere in the template.

The field is part of a matrix and will repeat.

What I have so far is:

{# extra image #}
{% set asset = block.extraImage.first() %}
{# set variable empty so it's avialble outside of conditional #}
{% set float = "" %}

{% if asset %}

    {% set float = yes %}
{% endif %}

 more code here

The above code doesn't give me any template errors. But it also doesn't output the class as expected.

The full template code can be viewed here.

You're trying to your float variable using another variable at the moment that isn't defined. I expect you mean to set float to the string value "yes" like so:

{% set float = "yes" %}

You could also use a conditional around your class declaration so you don't end up with empty classes and it'd also remove the need to define float as an empty value.

<div{% if float is defined %} class="{{ float }}"{% endif %}> more code here </div>


Forward users to the right template according to the current active site's language I am using Craft 2 and trying to forward users to the right template according to the current active site's language when they reset their password. The problem is that the reset URL that Craft creates and sends the user's email only forwards it to the primary site.

To be more clear, if the user changed site language to Germany and sends for a reset password request, the URL sent to his email sends him to the primary site, which is the French  one.

I added the setPasswordPath in the config file as such:

'setPasswordPath' => array(
    'de' => 'de/passwordreset'
    'fr' => 'passwordreset',
),

But still not working. What am I doing wrong?

I'm not sure there's a good solution for this in Craft 2 without some custom plugin logic.

To be fair, this was the same behavior in Craft 3 until pretty recently as well.

You might want to comment on that Github issue to see about the feasibility of backporting something to Craft 2 for this.


Webhook Error with Charge plugin Stripe is throwing a server error when trying to access a webhook to the Charge plugin. Some investigation revealed the error is triggered by an 'invalid or missing CSRF token.

If CSRF protection is enabled (and it is by default for the latest versions of Craft), Stripe was getting a server error when using the Charge webhook url. The solution is to disable CSRF for the webhook URI - you can read more about it here

or simply add this to your config/general.php file:

'enableCsrfProtection' => (!isset($_SERVER['REQUEST_URI']) || $_SERVER['REQUEST_URI'] != '/actions/charge/webhook/callback'),


504 error on home page of Craft 3 website Recently, I developed a Craft 3 website. Its working perfectly on development server. But after deploying to another server, I am getting 504 error for home and all front end pages while Craft dashboard is working perfectly. I looked into logs but didn't find anything related to it.

This is kind of hard to debug without any logs, but because 504 is a gateway timeout error, I would start by checking if your site uses any external services, other servers it tries to reach (only from within your templates, because the admin works fine).

This could be anything from Google's geolocation API to an external image service, that can not be reached because of server settings on either side.

Is there anything in your server logs, or could you activate logging for your server to get more details?


Smart Map - Static map displays fine, dynamic map does not I enabled the three API's at Google:

Google Maps JavaScript API
Google Maps Geocoding API
Google Static Maps API

I get a static map OK. All I get with the dynamic map is a "Loading Map...".
My code:
{% for entry in craft.entries.section('groups').limit(5).find() %}

{{ entry.title }} , {{ entry.address }}, {{ craft.smartMap.map(entry.address) }}

{% endfor %}

It's possible that some other JavaScript (unrelated to Smart Map) is throwing an error, and Smart Map never gets a chance to load the map. Loading a dynamic map is intentionally done late in the process, so that it doesn't interfere with other scripts you may have running.

The static map is simply loaded as a remote image, so no JavaScript is required.


Saving entries in admin panel I have a problem with the admin panel being very slow when saving an entry. It takes about 30 seconds to save an entry. I use a matrix for the different part of the entry (imgs, textfields, titles and so on). Does anyone else have this problem, and have someone found a solution for this? :)

To debug where the delay is, you can enable devMode, which will write out a bunch of code and database profiling information to your log files in craft/storage/runtime/logs.

After you do that, save an entry then find that request in the log files.  You can look at the timestamps on that request to see what part of the code the 30 second delay is occurring on, which will point you in the direction of the underlying problem.


Can I have a Craft Commerce product with options that change the product’s price? I have a product with multiple options (e.g. colour, size, material) that all effect the price that the product then sells for. Is it possible for example if someone chooses the material:walnut that it adds $200 to the current price? How can I set this up inside Craft Commerce.

Absolutely that is possible.  You can see an example of a complex options set up here for example (click Add Prints to get going...):

https://imagescience.com.au/services/fine-art-printing/order-fine-art-printing

Variants are also used for pages like these:
https://imagescience.com.au/products/inkjet-papers/museo-portfolio-rag

In terms of the front end, how you set up the UI is entirely up to you - in the top case, it's a React form at work, and in the second case just a simple table really.

Each of these forms ultimately just POSTs a list of fields to a Commerce controller - purchasableID and qty and optionally notes for each item the user chooses using the form.  These is posted to a Commerce addToCart controller.

The products themselves are all set up in teh back end of Commerce as variations - see https://craftcommerce.com/docs/products for an overview of that.  Basically you define a grid of variant options, each of which gets its own ID (later POSTed, as above) and has its own unique SKU (Stock Keeping Unit).  Each variant can have as many or as few custom fields as you wish (as can the parent product)..and of course each variant can have its own price.

The product & variants system in Commerce is VERY powerful indeed, but does take a little getting used to.  Best way to get started is to download Commerce and have a look through the sample templates to get an idea how it all works, enter some sample products in the back end, then attempt to make a few simple add to cart forms of your own - one that works for jsut products, then one that works for variant products.


How do you prevent white space from being removed after line breaks within a Rich Text Field? I am utilizing a CSS class within headlines for responsive line breaks. This class shows the line break for large displays and hides the break for small displays.
Using the HTML/Source button within Redactor works fine until the entry is saved.
Line breaks were the first thought.
 Not an afterthought.

The code above produces this for large displays:
Line breaks were the first thought.
Not an afterthought.
And should produce this for small displays:
Line breaks were the first thought. Not an afterthought.
However the white space after the line break is removed upon save, which produces this:
Line breaks were the first thought.
Not an afterthought.

Which displays like this on small displays:
Line breaks were the first thought.Not an afterthought.
This is not the desired result.
While I am able to correct this with the Twig replace filter, I would prefer not having to manage those filters within the templates.
Any clue how to prevent the original white space from being removed after line breaks within a Rich Text Field?
(Note the white space is not removed within Plain Text Fields.)

Unfortunately you can't really configure how Redactor formats it's input. Given this I think your current solution is the most effective.

That said, you could try this alternative style for your <br> tags when hiding:

br.hide-for-small {
    content: '';
    display: inline-block;
    width: 1ch;
}

This will collapse the line break with an added space. It'll only work on Safari and Chrome though. That might be good enough since most mobile users are using Webkit-based browsers.


Does defineSearchableAttributes() work with getter methods on the model? If I define searchable fields via IElementType::defineSearchableAttributes(), the provided fields have to be model attributes. Can they also be getter-methods on the model class, which may return values from other related elements?

e.g. on Plugin_XYElementType.php:

public function defineSearchableAttributes()
{
    return ['relatedTitle','otherField'],
}

in Plugin_XYModel.php:

public function getRelatedTitle()
{
    return craft()->plugin_service->getTitleFromRelatedThing($this->relatedThingId);
}

Will this fields be correctly indexed and searchable in a ElementIndexView, where I use this related fields in a table column? Or does this only work for Attributes, that were defined via defineAttributes() ?

Thanks!

I have since discovered that searching on a related model is fairly easy to implement. You just define the related model as an attribute that can be searched on in defineSearchableAttributes method of the element type.

For example:

/**
 * @inheritDoc IElementType::defineSearchableAttributes()
 *
 * @return array
 */
public function defineSearchableAttributes()
{
    return ['dateCreated', 'totalPaid', 'customer'];
}

Then you just have to have a matching handler for that attribute (customer) in the modifyElementsQuery method, like so:

    if ($criteria->customer) {
        if ($criteria->customer instanceof MyPlugin_CustomerModel) {
            if ($criteria->customer->id) {
                $criteria->customerId = $criteria->customer->id;
                $criteria->customer = null;
            } else {
                return false;
            }
        }
    }

    if ($criteria->customerId) {
        $query->andWhere(DbHelper::parseParam('orders.customerId', $criteria->customerId, $query->params));
    }

Then once search indexes are rebuilt, you'll be able to search on all attributes of a customer.


Include Time In PostDate/DateTime Field Control Panel Display In Craft 3 if you use a DateTime field and have it set to time only, it still displays as a date in the Control Panel with no time.

Even if it is used as a date and time field, just like entry post date it will only display time if it's on the current day.

Is there a way to modify this format to include the time in the control panel display?

There's a plugin for Craft 2 that did this called BigDates.

As of 7/19/2018, it's been ported to Craft 3 on the v2 branch, but not tested or added to the Plugin Store yet, so there might still be some issues: https://github.com/pixelandtonic/BigDates/tree/v2


Is there a way to allow users to control alignment of images in the Redactor plugin using Craft 3 I'm looking to let editors determine the alignment of images in a Redactor field.

I wasn't sure if it worked out of the box with Craft 3 (I'm using 3.0.9).

I did find this plugin: https://github.com/picdorsey/craft-redactorimageposition but it looks like it is Craft 2 and I don't see any forks that are updated for Craft 3.

Any suggestions on how to let users in the Control Panel control alignment of images in a WYSIWYG field would be very helpful. (This link suggests using a Matrix field, but I'm not sure how that would give the user control: Using the Redactor rich text field, how can I dynamically wrap my images with a fancyBox link (with attributes as parameters)? )

It looks like the right way to do this is to tweak the redactor settings:

https://github.com/craftcms/redactor#redactor-configs

and

https://imperavi.com/redactor/docs/settings/image/#s-imageposition

All you have to do is add this key to your redactor config:

"imagePosition": true,

and clear your control panel cache.

The option for image position shows up on the 'edit image' screen.

If you want to use classes to control your image alignment and you want the redactor fields to continue to be WYSIWYG, you need to share those CSS classes between the CP and your front end. This answer will probably help: Where do I add custom css for the Redactor editor in the Craft control panel?


Category filter returning all entries I've been trying to build a category filter. I managed to make my buttons respond with categories but the returned entries on the page stay the same. So when I click one of the links "/?category=koop" gets added to the URL, but my entries don't respond upon that URL. I do have added the categories in the CP and assigned them to my entries.

Here is the code of my filters:

{% if craft.request.getParam('offerCategory') is not null %}

    {% set offerCategory = craft.categories.slug(craft.request.getParam('offerCategory')) %}
    {% set offers = craft.entries.section('offers').relatedTo(offerCategory).find() %}

{% else %}

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

{% endif %}

And my button list

{% for offerCategory in craft.categories.group('offerTypes').find() %}

        {{ offerCategory.title }}

{% endfor %}

I'm quite new to Craft. One of the resources I'm using to build this is: http://craftcookbook.net/recipes/197.

If anyone knows what I'm overseeing, thanks in advance.

I suggest changing the couple places where you use getParam('offerCategory') to getParam('category') so it matches the parameter set in the URL.


Solspace Freeform: loop over all form errors I can only find the following method in the documentation (https://solspace.com/craft/freeform/docs/form/#templates)

form.hasErrors

Is there an array available with all the error messages combined? I'm looking for a way to iterate over all form errors.

There currently isn't a way to get all errors directly from the form, but you could do it this way for now:

{% for row in form %}
    {% for field in row %}
        {% for error in field.getErrors %}
            {{ error }}
        {% endfor %}
    {% endfor %}
{% endfor %}


Error using environment variable for email setting I'm trying to create an environment variable for email settings, but it doesn't work. Here is my email setting at config/general.php

'dev' => [
    '@host' => 'host',
    '@port' => '587',
    '@username' => 'user@user',
    '@password' => 'passwrod'
],

I have also tried before to configure the email setting using this way at config/app.php, but it doesn't work.

'components' => [
    'mailer' => function() {
        // Get the stored email settings
        $settings = Craft::$app->systemSettings->getEmailSettings();

        // Override the transport adapter class
        $settings->transportType = \craft\mail\transportadapters\Smtp::class;

        // Override the transport adapter settings
        $settings->transportSettings = [
            'host' => 'host',
            'port' => '587',
            'useAuthentication' => true,
            'username' => 'user@user',
            'password' => 'passwrod'
        ];

        return craft\helpers\MailerHelper::createMailer($settings);
    }
]

Am I doing anything wrong?

I think you're getting a few conventions mixed up.

Using an @ is typically reserved for aliases https://docs.craftcms.com/v3/config/environments.html#using-aliases-in-control-panel-settings

What you're probably looking for is environment variables in your .env file.

You could set:

EMAIL_HOST=myhost
EMAIL_PORT=myport
EMAIL_USERNAME=myusername
EMAIL_PASSWORD=mypassword

Then from Settings->Email in the control panel, you can reference them with $ https://docs.craftcms.com/v3/config/environments.html#control-panel-settings

$EMAIL_HOST
$EMAIL_PORT
$EMAIL_USERNAME
$EMAIL_PASSWORD


Entries from hardcoded category Should be easy i thought. How can i display all entries from a section from a certain category?

This is my code now, but nothing shows up (screenshot bottomleft):

{% set category = craft.categories.slug('b2c').first() %}
{% set entries = craft.entries.section('homeBlocks').relatedTo(category).find() %}

{% for entry in entries %}
    {{ entry.title }}
    {% for cat in entry.businessSegment %}
        {{ cat }}
    {% endfor %}
{% endfor %}

This code shows all entries (screenshot topleft), and you can see there are entries with b2c:

{% set category = craft.categories.slug('b2c').first() %}
{% set entries = craft.entries.section('homeBlocks').find() %}

{% for entry in entries %}
    {{ entry.title }}
    {% for cat in entry.businessSegment %}
        {{ cat }}
    {% endfor %}
{% endfor %}

My Category Group is called Business Category (with handle "businessCategory"). It contains two categories:

b2c (slug "b2c")
b2b (slug "b2b")

The field handle used in the section "homeBlocks" is "businessSegment"

Where's the error? :)

Give this a try. I'm not 100% sure I've got my site set up the same, but I think it's close.

I have a category group called Categories. It looks like this:

Categories
    b2a
    b2b
    b2c

I created a section called homeBlocks which is a channel (shouldn't matter).
Then on my entry, I have a Categories field with a handle of categoryOne.

On my template:

{% set category = craft.categories.slug('b2c') %}
{% set entries = craft.entries.section('homeBlocks').relatedTo(category).find() %}

{% if entries | length %}
    {% for entry in entries %}

{{ entry.title }}

    {% endfor %}
    {% else %}
        {# No entries found. #}
{% endif %}

I have created 3 entries within my homeBlocks channel, and I've assigned the 1st entry and the 3rd entry to b2c.

Now I am seeing this when I view the page:

Entry Three

Entry One

EDIT

Sorry for the bad info - I think I understand what you are looking for now. I've updated my answer so give it another try.


Is there any way to group Matrix blocks in the control panel (see image)? Sorry if my question seems incomprehensible, it's my first question here so please go easy on me :) !!

I'd like to group the fields in the image in one drop-down menu where, if possible, I can add some description to each block.  So is it possible or do I need to learn plugin dev and create one of my own?

There is a plugin that allows you to organize matrix blocks into groups, perhaps that is worth taking a look at. pimp my matrix


Synching content and template files across environments I'm new to CraftCMS and have a few basic questions about synching contents between local and remote development environments. This has been discussed in other posts by I'm looking for more specific answers.

Traditionally, in the old CMS we use, we do all content changes in the remote dB. And then each team member imports the remote dB and updates their local dB (similar to what is described here). However,  during the dB export, we need to update all the entries to reflect the local URLs. How does this work with Craft? do dB entries need to be updated to reflect the new URLs? And is there a widely used plugin for this step?

Reviewing a Craft migration plugin, it mentions that one has to follow a migration dependency order, and that one has to break migrations into smaller steps to prevent issues, instead of one large migration. Is this the general practice for Craft? Is there no other way to have a single large migration (contents, settings, fields, etc.) happening at once?

Thank you so much.

Here's a blog I wrote that might be useful to you: Database & Asset Syncing Between Environments in Craft CMS
This was written before Project Config was a thing, but the technique works great with Project Config too.


Passing Entry to craft()->templates->render() In looking over the docs on template rendering I am not seeing a way to pass in an Entry model. It seems more efficient to pass in an existing model rather than have the template do another lookup. Something like:

$html = craft()->templates->render('path/to/template', $myEntry);

Here is my use case. I want to use the craft template rendering engine to compose email messages.

You can just pass in the EntryModel straight to the view.

$html = craft()->templates->render('path/to/template', [ 'entry' => $entryModel ]);


Merge trashed element with existing one Is there any way to merge trashed elements with an existing element? I'm creating a custom restore action so you can merge a trashed (commerce) Product with an existing one. The mergeElementsByIds function is failing because it uses the getElementById function which ignores trashed elements. Is there any work around?

Thanks in advance!

https://github.com/craftcms/cms/pull/4404

You can now delete objects that implement ElementInterface using this method:

craft\services\Elements::mergeElements()


Can you pass a variable with includeJsFile? Can you do something similar to using "with" in twig's include tag (http://twig.sensiolabs.org/doc/tags/include.html), but instead with includeJsFile?

I am using a plugin to filter my entries by their tags. The js initiation for this plugin requires me to list all the tags I'm using as a variable. I'd love to assign a variable to the tag group I'm using and pass it to the javascript file, rather than hard code the tag names. Is this possible?

You can't pass a JS variable into a JS file (that doesn't quite make sense). What you can do is to create a JS variable, and make it accessible to the script you are including.

So you'd include your JS file as you are already doing:

{% includeJsFile 'path/to/file' %}

And then you would create your variable, and in JavaScript pass that variable back into the script which you called.

{% includejs %}
    var myData = 'whatever your data needs to be';
    functionFromIncludedScript(myData);
{% endincludejs %}

The snag you're going to run into here is, the order matters. When you use Craft's include methods, they will always include any files before any raw scripts. So using this method, your variable will be defined after the file has already been included.

  It's important to note, the "files before raw scripts" will happen regardless of which order you defined them in Twig.

Similarly, be aware that your file include and raw script include will both happen at the bottom of the page, just before the closing </body> tag.

Now I'm going to make an assumption... You're about to say "But I need my variable declared before the file is included!"

Fair enough, and the solution is pretty simple. Just declare your JS variable in the middle of the page, while you're rendering the main Twig code:

<script>
    var myData = 'whatever your data needs to be';
</script>

So your variable declaration gets rendered along with the rest of your HTML, and your includeJsFile still happens at the bottom of the page. By the time that file is included, your JS variable is sitting around waiting for it.


How to add a button or format style in Craft 3 CKEditor (rich text field) I'm looking to customize the CKEditor (rich text field) to restrict my client to only these buttons: h2, p, bold, italic, underline, link & unordered list.

I asked the question on the Slack channel & got my answer. Thank you @kenyonkowal.

The best way to customize your rich text editor is to use Redactor instead of CKeditor.

You need to add a config file to the config folder, i.e. config/redactor/basic.json and then in that you would put

{
"formatting": ["p", "h2"],
"buttons": ["formatting", "bold", "italic", "underline", "link", "ul"],
"toolbarFixed": true
}

You can edit add or remove a lot more, here's a link to the documentation:
https://imperavi.com/redactor/docs/


How to assign a group to a user in PHP The following doesn't assign an existing user to a group. I've confirmed that both the user and the group exist. Any ideas?

$user = User::find()->username($username)->one();
$user->setGroups([Craft::$app->userGroups->getGroupById(1)]);
Craft::$app->elements->saveElement($user);

I found this answer, which will probably solve it for me, but it leaves me wondering what the purpose of setGroups is.

Apparently this is the right way to do it:

$user = User::find()->username($username)->one();
Craft::$app->users->assignUserToGroups($user->id, [1]);

It's unclear how setGroups is supposed to work.


Does Craft Have Publishing Workflow? Is it possible to allow some users to write content & an editor can edit & publish / approve it?

You can give a user or a user group the following permissions (on each section separately):

Edit entries

Create entries
Publish live changes
Delete entries
Edit other authors’ entries
Edit other authors’ drafts

If a user only can "create entries", but not "publish live changes", then he is not able to publish an entry (but he can create the entry).


Live preview not working for CORS For production site, the backend url is like - 'www.abc-prod.com'
While the actual live site url is - 'www.xyz.com'

When opening live preview for an entry, page never loads. Instead '301 Moved Permanently' is the status of response.

I have enabled CORS by adding following headers in response-

  Access-Control-Allow-Origin: https://www.abc-prod.com
  Access-Control-Allow-Headers: origin, x-requested-with, content-type
  Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS
  Access-Control-Allow-Credentials: true

Still getting blank page for live review. What exactly I am missing?

Live Preview across different root domains is currently not possible in Craft. See here for more info: https://craftcms.stackexchange.com/a/14966/57

You can use it across different subdomains that share the same root domain, though: https://craftcms.com/support/cross-domain-live-preview


EVENT_BEFORE_SAVE_ELEMENT Saving element loop in task/queue I'm calling EVENT_BEFORE_SAVE_ELEMENT to trigger a task that then updates the entry, but it's causing a loop?

The event is triggered when a specific entry type is saved:

Event::on(
  Elements::class,
  Elements::EVENT_BEFORE_SAVE_ELEMENT,
  function(Event $event) {
    $entry = $event->sender;
    if ($event->element instanceof \craft\elements\Entry) {
      $entry = $event->element;
      if (ElementHelper::isDraftOrRevision($entry)) {
        return;
      }
      if(($entry->sectionId == 18) && ($entry->typeId == 26)) {
        $signpostURL = $entry->getFieldValue('signpostUrl');
        if(($signpostURL) && ($signpostURL !== '')) {
          Craft::$app->queue->push(new BrowshotTask([
            'description' => 'Grabbing screenshot for '.$signpostURL,
            'url' => $signpostURL,
            'entryId' => $entry->id
          ]));
        }
      }
    }
  }
);

BrowshotTask then performs some API calls to a third-party service, gets a screenshot, saves an asset and saves the asset in the asset field of the entry.

But this triggers the event again and causes a loop:

$entry->setFieldValue('browsershotUrl', [$assetId]);
if(Craft::$app->elements->saveElement($entry)) {

Sometimes BrowshotTask can take 20 seconds due to the third-party service.. so I thought putting it in a task would be a great idea, but now it's causing me so many problems :(

The easiest solution for this would be either a special fieldvalue or a property in a behavior that you set in your job.

class MyJob extends BaseJob
{
    public function execute($queue): bool
    {
        // do some api calls here
        // ....
        $entry->isSavedViaApi = true;
        $entry->setFieldValue('browsershotUrl', [$assetId]);
        Craft::$app->elements->saveElement($entry)
        // ....
    }
}

and in your event, you can check against this property

Event::on(
  Elements::class,
  Elements::EVENT_BEFORE_SAVE_ELEMENT,
  function(Event $event) {
    $entry = $event->sender;
    if ($event->element instanceof \craft\elements\Entry) {
      $entry = $event->element;
      if (ElementHelper::isDraftOrRevision($entry)) {
        return;
      }

      if(($entry->sectionId == 18) && ($entry->typeId == 26)) {

        // make sure to check the section first, because otherwise the entry
        // may not have this property of field
        if($entry->isSavedViaApi === true){
            return;
        }
        //

        $signpostURL = $entry->getFieldValue('signpostUrl');
        if(($signpostURL) && ($signpostURL !== '')) {
          Craft::$app->queue->push(new BrowshotTask([
            'description' => 'Grabbing screenshot for '.$signpostURL,
            'url' => $signpostURL,
            'entryId' => $entry->id
          ]));
        }
      }
    }
  }
);

If you want to use a behavior instead of a field value for this

use yii\base\Behavior;

class MyBehavior extends Behavior
{
    public $isSavedViaApi = false;
}

and in your main module file

use craft\elements\Entry;
use craft\events\DefineBehaviorsEvent;

Event::on(
    Entry::class,
    Entry::EVENT_DEFINE_BEHAVIORS,
    static function(DefineBehaviorsEvent $event) {
        //so every element gets a isSubscribed attached
        $event->behaviors[] = MyBehavior::class;
    }
);


Kind of virtual entries possible? we are currently working on a website with an event calendar on it. The events should be filterable by categories and dates of course. Some of these events are repeated on another date. Now we are looking for a strategy to add the same event on another day without duplicating the entry and just modifying it's date. Is there a way to add an entry with it's own date but it inherits the contents and relations of another entry? These "virtual" entries should behave like "real" entries, so if the calendar is being filtered by the category "concerts" for example, all entries/virtual entries related to "concerts" should be listed. Any hint on that matter?

Thanks for your support!

Thanks for your reply! We'll look into Solspace Calendar which appears to be very powerful and should fulfil our requirements.


Get the variables of a loop from an include file So my 1. file is "_overview-topicTeaser.twig" which is within a matrix:
{% include 'modules/module-squareteaser/_module-squareteaser' with {
  squareTeasers: block.topicTeaserItems.all(),
  squareteaserHeadline: block.topicTeaserItems.one().entryTopicHeadline
} %}

And my 2. file is "_module-squareteaser.twig":

    <div class="squareteaser__wrapper _parent-3-child">
      {% for item in squareTeasers %}

        {% include 'modules/module-squareteaser/_module-squareteaser-item' with {
          headline: squareteaserHeadline
        } %}

      {% endfor %}
    </div>

So i am looping in the 2. file the file "_module-squareteaser-item.twg" and want to put out the "squareteaserHeadline" in the frontend. But it always gives me the same headline from my first teaser in the loop, makes sense to me cause i am using the "one()" when i include the variable "squareteaserHeadline" in the first file.  But if i delete the "one()" i get nothing... so how do i get all teasers whith their own headline?

Can't you fetch all the blocks with block.topicTeaserItems.all()

{% include 'modules/module-squareteaser/_module-squareteaser' with {
  squareTeasers: block.topicTeaserItems.all()
} %}

And then you display the headlines with item.entryTopicHeadline

  {% for item in squareTeasers %}
    {% include 'modules/module-squareteaser/_module-squareteaser-item' with {
      headline: item.entryTopicHeadline
    } %}
  {% endfor %}

A simplified version would look like

    {% for item in block.topicTeaserItems.all() %}
        {{ item.entryTopicHeadline }}
    {% endfor %}


Downloading file from custom element action I'm trying to download a CSV file from a custom created element action

Here's the performAction function

    public function performAction(ElementCriteriaModel $criteria) {
        $contents = 'row1column1,row2column2'.PHP_EOL.'row2column1,row2column2'.PHP_EOL;

        craft()->request->sendFile('export.csv', $contents, array('forceDownload' => true), false);

        return true;
    }

No error is thrown, the code passes right through the function. When I check the craft logs, there's no sign of any error

And yet, there's no download occuring. When I try this same code in a controller or a service, it works just fine. But in this element action class, nothing happens

It's because those element actions happen over an AJAX and you have to jump through a few hoops to send a file to the browser over an AJAX request.


When to create a new asset volume? I'm not sure if I've been using asset volumes correctly.

For each folder inside my /uploads directory, I've been creating a new volume. So they're all relative to /uploads

I have volumes for things like blog, general, locations, brochures, etc.

so folder structure is like:

 - Uploads
    - general
    - blog
        - subfolder
    - locations
    - brochures

Should I just have a single Volume called "uploads" and then create the subfolders within the craft dashboard via Assets?

Is there a downside in creating a volume per folder?

Should I just have a single Volume called "uploads" and then create the subfolders within the craft dashboard via Assets?

I think that's typically how people would set it up.  You might run into some edge-case synchronization issues with nested Volumes.


Is there an alternative to the Dukt Rest plugin for Craft 3? I am using a combination of two Craft 2 plugins, Cookies and Rest to get the logged in status of a user. What is the recommended way of doing this in Craft 3?

{% set userReq =
  craft.rest.request
    .headers({
      Cookie: cookie
    })
    .url("https://api2.lumi.com/auth/current")
    .send()
%}

You can use the Fetch plugin to make HTTP requests from a template in Craft 3 and there's a Cookies plugin for reading and writing cookies via a template that should do what you want.


How to add attributes to links/scripts? How do I add additional attributes values while registering a CSS/JS file?

I want to add a media attribute to one of the CSS links

Example code:

{% do view.registerCssFile(siteUrl ~ 'css/print.css', [ ['media' => 'print'] ]) %}

The above code produces an Unexpected token "operator" error.

Try this:

{% do view.registerCssFile(siteUrl ~ 'css/print.css', {'media' : 'print'}) %}


How to apply a discount or sale to a variant? The sale and discount menus only discount at the product level. However, I need the ability to apply discounts and sales at the variant level. How would I do this?

Example:
I sell a piece of software (the product). There are new licences and upgrade licences (the variants). I want to apply a discount to only the new licences.

Variants can not be selected when setting up discounts in the UI.

We have variant-based sales/discounts high on the list for the next version of Craft Commerce, but nothing planned to make available in the short term. It will also allow sales and discounts to work with any custom purchasable.

I tried to think of a way around it, and the one way I can came up with in the short term is a little hack:

You could use the description field to limit the discount to specific variant SKU's.

So all discounts would work and be set up as they normally would, but with a condition on the product, but if you got them to put the keyword "ONLY" into the description and then got them to paste the variant SKU into the description. i.e:

ONLY the red tubs (SKU162839) are on discount.

or

Discount ONLY applies to SKU78439 and SKU94300

You could then add the following event listener into a plugin:

// So far this would only be called when the discount has
matched with everything else about the product.
craft()->on('commerce_discounts.onBeforeMatchLineItem',
function($event){
   $lineItem = $event->params['lineItem'];
   $discount = $event->params['discount'];

    if (stripos($discount->description, 'only') === false) {
        return; // do nothing, and let the discount match as it normally would, because the discount does not have 'only' in the description.
    }else{
        if (stripos($discount->description, $lineItem->sku) === false) {
            $event->performAction = false; // since this SKU is not in the description string, then don't apply this discount
        }
    }
});

I wrote the above code without testing, but something along those should work.

Alternatively you could place a custom field on the product which list the variants on discount, and have the above event listener check use that information on the product (instead of matching the SKU on the discount description).

Sorry it's a bit of a hack for now, we will get discounts on variants in the next version of Commerce.

Hope that helps.


Fieldtype with multiple form elements Front-end developer here playing with fire. I'm developing a site that as a specific UI element that I want to reuse throughout the site. Specifically it's a button that has different "configuration" options. You can change the colors, add an icon, etc. It's currently all controlled via CSS classes. You can think of the element as something akin to a Button within Twitter Bootstrap.

I'd like to build a custom fieldtype so that users within the CMS can add in these UI elements throughout the site and change the options such as color, size, name, link, etc. I'd like to be able to place this type inside of Matrix blocks. So doing this within an existing Matrix isn't really feasible.

I'm kind of thinking of it as a mini-matrix or an advanced table element. If someone can point me in the right direction that'd be great. Thanks!

The concept I'm currently struggling with is how to create the fieldtype and have it save the data from the different form elements within my fieldtype to the database.

You have (at least) two options here:

Create a matrix block with the fields you need. That way, the user kan add one or more blocks of the type 'button' (for instance) to the page. Within button, you could have a plain text field for the link and name, a color field for the color, a number field for size, etc.
Create your own fieldtype (http://buildwithcraft.com/docs/plugins/field-types, not as easy as first option). That way you have optimal control over the way your user inputs values.

I would go with option 1.


How to display Craft Commerce subscription description from a linked entry I must be missing something obvious here but I don't see any reference to this in the docs.

Under Commerce Settings > Subscription plans > You can link a related entry to the Description but it is not clear how to display it on the front end.

I found the answer by viewing the source code in CP. To display the content of the related entry:

{{ plan.information.<fieldHandleInTheRelatedEntry> }}


Multiple category relationship criteria (or)and(or) Is there a way to do relatedTo categories where the category is (a or b) and (c or d or e)?

I can get (a or b) working using:

{% paginate craft.commerce.products.relatedTo(categories).limit(20) as pageInfo, products %}

I can separately get (a and b) working using:

{% set relationParam = ['and', { sourceElement: product }] %}
{% for category in categories %}
    {% set relationParam = relationParam|merge([{ targetElement: category }]) %}
{% endfor %}
{% paginate craft.commerce.products.relatedTo(relationParam).limit(20) as pageInfo, products %}

I need to combine these though as I am working with 3 category groups for filtering and want to match products where it is related to any of the selected categories in group 1, and any of the selected categories in group 2, and any of the selected categories in group 3.

An example of selections would be like so:

Group 1: Essentials, Pearlised

Group 2: C6

Group 3: Reds, Greens

Using the 'or' syntax gives me too many results where they no longer match on each group and using the 'and' syntax is too restrictive and wants the product to have all of the selected categories. Does anybody know how I can nest the relatedTo criteria in such a way to get what I need?

I've attempted using the following but it didn't yield any results at all:

{% set relationParam = ['and'] %}
{% if rangeCategories|length %}
    {% set rangeParam = ['or'] %}
    {% for category in rangeCategories %}
        {% set rangeParam = rangeParam|merge([{ targetElement: category }]) %}
    {% endfor %}
    {% set relationParam = relationParam|merge(rangeParam) %}
{% endif %}
{% if sizeCategories|length %}
    {% set sizeParam = ['or'] %}
    {% for category in sizeCategories %}
        {% set sizeParam = sizeParam|merge([{ targetElement: category }]) %}
    {% endfor %}
    {% set relationParam = relationParam|merge(sizeParam) %}
{% endif %}
{% if colourCategories|length %}
    {% set colourParam = ['or'] %}
    {% for category in colourCategories %}
        {% set colourParam = colourParam|merge([{ targetElement: category }]) %}
    {% endfor %}
    {% set relationParam = relationParam|merge(colourParam) %}
{% endif %}
{% paginate craft.commerce.products.relatedTo(relationParam).limit(20) as pageInfo, products %}

I've not seen any examples of people using both 'and' 'or' syntax and there are no notes about this on the documentation so any help would be appreciated. Thank you.

I think what you want here is the union of (products related to a or b) and (products related to c, d, or e).

One good way to do these more complicated queries is to construct a set of the ids, and then do your final query based on that.

So, we will get the ids of products related to a or b:

{% set aOrBProductIds = craft.commerce.products({
    relatedTo: aOrBCategories,
    limit: null
  }).ids()
%}

and the ids of products related to c, d, or e:

{% set cOrDorEProductIds = craft.commerce.products({
    relatedTo: cOrDorECategories),
    limit: null
  }).ids()
%}

Now merge those arrays into one array with all of the ids:

{% set productIds = aOrBProductIds | merge(cOrDorEProductIds) %}

Finally, get the products, and paginate:

{% set productsToPaginate = craft.commerce.products.id(productIds) %}
{% paginate productsToPaginate.limit(20) as pageInfo, products %}


CSS uploaded to S3 is not rendering in the browser I have created a separate asset source to upload my css on Amazon S3 cloud service. Initially, it was not allowing me to upload the files to S3. After adding CSS in the extraAllowedFileExtensions in the config>general.php file, I was able to upload the CSS file.

Here is the code in the template to load the css

<head>

{% for cssfile in craft.assets.source('css') %}
        <link rel="stylesheet" type="text/css" href="{{ cssfile.url }}" />
{% endfor %}

I can see the link tags for each CSS file in the HTML source code, the URL is functional. However, browser refuses to render those files. If I go into chrome console>sources, I can see all the CSS files listed there but they are empty!

When I create a new css asset source locally on the server, everything works (without changing anything inside the template)

I am really confused. I have never ever encountered a problem where browser refuses to read the css file.

Other assets such as js, images etc are loading properly from amazon S3. The only issue seems to be with css

Any ideas?

Have you added the css content-type on S3? You can check this in the console > network tab

s3cmd put -m "text/css" $YOUR_PATH s3://$BUCKET/$YOUR PATH


Working with non-craft database table What is the best way to work with non-craft database tables as models?

I have a given table and I should render its records with multiple filtering and pagination. Importing them to entries is not an option, the table is always changing. So I would like to use as an ElementCriteriaModel.

Where should I get started? Writing a plugin is the only way? Iy yes, how can I create a model from this external table?

Sounds like a plugin is your best option. Creating a model is simple, but if you want to use ElementCriteriaModel, you need to create a custom entity, which gets a little more complex. Check out https://github.com/pixelandtonic/Events for a great example on setting up custom elements.

If you were to just stick with a model, you could run queries to fetch models using BaseRecord and avoid writing queries.

Check out a these files from a plugin I wrote. I am storing API keys in a table with two custom columns, 'service' and 'api_key'.

Model (https://github.com/aberkie/transit/blob/master/models/Transit_KeyModel.php):

<?php

namespace Craft;

class Transit_KeyModel extends BaseModel
{
    protected function defineAttributes()
    {
        return array(
            'service' => AttributeType::String,
            'api_key' => AttributeType::String
        );
    }
}

Record (https://github.com/aberkie/transit/blob/master/records/Transit_KeyRecord.php):

<?php

namespace Craft;

class Transit_KeyRecord extends BaseRecord
{
    public function getTableName()
    {
        return 'transit_keys';
    }

    protected function defineAttributes()
    {
        return array(
            'service' => AttributeType::String,
            'api_key' => AttributeType::String
        );
    }

    public function create()
    {
        $class = get_class($this);
        $record = new $class();

        return $record;
    }
}

It is best to use Services to use the records to get the data and populate the models for use.
Service (https://github.com/aberkie/transit/blob/master/services/Transit_KeyService.php):

<?php

namespace Craft;
class Transit_KeyService extends BaseApplicationComponent
{
    protected $keyRecord;
    public function __construct($keyRecord = null)
    {
        if(is_null($this->keyRecord))
        {
            $this->keyRecord = Transit_KeyRecord::model();
        }
    }

    public function getKey($service = null)
    {
        if($service === null)
        {
            $records = $this->keyRecord->findAll();

            return Transit_KeyModel::populateModels($records);
        } else {

            $condition = "service = '$service'";
            $records = $this->keyRecord->find($condition);

            $model = Transit_KeyModel::populateModel($records);

            return $model->api_key;
        }
    }
}

You can use Yii's find function on records to limit results and use populateModels to return models.

$condition = "service = '$service'";
$records = $this->keyRecord->find($condition);
$model = Transit_KeyModel::populateModel($records);

If you didn't want to get this fancy, you could even just write your own mysql queries in your service files using craft()->db->createCommand()

$query = craft()->db->createCommand()
->select('*')
->from('myTable')
->where("myTable.name = '$name'")
->order("myTable.name")
->queryAll();

Hope this helps! Long answer short...look into making a plugin!


Is environmental routing possible? In the general.php config file, I can target settings for multi-environments like so:

return array(
  '*' => array(
    'devMode' => false
  ),

  '.loc' => array(
    'devMode' => true
  )
);

Is it possible to do something similar in the routes.php file too?

return array(
  '*' => array(
    'test' => 'index'
  ),

  '.loc' => array(
    'test' => '_test/index'
  )
);

I don't want to differentiate the locales, but the environment instead. I know it's possible to query how content gets included within the templates themselves. I just wondered if this is possible instead... I don't actually have a use-case example.

Maybe a time will arise where I want to allow certain content to be accessible for 'staging.' domains only.

Thanks,

Mark

The routes.php config file doesn't support multi-environment setups in the manner that general.php or db.php does – in other words, your example code using a multidimensional array would throw an error.

As a workaround, you can write some PHP in your routes.php file. For simple stuff, a ternary operator may suffice:

return array(
    'test' => strpos(CRAFT_ENVIRONMENT, '.loc') !== false ? '_test/index' : 'index',
);

For more complex stuff, you could set up different arrays of routes for different enviroments, and maybe do some merging:

$routes = array(
    'foo' => '_foo',
    'bar' => '_bar',
);

$devRoutes = array(
    'baz' => '_baz',
);

$stagingRoutes = array(
    'baz' => '_staging/baz',
);

if (strpos(CRAFT_ENVIRONMENT, '.loc') !== false) {
    $routes = array_merge($routes, $devRoutes);
} else if (strpos(CRAFT_ENVIRONMENT, '.staging') !== false) {
    $routes = array_merge($routes, $stagingRoutes);
}

return $routes;

If you're wondering about the CRAFT_ENVIRONMENT constant, that'll default to your hostname (e.g. myawesomesite.loc) unless you explicitly set it to something else before bootstrapping Craft (e.g. in your index.php file). The simple strpos(CRAFT_ENVIRONMENT, $env) test is how Craft merges multi-enviroment configs (e.g. from general.php) under the hood.


Craft 3 Plugin Routing Problems So I am working on converting a previously-standalone Yii 2 app into a Craft module and am having some issues with routing.  I wish to keep my old URL structure as much as possible.  As such, I created a plugin and register routes.  However, I've noticed an issue: When I call Url::to(), I get back URLs that seem to rely on the actionTrigger parameter, even if I explicitly defined routes in my plugin.

Here are the routes as I have them in my plugin:

class CustomerPortal extends \craft\base\Plugin
{
    public function init()
    {
        Event::on(
            UrlManager::class,
            UrlManager::EVENT_REGISTER_SITE_URL_RULES,
            function(\craft\events\RegisterUrlRulesEvent $event) {
                $event->rules['portal/<action:[\w-+]>'] = 'customer-portal/portal/<action>';

If I make the call in a controller to redirect to a route, it builds the URL using an action param, not the rules we defined.  For example:

class UserController extends \craft\web\Controller
{
    public function actionRedirect()
    {
        echo Url::to(['checkout');
        // I'd expect to see '/checkout', but instead we get
        // '/actions/customer-portal/user/checkout' since we aren't
        // applying either of our rules.
    }

    public function actionCheckout()
    {
    }

It seems that the rules are checked when parsing, but not during URL creation, and if you come in with an action prefix, the rules aren't parsed then, but the raw action is attempted.

Am I missing something or is this a bug and either way, can anyone think of a way to work around it?

Edit: Figured out the issue with routes not resolving I had originally, it turns out in the end, my issues was that the regex in the rules wasn't accounting for the fact that many of routes have dashes in them (for example: /user/billing-info).  The default Yii docs say to use <action:\w+>, but that doesn't match the dash character in the URL.  Using <action:[\w-]+> works perfectly and makes this all work.

That said, I'm still not getting Url::to or anything else that references UrlManager to work properly since UrlManager seems to add the action param to the URL before checkout to see if we match existing routes.

EDIT:
I'm so sorry - I messed it up... I rechecked the craft code and I was all the way wrong with the first answer. I hope you had no trouble because of me.
The correct answer is this one....
Event::on(UrlManager::class, UrlManager::EVENT_REGISTER_SITE_URL_RULES, function(RegisterUrlRulesEvent $event) {
    $event->rules['redirect/<action:\w+>'] = 'customer-portal/portal/';
    $event->rules['checkout']              = 'customer-portal/portal/checkout';
});

and in your controller
public function actionIndex(){
    $request = Craft::$app->getRequest();
    $method = $request->getParam('action');
    return $this->redirect($method);
}

In order to have access to the backend function you need to make it "public" so you have to include a protected $allowAnonymous = true; or an array with all functions protected $allowAnonymous = ['functionOne', 'functionTwo'];
Your Controller could look like this
class UserController extends Controller {
    protected $allowAnonymous = true;

    // pretend the request is /redirect/foo and we have created the rule
    // $event->rules['foo']                    = 'customer-portal/user/foo'; and
    // $event->rules['redirect/<action:\w+>']  = 'customer-portal/user/redirect';
    public function actionRedirect(){
        $request = Craft::$app->getRequest();
        $method = $request->getParam('action');
        return $this->redirect($method);
    }

    public function actionFoo(){
        die("foo");
    }

}

Old Post... ignore this
It's not a bug, that's the way how craft handles it. Unlike in other cms plugins in craft are not supposed to handle entire frontend page requests in order to render the entire page.
You can access actions from controllers only via the /action url. Everything else is handled by entries/elements
So you'll not be able to achieve what you want since craft tries to access an entry when you don't include an action url. All frontend request without an action url need to be related to an entry/element or a category. So when you try to access /redirect craft will search for an entry with the slug redirect
What you want is the following:

creating an entry with the slug "redirect"
$entry = Craft::$app-> //your logic to fetch this specific entry
$this->redirect($entry->url)

When you want to create a plugin for other people to use it, you have to create a settings page, include a relation field to that and let other people link an entry to the redirect -> you can fetch this entry from your settings and redirect to it.
The other thing... $event->rules['portal/<action>'] = 'customer-portal/portal/<action>'; is wrong.. Take a look at this documentation
$event->rules['portal/<action:\w+>'] = 'customer-portal/portal/handle-redirect';
and in your portalController
public function actionHandleRedirect(){
    $request = Craft::$app->getRequest();
    $function = "action" . $request->getParam('action');
    $this->$function();
}

But I would suggest you not to do that and use the craft way to handle these things


Empty matrix object after checking for a block type Not sure if this is a bug or my logic is off. I'm trying to add caching logic to templates to not cache certain pages if they have a block type form present because of the dynamic CSRF tokens.

The logic:

{% set doNotCache = entry.mainBody.type('form').all()|length or craft.retour.getHttpStatus != 200 ? true : false %}

If the page returns true, the page renders properly. If the logic returns false the entry.mainBody object is empty (ie. doesn't render the matrix content). If I remove the logic all together the pages render properly.

So there are some changes to how .type() works in Craft 3 which you can read about here. What's happening is the type() you're setting here in your doNotCache is also getting applied later on in your template when you start actually looping over the blocks in entry.mainBody. There are two ways to solve this:

Reset the type() in your matrix block loop

{% for block in entry.mainBody.type(null).all() %}

Clone the mainBody field before you manipulate it

{% set doNotCache = clone(entry.mainBody).type('form').all()|length or craft.retour.getHttpStatus != 200 ? true : false %}


Assets Error: Unknown or bad format (years) at position 0 (y) I am getting a new error, after no apparent updates from me or the client.
The error only appears on pages with this one particular field.

  "DateInterval::createFromDateString(): Unknown or bad format ( years) at position 0 (y): The timezone could not be found in the database"

(then a whole description of errors after it - the first from /craftcms/cms/src/helpers/DateTimeHelper.php)

The field in question is an asset field (within a Matrix field).
The files are uploaded / stored in an S3 bucket.

Everything was working fine for a few months, now any site or admin page with content from this particular field throws that error.

I have looked at the database and could not spot any obvious errors (to my eyes anyway).

I've also cleared caches and updated asset indexes

Any ideas as to what I am looking for / do next?

In case this effects anyone else, here's what I did to get working:

update craft to latest version (in this case 3.1.24)
flush cache using Blitz cache plugin (clear is not enough)
use Cloudfront and not just S3
update all asset indexes in cms

That seemed to have done the trick.


Matrix block fields returning NULL when using MatrixBlock query $blocks = MatrixBlock::find()->relatedTo($entry)->all();

The above returns the correct blocks but all fields are returned as NULL.

I've read over at GitHub that we need to specify a fieldId param but can't seem to figure out how.  The below e.g. doesn't work:

$blocks = MatrixBlock::find()->relatedTo($entry)->fieldId([33])->all();

Help anyone?

The right Field ID to add is the Matrix field id as defined in the Fields section.  Do not use the ids of the matrix block fields.


Craft 2.6.2999 install error: Base table or view already exists: 1050 Table 'craft_entryversions' already exists' I keep getting stranded at the "Oops" modal on install. This is on the third Craft site I've started. The other two Craft 2 sites stood up fine, an I've been developing them for nearly a year.

I've seen questions about this but haven't seen a resolution. Maybe my situation will help figure this out.

Log error output:

[error] [exception.CDbException] exception 'CDbException' with message 'CDbCommand failed to execute the SQL statement: SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'craft_entryversions' already exists' in /var/www/thesite/craft/app/framework/db/CDbCommand.php:358

Stack trace:

#0 /var/www/thesite/craft/app/framework/db/CDbCommand.php(1352): CDbCommand->execute()
#1 /var/www/thesite/craft/app/etc/db/DbCommand.php(507): CDbCommand->createTable('craft_entryvers...', Array, NULL)
#2 /var/www/thesite/craft/app/records/BaseRecord.php(301): Craft\DbCommand->createTable('entryversions', Array, NULL, true)
#3 /var/www/thesite/craft/app/services/InstallService.php(172): Craft\BaseRecord->createTable()
#4 /var/www/thesite/craft/app/services/InstallService.php(56): Craft\InstallService->_createTablesFromRecords(Array)
#5 /var/www/thesite/craft/app/controllers/InstallController.php(159): Craft\InstallService->run(Array)
#6 /var/www/thesite/craft/app/framework/web/actions/CInlineAction.php(49): Craft\InstallController->actionInstall()
#7 /var/www/thesite/craft/app/framework/web/CController.php(308): CInlineAction->runWithParams(Array)
#8 /var/www/thesite/craft/app/framework/web/CController.php(286): CController->runAction(Object(CInlineAction))
#9 /var/www/thesite/craft/app/framework/web/CController.php(265): CController->runActionWithFilters(Object(CInlineAction), Array)
#10 /var/www/thesite/craft/app/framework/web/CWebApplication.php(282): CController->run('install')
#11 /var/www/thesite/craft/app/etc/web/WebApp.php(823): CWebApplication->runController('install/install')
#12 /var/www/thesite/craft/app/etc/web/WebApp.php(790): Craft\WebApp->_processActionRequest()
#13 /var/www/thesite/craft/app/etc/web/WebApp.php(203): Craft\WebApp->_processInstallRequest()
#14 /var/www/thesite/craft/app/framework/base/CApplication.php(185): Craft\WebApp->processRequest()
#15 /var/www/thesite/craft/app/index.php(62): CApplication->run()
#16 /var/www/thesite/public/index.php(19): require_once('/var/www/thesite...')
#17 {main}
REQUEST_URI=/index.php?p=admin/actions/install/install

I've tried this on a couple of local vagrant boxes:

ubuntu xenial 64, nginx, php7.0-fpm, mysql server 5.7.20
ubutnu trusty 64, nginx, php5-fpm, mysql-server 5.5.58

I have successfully installed an older version of Craft on both of these boxes before.

The DB user was root for both environments, so DB permissions shouldn't be an issue as suggested in another post about this.

I also tried deleting the tables mentioned in the log and tried again, as mentioned in another post about this. I just got an error about another duplicate table.

I also destroyed and recreated each vagrant box, so I don't think lingering sql temp files are an issue as reported elsewhere.

Any new direction on this would be awesome. We already have a Craft site ready for production, but if we can't use it for a related site for the same client, we'll have to move on to something else, and that's the last thing I want to do.

This is an indirect answer, but if you don't have time to debug the install process to set up a Vagrant box, grab this:

https://github.com/niceandserious/crafty-vagrant

Something about it doesn't trigger the duplicate table trouble. Someday I'll have time to figure out why.


How do I handle and/or repopulate checkbox group(s)? I have a contact form (public facing only) on my site that has a checkbox group. The user can pick their favorite color(s). Upon successful submission I am capturing that data within the CP via a plugin.

I have a checkbox field within the CP called "colors".

This is how I am outputting the values in my template:

<input type="text" id="name" name="name"class="form-control" value="{% if contact is defined %}{{ contact.name }}{% endif %}" placeholder="Full Name"/>
{{ contact is defined and contact ? errorList(contact.getErrors('name')) }}

....

{% for option in craft.fields.getFieldByHandle('colors').getFieldType.options %}
<div class="checkbox">
    <label>
        <input type="checkbox" name="fields[colors][]" value="{{ option.value }}">{{ option.label }}
    </label>
</div>
{% endfor %}
....

So far so good. Name is required, so if a user submits the form without entering a name, but has chosen a few colors, I would like the colors to be checked when the page reloads. I am able to do that on the name field easily.

The next part of the question, how do I handle the array of options via my plugin?

Here is what I have in my controller:

ContactFormController

....
$contact->profession = craft()->request->getPost('profession[]');

When I log what the model is getting here is what I am seeing:

[name] => My Name
[colors] =>
....

I assume that I will also need to set up a FK relationship in my record file so once the form is submitted I can have a 1:many relationship. I'll look at the docs on how to set that up - and post what I've done back for future reference.

I wanted to follow up with this thread in case someone else came across this. If there is a better solution, let me know and I will update the answer accordingly.

Using the example above, the user filling out the form can choose their favorite color(s).

I should mention that the colors checkbox field was created in the CP, and all values for the checkbox are managed there. That way I can easily loop through the values within my template.

twig/html

    {% for option in craft.fields.getFieldByHandle('colors').getFieldType.options %}

                <input type="checkbox" value="{{ option.value }}" name="fields[colors][]" {% if account is defined and option.value in account.colors %}checked{% endif %}>{{ option.label }}

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


Images Uploaded in CMS not showing on mobile [desktop is fine] Just want uploaded images for entries to show for desktop AND mobile

{% set assets = entry.galleryImage %}

{% if assets | length %}

{% for asset in assets %}
    {% if asset.kind == 'video' %}
        <video class="vid" preload="none" controls="false" loop webkit-playsinline muted>
            <source src="{{ asset.url }}" poster="{{ asset.url }}" type="video/mp4">
        </video>
    {% else %}
        <img class="gallery_img_1"  src="{{ asset.url }}">
    {% endif %}
{% endfor %}

From Craft's POV, there's no difference between desktop and mobile.  I'd check your CSS to see if you're changing how things are displayed depending on the @media query breakpoints.


Video Asset URLs not rendering I'm trying to output the video files from within a block but get a Calling unknown method: craft\elements\db\AssetQuery::url() error when using the following:
{{ block.video.videoFileWebm.url }}

Assets in this volume have public URLs so I'm not sure why this isn't working.
FULL CODE
{% if block.video %}

                <video {% if block.video.videoAutoplay %}autoplay{% endif %} {% if block.video.videoLoop %}loop{% endif %}

                    {% if block.video.videoThumbnail %}
                    {% set optimizedImages = block.video.videoThumbnail.one().imageVariants16by9 %}
                    poster="{{ optimizedImages.srcset() }}"
                    {% endif %} muted>

                    {% if block.video.videoFileWebm %}
                        <source src="{{ block.video.videoFileWebm.url }}" type="video/webm">
                    {% endif %}
                    {% if block.video.videoFileOgg %}
                        <source src="{{ block.video.videoFileOgg.url }}" type="video/ogg">
                    {% endif %}
                    {% if block.video.videoFileMp4 %}
                        <source src="{{ block.video.videoFileMp4.url }}" type="video/mp4">
                    {% endif %}

This browser does not support the video element.

                </video>

            {% endif %}

Asset fields return like an array so they can potentially have more than one item, you need to request the first item only with .one() (as opposed to requesting .all())
//First check if the asset field has more than zero items
{% if block.video.videoFileWebm|length %}
    // Retrieve the first and only item in the asset field
    <source src="{{ block.video.videoFileWebm.one().url }}" type="video/webm">
{% endif %}

I would also set block.video to a variable to clean up the code a bit and maybe speed it up a little.


How to insert a Sprout Form into a new page in Craft CMS I am a Wordpress guy, and I've been given the task of handling my companies Craft site.

I have been at this for hours, and can't seem to figure out how to get the damn form to appear on the page I created.

The one line of code thing does not work when I copy paste it.
I have no website data on my local device, so this is all browser-based.

I really have no clue where to go from here, and the boss expects results.
I have the form created in Craft, it is only a matter of figuring out how to make it appear.

Please help a major n00b. Thanks.

Edit: My form is named stlForm
When I say it's all browser based, I mean I can only edit as much as I can by logging in as an admin. I have no Local data, FTP to access that I know of (our web people are MIA).

If you don't have a local development environment setup, you will need FTP access to the server where Craft is installed to edit templates. The one line of code cannot be copied and pasted into a field in the control panel like one might do with WP.

First of all you will need to make or edit a template to show this form. The "one line of code" needs to be placed in the template where you want to show the form.

For Example

If you are adding a “Contact Us” form that you want to appear at https://[YOUR-DOMAIN-HERE]/contact-us then you would do the following steps:

Login to your company’s server via FTP with and FTP client like Filezilla, Transmit, or Cyberduck. You’ll need to get the FTP login credentials from your company.
Find the location where Craft is installed. If it has not be placed above the webroot then you could probably find it under public_html/craft or www/craft.
Find the templates folder inside the craft folder.
You have a few options at this point:

Make a new file and name it contact-us.html or contact-us.twig depending on your preference. You can probably just make a new file with the .html extension if you don’t have a local development environment set up. I don’t know if there is any performance gains using .twig over .html. You can make a new file usually by right-clicking in the folder where you want it created and there is a context menu to make a new file.
OR you can make a new folder under templates and name it contact-us. Then under that folder you can make a new template named index.html. Your folder structure will then look like craft/templates/contact-us/index.html.

Open the new file that you created in the previous step.
Add the "one line of code" referring to your form.
Save the template.
Go to your browser and type in httpS://[YOUR-DOMAIN-HERE]/contact-us and you should see the form there.

This is probably the simplest way to get your form to show up on your site. There are more advanced and client-friendly ways to do this but this should hopefully get you started.

You’ll need to check the other templates to see how they are created if you want to include the same style as the rest of your site. There is usually a line of code at the top of the template that says something like {% extends '_layout.html'%} or similar.


PDF preview thumbnail options? I'm using the most recent Craft CMS 2.6.2791. I'd like to generate preview thumbnails for pdf assets in my templates, so I found this plugin:

https://github.com/carnesmedia/pthumb

However, following the instructions on the readme page gives a nonsense url. In my template, I have:

<img src="{{ craft.PThumb.thumbnail(pdf) }}">

If I inspect the src generated by this I see

http://localhost:8888/myproject/public//assets/pdfs/previews/b15c8529f2b4a9b354c5e592e84d1ac5.png

However, this renders as a broken image. I check my project structure and the previews directory is nowhere to be found. Am I doing something wrong or perhaps missing a step?

I'm also open to any other solutions that could generate a thumbnail from the first page of a pdf asset automatically. Thanks!

For anyone looking to do this on Craft 3, I used pThumb previously, but I created a plugin specifically to do this for Craft 3 - https://github.com/bymayo/craft-pdf-transform

It takes Asset PDF files and coverts them to JPEG / PNG files automatically when they are uploaded.

Or, do theres a Twig method that lets you convert the PDF to an image if the image already exists in Assets. But this can be a bit labour intensive on the server to do when a template is rendering so is only advised for small files.