Serve remote files instead of local ones (with a nitro setup) I'm new to CraftCMS and slowly learning how to use it. I'm creating a site. The local setup was done with Nitro. I have read about the ways to synchronize data and assets across environments. But I have a special situation:
The client has thousands of images (over 9GB), as we do our development, they are continuously adding new media. We don't want to download all those images, and going through refreshes every time they add new images or edit existing ones. With the previous CMS I used to work with, I could modify a local .htaccess file so that when there is a local image request it would be served from the remote server instead.
Does anyone know how to achieve this with a Nitro setup?
Thank you so much.

There's a couple different ways to handle this.
Base URL on Asset Volume
One way is just to treat the asset volume like you might a CDN.
Unlike other CMS (ahem WP), Craft doesn't hardcode URLs into the database and will build them up on-the-fly.
On the local dev server, you just need to set the base url (i.e. server name) of a volume to that of the production server instead of serving locally.
Your Asset volume config might look something like:

Instead of setting a value in the control panel, you can also use an alias if you want to advantage of Craft's multi-environment support.
Server Rewrites
If you have other assets that aren't necessarily managed by Craft, you can do some server rewrites like you did using Apache's .htaccess config.
Nitro uses nginx as the web server, not Apache, so there's not quite a direct equivalent of .htaccess other than editing the configuration (which is easy enough to do).
You'd want to ssh in to the appropriate container and then edit the nginx config (usually located in /etc/nginx/sites-enabled/yourtestservername.
To make the server rewrite work, try something like:
location ^~ /images {
return https://productionserver.example.com$request_uri;
 }

Place this before the closing bracket "}". This assumes your asset volume is stored at "/images". If you have any others, you can add them separately. nginx will redirect any content that's in /images to the production server.


Is there a way to reset the focal point in Craft? As the question states. Is it possible to reset the focal point in the CMS?
I cannot see any obvious setting?
If not could this perhaps be a feature request for a reset focal point button?

if you're referring to an image focal point then...

How do image focal points work in Craft 3?

help out somewhat...


Trigger sent before user is added in user group so no email is sent I am trying to send custom welcome emails to custom user groups but Sprout email is attempting to send the notification before the user group is created which means the email isn’t sending. The log just outputs that the user doesn't belong to any user group.

Note: We are using a custom plugin to create the user and trigger a set your password email which could be the problem, is there a way to hook into sprout email so we can trigger the send from our plugin?

You can programmatically trigger a notification email using the Sprout Email service layer. Notification Emails are sent via the SproutEmail_DefaultMailerService using the sendNotification() method:

craft()->sproutEmail_defaultMailer->sendNotification($campaign, $object);

$campaign needs to be a SproutEmail_CampaignModel
$object, in your case, would be the Craft UserModel (and more generally is any object that you want to make available to your email templates


Issues migrating Craft site to a new host We've tried moving an existing, live Craft site to a new host (where we currently just have http access via an IP). We simply copied all files (all 'craft' files, the index.php file and our related assets) across to the new host and updated permissions where necessary. We then moved across the DB and updated config settings to connect to it.

However, something is wrong. On the front end we get this message:

Our site is temporarily unavailable. Please try again later.

And when trying to access the CP, all we get is this message:

Oops!

Craft does not support backtracking to this version. Please upload Craft 2670 or later.

No idea what this means. As well, the version that the message references (2670) is the version we have installed on the live site and are trying to migrate across. Any help would be much appreciated - and I can share the dev URL non-publicly if needed.

Sounds like the database you restored on the new server isn't matching the files that are in place on that server.

Check the craft/app/Info.php file's CRAFT_BUILD and CRAFT_VERSION numbers and make sure they match what's in the version and build in the craft_info table in the database.

If you need to download a previous version of Craft to get a different build/version of the files, you can do so like this.


Automatically add an insurrance for a product What would be the best way to automatically add a product when another product is added to the cart?

For example, if I where to add a TV to the cart, I would like to automatically add a HDMI cable as well.

You could write a custom Craft plugin (generate the boilerplate for it at https://pluginfactory.io) - and in that listen to the onPopulateLineItem event.

https://craftcommerce.com/docs/events-reference#commerce_lineitems.onpopulatelineitem

Then, check the purchasableId of the item being added to the cart - if it is the TV, then add the cable to the cart at the same time.  Something like this (untested):

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

    $purchasable= $event->params['purchasable'];
    $cart =  craft()->commerce_cart->getCart();

    if($purchasable->getPurchasableId() == 123){
        craft()->commerce_cart->addToCart($cart, 456);
    }
}

(See addToCart() in plugins/commerce/services/Commerce_CartService.php for the full function definition).

But the bigger question is should you do this....

Be aware that customers don't generally like this sort of behaviour in cart systems, and you should make sure that if you do do this, you at least take care to remove the accessories when they remove the main item from the cart.

Note that it soon gets complex, because can you be sure the accessory was added this way etc?

My advice is to instead use MultiAdd (https://github.com/engram-design/MultiAdd) to build a form that gives them the option of adding the accessories at the same time as the main product.  Like we do here for example:
https://imagescience.com.au/products/monitors/eizo-coloredge-cs2730


Craft 2 -> 3 Update /admin 404 I'm attempting to update a craft 2 site to craft 3.

Following these instructions, I used composer to install Craft:
https://docs.craftcms.com/v3/upgrade.html#if-you-want-your-directory-structure-to-resemble-a-new-craft-3-project%E2%80%A6

I have got to the stage where I go to the domain.com/admin but I am getting the error:

  The requested URL /admin was not found on this server.

Thanks for any help - at a dead end I am sure its something v simple!

Is a lot of potential reasons for what issue may be. Is Craft handling the 404 error? If not, it could be your server is not pointing to the web/index.php properly.

Can check that just putting a die('hello world'); at the top of your index file at least.


Can someone help me with my site structure? Sections/Category setup Thank you for your time and patience I'm a newbie to the Craft world. I've been all over the Craft Documentation and this site trying to figure out the best approach for a site I am putting together. The prototype I did makes sense however when it came time to put it into Craft I'm hesitant or lacking confidence in the setup. I just need a sound board to bounce off my setup.

Current Section setup:

Home (Single)
Company (Single)
Products (Single and Structure with multiple entry types)

Product Category A

Type A

Size A
Size B

Type B
Type C

Product Category B

Product

Product Category C

Type D
Type E

Support (Single)
Contact (Single)

How would I best create a template structure for the products section? How can I setup categories to help create this structure?

URL would ideally be
site.com/products/product-category/product

or do I even need products? Just jump to the product-category?

I want to have a category page, comparison page (Size) and dedicated product page. The category page with the type category wouldn't need an intermediate page.

It's fairly straight forward. You could go with a single "layout" file and then a template file for each unique template that utilizes that simple header/footer layout

templates/layouts/_layout.html
templates/index.html (homepage)
templates/products.html
templates/support.html
templates/contact.html

Extending a layout:

{% extends "layouts/_layout" %}

Your product template would then just need to be coded to handle the category handle in the URL.

For instance, listing entries (products) that are assigned to a category (untested):

{# get categorySlug from URL segment 2 #}
{% set category = craft.request.getSegment(2) %}

{# get instance of category #}
{% set category = craft.categories.slug('categorySlug') %}

{# get entries related to the category instance #}
{% set entries = craft.entries.relatedTo(category) %}

{# loop through the entries #}
{% for entry in entries %}
    {{ entry.title }}
{% endfor %}

That's obviously just an example, but should get you going in the right direction.

Related reading material:

https://craftcms.com/docs/templating/craft.request#getSegments


Purge HTML but leave Line Breaks I'm looking to purge all the html from a text field, but leave the line breaks in there. I currently have the following code, which makes line breaks happen, but unfortunately, people can add html to the text field and it will render it.

    {{ user.userAbout|raw }}

Is there any way to do this?

Sounds like you're looking for the Twig |striptags filter, which is a wrapper for PHP's strip_tags


How to use a Numeric Field with a Default Value I have a case where I need to use a numeric field which also has a default value.

For example: numericField needs to have a minimum value of 100 and a max value of 1000, but when the user adds a new entry, the field value should default to 256 in the entry form.

Unfortunately, I cannot trust the user to enter the correct default value, even if it is clearly indicated in the field notes.

Right now, when the user adds a new entry, numericField will always be set to 100 the minimum value.

Is there another integer field type which would work as I have described?

You can:

1) Write a plugin that extends Craft's native Number field type and adds the functionality you're looking for.

2) Make a feature request for a default value for the native Number field type.

3) Potentially fake it using something like the CP CSS plugin.


How do I filter entries in CP by Entry Type? I have an entry type called industry and am trying to use this search syntax in the CP to filter my entries by that type:

type:"industry"

I am getting no results whatsoever. How do I filter entries in CP by Entry Type?

There is a great plugin that allows you to add columns Craft doesn't initially provide.  This plugin also allows you to filter by those, like Entry Type.

https://github.com/mmikkel/DashCols-Craft/


How do I sort categories by title while preserving hierarchy? New to Craft. I'm outputting a list of all the categories in my site.

When I do this:

    {% nav category in craft.categories %}

        {{ category.title }}
        {% ifchildren %}

                {% children %}

        {% endifchildren %}

    {% endnav %}

I end up with (for example):

Legumes

Peas
Beans
Lentils

Meat

Ground Beef

Fruit

Peach
Banana
Strawberry
Grapes

I'd like those to be alphabetical, though, so Fruit, Legumes, and Meat, are listed in that order, with their children also listed in alphabetical order in the nested list.

However, when I do THIS:

    {% nav category in craft.categories.order('title') %}

        {{ category.title }}
        {% ifchildren %}

                {% children %}

        {% endifchildren %}

    {% endnav %}

The entire list gets flattened, alphabetized, and then spit back out into a nonsensical hierarchy, like so:

Beans
Banana
Fruit

Grapes
Ground Beef

Lentils
Meat

Peas
Peach
Strawberry

Is there any way to alphabetize by one level at a time, without completely reinventing the way Craft handles categories? Thanks!

You should be able to do this with a recursive macro.
Here is a macro alphaList which is passed a list of categories (in alphabetic order). For each category, it outputs that category, and then if that category has any children, it calls itself on an alphabetic list of those children.

To get the children of a category c, you combine descendantOf with descendantDist of 1: craft.categories.descendantOf(c).descendantDist(1)

To get the initial list of top level categories, you use the level parameter: craft.categories.level(1). That will mix together categories from all your category groups, so probably you want to specify the group: craft.categories.group('myGroup').level(1).

{% import _self as self %}

{% macro alphaList(cats) %}
{% import _self as self %}
  {% for c in cats %}

      {{c.link}}
      {% set children = craft.categories.descendantOf(c).descendantDist(1) %}
      {% if children|length %}

          {{ self.alphaList(children.order('title')) }}

      {% endif %}

  {% endfor %}
{% endmacro %}

{% set topCats - craft.categories.level(1) %}

  {{ self.alphaList(topCats.order('title')) }}


Check paginated currentPage before setting the paginate tag This might sound counter-intuitive, but I'm trying to set a specific limit; if the currentPage is the first paginated entry.

{% set limit = paginate.currentPage == 1 ? 5 : 8 %}
{% paginate craft.entries.section('news').limit(limit) as articles %}

I know this isn't going to work because I'm querying the paginate tag before I've set it.

So is there a way to set a custom limit for the first page only?

Ok, so after discovering the getPageNum request, I found the following solution:

{% set pageNumber = craft.request.getPageNum %}
{% set firstPageLimit = 5 %}
{% set defaultLimit = 8 %}
{% set limit = pageNumber == 1 ? firstPageLimit : defaultLimit %}
{% set offset = pageNumber == 1 ? 0 : firstPageLimit - defaultLimit %}
{% paginate craft.entries.section('news').limit(limit).offset(offset) as articles %}


Ignoring "The " and "A " when sorting entries I have this code which used to work with 2.x versions:

{% set foobars = craft.entries({ section: "foobars"}).order("(CASE WHEN title LIKE 'The %' THEN SUBSTRING(title, 5) WHEN title LIKE 'A %' THEN SUBSTRING(title, 3) ELSE title END) asc") %}

The idea is sort the entries ignoring the possible "The " and "A " prefix in the entry title, so that the order is more natural and what my client expects.

However the code is giving a SQL error message:

You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '`subquery` INNER JOIN `entries` `entries` ON `entries`.`id` = `subquery`.`elemen' at line 9

How to achieve the same functionality on Craft 3?

SOLVED (thanks to Brad):

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

This is still unsolved:

In addition I have to get the previous and next entry in this channel based on the entry title, while excluding "The " and "A " in the beginning.

In Craft 2 this was done with:

{% set foobars = craft.entries({ section: "foobars" }).order("(CASE WHEN title LIKE 'The %' THEN SUBSTRING(title, 5) WHEN title LIKE 'A %' THEN SUBSTRING(title, 3) ELSE title END) asc") %}

{% set prev = entry.getPrev(foobars) %}
{% set next = entry.getNext(foobars) %}

In Craft 3 this seems to be a bit more complicated than that. According to what I've discovered this would almost work:

{% set query = craft.entries.section("foobars").id("not " ~ entry.id).limit(1) %}
{% set prev = clone(query).title("<= " ~ entry.title).orderBy("title desc").all() %}
{% set next = clone(query).title(">= " ~ entry.title).orderBy("title asc").all() %}

But I would have to be able to set the orderBy-clause to use the "(CASE WHEN title LIKE 'The %' THEN SUBSTRING(title, 5) WHEN title LIKE 'A %' THEN SUBSTRING(title, 3) ELSE title END) asc", which does not work in Craft 3.

Now I've tried using this:

{% set query = craft.entries.section("foobars").id("not " ~ entry.id).limit(1) %}

{% set prev = clone(query).title("< " ~ entry.title).orderBy("(CASE WHEN `title` LIKE 'The %' THEN SUBSTRING(`title`, 5) WHEN `title` LIKE 'A %' THEN SUBSTRING(`title`, 3) ELSE `title` END) desc").one() %}

{% set next = clone(query).title("> " ~ entry.title).orderBy("(CASE WHEN `title` LIKE 'The %' THEN SUBSTRING(`title`, 5) WHEN `title` LIKE 'A %' THEN SUBSTRING(`title`, 3) ELSE `title` END) asc").one() %}

But the problem is that if I'm on an entry titled "The Foobar", I would need to search for entries around "Foobar" and not "The Foobar".

How would you modify the query, so that it would include the MySQL "(CASE WHEN...)" logic?

{% set prev = clone(query).search("(CASE WHEN `title` LIKE 'The %' THEN SUBSTRING(`title`, 5) WHEN `title` LIKE 'A %' THEN SUBSTRING(`title`, 3) ELSE `title` END) < 'Foobar'").orderBy("(CASE WHEN `title` LIKE 'The %' THEN SUBSTRING(`title`, 5) WHEN `title` LIKE 'A %' THEN SUBSTRING(`title`, 3) ELSE `title` END) desc").one() %} ?

How to achieve the same functionality on Craft 3?

This is a MySQL specific answer (Craft 3 supports PostgreSQL as well), but you probably just need to escape your column names like so and that should solve both of your problems:

{% set entries = craft.entries({ section: "test"}).order("(CASE WHEN `title` LIKE 'The %' THEN SUBSTRING(`title`, 5) WHEN `title` LIKE 'A %' THEN SUBSTRING(`title`, 3) ELSE `title` END) asc").all() %}


Overcoming Rackspace Cloud Files 10,000 object limit Original question from Craft Slack:

Is there anyway to hack the AssetIndexTool to start at a certain asset/position/filename/index?

We’re using Rackspace Cloud Files and have around 25k images loaded. However, Cloud Files is limited to returning 10,000 objects per “page”. And it doesn’t look like Craft will paginate these objects. Wondering if we can just hack it to start the asset indexing at a certain place instead of starting at a certain index/filename, etc.

Found the spot to hack this. It was not within the AssetIndexTool as originally theorized, but in the  In RackspaceAssetSourceType in the _getFileList function you can append a marker marker_end and/or limit to the file list.

The marker should just be a URI without the extension. As an example, we change the parameters on $targetUri to look like so:

&format=json&marker=products/BC-174&limit=250';

This will index the items form that marker and effectively ignore all the other assets you have already indexed. Craft will prompt you to delete the items you already have, as they are not found because you have skipped them by hacking the $fileList.

I've found you can safely hit Cancel and your items from the marker range will be imported, and your other indexes will not be affected.

This article is very helpful in finding out what you can do with the marker params.


Commerce discount promotions as a fieldtype? I'd like to create an entry in Craft that talks about a new discount, and then choose that discount via a field (so a bit like you can choose an entry or a product). That way, should the parameters of the discount change, I'm not having to manually update the information in the entry to match any changes to the discount details. Is there a plugin for this?

That field type doesn’t currently exist, but it wouldn’t be hard to create it.

Here’s the relevant code you’d need if you want to take a stab at it:

use Craft;
use craft\base\ElementInterface;
use craft\commerce\models\Discount;
use craft\commerce\Plugin as Commerce;

// ...

public function normalizeValue($value, ElementInterface $element = null)
{
    if ($value !== null) {
        return Commerce::getInstance()->discounts->getDiscountById($value);
    }

    return $value;
}

public function getInputHtml($value, ElementInterface $element = null): string
{
    $options = [];
    foreach (Commerce::getInstance()->discounts->getAllDiscounts() as $discount) {
        $options[] = ['value' => $discount->id, 'label' => $discount->name];
    }

    /** @var Discount|null $value */
    return Craft::$app->view->renderTemplate('_includes/forms/select', [
        'id' => $this->handle,
        'name' => $this->handle,
        'options' => $options,
        'value' => $value->id ?? null,
    ]);
}

With that, the field type’s value would always either be a Discount model or null, so in your templates you could do this:

{% if entry.myDiscountField %}
    Code: {{ entry.myDiscountField.code }}
    ...
{% endif %}

Alternatively, you could pull this off with a simple Plain Text field that stores a discount code, and then fetch the discount manually from your template.

{% if entry.myDiscountCodeField %}
    {% set discount = craft.commerce.discounts.getDiscountByCode(entry.myDiscountCodeField) %}
{% else %}
    {% set discount = null %}
{% endif %}

{% if discount %}
    Code: {{ discount.code }}
    ...
{% endif %}


Best Practices for plugin development The plugin docs are a good reference but can be a bit daunting when piecing things together, any good plugins from the community that are well commented/built etc. ? Especially in regard to elements.

Mijingo has a great video on plugin development at https://mijingo.com/products/screencasts/craft-plugin-development/

Outside of that I'd take a look at the plugins at https://straightupcraft.com/craft-plugins/


Environment variable doesn't work in Assets field settings I created an environment variable (in config/general.php) called {baseAssetPath} which contains the server path to the folder where all my assets are stored. This makes it easier to populate the Path field in Assets settings.

However, this variable does not appear to work to configure the Upload Location when setting up an Assets field. Now, when I attempt to add an asset, or edit an existing entry, I get the following error.

Internal Server Error

Craft\EntryModel and its behaviors do not
have a method or closure named
"baseAssetPath".

Is Upload Location looking for a server path or a URL path?

If it's looking for a server path, why doesn't my {baseAssetPath} variable work here?

"Upload Location" doesn't reference you're environment variables. Instead, you've got a dropdown menu of your pre-defined Assets sources. Whichever one you choose will be used as the base of your file path.

Anything you put in curly braces after that will become a subfolder of that asset source. So your subfolder names will be created based on whichever Entry fields you define.


How can I change the Date Created for Assets? I'm using graphql to pull in some assets/pdfs and ordering them by dateCreated, however the files go back a few years (i.e. files from 2019, files from 2018 etc.) but they weren't uploaded in the correct chronological order. Is there a way I can change the 'dateCreated' or 'Created at' date?  I changed the dateCreated column within the assets table of the database, but that didn't change anything within Craft or the graphql query.
Any help is appreciated.

The dateCreated column you're referring to is more of a minimum internal audit trail that Craft uses when a new row is inserted into the database (along with dateUpdated).
Is sounds like you want something that references the original time the asset was created, which would be stored in the images EXIF/metadata.  You could write a plugin that read that information: https://craftcms.stackexchange.com/a/8521/57


List related siblings I've been reading a lot of documentation (getSiblings, getDescendants etc) but can't get this to work:

I have a structure, named 'areas'. When showing an entry that is a child of an area in 'areas', I would like to list its siblings (that is in the same place in the hierarchy).

So for example on the url http://localhost/areas/some-area/very-nice-area-number-1, I would like to list very-nice-area-number-2, very-nice-area-number-3, very-nice-area-number-4 and so on (but not the current one (very-nice-area-number-1), of course).

To explain further, using the getNext function is the closest I've come, except that it only gives me one entry, and I want all other entries that holds the same place in the hierarchy under 'some-area'.

As already mentioned in the comments, getSiblings should do exactly what you need.

{% for sibling in entry.getSiblings() %}
    {{ sibling.title }}
{% endfor %}


How to cache and serve different data to different users using Blitz? What strategy should I take when I want to serve different data to different users with (Blitz) cache? Logged in users get one set of prices (that can vary depending on their price group memberships), users that are not logged in don't see prices at all.
I read and implemented a test of Dynamic Content as described in the Blitz Cache documentation, and the result looks promising. Lighthouse says between 97-99 on performance with a 0,6s Fist Contentful Paint, serving gzipped caches from Blitz Storage on the Hyperlane VPS (I will test Cloudflare too).
The question is rather about the potential user experience of having the prices ajaxed into the body of the html document. I've never seen any site do it this way before. Have a look at the result. Pay attention to how the prices appear and the related network events on the right:
https://vimeo.com/507996281/0d16df559d

(I realize that the defaultPrice is passed as a parameter to the productPrice template, and therefore the price is exposed - I've later replaced it with an encrypted string using the free plugin Cryptographer)

It looks like your approach is working rather well, so I'll assume you are simply asking for an alternative approach.
To make 1 AJAX request rather than the 80 or so that the page is currently making, I would use Blitz's dynamic content feature to load all of the products in one single template. In that template you can check whether the user is logged in, and hence whether to the display the prices or not, as you are already doing.
An alternative alternative would be to use Sprig, see the dynamic content recipe. Sprig gives you more control over how things are dynamically loaded. You could even tweak the way products are loaded to create a smoother user experience. For example, cache the products without the prices (the default for non-logged in users) and on page load, use Sprig to re-render the component with or without the prices (based on the user type).


User registration approval/activation Want to do two things and wondering if I'm missing something in the docs or if someone has tackled this already:

User registers on the front end and get success messages saying they will be notified when approved.
Admin is notified that they just did that.
Admin activates them
They get email saying they are good to go. (optional I guess)

There is no current way that I know of that does this, but you can probably do it relatively easy with a custom plugin.

If e-mail validation is turned off in the Users settings, the created user is verified by default. You can hook into the users.onBeforeSaveUser event and set the status as UserStatus::Pending. Then redirect them to a screen saving something like "Blah blah you will be notified once we activate you blah blah".
Hook into the users.onSaveUser event, check if this is a new user (isNewUser) and send off an e-mail to a given e-mail.
Admin logins and activate as normal.
(Optional) In the same users.onSaveUser event, if this isn't a new user and the user status is UserStatus::Active, send out an e-mail to the address given by the user.


Element type with 'baked-in' fields I've created an element type and want to have a 'Categories' and 'Tags' field built-in (the sources for each will be selectable in settings), but can't figure out the best way to go about this whilst supporting custom field layouts with tabs.
Do I just hard-code these fields into the edit page/hud html code then handle the logic on the save controller (this is fiddly whilst keeping it customisable/tab-able), or is there a better way to do it? I.e inject them into the field layout via the controller?
Can't get my head around this one.

I've given up on this, from what I've looked at it's not going to be easy without a migration that creates the fields first (don't really want to do this for updatability issues). I've changed the scope of the plugin to be more bare-bones, and I think it's better for it.


Retain empty lines in a RichText field I am using a RichText field type of my site content and I am inserting blocks of code within some <pre> tags which I add in the HTML view of the editor, however when I leave the HTML view, all of the empty lines within the <pre> block are stripped out.

I've tried turning off the clean up HTML option etc with no luck. Is there a way to keep the empty lines (multiple consecutive newlines).

Don't use Redactor / a Rich Text field for code blocks is probably the only answer one can give right now.

Instead you could use a Plain Text field for your article and get the formatting done with markdown. Or you could use Matrix and keep using Redactor for the text parts of your article and have a separate block type for code.


Looping Entries in Super Table, display row details I have a Super Tables field, containing related entries:

I'd like to display the field name (ie 'English Links') in a template, but can't figure out how, the following outputs a string of values and if I try to add a handle to the row output I get 'Impossible to access an attribute ("handle") on a string variable'.

{% for row in entry.relatedArticleLinks %}
    {{ row }}
{% endfor %}

I really don't think this was written very well in the first place tbh, as the rows are hard coded:

English

            {% for link in entry.relatedArticleLinks.englishLinks %}

{{ link.title }}

            {% endfor %}

I'm sure there's a better way of displaying this field which would allow new rows to be displayed automatically?

This can be done, but it does require additional calls to query this information. It might be more efficient to hard-code this text in your template, unless you really want to make this text dynamic.

There's two concepts here. When you call entry.relatedArticleLinks you're fetching Super Table blocks that are related to the entry in question. Calling englishLinks on each of these blocks will return the content for this field - nothing about the field definition itself, such as the handle, name, or settings - just the content.

What type of field is englishLinks?

If you wanted to grab the field definition as well, you can by calling:

{% set field = craft.app.fields.getFieldByHandle('relatedArticleLinks') %}
{% set blocks = craft.superTable.getSuperTableBlocks(field.id) %}
{% set fields = blocks[0].getFields() %}

{{ fields.englishLinks.name }}


Custom data source without options - Sprout Forms Is it possible to create a custom data source that does not include end user options? I have tried not including the getOptionsHtml(), returning null, returning an empty string, and just return and the all fail.

A Custom Data Source does not require any settings. If desired, you could create a Data Source that only had a title and did whatever logic and queries that you wanted behind the scenes.

In Craft 2, getOptionsHtml returns null by default and shouldn't need to be set to anything in your Custom Data Source if that is desired:

public function getOptionsHtml()
{
    return null;
}

In Craft 3, the default is to not display any settings also:

public function getSettingsHtml()
{
    return null;
}


Conditional if statement for Matrix dropdown option Ok, so I've tidied up the code a bit and using option.selected instead of option to see if the option is selected. But, it isn't behaving how I'd expect it:

{% for telephone in user.profilePhone.type('details') %}

      {% if telephone.type == 'details' %}
        {% for option in telephone.icon.options %}
            {% if option.selected == 'mobile' %}

            {% elseif option.selected == 'home' %}

            {% else %}

            {% endif %}
        {% endfor %}
        {% if telephone.country %}{{ telephone.country }}{% endif %}
        {{ telephone.number }}
      {% endif %}

{% endfor %}

So this is how I read it:

Loop through all Block Types details

As I understood from the docs, there is no need to be specific if there's only one Block Type (regardless of max blocks setting). The extra if conditional seems redundant?
I also understood that a for loop would act as a conditional anyway, so it would return false if no Blocks existed?

Loop through the icon dropdown options

Whichever one is selected, display it's corresponding icon.

But what it actually outputs is this:

So it's outputting all of the available options, not just the selected one (and not even the correct icons). I've managed (with separate if statements for just 'home' and 'mobile' to get this:

But it's still outputting all options declared in the if statement, instead of the desired single icon. Here are the dropdown options:

I'm new to programming, so perhaps I'm getting muddled up with things, but it seems like it should only output the icon I want, not the entire dropdown list (I realise I may need another conditional for if 'other' or 'work' is selected)

Perhaps the issue is you can't check in the for loop for just the selected option with an if condition. Something like:

{% for option in telephone.icon.options if option.selected %}

If I understand things correctly, you have a matrix block telephone, which contains a dropdown field telephone.icon, and you want the value of the selected dropdown option. That value is telephone.icon.value (which will be one of mobile, home, work, or other).

{% for telephone in user.profilePhone %}

    {% if telephone.icon.value == 'mobile' %}

    {% elseif telephone.icon.value == 'home' %}

    {% else %}

    {% endif %}

    {% if telephone.country %}{{ telephone.country }}{% endif %}
    {{ telephone.number }}

{% endfor %}


Local and Staging Environments allow for updates, Live doesn't (and doesn't recognise the license.key) I'm just in the process of migrating a site from staging to live. I've pushed everything over and have copied/moved a license.key file from a site that we're no longer using to this one. However, when I log into the backend, I'm stll getting the You’re running Craft Pro with a Craft Personal license. message at the top. If I click on 'Resolve' - I get a spinner modal and nothing else happens, until eventually I get An unknown error occurred.

Running version Craft CMS 2.6.2952

I'm presuming it's not able to phone home for some reason to validate the license key - but I'm unsure what could be stopping it? Anyone?

The problem is that I had disabled a few PHP functions as part of a security tweak.... I'm assuming it's using cURL to make the request to phone home.


Development system with MAMP won't run after MAMP upgrade? I have a development system with MAMP and gulp and my localhost version of my website was running fine.  I upgraded MAMP from 3.5.2 to 4.4.1.  When I restarted MAMP it said it needed to upgrade the database, which I let it do.  Now when I try to start the website, it just spins at the localhost:6002 (for example) website address and the site will never launch.

Any thoughts on how to chase down this problem.

The ports were changed to 7888 and 8888 and I needed to set them back to what I was currently using.


List entries by category I have a number of entries that all belong under a Channel that I created. Each entry has a category field where the user can select one or many categories to associate the entry with.

I am displaying these entries on my page, but would like to display each entry under the appropriate category.

For example, my entries are currently displayed like this:

Entry 1 (Category A)
Entry 2 (Category C)
Entry 3 (Category A)
Entry 4 (Category B)
Entry 5 (Category A)

I want it to display like this:

Entry 1 (Category A)
Entry 3 (Category A)
Entry 5 (Category A)
Entry 4 (Category B)
Entry 2 (Category C)

What's the best way to do this?

This will exclude empty categories, meaning they don't have any entries associated with them.

{% set entryIds = craft.entries.section('channelHandle').ids() %}
{% set categories = craft.categories.relatedTo({ sourceElement: entryIds }).group('categoryGroupHandle') %}

{% for category in categories %}

{{ category.title }}

        {% set entries = craft.entries.section('channelHandle').relatedTo(category) %}
        {% for entry in entries %}

{{ entry.title }}

        {% endfor %}

{% endfor %}


Is it possible to use same template for index and archive template? I'm new to Craft from ExpressionEngine and wondered how people handle Month/Year archive pages.  I have figured out how to get the archives to display but the code seems overly complex.  I wondered if there is a more straightforward approach or if it is possible to display your archive using the same template as the news/index  which displays all. In EE this was possible and just wondered if it was in Craft.

Thanks in advance.  My archive template code below.

{% if month is not defined %}
    {% set before = year + 1 %}
    {% set after  = year %}
{% else %}
    {% if month == 12 %}
        {% set yearBefore = year + 1 %}
        {% set monthBefore = '01' %}

        {% set before = yearBefore~'-'~monthBefore %}
        {% set after = year~'-'~month %}
    {% else %}
        {% set before = year ~ '-' ~ (month + 1) %}
        {% set after  = year ~ '-' ~ month %}
    {% endif %}
{% endif %}

{% set allEntries = craft.entries.section('news').limit(null).after(after).before(before) %}

{% for date, entries in allEntries | group("postDate|date('F Y')") %}

Entries from {{ date }}

    {% for entry in entries %}

            {% for asset in entry.newsthumb %}

            {% endfor %}

{{ entry.title }}

                <time datetime="2017-07-27" class="post-time">{{ entry.postDate.format('F d, Y') }} </time>

                {{ entry.newssummary }}

                {% if entry.newscategory | length %}
{% endif %}
                {% nav category in entry.newscategory %}

{{ category.title }}{{ not loop.last ? ', ' }}

                {% endnav %}

                {% if entry.newscategory | length %}
{% endif %}

    {% endfor %}
{% endfor %}

The way I do this is to use a different template for each set of entries. So there would be an archive one for all the articles from a given month: _news/index-archive, and a category one for all the articles in a given category: _news/index-category, and one for all of the entries: _news/index-all, maybe one for articles by tag, etc.

Each of these templates sets entries to the relevant entries, and then does

{% include '_news/index-generic' with {
  entries: entries
} only %}

And index-generic has all the shared display code.

Probably there will be a couple of other things that vary as well, for example a heading:

{% include '_news/index-generic' with {
  entries: entries,
  heading: 'Category: '~category.title
} only %}


FeedMe Pro Import JSON When I import using JSON with FeedMe Pro and need to import more records into an entry that has a Matrix field. I find it deletes the previous and adds the new data only.  Is there anyway to append to the Matrix field leaving the previous data intact?

In addition to How to save Matrix data programmatically in Craft 3

You'll fetch your data loop each row and fetch the element / create a new element if none exists

$section = Craft::$app->sections->getSectionByHandle('news');
$entryTypes = $section->getEntryTypes();
$entryType = reset($entryTypes);
foreach ($jsonData as $row) {
    // try to fetch an element
    $element = Craft::$app->getElements()->getElementById($row['id']);
    // no element exists, create a new one
    if ($element === null) {
        $element = new Entry(
            [
                'sectionId'     => $section->id,
                'typeId'        => $entryType->id,
                'fieldLayoutId' => $entryType->fieldLayoutId,
                'authorId'      => 1,
                'title'         => 'My Entry',
                'slug'          => 'my-entry',
                'postDate'      => new DateTime(),
            ]
        );
    }
    // get the field by handle
    /** @var \craft\fields\Matrix $field */
    $field = Craft::$app->getFields()->getFieldByHandle('matrix');

    // get the existing matrix blocks
    $existingMatrix = $element->getFieldValue('matrix');

    // serialize the data
    $serializedMatrix = $field->serializeValue($existingMatrix, $element);

   // loop your json matrix blocks
    foreach ($row['yourMatrixBlocks'] as $key => $block) {
        // append your new Matrix fields
        $serializedMatrix['new' . $key] = [
            'type'   => 'block',
            'fields' => [
                'field' => $block['field']
            ],
        ];
    }

    // set the new field value
    $element->setFieldValue('matrix', $serializedMatrix);
    $success = Craft::$app->getElements()->saveElement($element);

    // display errors - just in Case
    if($success === false){
        Craft::dd($element->getErrors());
    }
}


CBdException: Column 'id' cannot be null I receive the following error only when I clear the cache:

When I try to rebuild the image index, all of my image paths go missing.
I'm not sure what caused this error but I do need to fix it.

I've checked my image transforms and everything is named correctly. I even tried to delete and re-add and still nothing. I'm getting this same error on another one of my craft sites when I empty the cache.

I have no idea what's causing it.

I did come across this post:
CDbException: Column not found

I read through the comments but no solution has been posted. I did a db search for CONSTRAINT or FOREIGN KEY and have both.

Any and all help is appreciated.
Thanks in advance.

UPDATE!!!

Things I tested and found:

I looked at the assettransformindex in the database and it was empty.

I ran an INSERT statement to populate the rows with proper information - it inserted successfully.
I refreshed the site, the CBd exception was gone.

I cleared the cache, minus the image transform index and the site still worked perfectly.

I cleared the cache with image transform index selected and it stripped everything from the DB.

If I try to upload an asset that uses the transform, it throws the CBd exception again and clears the DB.

I hope this information helps...
Thank you in advance.

Turns out this was because several tables were missing the MySQL auto-increment flag for their id integer primary keys.


Dynamic Category template paths I've got a site with several locales and want to reuse a set of categories across locales but want to target a locale specific template from within each.

Is it possible to set a locale-specific path within the category group settings, eg

{{ craft.locale }}/_video

Cheers,

Cole

It looks like this isn't possible. But what you can do instead is either:

Route them to a shared template using the category settings and use include programatically:

{% include 'myCatTemplate--' ~ craft.locale %}

Disable "Categories in this group have their own URLs" in the category settings and add your own dynamic routes.


How to allow guest to make entry without login I have a pretty simple form. I just realized that it doesn't work unless I'm logged in as admin.

Is there a way to bypass that, or to simply turn off authentication altogether for Craft CMS? For this project, I think that would be fine.

Any ideas? I'd prefer to not use a plugin.

Here is the form:

        {% for entry in craft.entries.section('ScoreRequest').limit(1).find() %}
            <form method="post" action="" accept-charset="UTF-8">
            <input type="hidden" name="action" value="entries/saveEntry">
            <input type="hidden" name="sectionId" value="{{ entry.sectionId }}">

                  <input class="form-field" placeholder="Your Name" id="title" type="text" name="title">

                  <textarea class="form-field-2" placeholder="Your Email Address" id="body" name="fields[email]"></textarea>

                            <textarea class="form-field-2" placeholder="Your Phone Number" id="body" name="fields[phone]"></textarea>

                  <textarea class="form-field-2" placeholder="Your Company" id="body" name="fields[body]"></textarea>

            <input class="form-button" type="submit" value="Send">
            </form>
        {% endfor %}

The Guest Entries plugin is made for this scenario!


getAllSections but not these specific sections I'm looping over my sections to produce a section filter group. But I want to exclude at least 2 of the sections.

I'd have thought I could do craft.sections.getAllSections('not 18') for example but it seems not.

What's best approach?

Here's how I've gone about that in the past.

Loop through all sections, and only if section.type is structure and doesn't have the handle 'pages' (skip that section, essentially);

{% for section in craft.sections.getAllSections() if section.type == 'structure' and section.handle != 'pages' %}
  What you want to do here... Print the content or whatnot.
{% endfor %}

And if you only want to get channels;

{% for section in craft.sections.getAllSections() if section.type == 'channel' %}
  What you want to do with the channels here...
{% endfor %}


How can I implement advanced action routes (in routes.php)? We want to mask specific action routes in our project's routes.php file. Currently what we have looks like this:

return array(
    // /actions/api/element/section/name/{$name}/
    'api/test/(?P<name>)'  => ['action' => 'api/element/section'],
);

We would like to pass name into the action array somehow. Is there something documented or undocumented that I'm missing? Or is what I'm attempting not possible at this time?

Yes it’s possible. First you will need to update your route key so that you’re capturing the name parameter with a valid named subpattern. (You were close, but missing the actual pattern part of it).

return array(
    'api/test/(?P<name>[^\/]+)' => ['action' => 'api/element/section'],
);

Any named subpattern matches in your route will be passed to your controller action’s $variables argument, if it has one.

class Api_ElementController extends BaseController
{
    // ...

    public function actionSection(array $variables = array())
    {
        $name = $variables['name'];

        // ...
    }
}

Note that you specifically need to call the argument “$variables”, and you need to typeset it to an array for this to work.


Is there a better way to localise channel url? I'm working on a bilingual site (en and cy) and have a news channel with entry urls news/{slug} and the translated cy/newyddion/{slug}. Everything is working well with entries and if the url is accessed without the slug then a list of entries is displayed.

However, when accessing without the slug the translation of news is cy/news not cy/newyddion as required. If I attempt to access cy/newyddion I get a 404 not found error. I have tried different solutions such as adding files in templates/cy/newyddion but still get 404s.

The only way I've got it to work is by adding a new single section named news which has no content and loads the news index template and renaming the news section handle to avoid conflicts.

What I would like to know is if there is a better way of accomplishing this as it seems like a cumbersome way of doing it.

In my experience, the easiest and best to maintain way to do this is to use entries only. If you make that news index page an entry (e.g. structure or single section) it is as easy as entering your translated slug in that entry's CP.

Another advantage is that you can add fields to that entry (e.g. to edit the meta description or some copy), so this can make sense in many cases, not just for multilingual routing.


How to create multisite in Craft CMS v3? I am looking to create multisite in Craft 3. Is there any way to create multisite in Craft?

This is a very general question. Take a look at the following resources as a starting point:

Managing Multiple Sites in Craft 3 – Sites and Localization - Straight Up Craft
Using Craft CMS Multi-Site - Mijingo


Error on updating Craft install with Sprout vendor files I was updating an Craft install on Mediatemple server yesterday. Im now getting the following error:

Cannot use barrelstrength\sproutbase\app\import\base\FieldImporter as FieldImporter because the name is already in use

I tried creating a new install but I get the same error - any ideas what I can do to rectify?

I was also getting the same error and tried so many times install/uninstall but couldn't succeed. In my case, it was basically php 7 version compatibility issue.

You should change your php version to php 7.1.16 or higher, if using lower like php 7.0

Fixed by Dev: https://github.com/barrelstrength/craft-sprout-forms/issues/195

Code to be modified: https://github.com/barrelstrength/craft-sprout-base/commit/5e8ce5eb9b1815d1d2a66ed69664a890271d6620

Regards

Ankit Chauhan


getting fields of a section (getFields()) I feel like I'm doing this wrong (looping on section fields):

{% for fieldLayoutField in craft.entries.section('rentalsBulletin').getEntryTypes().first.getFieldLayout().getFields() %}
    {% set field = craft.fields.getFieldById(fieldLayoutField.fieldId) %}
    {% include 'rentals-bulletin/_components/form-field-types/' ~ field.type %}
{% endfor %}

Building a front-end "create" page. Goal is loop through fields and depending on type include a snippet to build the form. Basically, get section fields and build the form dynamically.

EDIT: if you didn't see the accepted answer comments, the way to do this when you don't have an entry to work with is:

{% for fieldLayoutField in craft.sections.getSectionByHandle('rentalsBulletin').getEntryTypes()[0].getFieldLayout().getFields() %}

You don't need to go through craft.fields to get the fields. They are already there.

{% set fields = craft.entries.section('rentalsBulletin').getEntryTypes().first.getFieldLayout().getFields() %}
{% for field in fields %}
    {% set type = field.getField().type %}
    {% include 'rentals-bulletin/_components/form-field-types/' ~ type %}
{% endfor %}

You will probably also want to pass some variables into your included templates to actually build the fields with the proper field names as well.

{% set properties = { 'name': field.getField().handle } %}
{% include 'rentals-bulletin/_components/form-field-types/' ~ type with properties %}

There are also a few plugins available on the plugins page for form building that you might want to check out.

Update Looks like craft.entries.section('rentalsBulletin').getEntryTypes() returns null when there are no entries defined. Instead you can go through a different route that doesn't seem to depend on entries.

{% set fields = craft.sections.getSectionByHandle('news').getEntryTypes()[0].getFieldLayout().getFields() %}


Get every slug from entry for each language For the robot.txt file, I want to get every URI from the entries for every language. Right now it just gets the URI from one language.

{% set crawledEntries = craft.entries({
    relatedTo: { sourceElement: crawlSites, field: "entryCrawler" },
    order: "sortOrder"
}) %}

{% for entry in crawledEntries %}
    Disallow: /{{ entry.uri }}
{% endfor %}

This now loops just through one locale.

Got it...

{% set crawledEntries = craft.entries({
    relatedTo: { sourceElement: crawlSites, field: "entryCrawler" },
    order: "sortOrder"
}) %}

{% set otherLocales = craft.i18n.getSiteLocaleIds()|without(craft.locale) %}

{% for entry in crawledEntries %}
    Disallow: /{{ entry.uri }}
    {% for locale in otherLocales %}
        {% set entryL = craft.entries.id(entry.id).locale(locale).first() %}

        {% if entryL %}
            Disallow: /{{locale}}/{{ entryL.uri }}
        {% endif %}
    {% endfor %}
{% endfor %}


Assets Folder: Images don't show up I have an Asset Source, called files, with two subfolders:

group1
group2

I also have two User Groups, with the same names.

I want everyone in “group1” to save images into files/group1; and I want everyone in “group2” to save images into files/group2.

I have a Matrix field which contains an Assets field. It is configured to:

Restrict uploads to a single folder => files/{owner.author.groups[0].name}/images
Restrict file types to Image

When a user from group1 logs in and adds an entry, the image asset folder doesn't display all the data from their images folder.

If I upload images in the Assets folder directly to their images folder and go back to create a new entry, the new image doesn't show up in the image list.

Any ideas what is going on?

Okay. So, my problem was that I had multiple Asset Sources since I was trying to give my groups permissions to specific sub-directories. This was causing indexing issues which is why I wasn't seeing the images show up.

CraftCMS has an excellent customer support. They were able to create a plugin that allowed me give my groups permissions to their subdirectories.

Link to plugin: https://github.com/pixelandtonic/AssetSubfolderAccess

All you have to do is create your user groups. Then create an asset source configuration that points to your root folder that will contain the subdirectories. Give your user groups permission to the Asset Source (Root folder).

Then on the plugin page after you have installed the plugin. Click on the plugin to go to its settings. This is where you can configure each of your user groups to only have access to their sub-folder. =)

Huge thank you to CraftCMS, Pixel And Tonic, and Brandon for all the help. You guys are amazing!!! =)


Getting Wordpress 404 when accessing /craft/admin My current site is with Wordpress in the folder /blog. My new Craft install is in a sibling folder /craft. When i try to load brianfeeney.us/craft/admin, i get the wordpress 404. Must be an .htaccess issue, right? Can't figure out or find the solution anywhere.

Wordpress’ .htaccess file and Craft’s .htaccess file both use the same strategy: If the request is not pointing to a valid file or folder, rather than have Apache respond with a 404, re-route the request to index.php.

It sounds to me like you’ve got a .htaccess fie at your web root which is handling Wordpress’ index.php redirect, and that is taking precedence over Craft’s for whatever reason.

Since your Wordpress install lives within /blog/, you should move that Wordpress .htaccess file to /blog/.htaccess, so it’s only affecting blog/* requests. (You’ll also need to tweak it a bit; post the file’s contents if you need help with that.) Or another option is you could add this condition it, before the RewriteRule line:

RewriteCond %{REQUEST_URI} ^/blog [NC]

Likewise, Craft’s .htaccess file should live at /craft/.htaccess (no modification will be necessary as the one Craft ships with already accounts for the possibility that it’s within a subfolder), or a similar RewriteCond line could be added to it if you really want to keep all your redirects in one place at /.htaccess.


Create an Array in Twig and loop through fields in global set So I've created a globals set (socialMedia) with 10 input fields, but this could grow in the future, for clients to add links to various social media accounts. This works fine except that the code for this seems overly long and reptitive since I need to put a conditional to check if each field has been output. Like this:

  {% if socialMedia.facebook | length %}

  {% endif %}

  {% if socialMedia.twitter | length %}

  {% endif %}

  {% if socialMedia.flickr | length %}

  {% endif %}

  {% if socialMedia.instagram | length %}

  {% endif %}

  {% if socialMedia.email | length %}

  {% endif %}

  {% if socialMedia.vimeo | length %}

  {% endif %}

  {% if socialMedia.youtube | length %}

  {% endif %}

  {% if socialMedia.linkedin | length %}

  {% endif %}

  {% if socialMedia.tumblr | length %}

  {% endif %}

  {% if socialMedia.googlePlus | length %}

  {% endif %}

  {% if socialMedia.dribble | length %}

  {% endif %}

Ideally I could set an array and then do a for loop and output everything as needed in a couple of lines. However I'm not sure how to proceed with that or if it is even possible.

Seems like a great use case for a Twig macro.  Completely untested, but something like this:

{% macro social(object, type) %}

    {% set value = attribute(object, type) %}

    {% if value | length %}

    {% endif %}
{% endmacro %}

{% import "myMacros.html" as myMacros %}

{% set socialArray = ['facebook', 'twitter', 'instagram', 'vimeo', 'youtube'] %}

{% for socialType in socialArray %}
    {{ myMacros.social(socialMedia, socialType) }}
{% endfor %}


Twig: Convert time format I have a video Object with a duration property formatted in SCORM 2004 time format. Like so: PT51M55S. How do i convert this into a human readable time format like: 51:55? date() does not seem to work obviously.

I'm not sure this is possible in Twig alone, but it should be easy enough in PHP.

To do that, you could write a Craft plugin that adds a custom Twig extension that has a ScormIt filter that uses PHP's DateInterval class to output it in the format that you're looking for.

That way, you could do something like:

{{ videoObject.duration|ScormIt }}


Navigation, Structure, Usage, WOES! As some of you may have seen I've been asking on here and on Slack regarding the best way to go about creating a navigation on a site.

As yet, nothing I have tried is working and any code that I've been given to try also hasn't worked. (Thanks to everyone who has given code so far though).

Therefore I have literally stripped down everything in the hope that someone might be able to tell me where I'm going wrong as I'm sure that something as simple as this shouldn't be as difficult.

I have a completely fresh install of Craft 2 with the standard templates that come with Craft and I have then created a Structure called (creatively enough) Navigation of which the hierarchy can be seen below.

Home
Services
---- Service 1
---- Service 2
--------- Sub Service 1
---- Service 3
Galleries
---- Gallery 1
---- Gallery 2
............

The above is actually just an example but reflects the sort of items that could go into the site.

Any of the items above could also be either an entry, a single or a template that has a channel on it and so on and so forth.

First up I'm not sure if I actually need to place any information into the Entry URL Format and Entry Template settings for the section as I'm guessing these aren't maybe all that important as the section is literally just being used for creating navigation on the site. That said I did fill them out with standard information just in case.

Next on the standard news/_entry.html template I placed this code :

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

        {% nav page in pages %}

                {{ page.getLink() }}
                {% ifchildren %}

                        {% children %}

                {% endifchildren %}

        {% endnav %}

This allows me to spit out the entire navigation which is good so far but in my Structure section I have an Entries field which allows me to choose an entry. I first of all have no idea of how to spit out this as the link instead of the {{ page.getLink() }} code above.

My Entries field is called singleEntrySelector and I tried {{ page.singleEntrySelector }} to see if it would spit anything out but that didn't work and I got an error on the page.

So I'm wondering how do I go about spitting out the content of the singleEntrySelector field so that my navigation items can point to the correct URL?

Once that is working I'd like to have it so that when I'm on say Sub Service 1 that I can create a secondary navigation on the page which will show me everything from Services down to (in this example) Service 3 so pretty much a very standard secondary navigation output.

That should (I'm hoping) allow me to do what I need here although I am definitely open to other ways of approaching this if I'm completely seeing things wrong here?

Many thanks,

Mark

P.S. I'd also like to be able to in the end spit out the navigation using whatever HTML code I need to as I will be utilising this on a responsive site and so have no idea yet as to what code I will need to encapsulate it all in. Therefore if the {% nav %} tag isn't the right fit here in that it won't allow me to do that then I'd really appreciate being shown how to spit it out in some other way that will allow me to do just that.

First up I'm not sure if I actually need to place any information into the Entry URL Format and Entry Template settings for the section

Nope, you can probably just un-check the Entries in this section have their own URLs checkbox in the Section settings and don't worry about it – I'm guessing the nav items should only function as pointers to "actual" entries, and won't need their own URLs or template.

  [...] in my Structure section I have an Entries field which allows me to
  choose an entry. I first of all have no idea of how to spit out this
  as the link instead of the {{ page.getLink() }} code above.

You can't use the getLink() function when the URL you want is the URL for the entry in the Entries field, and not the actual URL for the nav item (phew). You'll have to build the  tag yourself – something like this should work:

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

        {% nav page in pages %}

            {{ page.title }}
            {% ifchildren %}

                    {% children %}

            {% endifchildren %}

        {% endnav %}

The crucial part here is the page.singleEntrySelector.first().url|default part for the  tags's href attribute.

It's important to realize that whenever you call an Entries attribute/field – such as page. singleEntrySelector in this case – Craft returns an instance of ElementCriteriaModel, which essentially is an array-like object. That means that even if the Entries field only has 1 entry inside it, you can't call page. singleEntrySelector.url directly – you'll need to explicitly select an entry inside the model, either by looping over it, calling a specific index (page. singleEntrySelector[0].url) or use the first() method to return the first entry. This is true for Asset, Tags, User and Category fields as well – basically any fieldtype that returns one or more related elements.

If you're wondering about the |default filter applied to the URL, that's there to prevent Craft from throwing an error if the page doesn't actually have an entry selected in the singleEntrySelector field. If you make the latter a required field, you can skip the |default part.

  [...] I'd like to have it so that when I'm on say Sub
  Service 1 that I can create a secondary navigation on the page which
  will show me everything from Services down to (in this example)
  Service 3 so pretty much a very standard secondary navigation output.

To output a sub navigation containing all nav "descendants" of the current entry, you'll first need to find the relevant nav item using the current entry in a relation query. Then, you can use the descendantOf() method to build the pages array, using the nav item as the ancestor:

{% set navItem = craft.entries.section('navigation').relatedTo(entry).first() %}
{% if navItem %}
{% set pages = craft.entries.descendantOf(navItem) %}

        {% nav page in pages %}

                {{ page.title }}
            ...
{% endif %}

If you want the sub nav to display the entire sub tree for the current entry – not just the descendents – this is how that could look:

{# Get the related nav item for the current entry #}
{% set navItem = craft.entries.section('navigation').relatedTo(entry).first() %}
{% if navItem %}
    {# Get the top level item #}
    {% set topItem = navItem.getAncestors().level(1).first()|default(navItem) %}
    {# Build a "pages" array w/ the top item and its descendents (child entries) #}
{% set pages = craft.entries.id([topItem.id]|merge(topItem.getDescendants().ids()|default([]))) %}

    ....

Note: If you use the same Entry for the Entries field multiple times in your Navigation Structure, results may vary. The examples above will pull the first nav item that has a relationship with the current entry, and disregard any others. However, a many-to-one relationship between the Navigation Structure's entries and the entries in the Entries field, with single sub tree output for the sub nav doesn't really compute – so I've disregarded that particular issue and assumed the relationship will always be one-to-one.


PS-4 Autloading custom module I have created a module in modules/Core.php which works great and I can reference it using modules\Core::class. But I want to re-organise my modules.

I'm not super familiar with PSR-4 loading but I have taken a look at a bunch of modules to try and copy the file structure and composer file.

Here's the file structure I want:

modules
  └── wrux
    └── Core
      ├── README.md
      ├── composer.json
      └── src
        └── Core.php

Here's my modules/wrux/Core/composer.json file:

{
  "name": "wrux/Core",
  "require": {
    "craftcms/cms": "^3.2.0"
  },
  "autoload": {
    "psr-4": {
      "wrux\\Core\\": "src/"
    }
  }
}

After I run composer dump-autoload I was hoping that I can use the wrux\Core namespace but it's not working. My module is only accessible from then modules\wrux\Core\src namespace.

Any ideas here?

I don't think you need to add any composer.json in your module folders
You have to update the project composer.json file only to let the craft know about custom module so that it can load on each boot.
Folder Structure might be like  (inside module folder at the root)

wruxmodule
└── src
    ├── controllers
    │   └── DefaultController.php
    ├── models
    │   └── WruxModuleModel.php
    ├── variables
    │   └── WruxModuleVariable.php
    └── WruxModule.php

Copy below line to config/app.php

 return [
    'modules' => [
        'wrux-module' => [
            'class' => \modules\wruxmodule\WruxModule::class,
        ],
    ],
    'bootstrap' => ['wrux-module'],
];

Now update the project composer.json file

"autoload": {
    "psr-4": {
      "modules\\wruxmodule\\": "modules/wruxmodule/src/"
    }
},

Finally run

composer dump-autoload ( at project root)


Displaying Sub Categories on Category Page First, a disclamer -- I am new to Craft CMS.

With that said, I am trying to create a category page whereby the page will show the title, description and image of the sub-categories of the current category.  It will do this so long as there are still sub-categories.  When there are no longer sub-categories it will then show the entries for that category.

I think I have figured out the code (see below), but I'm having a problem showing the images.  On one level the images show fine, but on a lower level the images are being shown in reverse order.  I can't figure out why.

Here is the code:

{% set num = 0 %}
{% set children = category.getChildren() %}
        {% if children|length %}
         {% for child in children %}

        {% set assets = craft.assets.relatedTo(children).nth(num) %}
            {% if assets %}

            {% endif %}

{{ child.title }}

{{ child.description }}

        {% set num = num + 1 %}
        {% endfor %}

            {% else %}

                {% set entries = craft.entries.relatedTo(category).level(1) %}
                {% for entry in entries %}

{{ entry.title }}

{{ entry.description }}

                Learn more
                {% endfor %}

        {% endif %}

Now, on the category page:  /topics/life/ the images are associated with the proper category.

But on the category page:  topics/life/cells, the order is reversed.  The first category displays the image for the last category and the last category dispalys the image for the first category.  Why is that and what can I do to fix it?

Thanks in advance for any help you can offer.

P.S.  Please feel free to let me know if there is a better way to code what I'm trying to do.

It's hard to figure out exactly what your trying to do, but I can see a few potential problems.

No need for the 'num' variable, instead use loop.index (or loop.index0 for a zero indexed array); although I don't think you need it at all in this case.
nth() is currently returning the 'nth' offset of all assets that are related to all children collectively (thus the strange results). I would guess that you want the asset(s) related to the child category in the current loop. I would also guess that the asset(s) are defined in an assets field in the categories field layout, in which case you can get the asset(s) from the field directly, rather than using .relatedto(child).

Try the following — without understanding your structure entirely, it might at least be a bit closer to what you're looking for.

{% if category.hasDescendants() %}

    {% for childCategory in category.getDescendants() %}

                {% set asset = childCategory.myAssetsFieldHandle.first %}
                {% if asset %}

                {% endif %}

{{ childCategory.title }}

{{ childCategory.description }}

    {% endfor %}

{% endif %}

        {% set entries = craft.entries.relatedTo(category) %}
        {% for entry in entries %}

{{ entry.title }}

{{ entry.description }}

            Learn more
        {% endfor %}

Note: this is assuming that you want to show the subcategories and then the entries related to the main category. If not, then I misinterpreted your question and you will want to reconfigure this a bit, but the principles should be the same.


How to display multiple entry loops on the homepage (Single section type) I've been learning Craft 3 for a couple weeks and I've run into a little snag. I have a homepage that I would like to display multiple entry loops and/or types. However, I cannot find how to do this on a Single (section). Ive been experimenting around, and I can get the desired effect by making the homepage a Structure (section) via multiple entry types, but that gets janky with the URL/URi setup (I've seen other articles saying to use the __home__ method, but seems like it gets messy to try and work around that with sub-pages).

Here is kinda what I'm going after for the homepage:

Hero Element (has a few of it's own fields)

Intro Element (has a few of it's own fields)

Image Slider Element (loops through some image asset entries)

MAIN ENTRY LOOP (loops through some entries that you click to go to the full entry (which has its own template))

So in summary,
How can I have multiple entry loops/types on a Single, OR Use a Structure section as the homepage without getting to janky with the URL/URi? OR is there a better way to set this up that I'm not thinking of?

You can do this in a Single without too much trouble. Your homepage will presumably have its own template, so the simplest solution is to content-manage the fields for your Hero, Intro and Image Slider in the homepage Single, and then in the homepage template, hardcode the channels which will form the source of your main entry loop. That way, your homepage Single is responsible for managing content that is specific to that page only, and then outputs other content from elsewhere below.

Here's a quick example of how that might look in your homepage template Twig file:

{% set myHeroField = entry.myHeroField %}
{% set myIntroField = entry.myHeroField %}
{% set sliderImages = entry.sliderImagesField %}

{{ myHeroField.heading

{{ myHeroField.strapline

Read more

{{ myIntroField.textContent }}

See more

{% for sliderImage in sliderImages.all() %}

{% endfor %}

{% set myContentEntries = craft.entries.section('myContentSection').all() %}

{% for contentEntry in myContentEntries %}

{% endfor %}

If you want to get more advanced and flexible, you could use a dropdown or similar in your homepage fields to define which Sections you want to be included in the main entry loop. Sadly, there isn't a first-party Section fieldtype, though there is a third-party plugin (now deprecated, unfortunately). Alternatively, depending on how complex and changeable your content model is, you could use a Dropdown fieldtype and just hardcode your section handles into the values.

In your homepage template, you'd then do something like this to fetch entries to show in the main entry content:

{% set myContentEntries = craft.entries.section(entry.sectionsToShow).all() %}


Getting error when using bootstrap: Craft\WebApp::$request I am using a testing library and while trying to load Craft through bootstrap with:

$craft = require '<full path here to>/app/bootstrap.php';

(but with the real path)

I dumped the error to a html file from the console and get this:

I see that Ben Parizek got a similar error (but i don't believe it was while using bootstrap only from the command line) in this question.

I tried setting cache to file in general.php and also cleared all caches in craft.

Got testing working by requiring the tests/bootstrap.php  (not app/bootstrap) like here: https://github.com/selvinortiz/craft.loath/blob/master/tests/run.sh#L6


Order by Numeric Custom Field Value I'm trying to order my entries by a numeric custom field named score, some of these values can be 0 but unfortunately, it's not getting ordered at all?

{% set users = craft.users.group('influencer').order('score').limit(24) %}

{% if users|length %}
    {% paginate users as pageInfo, pageEntries %}
    {% for user in pageEntries %}

/* New Code */

  {% set users = craft.users.group('influencer').orderBy('score desc').limit(24) %}

          {% if users|length %}

          {% paginate users as pageInfo, pageEntries %}
          {% for user in pageEntries %}

Assuming this is in Craft 3, you should be using .orderBy() instead of .order(). Does the following work as expected?

{% set users = craft.users.group('influencer').orderBy('score desc').limit(24) %}

{% paginate users as pageInfo, pageUsers %}

{% for user in pageUsers %}
    {{ user.username }} : {{ user.score }} <br>
{% endfor %}

Here it is in the docs: https://docs.craftcms.com/v3/dev/element-queries/user-queries.html#orderby

Also turn on devMode to be sure that no errors are being suppressed.


HTTP 503 – Service Unavailable – craft\web\ServiceUnavailableHttpException [installation] I tried installing Craft 3.0 using composer (php composer.phar create-project craftcms/craft PATH)

And when I try to access the /web folder it's giving me the following error. I have tried removing the folder and installing it afresh again. I am currently using MAMP on my osx localhost.

  in /Applications/MAMP/htdocs/craft/vendor/craftcms/cms/src/web/Application.php at line 498
  in /Applications/MAMP/htdocs/craft/vendor/craftcms/cms/src/web/Application.php at line 175 – craft\web\Application::_processInstallRequest(craft\web\Request)
  in /Applications/MAMP/htdocs/craft/vendor/yiisoft/yii2/base/Application.php at line 386 – craft\web\Application::handleRequest(craft\web\Request)
  in /Applications/MAMP/htdocs/craft/web/index.php at line 21 – yii\base\Application::run()

Very likely it cannot connect to the database; that's typically what the 503 error is about:

https://httpstatuses.com/503

...so check the credentials in your .env file, and make sure that the version of MySQL that your website is using is the internal MAMP MySQL, and not the system-wide MySQL (if any).

This video may help you: Installing Craft CMS v3 with MAMP Pro

...and also a discussion of local development environments we had here might be of interest as well: Shootout at the Local Dev Corral


getParam not working anymore I encountered a problem which is very similar to this post. I've been using the letter "p" as part of a search string so www.website.com/test?p=querystring. It worked for more 6 months and now all of a sudden it doesn't work. Thanks to the other post I looked in my .htaccess file and see this rewrite rule: RewriteRule (.+) index.php?p=$1 [QSA,L] which was there by default when I installed Craft. I changed my query string parameter to "q" and now it works again. Not sure if something changed when I updated to the latest Craft version which at the time was version 2.6.2945, or if it's something else.

The query value for p has been the pageTrigger since Craft 1.0 (and probably in the beta as well).

I'm not sure why you were still able to use it for other purposes up until recently. To be honest, it sounds like you were accidentally exploiting a bug, which has since been fixed.


Add an add entry button to my Plugin in Craft CP Hey I'm writing my first Craft plugin and would like to add a button to have a dialog box in . I want to create a link to a page entry with this and save it to the database.

This is the code I want to extend in my template:

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

    <div class="" style="width: 50%">
        <form method="post" action="" accept-charset="UTF-8">
            <input type="hidden" name="action" value="glossary/entry/saveEntry">
            <input type="hidden" name="redirect" value="glossary">
            {{ forms.textField({
               label: 'Glossary Entry'|t,
               instructions: 'Enter a new Word'|t,
               id: 'entry',
               name: 'entry',
               value: ''}) }}
            <input class="btn submit" type="submit" value="{{ 'Submit'|t }}">
        </form>
    </div>

I believe what you need is the elementSelect field type which Craft bundles with the CMS. You can find the template of this field in craft/app/templates/_includes/elementSelect.html

Here's a quick example that will get you started:

{{ forms.elementSelectField({
    label: 'Select An Entry'|t,
    instructions: 'Select...'|t,
    id: 'entry',
    name: 'entry',
    elementType: craft.elements.getElementType("Entry"),
    source: '',
    criteria: '',
    sourceElementId: '',
    elements: '',
    storageKey: '',
    viewMode: 'list',
    limit: 1
 }) }}


Fetching entries from an advanced search form on the front end I'm trying to fetch entries from a channel via a front-end form featuring multiple filters - several dropdown selects and one checkbox field - kind of like an advanced search feature.

The form works OK when using the select dropdown fields but for some reason I can't get the checkbox input in the form to work. I have followed the example in the docs here.

This is what the checkbox part of the form looks like:

{# Checkboxes Based on a Checkbox Field #}
<label class="heading" for="features">Features</label>

{% for option in craft.fields.getFieldById(15).settings.options %}
    {% set checked = false %}

    {% if option.selected %}
        {% set checked = true %}
    {% endif %}

    {% if not checked %}
        <input type="hidden" name="fields[features][]" value="">
    {% endif %}

    <label>
        <input type="checkbox" name="fields[features][]" value="{{ option.value }}" {% if checked %} checked="checked"{% endif %}>{{ option.label }}
    </label>
{% endfor %}

This throws an error in the template:

  Key "selected" for array with keys "label, value, default" does not exist

On the line above:

{% if option.selected %}

Further, on my search results template, I'm using getParam to pull the values from the query string like so:

{% set location = craft.request.getParam('location') %}
{% set realEstateType = craft.request.getParam('type') %}
{% set bedrooms = craft.request.getParam('bedrooms') %}
{% set priceRange = craft.request.getParam('price-range') %}

and then

{% set results = craft.entries.search().location(location).realEstateType(realEstateType).bedrooms(bedrooms).priceRange(priceRange) %}

This works OK without the offending Checkbox field. I suspect because there are possibly multiple values submitted for a checkbox field that it may not work - should I use search instead of getParam?

Sorry for the long-winded question, any help would be appreciated.

I came across a similar issue today where I was creating a search form that included checkboxes. I did it as follows.

First, I checked if the URL had the query string I was looking for and joined the query string since it's an array. I used OR because I want it to search for any of the checked options.

{% if craft.request.getParam('services') %}
    {% set services = craft.request.getParam('services') %}
    {% set services = services|join(' OR ') %}
{% endif %}

The query string in getParam('services') is the same as the name field of the checkbox.

Then I listed out my options

{% for option in craft.fields.getFieldByHandle('memberServices').settings.options %}

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

{% endfor %}

The conditional that gives the checkbox the checked attribute is

{% if services is defined and option.value in services %}checked{% endif %}

That is, if services is defined (is in the URL) and the option value is contained within the services variable, apply the checked attribute.

It also works with multiple checkboxes, IE the URL search?q=&services%5B%5D=counselling&services%5B%5D=supervision&sessions=individual will check the "Counselling" and "Supervision" "services" checkboxes, and the "Individual" "sessions" checkbox.


Does normal authentication occur before userSession.onBeforeLogin event? I'm trying to take advantage of the userSession.onBeforeLogin event to interrupt the normal Control Panel login (/admin/login) so that I can first authenticate the user against an LDAP server. However, in my testing it seems that Craft runs its own authentication prior to onBeforeLogin event.

class AdminAuthPlugin extends BasePlugin
{
    public function init()
    {
        parent::init();

        craft()->on('userSession.BeforeLogin', function (Event $event) {
            if (craft()->request->isCpRequest() == true) {
                $event->performAction = false;
                exit();
            }
        });
    }
}

Using the above example, attempting to log in with a known username (with correct password) who has access to the CP, UserSessionService throws an error--which I expect to see due to the exit(): "An unknown error occurred." However, if I try to log in with the same username and an invalid password, UserSessionService throws the standard error, "Invalid username or password", which indicates that onBeforeLogin has not been executed.

Am I correct to understand that the userSession.onBeforeLogin event indeed fires after the default authentication attempt?

The onBeforeLogin event is fired after the username/password is already authenticated, but before the actual authenticated session is started, which is why you're seeing the behavior you're seeing.

For the same reason that you wouldn't expect the onBeforeSaveEntry event to be fired before entry validation has occurred.

I believe to pull off what you're looking for, we'd need to add a new event... something like onBeforeAuthenticateUser.

Probably worth adding as a feature request.


Sprout Email not triggering from Sprout Form I'm getting the following error:

An exception has been thrown during the rendering of a template ("Craft\SproutForms_EntryModel and its behaviors do not have a method or closure named "CONTACTFULLNAME".") in "CONTACT FORM ENQUIRY FROM: {{object.CONTACTFULLNAME|raw}}

The form has the following fields:

contactFullName
email
message

The email notification fields for the first email Contact Form - Thank You message contain:

Subject: Contact Form - Thank You {contactFullName}

Message: Thank you for contacting us, {contactFullName}. We will be in touch soon.

And for the other email:

Subject: Contact form enquiry from: {contactFullName}

Message: You have received an enquiry Enquiry from {contactFullName} - {email} “{message}”

Can anyone shed any light onto why this capitalised reference to the CONTACTFULLNAME missing method or closure (by this I presume field) appears in the logs? The form is getting saved, but no email sent due to this message.

Variables in Craft are case sensitive.  You'll run into the same error if you try to output the Craft {{ siteName }} global as {{ SITENAME }}.

Updating the casing to {contactFullName} or {{ object.contactFullName }} should get things working for you.

An extra note regarding the comments above. Luke is onto the right answer in the comments, however, one more distinction needs to be made. There are multiple variables available to your Sprout Email templates. To quote the docs linked in Luke's comment:

  In your notification templates you can use any Twig code that you
  would use elsewhere in your templates. Additionally, Sprout Email
  Notifications give you access to the Notification Email Object (entry)
  and any Dynamic Object provided by the event (object)

Your variable contactFullName is not a field on your Notification Email Entry, it's a field on your Sprout Forms Submission Entry.  It's correct that you would get an error trying to refer to it as {entry.contactFullName} because 1) the Notification Email doesn't have that field and, 2) the shorthand syntax is going to add the object variable behind the scenes, so the variable would be seen as {{ object.entry.contactFullName }}.


Cache controller/action Does Craft have a built-in Controller/action for clearing the cache?
We have auto-deployment set to a server and would be useful to set up a POST-receive hook to force the cache to clear when deployments are made.

You'd need to write a super-simple plugin that exposes a controller's action URL your deploy hook could hit.  That action would basically just mimic what the ClearCachesTool does for clearing the various caches in Craft.

E.g. Template caches, Asset Transform Index caches, Asset Index caches, general data caches, etc.


Does Craft have a timeout setting for template requests? I created a RSS feed template and setup a route to it.  If I output more than 40 entries I get a timeout on both FeedBurner and FeedValidator.  Is there a setting in Craft that updates a timeout time or could it be something else going on?

Nothing directly in Craft, but you're probably looking for PHP's max_execution_time, which governs how long a PHP script is allowed to execute.  It defaults to 30 seconds.

You can edit that value from you php.ini file.


What are useful guidelines for Craft CMS security on VPS (virtual private servers)? We have the choice of engaging services like Forge and ServerPilot, or rolling our  own.

Besides pricing, the opacity of what the services are actually providing can be a question -- just how well do they protect?

Would it be equal or better to provide our own securing when using VPS?

To decide, it would be good to understand an apparent baseline for server security.

This morning a couple of postings on Craft Slack #devops area linked good descriptions of basic server security, led by @merlingore there.

Their instructions are tilted towards Ubuntu as far as specifics, but should fit for any Linux VPS.

Recording the links here so we don't lose the patterns. I agree with them because they're actually the same as what I came up with personally in arranging VPS security, and they say what's needed clearly and concisely.

https://plusbryan.com/my-first-5-minutes-on-a-server-or-essential-security-for-linux-servers

and to complete on automatic security updates,

https://blog.mafr.de/2015/02/26/ubuntu-unattended-upgrades/

IT's quite worth reading the comments also on each of these, particularly the second. I like the so-often Germanic completeness there, if would suggest that auto-reboot is not just for personal servers.

You can control time-of-day via the auto-cron setting, and if you need 100% uptime, this is very likely better managed (and likely only actually possible for many scenarios) by providing more than one load-balanced server, updating them in a sequence, which again the cron portion could be one way of handling.


Setting body ID from includes does not work This is my _layouts/main.twig:

<body {% if bodyId is defined %}id="{{ bodyId }}"{% endif %}>

  {% include '_layouts/header.twig' %}

  {% block main %}

  {% endblock %}

</body>

Then i have blog/_entry.twig with:

{% extends '_layouts/main' %}

{% block main %}

{% switch entry.entryType.entryIs.value %}
    {% case 'listing' %}
        {% include 'blog/_listing.twig' %}
    {% case 'listingSimple' %}
        {% include 'blog/_listing-simple.twig' %}
    {% case 'article' %}
        {% include 'blog/_single-entry.twig' %}
{% endswitch %}

{% endblock %}

If I do:

{% set bodyId = 'article' %}

in my blog/_single-entry.twig that does not work.

But it works if i set bodyId in my index.twig in the root that is not a include.

So Twig has a particular processing order for things like variables, includes, extends and all that sort of stuff. Basically, you can't set a variable in an included template and then use that in an extended template.

Here's a great article that goes into this topic in a little more depth: https://nystudio107.com/blog/twig-processing-order-and-scope - I'd highly recommend you give it a read.


Entries retain field data that has been removed from entry type layout I have a single page section titled "About".  At one point, I had assigned a "text" Rich Text field to the entry type layout.  I then put some filler text in this field and saved the entry.  Later I removed this field from the field layout.

The issue is that craft still populates this entry field on the front-end, i.e. {{ entry.text }} still shows the filler text.

This is problematic for several reasons, but most importantly (in my scenario) because I am working on a search results template which shows an excerpt from each entry; different entries may have different fields available, so I am doing a basic if/else to see what fields may be available, i.e.:

{% if entry.text is defined %}
    {{ entry.text }}
{% elseif entry.multiContent.text is defined %}
    {{ entry.multiContent.text }}
{% endif %}

This raises two questions:

1) Is there a way to tell if an field is actually actively assigned to the entry layout?

2) I understand why the field data would be retained in the database even though the field was removed from the layout, but under what circumstances would populating 'deleted' fields for entries be desired behavior?  It surely adds overhead, it is counter-intuitive (imo) and has the potential to cause all sort of issues.

Technically, all entries have all fields, regardless of their layout. Field layouts are mostly just a UI thing.

  1) Is there a way to tell if an field is actually actively assigned to the entry layout?

It’s a little cumbersome and would require the MN Break and Continue plugin, but yes:

{% for flf in entry.getFieldLayout().getFields() %}
    {% set field = flf.getField() %}

    {% if field.handle == 'text' %}
        {{ entry.text }}
        {% break %}
    {% elseif field.handle == 'multiContent' %}
        {{ entry.multiContent.text }}
        {% break %}
    {% endif %}
{% endfor %}

  2) I understand why the field data would be retained in the database even though the field was removed from the layout, but under what circumstances would populating 'deleted' fields for entries be desired behavior? It surely adds overhead, it is counter-intuitive (imo) and has the potential to cause all sort of issues.

Actually it’s faster for Craft to not worry about the field layout, which is why it’s not taken into account right now. Less data to fetch, and logic to run. If you check for entry.text, Craft just assumes you know what you’re doing.

Maybe a better approach would be to just check the entry type’s ID/name:

{% if entry.typeId in [1,2,3] %}
    {{ entry.text }}
{% elseif entry.typeId in [4,5,6] %}
    {{ entry.multiContent.text }}
{% endif %}

(or)

{% if entry.type.handle in ['one', 'two', 'three'] %}
    {{ entry.text }}
{% elseif entry.type.handle in ['four', 'five', 'six'] %}
    {{ entry.multiContent.text }}
{% endif %}


Rename the Globals Tab I'm only using Globals for the editable site footer content. Explaining to the user they need to look in "Globals" is a minor thing, but one extra step toward making a system less user friendly. If I can rename the tab to Footer it'll be a lot easier for the user to find by themselves.

I don't want to mess with the Craft build itself as I like to keep it up to date. Any ideas, is this something I can do with a plugin?

Yup! The Control Panel Nav plugin is exactly what you're looking for.

It allows you to easily rename, rearrange, or hide any of your tabs. It also lets you create additional custom tabs, using any URL you want.


Multi-Environment Config using port in database server I'm in the process of creating a multi-environment config and my client has set up a staging server with non-standard ports for the mysql server. I am unsure how to add the port number in the config file. I've tried the following with no success.

'STAGING' => array(
        'server' => '123.456.789.123:3939',
        'user' => 'myusername',
        'password' => '***********',
        'database' => 'mydatabase',
    ),

I've been able to successfully connect the database when on a completely different server/mysql combo so I know that the config files work.

Try using a port variable:

'STAGING' => array(
    'server' => 'localhost',
    'port' => '3939',
    'user' => 'myusername',
    'password' => '***********',
    'database' => 'mydatabase',
),


Would it be possible to create a plugin to warn a user if a page is being edited In a previous CMS we used (Processwire), one of the authors created a very useful plugin that would warn a user on an edit page that the page was currently being edited by another user.

I'm thinking this would be a useful addition, unless Craft's use of automatic versioning would somewhat rule out the risk of overwriting someone else's work?

Has anyone had any similar thoughts on the issue?

Thanks.

Inspired in part by Mats' detailed answer, I've written a plugin that does just this: MN Snitch

Enjoy!


How to get Current Entry ID in Plugin Variable? I need to get the current entry ID in plugin's variable file without submitting any form. I tried this but it gave an error Undefined property: Craft\PluginNameVariable::$element

namespace Craft;

class PluginNameVariable
{
/**
 */
public function totalitemsForElements($elements = array())
{
    $criteria = craft()->elements->getCriteria('MyElementType');

    $criteria->elementId = $this->element->id;

    $items = $criteria->find();

    return $criteria->find();
}
}

I was accessing this variable through

{% set itemElementType =  craft.pluginName.totalitemsForElements %}
{{ itemElementType|length }}

Please Help. Thanks in advance !!

It seems like what you want is to get elements related to an entry that is pre-loaded in a template, and that elementId is a custom field for MyElementType. If that's the case, this should work out:

public function totalitemsForElements($elementID)
{
    $criteria = craft()->elements->getCriteria('MyElementType');

    $criteria->elementId = $elementID;

    return $criteria->find();
}

We'll pass the entry id to the variable function. Here's the template code:

{% set itemElementType =  craft.pluginName.totalitemsForElements(entry.id) %}
{{ itemElementType|length }}


how to specify entry type on front end entry form? I have a section with 2 entry types. Logged in users need to be able to submit to each type. I had planned on having 2 different entry forms.

How do I tell the form which entry type to save to? I assume it's a hidden field but what's the field name and where do I find the value?

You just need to specify a hidden input with the typeId set correctly.

i.e.

<input type="hidden" name="typeId" value="{{ entry.typeId }}">


How to disable plugin when unable to log in? I'm getting a blank page for both the front end and the CP/admin, and am tyring to figure out why. I changed my hard drive at about the same time as making a bunch of changes to a plugin, so just trying to figure out what I've screwed up.

I already did this: deleted vendor/craftcms followed by

composer clearcache
composer install

Is there a way to disable plugins from outside the CP?

You can disable plugins by adding their handles to an array disabledPlugins in your config/general.php file:

<?php
    '*' => [
        'isSystemLive' => true,
        'disabledPlugins' => [
            'redactor',
            'some-plugin',
            ...
        ],
        ...
    ],


Simple linkage to singles For some reason there is not really a clear mention on the Craft documentation about this. And I couldn't really find anything in here that explains it either. I know this is kind of basic knowledge for Craft, so here goes:

I made a single section called 'work' and a folder of the same name in my templates folder (with an index.html inside). I try to link to it with http://www.mydomain.com/work/ but it doesn't work! It gives a 404 error. I don't understand why it doesn't work. I don't remember having trouble with this before.

What can possibly go wrong?

How do I create simple links like this to other singles?

You made the template filename and folder match the URI (routing case 6), which is not necessary for entries. Because you probably also set a template in the section setting, this is getting loaded for http://example.com/work/ (routing case 4).

So I think you should just edit the single section's settings and point to the right template.


Fetch Entries with Tags Only I'm trying to get all the entries which have tags associated with them.

At the moment I'm doing:

$entries = Entry::find()->with('tags')->all();

and then filtering the results in PHP as follows:

$filteredEntries = array_filter($entries, function($entry) {
    return count($entry['tags']) > 0;
});

This works fine, but I am still fetching all the entries, even without tags from the DB - I think this can be more efficient if I can specify in my query that I only want the entries with tags associated to them. How can I do this?

What you are looking for is the relatedTo parameter (docs) and this post will also help.

If you wanted to return any entries which has (any) tags attached, you could do:

$entries = Entry::find()->tags(':notempty:')->all();

Where tags is the handle of your tags field.


Craft CMS 3 - Manual database backup Since my hosting provider is blocking mysqldump on its server, I'm trying to do a manual backup of my database in order to import the DB into my test environment.

I'm stuck on the elements to ignore since a manual export on PHPMyAdmin (prod env) and then import to PHPMyAdmin (dev env) environment triggers errors.

Do you guys have any experience in manual backups?

Thanks! :)

When you do your export in phpmyadmin, make sure you check the 'disable foreign key checks' box in the custom options: