Extra margin in Default System on subpages like news On the default install, taking out all css. There is an extra margin space at the top of Chrome, and IE Edge but firefox is fine. I also checked out the error 404 page, and it too is fine like the standard layout page at home.

However, if I click news or create a new extends sub folder, they will have an extra 26 pixels at the top.

I noticed this trying to have a top bar flushed to the very top. I rolled back everything to stock and used the default template, took out all CSS from it, and still notice this issue.

here is an image comparison of the two pages, no css using Chrome.

Thanks,

Logan.

Unlike some other CMS systems, Craft doesn't specify what your front-end templates should look like in any way (you could output your content as .txt files if you wanted to). It also doesn't add anything to your rendered page output that you didn't specify (with the exception of error info if 'devMode' is set to true). The default templates are really just there as placeholders so that you can confirm the system is working properly.

I can't say specifically what is causing your rendering/margin issue, but I would just ignore it and start with your own clean templates. All of the browsers that you mention also have some form of web inspector/development tools. If you really want to know you can 'inspect element' with the browser tools and see what css if any is causing the problem.


Entry Post Date Format time since - X days ago Is there anyway to get my date formats looking like Facebook? I'd like to get my articles to have this as a date format: "5 min ago", "yesterday", "3 days ago", "4 months ago" and then once it reaches a full year ago, make it have a date format like "Dec 5, 2016".

If anyone has gotten this working, would you mind sharing with me(and the world) your code on how to achieve this in Twig?

Thanks in advance!

It looks as though Craft 3’s built-in duration Twig filter might help:

Posted {{ entry.myDateField.diff(now) | duration }} ago.

With a bit of additional logic, you can make this more useful, after an Entry leaves a specified window:

{% set dateOneYearAgo = now.modify('- 1 year') %}
{% set dateOneMonthAgo = now.modify('- 1 month') %}
{% set dateOneDayAgo = now.modify('- 1 day') %}

{% set elapsedMonths = entry.myDateField.diff(now).m %}
{% set elapsedDays = entry.myDateField.diff(now).d %}

{% if entry.myDateField < dateOneYearAgo %}
    {# Posted longer ago than one year... #}
    Posted on {{ entry.myDateField | date('M j, Y') %}
{% elseif entry.myDateField < dateOneMonthAgo %}
    {# Posted longer ago than one month (but more recently than one year, as we caught that, above)... #}
    Posted {{ elapsedMonths }} month{{ elapsedMonths != 1 ? 's' : '' }} ago
{% elseif entry.myDateField < dateOneDayAgo %}
    {# Posted longer ago than one day (but, as above, more recently than a month ago)... #}
    Posted {{ elapsedDays }} day{{ elapsedDays != 1 ? 's' : '' }} ago
{% else %}
    Posted {{ entry.myDateField.diff(now) | duration }} ago.
{% endif %}

The if statements compare the date objects, and returns true if entry.myDateField is earlier than the date one year ago (- 1 year), one month ago (-1 month), etc.

now.modify(…) is a convenient and human-readable way of getting a date relative to the current time—you can pass this method any relative date string.

The ternary statements (like {{ elapsedDays != 1 ? 's' : '' }}) are just a crummy way of properly pluralizing the units of time—I'd recommend using the Typogrify plugin, instead, as it offers some more declarative ways to handling this— say, {{ 'month' | pluralize(elapsedDays) }}.

  Note: I've omitted special circumstances for things like “yesterday,” as these constraints can be layered in as new else if statements—just be sure to put the tightest constraints at the top, so that it matches your priorities (i.e. a test for “last week” should come after a test for “yesterday”). Anything you don't care about can fall through to the default duration filter.


Require shipping method in Commerce order flow I have a page, almost exactly the default Commerce shipping.html template and flow. With just the default shipping method (Free), the user can simply click through without being required to select a shipping method. I've found how to use a Business Logic plugin to address required fields for the address/billing section, but there doesn't seem to be an event I can hook to so I can yell and provide a flash error message if the user clicks "Select Shipping Method" without actually selecting one.

I know I can redirect back to the shipping method page on the payment page by checking the cart (ex: {% if not cart.shippingMethod %}...) but this doesn't provide a flash error unless I use some hacky method like a GET string error message.

Is there an event I can hook to I'm not finding in the docs that will let me force the choice of a shipping method? Or a setting in the plugin I'm missing?

Edit

So I'm close, here's my event code that isn't working as I expect it to (did I tell you I'm new to Craft yet?):

    craft()->on( 'commerce_orders.onSaveOrder', function ( Event $event ) {

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

        if(craft()->request->getPost('validateShipping')){

            // add error to shippingMethod and see if we can get it
            $order->addError('shippingMethod',Craft::t('Please select a shipping option.'));
            $event->performAction = false;

            // pass a flash for testing
            craft()->userSession->setFlash('error', 'No shipping elected');
        }
    });

So this moves on to the payment page and doesn't return to the shipping page with the added error. However, I am able to retrieve the set flash message on the payment page but {{ dump(cart.getErrors()) }} results in an empty array, so either the error is not attached to the cart properly in my event, or it is lost for some reason.

Edit

I see I'm getting some up views; If anyone can still help I'd appreciate it. I have yet to get this working as per the only answer, and would love to know what I'm doing wrong in my Craft Commerce event.

Ok, so shipping is not a necessity for a Commerce site (e.g. think about  e.g. digital downloads - shipping is not relevant here) - so Commerce does not force you to set a shipping method on an order.

It's up to you to work out how and where you need to do this, if you do.

A lot (most,even) of it is often best tackled at the front end via your flow and some JS and/or general form validation stuff - you don't allow the user to proceed/submit if they have not chosen a method when you need them to.  We actually do it all, pretty much, in this end of things.

In addition, you CAN use any Commerce event you choose:
https://craftcommerce.com/docs/events-reference

...to add some extra validation (as you have with the address fields).  But it really depends on your precise checkout flow as to how you'd implement this.

For example, if your shipping page is POSTing to the Commerce controller updateCart when it submits, you could perhaps listen to:
https://craftcommerce.com/docs/events-reference#commerce_orders.onsaveorder

...and in that validate a shipping method is set (of course your order is saved many times during a commerce process so you should e.g. POST some other variable to check in there if you should actually trigger this validation).

<input type="hidden" name="validateShipping" value="true">

And then in your event handler

if(craft()->request->getPost('validateShipping')){ ... validation here }

If there is an error, then to add the error you'd add it to the model you retrieved as an event parameter:

$order->addError('shippingMethod','No shipping method supplied!');

..and to set a flash message

craft()->userSession->setFlash('error', 'No shipping selected');

....but there are MANY possible ways you can implement this (e.g. no server side validation at all, if you can handle it all at the front end) -> the key thing is to really understand your checkout flow (and all the many ways users can travel through it) - quite thoroughly BEFORE you start implement the actual validation you need.


Converting images to WebP - Overcoming Timeout Errors? I have over 1500 images... I'm trying to improve performance on our site and want to create WebP versions of our images.

WebP is installed - new images we upload get converted. When I resave the image variant it begins the process of conversion and optimisation of previous images but then we bump into timeout errors.

What is the best way to do this process in an efficient way? I'd be interested to know how we overcome the timeout error.

Note:

images are in a Digital Ocean S3 bucket.
we are using the incredible imageOptimize plugin
we host the site on Laravel Forge

You might want to check out the discussion on this pull request. Since ImageOptimize uses regular Craft transforms, it's likely that this is something in the AWS S3 plugin.

Indeed, there's an issue 400 Bad Request: token expired that appears to be identical. If there's something I can/should be doing to renew the token, I'll definitely make that change.

I'm pending information at the moment.

EDIT: I believe I have found and fixed the issue in the aws-s3 package from P&T; I created a pull request to address it.


How to target first or last item in a nav children loop I'm trying to use this code:

{% nav category in categories %}

   {{ category.title }}

   {% children %}

   {% if not loop.last %} BLAH {% endif %}

{% endnav %}

It appears that the {% if not loop.last %} conditional doesn't work inside of a {% nav %} tag.

How can I target/style the first and last items in each level of a nav structure?

Update Sorry, I originally thought you were building nav and just showing simplified code. If you just want to list the categories then this should work:

{% nav category in categories %}
    {{- category.title -}}
    {% if not loop.last %}, {% endif %}
    {% children %}
{% endnav %}

If your trying to build a nav system, then this should work. In either case just place your 'loop' before the children tag. See this answer for another example.

    {% nav category in categories %}

        {% if loop.first %}

        {% elseif loop.last %}

        {% else %}

        {% endif %}

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

                    {% children %}

            {% endifchildren %}

    {% endnav %}


Matrix getBlockTypesByFieldId() function doesn't work as intended? One of the functions in a plugin that I'm working on, is the ability to create fields. It has created a Matrix field, and directly after that, I want to know the MatrixBlockType.

I don't get any results if I use the following code:

$blockTypes = craft()>matrix>getBlockTypesByFieldId($newField->id, 'handle');

However, if I do the exact same thing as the above function should do, and run this code I do have results:

$results = craft()->db->createCommand()
->select('id, fieldId, fieldLayoutId, name, handle, sortOrder')
->from('matrixblocktypes')
->where('fieldId = :fieldId', array(':fieldId' => $newField>id))
->order('sortOrder')
->queryAll();

If you would debug both variables, you'll notice that the first one doesn't contain any data.

If I would be creating the fields and in later server request I would use the first example, I do receive the data. Somehow it's not available right after creating the field.

Can anyone help me out here by any chance? I want to use the first example, which is the correct way.

Turns out this was a bug in Craft and we've just fixed it for the next (post build 2568) release.


Bug with non-ascii characters, quotes and OR operator in search? There seems to be a bug when I combine non-ascii characters, quotes and the OR operator when searching.

All of these queries work ok:

"pølser"
"pålegg"
pølser OR pålegg
"egg" OR "spekemat"

but

"pølser" OR "pålegg"

always returns no result.

The search form uses roughly this code:

{% set searchTerm = craft.request.getParam('search') %}

{% set entries = craft.entries %}

... entries is optionally limited to a single section here, but it makes no difference here ...

{% set entries = entries.search(searchTerm) %}

Any ideas?

Cheers!

(cross-posted from google+ group as I only just found out about the stack-exchange)

(edit to add code sample)

This looks like a bug to me too. Here are the search terms and generated queries:

'pølser OR pålegg' -
   SELECT * FROM `craft_searchindex` WHERE (MATCH(`keywords`) AGAINST('pølser palegg' IN BOOLEAN MODE)) AND `elementId` IN (3,18,21,22,23,24)

'"pølser" OR "pålegg"' -
   SELECT * FROM `craft_searchindex` WHERE (`keywords` LIKE '% pølser or %') AND MATCH(`keywords`) AGAINST('+palegg' IN BOOLEAN MODE) AND `elementId` IN (3,18,21,22,23,24)

'"egg" OR "spekemat"' -
   SELECT * FROM `craft_searchindex` WHERE ((`keywords` LIKE '% egg %') OR MATCH(`keywords`) AGAINST('spekemat' IN BOOLEAN MODE)) AND `elementId` IN (3,18,21,22,23,24)


Associate child categories only to an entry When adding a Categories field to a section, if you select only child categories, Craft automatically selects the parent categories too. I emailed Craft support about this and they explained it's by design and the workaround is to use a Structure instead of Categories.

I'm unhappy with this as a workaround and was hoping their was another way to do this, either with a custom plugin or something else?

Any help much appreciated

Thanks!

I managed to workaround this by creating my own custom fieldtype which is 99% the code from the Craft CategoriesFieldType, but with the only difference being I removed the call to craft()->categories->fillGapsInCategoryIds($categoryIds).

This works but I've yet to see if it causes any side-effects I need to worry about.


Passing a screen_name to Dukt Twitter I'd like to set the screen_name for a list of tweets using Dukt Twitter.

The screen_name is set in an entry as a plain text field.

{% set entries = craft.entries.section('contactPage') %}
{% for entry in entries %}
{% if entry.twitterHandle|length %}
{% set tweets = craft.twitter.get("statuses/user_timeline.json?screen_name='~ entry.twitterHandle ~'&count=3") %}
    {% if tweets %}

Recent Tweets

    {% for tweet in tweets %}

{{ tweet.text|autoLinkTweet }}

{{ tweet.created_at|date('M j Y') }}

    {% endfor %}

    {% else %}

Recent Tweets

No recent tweets at this time.

    {% endif %}
{% endif %}
{% endfor %}

Not possible? No matter what I try, I only get the feed for the oauth user. Any help would be greatly appreciated!

Thanks!

Accomplished this by setting the get request url, then passing it into tweets:

{% set handle = entry.twitterHandle %}
{% set url = 'statuses/user_timeline.json?screen_name=' ~ handle ~ '&count=3&exclude_replies=true' %}
{% set tweets = craft.twitter.get(url) %}

Hope this helps someone else. Thx!


How to programmatically update a plugin's settings? Is there a way to programatically update a plugin's settings? I'm experimenting with setSettings() but not really getting anywhere - I'm still quite new to plugin development so there's a good chance i'm completely off target hehe.

For some context: I'm trying to update the plugin settings when an event is fired and picked up by a listener as follows:

public function init()
{

    // add event listeners
    craft()->on('assets.onReplaceFile', function(Event $event) {

        //Load Asset
        $asset = $event->params['asset'];

        //Check if asset is the svg sprite
        if($asset->getUrl() == $this->getSettings()->spritePath){
            $url = craft()->getSiteUrl().$this->getSettings()->spritePath;
            $this->setSettings(array('spriteDefs'=>$this->getSpriteDefs($url)));
        }

    });
}

getSpriteDefs returns an array.

Thanks in advance!

It's not 100% clear from your question, but I'm guessing that by "update the settings" you mean actually storing the new settings in the database, which the setSettings() method will not do; it will only update your plugin's settings model. This means that any following calls to e.g. getSettingsHtml() should return the updated data, but it will not persist.

To store the new settings in the database, you'll need to use Craft's PluginService:

craft()->plugins->savePluginSettings( $this, array( 'spriteDefs' => $this->getSpriteDefs( $url ) ) );

The $this variable in the call above refers to an instance of BasePlugin – meaning that the above code will only work if called from your plugins main class. I notice that your code is contained within your plugin's init() method, so you should be fine, however if you ever want to update a plugin's settings from outside the main class (e.g. through a service), you would first need to fetch an instance of the plugin:

$myPlugin = craft()->plugins->getPlugin( 'myPluginHandle' );
craft()->plugins->savePluginSettings( $myPlugin, $settings );


Why is using the cache tag more expensive than outputting static text? The Craft docs have a good overview of the {% cache %} tag.

The docs give a couple examples of when not to use the {% cache %} tag.  In particular, they give this example:

Don’t use them to cache static text; that will be more expensive than simply outputting the text.

Can someone explain to me the logic behind this statement? How do the two scenarios play out where caching static text is slower than just outputting it?

Additionally, what if you are caching a page with several queries that includes static text?  Does it follow that you'll want to cache the queries in and of themselves and let the static text remain uncached?

Since the {% cache %} tag solely stores its information in the database, it has a guaranteed minimum of one database call to make to see if what's inside of it has already been cached.

If you're just doing this:

{% cache %}
    Hi. I'm static text.
{% endcache %}

That's quite a bit more overhead than simply:

Hi. I'm static text.

With no real benefit.


Parent / Child user accounts We've got a client who would like to be able to create "Child" user accounts, the idea being that someone could register and then create multiple child accounts that would inherit the settings of their parent account. It would also mean that any entries created by those child accounts would be visible, and editable, by the parent account.

My current, and only, idea would be to have Parent / Children user relations fields on the users that I would read to work out what I should be displaying to or letting the current user do, but I have a feeling that this might prove cumbersome to manage down the line and messy to code at least the way I code.

Is there a clean way of doing this, or perhaps a plugin that does this already (I've looked but couldn't find anything). I'm also open to writing a plugin that would do this, I just don't really know where to start.

This will all be happening front-end, so no need to touch the control panel in any way.

The only way to do what you're describing out-of-the-box is by adding a user field for Users. Then you can either check that field for child users or get a little creative with relatedTo to get parent users.

If you want to, for example, prevent a child user being linked to several parents or you want the same field to display the parent (if any), you're looking at a custom field type implemented by a plugin.


404 problems, staging only I've got a bizarre issue that is only happening on staging. Locally all urls work correctly.

on staging http://domain.com/archives and http://domain.com/photography/entry_slug both return a 404 page generated by the host see screenshot

However if I actually try to visit a page that truly does not exist the craft 404 page shows, which is what I would expect for a real 404 error. For example http://domain.com/foo

This is only my second craft site and I have no idea how to troubleshoot. All help is appreciated.

Looking at your screenshots, the host names are different.  The cPanel 404 shows mysphotos instead of myphotos.

Probably a typo somewhere in your templates.


Can Craft handle social-esque frontend user interactions? I've got a potential client I'd like to build a Craft site for, but they have some specific features I'm not quite sure how to handle. Could someone tell me if Craft can handle the following features?

Frontend ability for users to create and join "groups". "Groups" is in quotation marks since I don't think they need to be actual Craft User Groups; they don't need differing permissions, just segregation—so Categories, perhaps, or Tags?
Frontend ability for users to invite others to specific "groups"—basically an email-a-friend a link with a signup/login token that will add them to the specified group.
The ability for users to have their own blog on the site, where other users can comment. I'm fairly certain Craft can do separate author-specific blogs natively, as it's essentially just a listing page of a specific author's entries. I also know comments are either Disqus or the Comments plugin by Engram Design. I'm leaving this point in here though because I haven't done this in Craft yet, so I'm blissfully unaware of any gotchas there may be... ;)

Thanks for any help!

What kind of social interactions are you asking for?

You can probably make most of this work in Craft but a lot of what you're asking for isn't really "built in." It's going to take a fair amount of effort on your part via some business logic to assign users to groups (or categories), etc.

  Frontend ability for users to create and join "groups".

How much security do you want? Just as a high level overview, users in Craft have various permissions depending on where (which section) they can "post" entries into.

Basically the system allows users to submit content on a section-by-section basis. It's up to the permissions you have set if other users are allowed to "see" such entries or not.

Without any additional checks, an enterprising user could theoretically mess with some of the front end forms and post to other "groups" if they have permission to do so. It'd be up to your code to make sure the user is part of such "group" (or category) first.

If it were me, depending on what you're trying to achieve, I might programmatically create new sections when a user creates a new "group" and only members of that group when invited are allowed to see / post in it. Craft would help you take care of the heavy lifting too; you would basically assign the permission of viewing/writing of that section to that user.

Plugins can also create their own permissions depending on what you need to do.

  Frontend ability for users to invite others to specific "groups"—basically an email-a-friend a link with a signup/login token that will add them to the specified group.

This wouldn't be native to Craft. You'd have to build the token generation and e-mailing process here, along with doing the business logic of figuring out who was invited by whom, if said token is valid, etc.

  The ability for users to have their own blog on the site, where other users can comment.

Yes, as you mentioned, this is relatively straightforward, as Craft is basically a CMS.

A hybrid approach might be to use a bulletin board/forum style software (xenforo, vbulletin, buddypress, etc.) to handle the discussions / social groups functionality then let Craft handle the blogging part. There is various authentication bridges you could use to handle user login between the two systems.

I'm sure there's a few other ways to pull this off as well.


Duplicating Matrix fields with content from another locale I'm working on an Element Action that will duplicate some fields from the primary locale, to whatever locale the user is currently in, if those fields are already empty.

Asset fields seem to work fine, but I can't find a way to duplicate Matrix fields with all their content, including their own relation fields.

So far I've got:

foreach ($criteria->find() as $element)
{
    $locale  = $criteria->locale;
    $content = $element->getContent();
    $gbr     = craft()->entries->getEntryById($element->id, 'en_gb');

    foreach ($element->getFieldLayout()->getFields() as $fieldLayoutField)
    {
        $field       = $fieldLayoutField->getField();
        $fieldHandle = $field->handle;

        if (in_array((string) $field->type, array('Assets', 'Entries', 'Categories', 'Tags')))
        {
            // only copy the relation's IDs if there's nothing there already
            if ($element->$fieldHandle->total() == 0)
            {
                $content->$fieldHandle = $gbr->$fieldHandle->ids();
            }
        }
        elseif ((string) $field->type == 'Matrix')
        {
            if ($element->$fieldHandle->total() == 0)
            {
                foreach($gbr->$fieldHandle->find() as $gbrBlock)
                {
                    // not sure what to do here to duplicate $gbrBlock,
                    // and save it to $locale with the same contents.
                }
            }
        }
    }
}

$element->setContent($content);

I've tried using craft()->matrix->getBlockById($gbrBlock->id, $locale) like you do when duplicating whole entries (they're both elements right?) but that always comes back null, so... I need to create a new MatrixBlockModel in that locale?

For Matrix fields, you would basically need to duplicate all of this logic (or move it to a separate function), to recreate each Matrix block.

$newBlocks = array();

foreach ($gbr->$fieldHandle->find() as $gbrBlock)
{
    $newBlock = new MatrixBlockModel();
    $newBlock->fieldId = $field->id;
    $newBlock->typeId  = $gbrBlock->getType()->id;
    $newBlock->ownerId = $element->id;
    $newBlock->locale  = $newLocale;

    $newBlockContent = $newBlock->getContent();

    foreach ($gbrBlock->getFieldLayout()->getFields() as $gbrBlockFieldLayoutField)
    {
        // same field value duplication logic...
    }

    $newBlocks[] = $newBlock;
}

$content->$fieldHandle = $newBlocks;

Unfortunately there’s just no easy way to duplicate element content at the moment. Field types each store things differently, and the way they expect their values to be formatted when saving an element may be different from how they are formatted when fetching an existing element from the DB. (This is something we’ve made much easier in Craft 3 though.)


Entries by non-contiguous postDate years I'm trying to display and paginate entries by years, that aren't necessarily contiguous.

{% set limitPerPage = 6 %}
{% set eagerFields = [
    'title',
    'press_release_name',
    'press_release_date',
    'press_release_body',
] %}

{% set pressEntries = craft.entries({
    section: 'pressReleases',
    with:    eagerFields,
}).limit(null) %}

{# I plan on building the query dynamically later, I just want test syntax here #}
{% set dateQuery = 'and, >= 2012-01-01, < 2013-01-01' %}

{% paginate pressEntries.postDate(dateQuery).limit(limitPerPage) as pageInfo, pageEntries %}

This works fine, but I'm wondering how to build upon the dateQuery to return more years with something like:
'and, >= 2012-01-01, < 2013-01-01, >= 2014-01-01, < 2015-01-01'

Is this possible?

You may be able to piggyback off of this answer on combining arrays of EntryModels, by providing the template with an array of dateQuery conditions.

For each date condition, you could retrieve the entries as you're doing above, and then combine them with the previous results using the method in that answer. You can then call {% paginate %} using the final combined array, which should contain results matching all of your conditions.

As a side note, this does dump a lot of logic into the template for twig to handle - it may be worth building a small Plugin with a Template Variable that takes in an array of dateQuery instructions, handles this processing for you, and then returns the final combined set to be used in your {% paginate %}.


Grouping by select - keep order of options I have a channel of entries that are being pulled into a single. I then  want to group the entries by a dropdown field called dealStatus.

This is working correctly, however the grouping is not outputting the order correctly. I expect the order of the groups to be in the same order that the dropdown field has them.

InMarket
postBid
closing
closed

Instead the groups are getting output in this order

postBid
inMarket
closing
closed

How do I get the groups ordered the same as the dropdown field option order?

My current code:

{% set allDeals = craft.entries.section('deals').relatedTo(entry) %}
{% set allDealsByStatus = allDeals|group('dealStatus') %}

{% for status, entriesInStatus in allDealsByStatus %}

      {{ status }}

          {% for entry in entriesInStatus %}

{{ entry.title }}

          {% endfor %}

{% endfor %}

This is on Craft 3.0.1

The group filter loops through the passed elements in the order that they are returned by your query and builds the groups array in the order that it encounters the values being grouped. So there’s no predictable way to control what order the array keys are ordered.

If you want to loop through all entries by dealStatus in a fixed order you could replace your for loop with:

{% for status in [‘InMarket’,’postBid’,’closing’,’closed’] %}
    {% if allDealsByStatus[status] is defined %}

        {% set entriesInStatus = allDealsByStatus[status] %}

        {# your list output code here #}

    {% endif %}
{% endfor %}


Need help with plugin for SAML authentication I'm trying to put together a plugin that allows for SAML authentication with Craft. We're working on a site that will be locked down but employees will be able to authenticate to the site using SAML. I came across a SAML toolkit from Onelogin that does the job and was able to get it configured and working outside of craft. With SAML you are not sending a username and password. It authenticates by redirecting the user to the Identity Provider(in this case the client's Proxy Server) and they enter user and password information there, and then the Provider issues a token that gets sent to the Service Provider(Our Craft Site) to allow them in. So far it's working pretty well and I'd like to get it integrated with Craft.

There are a few things I'm getting stuck on being new to Craft and also Yii.

Since we're not dealing with conventional users, is there a hook that I can use to establish a session that Craft understands but base it on the SAML attributes? Is extending userSessionService the way to go with that or should I be looking at creating a custom session?

I'd like to lock every page down on the front end and only show it if the user has authenticated. I've seen a few other plugins using the init function and if(craft()->request->isSiteRequest()). I've tried that and it works pretty well. Is this the way to go or should I be looking at something else?

If I do keep the authorization code in init, should I be offloading the heavy lifting to a Service? I'm already thinking about creating some controller actions for login and logoff along with registering some routes in the CP. That way I could include links on the front end for that.

Again, new to Craft. Any guidance would be appreciated.

Yii provides a CUserIdentity class that is meant for your typical username/password form/cookie-based authentication.  Craft extends that a bit and uses that in it's own UserIdentity class for logging into the control panel, etc.

But ultimately, Yii's CUserIdentity implements the IUserIdentity interface, which they intend for people to use that want to implement their own custom authentication mechanisms.

So you'd probably want to write a SamlUserIdentity class that implements the interface, provides it's own authentication logic (calls the Identity Provider, etc) and handles the interactions between Yii/Craft and SAML.

If you just want to enforce an authenticated session from the template, use:

{% requireLogin %}

If you want to do it from a controller's action, use:

$this->requireLogin();


Newly added child entries not showing on listing/parent page straight away I am running into an odd issue where creating new child entries does not bust the cache of the parent page(s) that lists them.

This is the structure I am working with:

I am displaying the Course entries on the Course Landing Pages like so:

{% cache using key craft.request.path %}

  {% set currentPage = craft.entries.id(entry.id).first() %}

  {% set entries = craft.entries({
    type: 'course',
    descendantOf: currentPage,
    with: [
      ['courseThumbnail', {
        withTransforms: [
          { mode: 'crop', width: 800, height: 800, position: 'center-center', format: 'jpg' }
        ]
      }]
    ]
  }) %}

  {% for entry in entries %}
      {% include '_includes/_listing-item-course' with { featured : true } %}
  {% endfor %}

{% endcache %}

When I publish a new Course entry, the cache for the parent page(s) is not busted and the new entry will not show unless I move/drag into a new position. This seems to clear the cache and the new entry shows on the parent page(s).

If I change the craft.entries call to not include the descendantOf part, so it looks like this:

 {% set entries = craft.entries({
    type: 'course',
    with: [
      ['courseThumbnail', {
        withTransforms: [
          { mode: 'crop', width: 800, height: 800, position: 'center-center', format: 'jpg' }
        ]
      }]
    ]
  }) %}

Then newly added Course entries will show up straight away on all the Course Landing Pages.

Why is that?

This is a known issue – automatic cache busting currently doesn’t work when the descendantOf param is set to an actual element.

Unfortunately there’s no easy fix on Craft’s end, without a pretty drastic change to how cache busting works.

As a workaround, you can change your descendantOf param value to currentPage.id rather than just currentPage.


redirectToPostedUrl with object (Model) passed to it and keep template resolving I am creating a plugin where the user is submitting data to a controller.

With a successful saving of the data in the controller/service I want to honour the standardised redirect param:

<input type="hidden" name="redirect" value="success/{stripeId}"/>

The stripeId is a property of the PaymentModel $payment being passed to the redirectToPostedUrl param:

$this->redirectToPostedUrl($payment);

This works in that when the person is redirected the person is brought to page desired with url like this:

http://web.dev/success/ch_5GW2RFTNvW8qeR

The problem is that craft cannot find the success template and the success page does not show since it is trying to find a template a success/ directory called ch_5GW2RFTNvW8qeR.html

2 Solutions I have found:

Option 1) My plugin users need to set up a route manually in the control panel to allow this to resolve correctly (and have full control over where the success page is and what the url looks like):

Option 2) The other option is that I use the Plugin hook registerSiteRoutes to register a front end route to that template. The obvious problem with that is I either need to make that hard coded, or user configurable (pain).

Since I would obviously need to make it user configurable, it kinda defeats the purpose of the user of the plugin being able to decide the name="redirect" value="success/{stripeId}" in the first place. I would imagine I would have to come up with my own redirection/routing config and logic. I understand this is not a problem in the control panel actions since I know what I want my urls to be, but as a plugin developer I want to give flexibility to users of my plugin to choose their front-end urls.

Any thoughts? I am leaning towards having to put into the documentation of my plugin that they need to do option 1 above, but still think its not optimal.

Edit:
Just had another idea. Option 3) Since I will be giving my users demo templates for the front end forms on installation - should I possibly create a route in the craft_routes table for  the user? That way on first install everything should work without needing to manually set up a bunch of routes manually to match my demo templates.

Maybe not the prettiest URL, but I think the simplest solution would be to redirect to something like:

http://web.dev/success?id=ch_5GW2RFTNvW8qeR


Internal Server Error when adding new Fields I was adding new fields to my Craft 3 install using the field manager plugin. Suddenly I am seeing a Internal Server Error when trying to access the admin area.

The front end looks fine. Anyone know how I can quickly resolve?

In web.log I get

Setting unknown property: craft\behaviors\ContentBehavior::announcementLink in /home/forge/www.uk-cpi.com/vendor/yiisoft/yii2/base/BaseObject.php:163

In phperrors.log I get

An Error occurred while handling another error:
yii\base\UnknownPropertyException: Setting unknown property: craft\behaviors\ContentBehavior::announcementLink in /home/forge/www.uk-cpi.com/vendor/yiisoft/yii2/base/BaseObject.php:163

announcementLink is the name of the field I was adding

Solution

Login to the server and access mysql and find your database.

Select the fields table to locate the ID of the problem field.

SELECT * FROM fields;
Remove the field using the ID.

DELETE from fields where id = '355';


Good practice to "Clear Caches" before you "Backup Database"? Every time I create a database backup, I find myself instinctively clearing the cache first. My gut tells me that any cached data would be unnecessarily included in the export.

Is this helpful, or am I just being OCD?

Is this helpful, or am I just being OCD?

Completely OCD. :)

The database backup class already excludes unnecessary tables like asset indexing data, sessions, template caches, etc. during a backup.

https://github.com/craftcms/cms/tree/master-v2/src/etc/db/DbBackup.php#L46


Using multiple Templates per section I'm using this support article as a guide and I'm stuck on what I'm doing wrong.

I have an "events" section, and I would like to use a different template for one the entries.  I've created a new entry type in the "events" section and gave it the handle "summerpreview."  I created a template in the "events" subfolder: "_types" entitled: "summerpreview.html."  That template uses the include tag:

{% include "events/_types/" ~ summerpreview.html %}

I've created an entry inside the "events" section using the "summer preview" entry type and gave it the slug of "summerpreview."

What am I missing here?  The entry pulls using the default "events" template and not the "summerpreview."  What do I need to do for this event to use "summerpreview" template?

You need to allow the entry.type value to be part of the include path...

{% include "events/_types/" ~ entry.type %}

Since your entry.type is "summerpreview", that will be parsed out like this...

{% include "events/_types/summerpreview" %}

With Craft, you don't need to specify the .html extension, so this include should work perfectly.

As a side note... I'd recommend turning on devMode locally. It would have thrown an error, telling you that summerpreview is not a legitimate variable.

  What Dev Mode Does


how to search for entries where a custom field is either not present or is empty Some of my entries have the optional plaintext field myCustomField. I want to retrieve all entries except those where myCustomField is filled out.

I can get all entries that have an empty myCustomField

craft.entries({
    myCustomField: ':empty:',
})

but that doesn't include entries that don't have the field myCustomField.

I don't know if you can do that at query level without adding the field to your other sections but you can do (although it's not very economical):

{% set entries = craft.entries.all() %}

{% for entry in entries %}
{% if entry.text is empty %}
    {{ entry.title }} <br>
{% endif %}
{% endfor %}


How to output 'selected' checkbox labels within a matrix Newbie here.

First Craft 3 CMS build and fumbling with logic of Matrix blocks.

I've created a relatively simple matrix field, and I can output plain text and dropdown options, but not sure how to do a multiple choice field like checkboxes within a matrix.

Thanks

You'd use the checkbox fields much the same way they would be used if they were added directly to the entry and not in the matrix field. Assuming you've got a basic matrix field structure (using if/else or switch):

{% for block in entry.myMatrixField.all() %}

    {% switch block.type %}

        {% case "text" %}

            {{ block.textField | markdown }}

        {% case "image" %}

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

        {% case "checkboxes" %}

            // HELP!!!

        {% default %}

A font walks into a bar.

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

    {% endswitch %}

{% endfor %}

You could use the same examples that are in the docs and just switch entry for the name of your block variable (block in our case):

Loop through the checked checkboxes:

{% for option in block.checkboxFieldHandle %}
    Label: {{ option.label }}
    Value: {{ option }} or {{ option.value }}
{% endfor %}

Loop through all of the available checkboxes:

{% for option in block.checkboxFieldHandle.options %}
    Label:   {{ option.label }}
    Value:   {{ option }} or {{ option.value }}
    Checked: {{ option.selected ? 'Yes' : 'No' }}
{% endfor %}

See if any checkboxes are checked:

{% if block.checkboxFieldHandle|length %}

See if a particular checkbox is checked:

{% if block.checkboxFieldHandle.contains('optionValue') %}


JS - Determine that an entry is unsaved? I've created a custom fieldtype... which is basically a button that triggers an AJAX action. When I add this field to my section, I can click the button while I'm editing an entry to perform an action.

Here's the thing... How can I tell if the entry needs to be saved? Clearly Craft is aware of whether an entry is unsaved or not, because it'll warn you before navigating away from the page. Is it possible for my button to tap into that same behavior?

MORE INFO:

This button does not take people away from the page, so I'm not sure if data-confirm-unload really comes into play here. If the entry is unsaved, the button will be replaced with a message saying, "you must first save the entry".

Craft checks if a form has changed using javascript in the cp.js file, see line 196.

You could replicate this quite easily yourself though, here is a stripped down example:

var initialFormValues = $('form[data-confirm-unload]').serialize();

function checkFormChanged() {
    if ($('form[data-confirm-unload]').serialize() != initialFormValues) {
        return true;
    }

    return false;
}


Where to place Webmaster Tools HTML File on CRAFT CMS? Im trying to setup my Web master tools for my site, but i'm not sure where to place the html file google provides:

I've tried the 5 main folders root but with no success. Also in the craft's root.

ANy advise on where should I put this code?

thanks in advanced...

You should place it in your public folder (may have a different name on your server) not in your Craft folder. The folder where all files (such as your assets) live in that are publicly accessible on your webserver.


CSRF in “Headless” Applications There are a number of answers here about how to send CSRF tokens along with AJAX requests, but I think my question is a little different. Please excuse the abstractness here:

In a headless application, I'd like to be able to log users in via AJAX, and keep a fresh CSRF token in the client-side application's state.

Is there a way to get a new token, once one has been consumed?

Imagine a case where a customer adds an item to their cart—that token is consumed, and a new one is issued on the next page load… but what if there isn't a new page load?

Am I even thinking about this the right way?

In looking at the UsersController, I noticed that the get-remaining-session-time action sends a csrfTokenValue. Any chance this is part of the answer?

A similar question was asked in the Craft Slack today, so I thought I'd transcribe the consensus:

Internally, CSRF tokens come from a call to Craft::$app->getRequest()->getCsrfToken(). This means that any controller (or template, for that matter—more often handled by the {{ csrfInput() }} shortcut method) can grab a CSRF token at will.

In the original post, I'd noted that the users/get-remaining-session-time action returns a token—that token comes from the above call, so it certainly sounds like a valid built-in method for grabbing tokens.

That said, it does have some potential side effects related to the session (aside from refreshing the CSRF token).

Ultimately—provided the time—it seems like the recommended method is to create a custom controller and call the method explicitly.

As far as the client-side handling… if your application has a means to consolidate AJAX calls, it'd be worth automating the refresh and inclusion of CSRF tokens as HTTP headers. For example, before a regular POST request is initiated, the client might first ensure it has a fresh CSRF token, then issue the request with the new token.

Hope this helps anyone else getting started with client-rendered applications!

  Edit: As of Craft 3.1.13, you get a CSRF token in the JSON response when a user logs in (assuming the login occurs over Ajax)!


Linking to channel via structure section I apologize for opening up a whole new question for this topic since it's been discussed a few times now, however I don't have enough rep yet to comment on the existing questions.

Regarding the answer to this question:

Channel index page linked in a structure

So what this answer is saying is that instead of having a whole separate channel for say, a blog, I should have it set up so that "Blog" is an entry type in my larger structure that also contains the various static pages for my site? if I'm understanding that correctly, doesn't the user lose out on some of the basic feature that a separate channel offers, such as not having to choose where in the structure hierarchy a new blog post should be?

I don't think that carlcs was suggesting that you incorporate individual blog posts into the 'pages' structure. He was only suggesting that you place those pages into the structure that you would want in your main navigation (using different entryTypes defined for each page layout); like your blog index page for example. In your case, what you would likely want to do (assuming you are following this strategy at all), is to create an entry for 'blog' in your structure, with a unique entryType called 'blogIndex' for example, and a matching template called '_blog.html' or '_blog.twig' which will be your blog landing/index page.

You would then create a channel for your individual blog entries, also called 'blog'.

In this way the urls will sync up nicely, such that the uri '/blog' will display your structure entry (which is designed to render, for example, a summary of the first 20 blog entries from your 'blog' channel); and the uri '/blog/my-blog-entry-title' will display your blog entry detail page from your 'blog' channel (assuming the blog entries are long enough that you even need a detail page).

Check out this answer for a more specific example with code examples.


How to fetch entries based on contents of several custom fields? I'm currently doing something like this:

{% set vars = "foo, bar" %}

{% set entries1 = craft.entries.section('sectionName').customField1(vars).limit(NULL) %}
{% for entry in entries1 %}
    {% if entry not in allEntries %}
        {% set allEntries = allEntries | merge([entry]) %}
    {% endif %}
{% endfor %}

{% set entries2 = craft.entries.section('sectionName').customField2(vars).limit(NULL) %}
{% for entry in entries2 %}
    {% if entry not in allEntries %}
        {% set allEntries = allEntries | merge([entry]) %}
    {% endif %}
{% endfor %}

But for each custom field I want to check, it's a trip to the database, and I've currently got to check three custom fields. Is there a way to merge these into one trip? I need to know whether the contents of vars are in either custom field. They might be in one, none of both, for example.

No, but this is possible with a few lines of plugin code. You just need to create a DbCommand object from your criteria model and add your WHERE conditions with a OR operator.

Add this function to your Template variable class and you can get the entries from your templates with a single query.

public function getEntriesWithVars($vars)
{
    $criteria = craft()->elements->getCriteria(ElementType::Entry);
    $criteria->section = 'sectionName';
    $criteria->limit = null;

    $query = craft()->elements->buildElementsQuery($criteria);

    $conditions = array(
        'or',
        array('in', 'field_customField1', $vars),
        array('in', 'field_customField2', $vars)
    );

    $query->andWhere($conditions);

    $results = $query->queryAll();

    return EntryModel::populateModels($results);
}

{% set vars = ['foo', 'bar'] %}
{% set entries = craft.myPlugin.getEntriesWithVars(vars) %}


How do I properly set assets paths? I'm having a problem getting my asset URLs to print properly in templates. The site is using a multi-environment configuration (dev/stage/live) with localized content (en/es/da) and shared assets. Here are the config and settings.

In the config file:

define('SITE_URL', URI_SCHEME . $_SERVER['SERVER_NAME'] . '/');
define('BASEPATH', realpath(CRAFT_BASE_PATH . '/../') . '/');

return array(
    '*' => array(
        // common config settings
    ),
    'site.craft.dev' => array(
        'siteUrl' => array(
            'en' => 'http://site.craft.dev:8888/',
            'es' => 'http://site.craft.dev:8888/es/',
            'da' => 'http://site.craft.dev:8888/da/',
        ),
        'environmentVariables' => array(
            'baseUrl'  => 'http://site.craft.dev:8888/',
            'basePath' => BASEPATH . 'http/',
        ),
    ),
    'stage.site.com'  => array(
        // etc
    ),
    'site.com'  => array(
        // etc
    ),
);

In the CP:

I have an 'Images' asset source defined with:

File System Path: {basePath}assets/img/
URL: /assets/img/

I have a 'printImage' asset field defined with:

Upload Location: Images (selected in dropdown); prints (in field)

Uploading images through the CP works great, and images go to the correct folder, and are viewable in the CP.

In the template (and here is the problem), when I request the image url using {{ printImage.url }} it outputs:

http://site.craft.dev:8888/prints/imagename.jpg

when it should be:

http://site.craft.dev:8888/assets/img/prints/imagename.jpg

Also, when I switch to another language it outputs:

http://site.craft.dev:8888/es/prints/imagename.jpg

It seems to be missing the portion of the path defined in Settings:Assets:Sources:'Images', and also is including the localization prefix.

All other paths and URLs in the site are working perfectly. Anyone have any ideas where I'm going wrong with assets? I guess I don't understand how it's crafting the asset URLs. Should I be defining an 'assetsPath' in my environment variables?

Thank you!

Everything is set up properly after all. I just wasn't referencing the actual image, but rather its parent record. Correct syntax in this context should have been:
{{ print.printImage.first().getUrl() }}

Feel free to delete this post, or leave it for the config details.


How to increment offset in FeedMe 2.0 I'm trying to decide if FeedMe would be a good choice to sync Craft with a fairly large Airtable database (more than 5k records). I'm inclined to say no just on general principle but I've done some quick tests and everything seems to work fairly well. For my next step in testing I wanted to try a larger sample dataset, but I can't figure out to increment the offset parameter.

When I make a request to Airtable, it returns 100 records, and an offset response that looks like

itrEk3iGk6zOddYqC\/recF5XRtrVtf6t0um

If I add that offset as a parameter to a new request, I get the next 100 records and a new offset value. So how do I tell FeedMe to automatically re-run the feed with the new offset parameter?

Received from the developer on Twitter:

  There’s no way to handle pagination or offsets automatically yet I’m
  afraid. You’d have to roll your own solution to handle this at the
  moment

I've been thinking about creating a plugin that polls the API and triggers a FeedMe task with a custom offset parameter. It would also need to record the status of the task once it's complete and the offset for the next 100 records as well.


Tips for running Craft in Microsoft IIS My client prefers to use a Microsoft IIS hosting environment he already has. After some gnashing of teeth I have managed to get it working there, but it is painfully slow (unlike my local LAMP version).

I was inclined to assume some sort of shared server MySQL bottleneck but the host's response to this thought has been…

  I don't see any bottlenecks on the server itself, mysql connections to the server and queries on it are running very quickly so I would be looking at the code itself. I've done some tests with simple php + mysql connections on the server and these run very fast, so this is pointing at the CMS doing something slowly, but I'm not familiar with the CMS to know what this is.

Does anyone have experience of Craft running well in IIS on a shared server?

Is there any particular config that is worth trying to get it to do so?

I run Craft on IIS/Win 10 on my main development box and don't have issues with it.  Don't recall having to jump through hoops to get it working, either.

I suspect it's more of the "shared server" that's the issue, but you can start by enabling devMode in Craft and check the timestamped profiling output (code and database) in the browser's console and craft/storage/runtime/logs to try and narrow down where the time is going.


Accesing craft.categories.slug ids within a MatrixBlock for search query I have a dropdown search query I have implemented using this blog (https://www.webstoemp.com/blog/combined-searches-and-filters-craft-cms)

This works excellent for searching my three categories and it's very fast.

{{% set searchContactFor = craft.request.getParam('contactFor') %}

{% if searchContactFor is not empty %}
    {% set searchContactForCat = craft.categories.slug(searchContactFor).ids() %}
    {% set categoriesArray = categoriesArray|merge([{
        targetElement: searchContactForCat,
    }]) %}
{% endif %}}

However, I have a category I need to search call 'institution', which is nested inside a MatrixBlock 'position'. When I attempted to use the same code for searching my other categories it is unable to retrieve the slug.ids(). I've been using the Kint debugger and I'm still unable to crack this one. I am assuming I need to reached into the Matrix block 'position' prior to grabbing the 'institution' slug.ids(). I have several hacks that work but are really terrible on query performance. Does anyone have a simple solution for this that I am missing? Here is an example of an expensive query. As you can see it's pulling back all the member.ids and then matching them to the intuition. Very Slow!

{% set searchInstitution = craft.request.getParam('institution')|lower %}
{% set searchInstitution = searchInstitution|split(',') %}
{% set memberIds = [] %}

{% if searchInstitution is not empty %}
    {% for entry in craft.entries.section('member').limit(null) %}

        {% set found = false %}

        {% for block in entry.position %}
            {% if block.institution.first()|lower in searchInstitution %}
                {% set found = true %}
            {% endif %}
        {% endfor %}

        {% if found %}
            {% set memberIds = memberIds|merge([entry.id]) %}
        {% endif %}
    {% endfor %}
{% endif %}

{% if memberIds|length %}
    {% set queryParams = queryParams|merge({
        id: memberIds
    })%}
{% endif %}

I wanted to post this in case someone can use a portion of it to help with their search queries. This is what we came up with, works in combination with our three other category dropdowns (all four can be multiple selections), plus some custom Javascript.

{% set categoriesArray = ['and'] %}

{# Institution #}
{% set searchInstitution = craft.request.getParam('institution') | replace({'|' : '\''}) %}
{% if searchInstitution is not empty %}
{% set institutions = craft.categories.search( searchInstitution ) %}
{% set categoriesArray = categoriesArray|merge([{targetElement: institutions, field: 'position.institution'}]) %}
{% endif %}

JS

var institutionNames = cbxInstitution.toArray()
      .reduce(function (p, c) {
        if (c.checked) p.push(c.value);
        return p;
      }, []);
    inInstitution.val(institutionNames.map(function(v){ return "|"+v.trim()+"|"; }).join(" OR "));


fileCache seems to expire even though I have it set to 0 I am using the fileCache command in a custom plugin. I've set it to never expire so that I can provide a special link to our client to force a refresh.

Problem is, the cache seems to be killing itself off. On one day I can see record of it regenerating three separate times, so it is

$craft->fileCache->add($cacheKey, $dataToAddToCache, $cacheExpire);
$craft->fileCache->add('my-hardcoded-key', 'string of data', 0);

So basically I am doing this.

if (NEED_TO_REGEN) {
   $craft->fileCache->delete($cacheKey);
}
$a_cacheVal = $craft->fileCache->get($cacheKey);
if (empty($a_cacheVal)) {
    //use the cached data
} else {
   $craft->fileCache->add($cacheKey, $dataToAddToCache, $cacheExpire);
}

Does admin modification of resources affect fileCache at all (updating an entry wouldn't kill of my plugin fileCache would it?) The admins is not doing a full Clear Cache inside settings or anything. So why would this particular cache be regenerating frequently (multiple times per day in some case)?

You should be using craft()->cache with the cacheMethod config setting set to file (which it is by default) instead of craft()->fileCache.  The latter is deprecated and won't work in Craft 3.

Yii does have garbage collection on cache, and by default an item has a 0.01% change of being purged from cache regardless of expiry time.

If you think you're not being garbage collected, you can check the file modified time of the files in craft/storage/runtime/cache.  If you explicitly pass in 0 as an expiration time, Yii will set the file's modification date to a year out.


Enforce search match multiple parameters I actually found this code on here Search Form with Craft Commerce. I had a problem with this code pulling up products that didn't match, and then after creating a new product it worked for a bit and then broke and continued to only pull up the same ones, even if I got rid the values inside with[].

So two questions, how do I enforce that the product has to match BOTH criteria in the with[] and does anyone have any clue about why it would stop refreshing products? I've tried clearing cache in both browser and craftcms.

I apologize if this has been asked before, I've been through multiple previously asked questions with little luck.

{% set spec = craft.request.getParam('a') %}
{% set spec2 = craft.request.getParam('b') %}
{% set category = craft.categories.group('productSpecs') %}
{% set products = craft.commerce.products({
            relatedTo: category,
             with: [
                spec,
                spec2,
            ],
            order: "title asc",
        }) %}
{% for product in products %}
    {{ product.title }}
{% endfor %}

I think you're misunderstanding what with does. Or I am. Ha!

From what I understand with is for eager loading, but doesn't control anything in the relation itself. I don't think your relation makes any sense either because all you'll do is substitute a string into your spec variables.

Try something more like:

{% set products = craft.commerce.products({
    relatedTo: [
        'and',
        CONDITION1,
        CONDITION2
    ],
    with: [
        fieldYouWantToShow,
        otherFieldYouWantToShow,
    ],
    order: "title asc",
}) %}

And your conditionals should be something like:

{ targetElement: category },
{ sourceElement: craft.entries.section('reviews').status(null) }

The bottom example here is what you're needing: https://craftcms.com/docs/relations


Is it possible to sort Sections? I now have 5 Structures that belong together (they are all different parts of our restaurant menu) together with my other structures its all very confusing. So what I want is a way to split up my
----Structures----

in the entries area to have like:

-----Singles------
  ..
-----Channels-----
  ..
----Structures----
  ..
-----FoodMenu-----
  ..
----Navigation----
  ..

Is there any way to achieve that ?

I don't think there is at the moment, but you could probably build a easy plugin to do that with Javascript.


oops screen on Mamp Pro install Hi got past the username etc screen for install but stuck on the 'oops' screen?
I've tried again and again but same deal, checked db settings just not getting past this, assuming the oops means it can't connect to the db but if the details are correct (I have a pw with its own un and pw with privs for that) and tested with root root, any ideas – seems most people are having no probs with this, then tried logging in and ok, why would it hang do you think on oops when seems to have installed?

If Craft can't connect to the database, it will let you know.  Some other error is occurring. Check your craft/storage/runtime/logs files for an [error] entry, and that will have the error message that is occurring.

Also, in between installation attempts, be sure to delete any tables that were created in the database from a previous install attempt.


How do I include custom fields of an entry type in the Guest Entries form? I want any visitor to be able to submit links to my blog via the Guest Entries plugin, but how do I include the custom fields of my "Links" entry type in the Guest Entries form? For example, a category field, text fields...

if you're using an Entry Form - [entries/saveEntry] you'll need to pass them in as fields.

For example if you had a text field called "Links" you would need an input like this

<input type="text" name="fields[links]" value="{{ entry.links }}">

Passing in inputs with the name fields[your_field_name] allow it to be picked up and populated correctly.


Setting structure section entry titles dynamically based on the entry level I'm trying to set a title for a STRUCTURE entry dynamically based on the structure level within the section hierarchy.

{% if entry.level('not 1') %}{ postDate|date('M') }{% else %}{ postDate|date('Y') }{% endif %}

I've tried using the above for the title format of my entry type but it only appears to work for setting YYYY for the parent entry and doesn't add the month for child entries.

I resolved the issue by using the following code for my title format

{% if object.parent %}{ postDate|date('M') }{% else %}{ postDate|date('Y') }{% endif %}


Bulk upload images, generating a seperate page for each image Building a photography website for a client, need a way to bulk upload images, much like using the assets field. I want these to be grouped into different sets by entry or category. So that I can apply whatever fields I need to the set then loop through these images based on set in the Front-End.

The method I have tried is using entries and having an assets field to upload the images. The problem I am having is I also need to have each image generate it's own seperate URL, meaning a template page for the set of images and then another template for each image in that set.

Is there a way to accomplish this using Craft's core features?

In your main image index template, you can iterated through all of the assets and generate URLs yourself like this:

{% for asset in assets %}
    {{ asset.title }}
{% endfor %}

Then set up a custom route for /photos/photo-detail/(slug) and point it at the photo-detail.twig template. In that template, you can get the slug for the asset via craft.request.getSegment(3) and then look up the asset via the slug.


Solution for Matrix-within-Matrix (or More Robust Table Fields) I was wondering if anyone has stumbled on a good solution for including matrix-like fields within a matrix block. I’m working on a site where each page's is constructed in one big matrix with several block types (each representing a “row" in the page) like…

Introduction
Stats
Quotes
Bios
etc.

Blocks like Stats, Quotes, etc. can hold either just one, or several of these items, so right now the subfields look something like this:

Block Title
Stat 1: Number
Stat 1: Text
Stat 2: Number
Stat 2: Text …etc. up to Stat 6

Rather than having all these fields in view by default, it would (obviously) be best if the user were just adding Stats as rows in an inner table or Matrix. Initially I thought that using Table fields would be the fix, but in several cases I need to include fields that aren’t natively supported in in Tables (like Assets, Rich Text, etc.).

At the very least it would be nice to collapse some of the fields that are likely not going to be needed so they are out of the way (so in the example above, maybe show fields for the first 2 stats, hide field for the next 4).

Has anybody stumbled on a good solution (maybe a Plugin) for either allowing more field types within Tables, adding a Matrix to a Matrix block, or collapsing fields by default?

Also open to other suggestions … seems like a lot of sites take this “stacked rows” approach, so guessing I’m not alone here. Thanks!

Rather than trying to store multiple stats together in a single block, another option would be to make a "Stat" (singular) block type, which only holds a single stat, and just have authors create as many of those as they need, positioned together.

From your template, when looping through blocks, you can check to see if the current block is the first/last of its type, and add some extra HTML when that's the case, so that consecutive Stat blocks still appear grouped together in the rendered HTML. Something like this:

{% for block in entry.myMatrixField %}

    {# Find out if this is the first/last consecutive block of this
type #}
    {% set type = block.type.handle %}
    {% set isFirstConsecutiveBlockOfType = (loop.first or type != block.getPrev().type.handle) %}
    {% set isLastConsecutiveBlockOfType = (loop.last or type != block.getNext().type.handle) %}

    {% switch type %}

        {% case 'stat' %}

            {% if isFirstConsecutiveBlockOfType %}

            {% endif %}

            {% if isLastConsecutiveBlockOfType %}

            {% endif %}

        {% case 'quote' %}

            {% if isFirstConsecutiveBlockOfType %}

            {% endif %}

            {% if isLastConsecutiveBlockOfType %}

            {% endif %}

    {% endswitch %}
{% endfor %}


Getting related project of a submitted 'wish' through the entry field. I have a channel projects and a channel wishes (People can submit their 'wishes' for that particular project.

In a project I made the 'entry field' projectHasWishes to connect wishes to project.

Now we use guestentries plugin to get wishes from the visitors. This form is that particular projectpage on the frontend. How can I relate them easily to the right project? Can I use a hidden field for this? Or something else? Thanks for helping me out.

The way you've set it up now, it won't be possible without doing 2 requests: one to create the wish, and one to alter the project (add the wish relation).

If you'd turn it around, and give the wish section a field 'belongsToProject' (or whatever else you'd like to call it), you'd be able to create this hidden input field in your wish form:

<input type="hidden" name="fields[belongsToProject][]" value="{{ project.id }}" />

Notice the []. Those are needed because a relation field can have multiple related elements, even if you limit it to have only one.
On saving, the field will be populated with the project relation you're looking for.

On viewing your projects and wishes, assuming you have a variable called project with your current project in it, you could simply do:

{% set wishesForProject = craft.entries.find({
    section: 'wishes',
    relatedTo: {
        targetElement: project,
        field: 'belongsToProject',
    },
}) %}

{% for wish in wishesForProject %}
    {{ wish.title }}
{% endfor %}


Least CPU intensive way to get number of matching elements? Which is the least CPU intensive (SQL-intensive) way to get the sum of products that are relatedTo a category?

Like this?

{% set productCount = craft.products.relatedTo(category)|length %}

When you call the |length twig filter you are implicitly treating the element query as an array.
This behaviour was depreciated in Craft 3, and also results in a DB query being sent that is equivalent to .count() (Craft 3) or .total() (Craft 2).

To remain up to date, while still minimising SQL load for your page: either call the relevant command (.count(), .total()):

{% set productCount = craft.products.relatedTo(category).count() %}

Or, if you're going to be doing a full (limit: null) query at some point anyway, do that now and then use the length filter:

{% set products = craft.products.relatedTo(category).limit(null).all() %}
{% set productCount = products|length %}


What is the correct way to include jQuery and jQuery UI in Craft? I am wondering what is the correct way to include jQuery and jQuery UI in Craft?

Thank you.

You would use <script> tags in your template, preferable in a _layout.html or _base.html template which you extend from all your other templates.


Freeform to show via Vue Js I have 3 freeforms - form 1, form 2 and form 3. I want a select option on which I click and the necessary form opens as per the selection.
Can I render the Freeform which are build using VUE js Select method?
If so how? Because when I try to render Craft.Freeform it shows me this error

It sounds to me like you're running into a collision with Vue's template delimiters vs Twig's, which by default are the same as each other ({{ ... }}). The solution is to change Vue's delimiters to something else when you initialise, like this:
const vm = new Vue({
    el: '#app',
    delimiters: ['${', '}'],
    ...
    ...
});

You'd then need to use ${ ... } as your Vue delimiters.


Plugin development Craft CMS 3 I am new to craft and I need help to understand how plugins work.
I am trying inject these functions to the CraftVariable

{% for item in craft.plugin.exampleFunction(test).hide("noTitle") %}

craft.plugin.exampleFunction(test) is working perfectly
but .hide() is not. Can anybody tell me how to call this function?

Based on the discussion you'll need to implement a fetch function similar like Craft does it with the ElementCriteriaModel / ElementQuery. So you'll return some kind of search object until you execute the .find()/fetch() (or whatever you like to call it) function

class ClassName{

    /** @var array $_searchObjects */
    private $_searchObjects;

    /**
     * @param $something
     *
     * @return $this
     */
    public function exampleFunction($something){
        $this->_searchObjects = ['test', 'insert', 'your', 'array', 'here'];

        return $this;
    }

    /**
     * @param $string
     *
     * @return $this
     */
    public function hide($string){
        // filter your elements
        $this->_searchObjects = ...//

        return $this;
    }

    /**
     * @return array
     */
    public function find(){
        return $this->_searchObjects;
    }
}

You can then use it like

{% set elements = craft.plugin.exampleFunction.find() %}
{% set filterElements = craft.plugin.exampleFunction.hide('something').find() %}


Streamlining a loop with a bunch of conditions I'm sure there must be a tidier and more efficient way of doing this so thought I'd throw it out there for some opinions.

Building a site that has the usual lists (in grid format) for Blog, Gallery, Meet the Team, etc... I'm calling these 'cards', and I'm including them with various attributes:

{% include "_modules/card"
    with {
        author: true,
        badge: true,
        date: true,
        magnify: true,
        meta: true,
        thumbnail: true,
    }
%}

Then in my card I've got:

{% if badge is defined %}

{% endif %}

{% if thumbnail is defined %}

{% endif %}

Heading Goes in Here

    {% if meta is defined %}

            {% if date is defined %}
                {% include "_modules/relative-date" %}
            {% endif %}
            {% if author is defined %}
                by John Doe
            {% endif %}

    {% endif %}

This all works as expected but I can't help feel it could be neater. There are a lot of conditions at work here for example, and this will all be part of an entries loop too. Anyone have any suggestions for streamlining this a bit? Much appreciated.

I'm not sure if this is better or not but one thing I'd do here is to set some defaults in my include. This also means you don't need to worry about checking whether it's defined or not. You're just checking whether it's true.

{% set options = {
    author: true,
    badge: true,
    date: true,
    magnify: true,
    meta: true,
    thumbnail: true,
} | merge(cardOptions | default({})) %}

    {% if options.badge %}

    {% endif %}

    {% if options.thumbnail %}

    {% endif %}

Heading Goes in Here

        {% if options.meta %}

                {% if options.date %}
                    {% include "_modules/relative-date" %}
                {% endif %}
                {% if options.author %}
                    by John Doe
                {% endif %}

        {% endif %}

Then when I use this include I can pass in an object of options that could overide those defaults. But I only need to pass in values that need to change the defaults. For example here I can set meta to false but can leave all the others to be handled by the default:

{% set cardOptions = {
    meta: false
} %}

{% include "_modules/card" with cardOptions %}

You said this would be included within an entries loop. You could do this in that case:

{% set options = {
    entry: false,
    author: true,
    badge: true,
    date: true,
    magnify: true,
    meta: true,
    thumbnail: true,
} | merge(cardOptions | default({})) %}

{# Wrap the whole card in a conditional #}
{% if options.entry %}
   // Card goes here
{% endif %}

And then in your entries loop you'd do:

{% for entry in entries %}

    {% set cardOptions = {
        entry: entry
    } %}

    {% include "_modules/card" with cardOptions only %}
{% endfor %}

I'd probably use the only option on the include tag to avoid stuff leaking in.

I've also played with options such as:

{% set cardOptions = {
    styleGuide: true
} %}

In my include this option will have a false default I'll have a conditional that checks for it being true and if so it'll ignore any dynamic content and instead I'll output an example of the module with fake content. It's good for testing and for keeping a library of modules.

You could also consider a macro that wraps your include tag. I gave a similar example in a blog post not long ago: Using macros to improve consistency in your Craft CMS templates

{% macro module(type, options = {}) %}
    {% include '_modules/' ~ type with options only %}
{% endmacro %}

And then in your template you'd do something like:

{% set cardOptions = {
    entry: entry,
    meta: false
} %}

{{ module('card', cardOptions) }}

Dunno if any of that helps!


Cannot post data to a plugin controller action I have a form in one of my templates

 <form method="post" action="" accept-charset="UTF-8">
    <input type="hidden" name="action" value="paypalPayments/payment/pay">

     [...]
 </form>

I also created a simple plugin like so:

//PaypalPaymentsPlugin.php
 <?php
 namespace Craft;
 class PaypalPaymentsPlugin extends BasePlugin {

    function getName() {
       return Craft::t('Paypal Payments');
     }

     function getVersion() {
       return '1.0';
     }

     function getDeveloper() {
       return 'Paul Timoce';
     }

     function getDeveloperUrl() {
       return "http://paultimoce.net";
     }
 }

And also a controller file inside a controller folder:

 //File PaypalPayments_PaymentController.php
 <?php

   namespace Craft;

   class PaypalPayments_PaymentController extends BaseController {

     public function actionPayWithPaypal()
     {
        echo "I'm in...";
     }
   }

All I want to do is post some variables through my form and process them with my plugin controller but every time I submit my form I hit the 404 page...

Do you guys have any idea as to why this is happening? I also installed and activated the sample cocktailRecipes plugin trying to do the same thing but unsuccessfully also... I tried to point my browser to /actions/paypalPayments/payment/pay and /actions/cocktailRecipes/ingredients/saveIngredient but also no luck... I always get redirected to the 404 page.

Can you help?

There's alot of different things that could be going on here.

First, if your action is named actionPayWithPaypal (as in the code above) the action url should be paypalPayments/payment/payWithPaypal I guess?

You won't be able to hit the cocktail recipes method directly from your browser since it requires the request to be a post. But you should be able to hit your controller with yourdomain.com/actions/paypalPayments/payment/payWithPaypal.

But, only if you're logged in. If you're not logged in, that will give you a 404 unless you enable anonymous access to the controller, see the documentation on how to do that.

Also, is your .htaccess rewriting working as it should? If not, that could cause problems with calling the action directly.

Try generating an action url and see if that works:

Test me


Creating an onSaveEntry event in Guest Entries Plugin I'm currently working on a plugin that sends an email before the Guest Entries Plugin saves the entry. But one of the fields is an asset field and the file may be renamed when uploaded so I need to switch this up so the email being sent after the entry is saved.  I tried creating an onEntrySave event in the Guest Entries plugin by doing the following.

Added to GuestEntriesService.php:

/**
     * Fires an 'onSaveEntry' event.
     *
     * @param GuestEntriesEvent $event
     *
     * @return null
     */
    public function onSaveEntry(GuestEntriesEvent $event)
    {
        $this->raiseEvent('onSaveEntry', $event);
    }

In GuestEntriesController.php I've added

$this->onSaveEntry(new GuestEntriesEvent($this, array('entry'=> $entry,'isNewEntry' => true)));

to the section of the code where the entry is saved.

if (craft()->entries->saveEntry($entry))
{
     $this->onSaveEntry(new GuestEntriesEvent($this, array('entry'=> $entry,'isNewEntry' => true)));
     $this->_returnSuccess($entry);

}

But this is where I've gone wrong as I get the error:

Craft\GuestEntriesController and its behaviors do not have a method or closure named "onSaveEntry".

How do I go about modifying the plugin to trigger an onSaveEntry event?

It probably would be better to just write your own plugin to do this, so that you don't have to worry about patching in your changes every time the guestEntries plugin is updated — and it could technically be just one file, although the recommended craft method would be to create a service method to handle the events.

In your plugins main class file, just create an init method that listens for the entries.saveEntry event for the section in question:

public function init()
{
    parent::init();

    craft()->on('entries.saveEntry', function(Event $event)
    {
        $entry = $event->params['entry'];
        if ($entry->section == 'MySection')
        {
            if ($event->params['isNewEntry'])
            {
                craft()->myplugin->handleNewSectionEntry($entry);
                // or do something directly
            }
            else
            {
                craft()->myplugin->handleUpdateSectionEntry($entry);
                // or do something directly
            }
        }
    }); // edited
}

If you need to test whether it is a 'guest' entry from the front-end vs the CP you can add:

if (!$currentUser) { ... }


(Apache) pages only load when adding index.php?p= It looks like Apache (or Craft?) isn't routing all of the requests to index.php. So http://SITENAME/index.php?p=admin/install works, but http://SITENAME/admin/install doesn't. The issue is this is happening with every URL, so the HTML for the install page loads, but none of the assets (CSS, JS) do.

Here's my issue in picture form:

Disabling the omitScriptNameInUrls config option makes it work. Not sure if this is a "solution" though


What is the best way to append CSRF token without using a form? I have built a plugin that simply makes requests to a 3rd party API. I am calling my plugin action via ajax.

I don't have a form on this page currently. Here is what I am using, but I am getting the error The CSRF token could not be verified.

I thought I could just put a hidden input field somewhere on my template:

twig

<input type="hidden" name="{{ craft.config.csrfTokenName }}" value="{{ craft.request.csrfToken }}">

Here is what my ajax call looks like...

jquery

var data = {
    'thing': value,
    'thing': value
};

data[window.csrfTokenName] = window.csrfTokenValue;

$.ajax({
    'type': 'post',
    'contentType': 'application/x-www-form-urlencoded; charset=UTF-8',
    'cache': false,
    'data': data,
    'url': 'myplugin/doAction',
    'dataType': 'json',
    'timeout': 50000
}).done(function (response) {
    callback(response);
}).fail(function (error) {
    // Total fail.
});

Later on in my site I will have a form that accepts user input, so I would like to keep CSRF enabled for the entire site. Perhaps I need to "skip" the CSRF token for these requests?

You need to pass the token and name into javascript. Easiest is to just have a script tag somewhere.

<script type="text/javascript">
    window.csrfTokenName = "{{ craft.config.csrfTokenName }}";
    window.csrfTokenValue = "{{ craft.request.csrfTokenValue }}";
</script>

Now they will be available to your ajax call.


GraphQL query entries by DateTime field between two dates I am trying to query entries in GraphQL by custom DateTime field value.
It works with the base String value like ">=2020-10-01",
However querying between two dates like "['and', '>=2020-10-01', '<2020-11-01']" it gives me an empty result.
What will be the correct query variable here?
Thank you

After trying multiple options found an answer:


Joining two plugin tables by reference Id causes duplicates I'm running a query in which I need to join two tables table_views and table_clicks. Both tables share several column names (mainly refId, month, year and total).

However when I try and join these tables together, instead of returning ~18 or 20 rows/records. It repeats the join for every single row, producing 360 records.

How can I query and combine both tables by their reference Id?

        $records = craft()->db->createCommand()
        ->select('*')
        ->from('table_views table_views')
        ->leftJoin('table_clicks table_clicks', 'table_views.refId=table_clicks.refId')
        ->where('table_views.refId = :refId', array(':refId' => $id))
        ->query();

You're probably looking for an inner join (which Yii just calls a join)instead of a leftJoin: https://blog.codinghorror.com/a-visual-explanation-of-sql-joins/


How to catch errors in a service and return to a controller? How do you handle “catching” errors in a plugin service and return the error to
the plugins controller?

To be more specific... I am sending an Ajax request to a controller, that controller is performing a few checks (is the user logged in for example, if not logged in - return a json response).

See the below controller code:

public function actionMyController($elementId)
{
    if ($this->notLoggedIn()) {
        return;
    }
}

protected function notLoggedIn()
{
    if (!craft()->userSession) {
        return $this->returnJson('You must be logged in!');
    }
}

However, when those conditions are met the data is passed to the plugin service. In this case $elementId and $userId. Before creating the record, I'm performing additional checks on the data. When those checks fail, it should return additional JSON responses to the controller to display on the front-end.

See the below service code:

public function saveThing($elementId, $userId)
{
    $this->validateUser($userId);

    $this->validateElement($elementId);

    // populate the model

    // save the record and etc.

}

protected function validateUser($userId)
{
    if ($userId == craft()->getUser()->id) {
        return true;
    }

    // return json to the controller?
}

protected function validateElement($elementId)
{
    $element = craft()->elements->getElementById($elementId);

    if (is_null($element)) {
        // return json to the controller?
    }

}

So when the conditionals fail on the service, we need to return a response to the controller. Thoughts?

There are several ways you could go about this.

One that I tend to prefer is to go ahead and have your controller grab whatever data it needs from POST and populate a Model with it.

That model is what gets passed into your service layer.  Your service layer can run validation on the model (if any validation fails, you can retrieve the errors with $model->getErrors().

You can perform any additional custom logic and if any of that fails, use $model->addError() and return false.

Since the model will have been passed in by reference, your controller can see that false was returned and call $model->getErrors(), format those however you need and use $this->returnJson($myErrors) to send the errors back to the browser as JSON.


Feedme plugin: importing tables Has anybody had issues importing JSON into table fields with the Feedme plugin?

I've got an issue where empty values in my feed are not being parsed into the correct table rows.

Source:

Result (after import):

Any thoughts on how best to resolve?

I'm sure I can give you a hand (Feed Me developer here) - would you be able to submit a Help request using the instructions here - https://github.com/engram-design/FeedMe#support? Happy to post back findings here.

EDIT: Thanks for your patience - This was indeed a bug, which has been fixed in the latest master.

Let me know if you continue to have issues!


Current Entry Children Count Does anyone know if I can output the number of children the current entry (structure) has?

Try this:

{{ entry.getChildren().total() }}


Adding class to images in rich text How can I add a CSS class to all images inserted into a rich text field ?

ie. so an image inserted has style= "image fit" added to the img selector

I wrote a plugin called Retcon HTML which will solve this nicely using PHP's DOMDocument class.

You'll want to use the attr filter, which is documented here:

{{ entry.richTextField | retconAttr( 'img', { 'class' : 'image fit' }) }}


Why choose Craft Commerce over Magento We have 2 clients that want to have an online shop website. One with 100 products, with 10,000 products.

We've built 100's of websites, but no e-commerce sites yet. We're in the stage of writing the proposals/estimates, but because the clients have been long-time clients, they have confidence that we propose them the right platform. Or, read: they will go with our proposals.

My question is: why would anyone choose Craft Commerce over Magento?
(I'm not even considering any WP based solutions).

Obviously it's going to depend on each specific project, and I can only talk from my own (store owning) perspective, but over the years I have evaluated and installed and played with just about every ecommerce system of significance on the planet today.  The ones I've spent most time with are BigCommerce (in it's self hosted form before it went SAAS), EE & CartThrob, and Craft Commerce.  I'm not going to slag off Magento as such or very specifically - although as I go through my points it should be clear I though about all of these with Magento, and found them lacking or painful...

Here are the reasons I chose Commerce, roughly in order of importance:

Pixel and Tonic - more than anything else, I think it was the considered, open and intelligent approach of Pixel and Tonic - that I carefully observed from 2012 to 2015 - that convinced me it was a solid, well thought our platform backed by some exceptional people.
Content driven ecommerce - basically, there are two types of systems in the world - either commerce systems that have a little CMS bolted on, or content systems with a little shop thingy bolted on.

For me it's essential that content, and absolutely great management of it, be the main thing.  BUT, I also do want a great shop on top of that - with integration between the two that feels completely transparent and natural.  This means, in essence, that a first party solution to both problems is ideal.  When you have separation between the two, it always feels bolted on and shoe-horned in (see CartThrob or WooCommerce as prime examples).

The fact is pretty much anyone can set up an online shop right now and if all you want are product grids with pretty pictures, and lots of discount options, and simple (but simplistic) integrations to popular shipping services, then Shopify or similar is your obvious option.  But if you want substantial, useful content (and anyone that wants to compete with Amazon etc really should!) - then you need a content driven approach.  Expertise & Service are the keys to successful long term commerce in a world of box moving mega-discounters.
The ExpressionEngine (i.e. Content Modelling) foundations  - before coming to Craft/Commerce, I was considering (and implementing) CartThrob with ExpressionEngine.  And if I am truthful it's the fact that Craft grew from this approach - but then vastly improved on it - that gave me the motivation to spend serious time evaluating it (credit where it's due - Craft, like everything else, stands on the shoulders of giants).

I fundamentally think structured content modelling is the key to excellent content management, which is fundamental to 'more-than-average' shops....see above.
Matrix - the problem with structured content is that it can be TOO structured for long form content - you simply can't have a dedicated field for absolutely everything - and so where you DO want to write longer form content, it tends (on lesser systems) to be that everything just gets dumped in a WYSIWYG.

Matrix (and Supertable/Neo/etc :) ) - is the (so far) best solution to this problem.  It gives you a structured-within-longform-content approach that is second to none.  You can build very flexible page assembly systems using structure where you really need it and freedom where you don't.  Which means you can build some wonderful content driven ecommerce stuff very quickly.
Cost & support.  Magento - while open source and sort of free in a community supported sense/version, superficially looks good value.  But if you add real support - the kind you need if livelihoods depend on things - it becomes fiercely expensive.  P & T support is fast, unlimited, generous and easy to access.
Ease of implementation.  Craft & Commerce, with Twig, is easy.  It's really, really simple and logical to write your templates, and Craft always seems to behave in natural, expected ways.  The more time you spend with it, the less gotchas you need to worry about.  It's that rare system that gets better with familiarity.  Magento has a reputation for being absolutely labyrinthe in scope and difficulty in terms of template implementation.  I've heard the term 'horror show' used more than once.
Flexibility - Whilst Commerce doesn't support a lot packaging, shipping stuff etc out of the box, and where it does the implementation can feel a bit basic, the inherent simplicity of Craft plugins (and V3 looks to improve on this further a lot!) - means you can implement just about anything you need easily.  In my experience for complex stores off the shelf things rarely meet real needs anyway - so what you really need is a well though out architecture for extension.
In terms of product & variation management, Commerce, like Craft itself, is wonderfully flexible and yet simple.  You can create elegant, responsive content entry systems for your editors with ease, and separate your data concerns in sensible, long term maintainable ways.  It nails content management as well as anything I've been able to find.

Personally, I think neither of them are good solutions for very simple stores - there are simply cheaper, polished, off the shelf things that do that well.  No - these systems are for complex, bespoke e-commerce, where a substantial investment of time and money is used, to make something a bit special.  For my money, Commerce is the flexible, powerful content driven approach that nails this problem.  And Magento (in my limited experience of it) is an over complex, over priced, frustrating to work with alternative.

Apologies, this is a bit of a ramble.  Someone should come along and write a 'The Commerce Advantage' to match the Craft one...but hopefully this helps a bit!


Migrate path from 2 to 3? Anyone have experience updating a CraftCMS site from 2.* to the 3-beta? I'm not in dire need of this at the moment, but can't seem to find it in the developer resources.

EDIT: Found the upgrade guide https://docs.craftcms.com/v3/upgrade.html

The documentation posts this link:
Upgrading from Craft 2

Mijingo has a tutorial: Upgrading Craft 2 to Craft 3

There is a hangout on the topic on Straight Up Craft: Migrating a website with plugins from Craft 2 to Craft 3

At the time of this posting, I have not seen any good documentation on how Plugin Developers should approach migrating their plugins.


{{ category.title }} error with category groups I feel like I'm missing something totally obvious here, but how do I output a category name for a category that is part of a category group on a single entry layout? The name of the category group is 'Archive' and the slug 'archive'.

Here is what I'm trying to do.

*name of category*

Here is what I tried

{{ category.title }}

However then I get the error "Variable "category" does not exist."

Trying the following code snippet from the official tutorial also did not work.

    {% for category in entry.postCategories.all() %}

        {{- category.title -}}

    {% endfor %}
  {% endif %}

resulting in the following error: "Calling unknown method: craft\elements\Entry::postCategories()"

Any help to solve this probably very simple problem is appreciated. Thank you!

You should replace postCategories with whatever the handle of the category field is for your entry.


Register front end member from admin area with password I'm not certain if this is possible but what we want to do is the following:

Have an admin register a new user in the admin, including a password for them so that they can pass along these credentials along via offline channels - and then that user will log into a front end client area.

I don't think it's possible to add a password - which surprises me in terms of use-cases needing to manage new users subscriptions by someone else and wanting disseminate specific credentials.

Is this possible?

If not, is it possible to:

Register the new member in the admin (without a password)
Have a custom Activate Account email confirmation go to them to finish their account signup, prompting them to go to:
A page where they can complete this, adding their new password and then logging them into their client account area

Thanks!

Your best bet here is going to be to create a plugin.

One way that this could work would be to set up a plugin that defines a record for the front-end users, and then create one or more Control Panel pages for your Administrator to handle these records. Because the records can be defined any way you'd like, they can exist separately from Craft's baked-in User system.

This may actually be preferable in your case, since (if I'm understanding correctly) it sounds like you'd like to manage users logging into a separate frontend area, not the Craft admin Control Panel.

Regarding the Admin ability to manage User's passwords from the Control Panel, this feature was removed in build 2.3.2615. However, this answer does offer a way around this.


Show a quote on my login page I have a number of entries, each with a quote (table field with one phrase and author row). I would like to show one quote on my login page, but some of these entries do not have quotes.

How can i filter the entries so that it can only choose from the entries that have quotes and exclude the ones who don't have?

Basically you want to retrieve all entries where a certain field is not empty?

Return entries where field is "not empty"


How can I link to an Asset from the Rich Text editor? I have some content on my entry like this:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus quis rutrum dolor.

I know I can link to an Entry or Category, but I would like to link to an Asset. For example, a PDF.

I would like to highlight Lorem ipsum and link that text to a PDF. I can change over to HTML view and manually enter the link, but that seems risky to ask a client who may not know any HTML. Is there a preferred way to select some text and link it to an asset?

This isn't really related to Craft specifically, but to allow a user to link to an asset, you will need to enable the feature in the redactor configuration file.

For example, within this file:

/craft/config/redactor/Standard.json

You will see something like this:

{
    "buttons": [
    "html",
    "formatting",
    "bold",
    "italic",
    ...

You will need to add file to that list so that it looks like this:

    {
    "buttons": [
    "html",
    "formatting",
    "bold",
    "italic",
    "file"
    ...

Make sure to clear out your cache to make sure that Craft can see your updated file.

Now when you highlight some text, you can choose "file" and then select an asset from one of your asset sources.