Craft 3 Plugin: Unable to add a new method to EntryQuery

You know you don't add a new function to Crafts EntryQuery you create a custom Element type with a custom Query and add a function to that one. By the way you should probably fix your namespaces

use by\prefix\elements\db\BirthdateQuery;
use by\tariffsinfo\elements\BirthdateElement;

In order to use your function you'll have to do

BirthdateElement::find()->birthdate('whatever');

To search for a custom field in an entries FieldLayout you just need to call the parameter by handle... So when you include a field into the layout with the handle birthday you can do

{% set entries = craft.entries.birthday('whatever').all() %}

When you want to search for your custom element type in your frontend you'll have to include a function to Twig like Craft does

/**
 * Returns a new EntryQuery instance.
 *
 * @param mixed $criteria
 * @return EntryQuery
 */
public function birthdays($criteria = null): BirthdateQuery
{
    $query = BirthdateElement::find();
    if ($criteria) {
        Craft::configure($query, $criteria);
    }

    return $query;
}

So you can access it via

{% set birthdates = craft.pluginName.birthdays.id(2).birthdate('whatever').all() %}


Users not being deleted from the craft_users table?

Solved this one by adding SET foreign_key_checks = 0; to the beginning of the SQL dump and SET foreign_key_checks = 1; at the end of the file. Not sure if it is the best solution but it certainly worked.


How can I retrieve older versions of a custom entry type in bulk?

Okay, here's my stab at this. No doubt Brad will swagger in at some point, and declare that this can all be done with one line of trivial PHP.

Whatever, Brad. Moving on...

You can't use the ElementCriteriaModel to retrieve specific entry versions. This leaves you with two options:

Option 1: Use the Entry Revisions service

The EntryRevisionsService has a getVersionsByEntryId method, which does precisely what it says. If you're only dealing with a small number of Entries, this may suffice.

Option 2: Go old(ish) school

If the first option doesn't suit, you'll need to get your hands dirty querying the database, and populating EntryModel instances from the result.

Here's an example, to get you started:

$versionIds = [];

// Retrieve all the versions created before your "threshold" date.
$versions = craft()->db->createCommand()
    ->select(['ev.entryId as entryId', 'ev.id as versionId'])
    ->from('entryversions ev')
    ->where('ev.dateCreated < :date', [':date' => '2017-03-20'])
    ->order('ev.dateCreated desc')
    ->queryAll();

/**
 * Construct an associative array where the key is the entry ID,
 * and the value is the most recent entry version ID created _before_
 * your date threshold.
 */
foreach ($versions as $version) {
    if (!array_key_exists($version['entryId'], $versionIds)) {
        $versionIds[$version['entryId']] = $version['versionId'];
    }
}

/**
 * Finally, we can do something useful with our lives.
 * Retrieve the desired version of the entries.
 *
 * Note: you'll need to retrieve all of the required entry
 * columns, in order to populate your EntryModel. I've just
 * done a wildcard, you may wish to be more specific.
 */
$results = craft()->db->createCommand()
    ->select('e.*, ev.*')
    ->from('entries e')
    ->join('entrytypes et', 'et.id = e.typeId')
    ->join('entryversions ev', 'ev.entryId = e.id')
    ->where('et.handle = :handle', [':handle' => 'entryTypeHandle'])
    ->andWhere(['in', 'ev.id', array_values($versionIds)])
    ->group('e.id')
    ->order('ev.dateCreated desc')
    ->queryAll();

Now that you've retrieved the results, you'll need to convert each row to an EntryModel. This could be fairly trivial, or a living hell, depending on whether your Entries contains Matrix fields, Relationships, and so forth.

Note: I don't think it's possible to do this in a single query, but your GROUP BY fu may be better than mine.


Not the most direct way, but you could do something like this from your plugin's record:

public function createTable()
{
    // Let the base class do the actual work
    parent::createTable();

    // Change the PK auto-increment starting point.
    craft()->db->createCommand()->setText('ALTER TABLE myTable AUTO_INCREMENT=9999')->execute();

}


How to handle soft delete behavior for a custom Element with custom content tables

Yo, read the docs.

He says to himself quietly, having not visited the plugin docs in a while.


License alert message for mysite.com, but not www.mysite.com

I'm worried that Craft might suspend the license because of the two different domains.

That will never happen, but from what you're describing you shouldn't be getting that alert.

Can you hit up support@buildwithcraft.com with some details about the domain name?

Regardless, you should probably be picking one of those (domain.com or www.domain.com) and forcing the other domain to redirect to it for SEO reasons.  Otherwise, the all-mighty Google will treat them as two different domains.


How can I set a custom URI for the confirmation link of account email update from a front-end form?

I can't think of a clean way to do this because of this function

public function actionVerifyEmail(): Response
{
    // ..
    // snip
    // ..
    if (Craft::$app->getUsers()->verifyEmailForUser($userToProcess)) {
        // ..
        // snip
        // ..
        // Redirect to the site/CP root
        $url = UrlHelper::url('');  // <---- this is where we are
        return $this->redirect($url);  // ALWAYS redirect to root page
    }

    return $this->renderTemplate('_special/emailtaken', [
        'email' => $userToProcess->unverifiedEmail
    ]);
}

A clean way to achieve this is:

Handle it entirely on your own -> custom controller + custom service, send the mail manually
Create a custom route to you'll only take care about activating them and overwrite the actionVerifyEmail - unfortunately you can't replace the controller via Dependency Injection
Create a feature request and hope Pixel and Tonic will be kind enough to create a config variable / event to overwrite this value


Instead of using the chained syntax, you should build a parameter object and pass that in to craft.entries, like so:

{# Get a start date value from the URL (my use case) #}
{% set start_date = craft.request.getSegment(3) %} {# e.g. '2015-12-10' #}

{# Create a parameter object, with default values #}
{% set params = { section: 'events' } %}

{# If start_date exists, add the after parameter to the object #}
{% if start_date != "" %}
    {% set params = params | merge({ after: start_date }) %}
{% endif %}

{# Get the entries by passing the parameters to craft.entries() #}
{% set entries = craft.entries(params) %}


The 503 error that is triggered from that log entry happens when Craft files are in place on the server, but it haven't been installed yet and someone loads the front-end of the website.

Assuming you've set everything else up correct, you just need to complete step #5 in the install docs: https://craftcms.com/docs/installing#step-5-run-the-installer


Get disabled related entry's data within plugin

Came across this same situation myself. Was able to resolve with:

$entry->entriesFieldWithDisabledEntry->status(null)->first()


In Twig, you never want to use delimiters inside other delimiters (e.g. {{ ... {{ ... }} }}).

Here's how you would format it instead:

{{ wordBoldTitle | replace('#', '' ~ entry.title ~ '') | raw }}

What we're doing here is using Twig concatenation (via the ~ operator) to combine our first string (), whatever string entry.title results in, and then our second string ().

Alternatively we can use string interpolation to achieve this; however string interpolation requires double-quotes, so to do this we'll need to escape the double quotes already in our string:

{{ wordBoldTitle | replace("#", "${entry.title}") | raw }}

I also changed your replace filter from using a hash (e.g. {'#':'xxx'} to the simpler (at least in this case) comma-separated parameters. The hash works well if you need to replace multiple items, but the comma-separated parameters looks cleaner in my opinion when you only need to replace one item. You can find more about the replace filter formatting here.


Reorder selection of categories in category fieldtype

Based on Brandon's answer here, this is currently not a feature of Craft CMS (as of v3.0.34).

If you need this functionality, I'd look into doing one of the following:

As mentioned in the comments and in Brandon's answer (linked above), create a matrix field with a block containing a category field that is limited to one category. This will allow you to add multiple categories but be able to rearrange the matrix blocks as needed (thereby changing the order of the categories).
Build your own plugin to achieve this functionality. Also check the current list of available plugins, as it's possible someone else has already created a plugin to achieve this.
Open an issue on the Craft CMS repo (based on Brandon's answer though, seems like P&T don't really think selected categories need to get reordered, so not sure how far you'll get with this unless P&T have changed their minds).


You can ad {author.username} to the file upload field, that way their files will always be in the folder of the user.

With assets you can define scale sizes which works way better then forcing a fixed size. It doesn't stop someone from uploading a 36 Mp image though. As far as I know it's impossible to check the canvas size before upload.


Pagination / Custom Routes (Based on Entry Existing)

For generating the nav, this should work.

{% set allEntriesByWeek = allEntries|group("postDate|date('Y-W')") %}
{% for week, entry in allEntriesByWeek %}

{{ week }}

{% endfor %}

For grabbing entries (using the 'week' and 'year' variables passed via the route).

{% set startDate = now.setISODate(year, week) %}
{% set endDate = startDate|date_modify("+7 days") %}
{% set entries = craft.entries.section('events').postDate('and', '>= ' ~ startDate, '< ' ~ endDate ) %}
{% for entry in entries %}
    {{ entry.title }}
{% endfor %}

For pagination.

Next Week
Previous Week


How to Deploy CraftCMS to Dreamhost w/Github

I'd recommend against DreamHost, FWIW -> How Agencies & Freelancers Should Do Web Hosting

In any event, to do what you want to do, you'll need something that triggers on that when a push to GitHub or what have you happens. If you use Forge as a provisioner, that comes baked in.

If not, you can use a service like buddy.works or the like to do it for you. This is discussed a bit in the Setting up a New Craft CMS 3 Project article under the DEPLOYING CRAFT CMS section.

We also discuss it on the Website Deployment without Tears podcast on devMode.fm

...but the general idea is that something has to receive a notification from GitHub when you push to a particular branch, to kick off the deployment process for you. Here's what my deployment script looks like on Forge: My deploy script for Forge


PHP Error log in CP gives me 403 forbidden

Had the same problem. I my case, it was the following code in my nginx config file:

location ~* (?:\.(?:bak|config|sql|fla|ini|log|sh|inc|swp|dist)|~)$ {
    deny all;
}

After removing log| from the list, the problem was solved.


multi-select OR values to filter entries

Not an expert myself, but you can try .contains('OR', 'a', 'b', 'c', 'e')

However, rather than first fetch all entries and then filter them, I would look into using relations when looking them up, so that the initial result only contains the entries you're after.

Have a look at https://craftcms.com/docs/relations to get started, and don't be afraid to ask for help if you can't quite figure them out (I found them a little tricky myself when first attempting to use them).


I also got the second error when trying to create a new field and the solution for me was running

./craft clear-caches/all

after a refresh it started working again


Apache is generally hosted on Linux which the vast majority of web hosting services use. IIS is Microsofts platform and is much more difficult to set up as well as less common with hosting providers.

Just use Apache.


Yes. Use the RequireLogin tag at the top of a page:

{% requireLogin %}

  This tag will ensure that the user is logged in. If they aren’t, they will be redirected to the Login page, and returned to the original page after successfully logging in.

(make sure you are logged out before you test this!)


You can create different Redactor Fields with different settings/plugins. The easiest solution would be to create a redactor field only with your sub/superscript options so users can only insert those 2 things and no other html elements (bold, italic and so on).

You can search for an existing plugin or create your own to disable line breaks as well


So it looks like you're using the old syntax for SEOmatic 1.x for Craft 2.x; here's how you do the same thing in SEOmatic for Craft 3:

{% do seomatic.meta.seoTitle("Some Title") %}

c.f.: https://github.com/nystudio107/craft-seomatic#twig-templating


The actual web root name doesn’t matter. Usually it’s “public_html” or something similar, and Craft’s “public” folder is only meant to represent that folder.

There are no references to the public/public_html folder within Craft itself; it’s the other way around: The index.php file within public/public_html is the one referencing Craft, via its $craftPath variable.

So here’s what you need to do:

Upload the craft/ folder to your web server, ideally on the same level as your public_html/ folder rather than inside it, but if you don’t have permission to do that, inside public_html/ is OK.
Upload the public/index.php file into your public_html/ folder
Upload the public/htaccess file into your public_html/ folder and rename it to .htaccess
Open up public_html/index.php and make sure the $craftPath variable is a valid path to the craft/ folder, wherever it is.


You're almost there.

Every block returns a MatrixBlockModel, so you have to reference your block when getting the attributes:

{% for block in entry.threeHomepageImages.type('images') %}

{{ block.imageTitle }}

    {# Save images to variable for reuse #}
    {% set image = block.image %}
    {# Check if there is any images #}
    {% if image | length %}
        {# Get url #}
        {% set image = image.first().getUrl() %}

    {% endif %}
{% endfor %}


First, you need to import your macro, and not just call {{ _self.doPeriod() }}. From the documentation:

  When you define a macro in the template where you are going to use it, you might be tempted to call the macro directly via _self.input() instead of importing it; even if seems to work, this is just a side-effect of the current implementation and it won't work anymore in Twig 2.x.

I always do: {% import _self as self %}

slice returns a sequence - in your case an array with one element, and the key is 0. Your macro is expecting a matrix block, not an array, which is why you get that error.

If you only want the first block, then {% set period = timelineText.first %} and period will be a matrix block. {{ self.doPeriod(period) }} will work.

If you want to call doPeriod on all of the matrix blocks, then:

{% for period in timelineText %}
  ... {{ self.doPeriod(period) }} ...
{% endfor %}


GraphQL query entries by DateTime field between two dates

After trying multiple options found an answer:


I don't think there's currently anything in Craft that's going to help you here.

Ideally we'd track for dirty/changed fields in JavaScript on an edit entry page and pass that as a parameter into the onBeforeSaveEntry event.


Use the ~ symbol to concat strings.

//loop through all database entries
{% for val in entries %}
    .....
    Edit
    .....
{% endfor %}


How to load a template based on the first segment (and ignoring the second)

There are a lot of ways to go about this depending on how you have your sections and templates set up, and where you are getting your content from for both 'dinnermenu' and 'nextweek'.

Using routes

If you just want 'dinnermenu/nextweek' requests to be directed to the 'dinnermenu' template, then one option would be to set up a dynamic route with a '*' token as the last segment (i.e. dinnermenu/*). This would route example.com/dinnermenu/any-uri-segment to your 'dinnermenu' template ('dinnermenu.html' or 'dinnermenu/index.html' or whatever you called it).

In the dinnermenu template you can then test for the uri segment and display custom 'nextweek' content, in addition to (or instead of) your dinner menu content.

{% if craft.request.segments(2) == 'nextweek' %}
    // display content for next week
{% endif %}

See craft.request for more info.

Using a structure

For more dynamic nav you could also use a 'structure' (with 2 levels). In the template you can then test for the level and include the parent content as needed.

{% switch entry.level %}
    {% case "1" %}
        {% set dinnermenu = entry %}
    {% case "2" %}
        {% set dinnermenu = entry.parent %}
{% endswitch %}

{{ entry.intro }}     // dinnermenu's or nextweek's 'intro' field
{{ dinnermenu.body }} // with dinnermenu's body field

Using ElementCriteriaModel

If on the other hand, you want to pull your 'dinnermenu' entry into your 'nextweek' template (no matter where it is), then you can use an EntryCriteriaModel to retrieve and display the 'dinnermenu' entry.

{% set dinnermenu = craft.entries.slug('dinnermenu').first %}
{{ dinnermenu.body }}
etc.

You could also just include the whole 'dinnermenu' template in the 'nextweek' template.

{% set entry = craft.entries.slug('dinnermenu').first %}
{% include 'dinnermenu.html' %}

Lot of options.


Craft 3 CMS How to get all Channel Names/Titles

This kind of solved my problem:

{% for section in craft.app.sections.allSections %}
    {% if section.type == 'channel' %}
        {% set navBarLinks = navBarLinks|merge([section]) %}
    {% endif %}
{% endfor %}


How to add time for repeats date with Solspace Calendar

I don't think it's possible at all to set a different time for each recurrance. In that case, you'd have to add each date and time as a separate calendar entry.


Contact Form plugin - different recipients per locale

You could write a plugin, which hooks in the contact form's onBeforeSend event, and modifies the recipients.

Here's an absolute bare-bones solution which does exactly that (not tested in any way whatsoever):

<?php namespace Craft;

class ExamplePlugin extends BasePlugin
{
    // Standard plugin methods omitted for brevity...

    public function init()
    {
        craft()->on('contactform.beforeSend', function (Event &$event) {
            $event->toEmail = 'john@doe.com';
        });
    }
}

Whether or not this is "officially" supported is unclear.

The fact it's an event (as opposed to a hook) might suggest not, but the contact form does check whether any listeners modified the event data, as evidenced by its check of the isValid property.


The short answer is no. Craft does not natively support this, and there's no way to implement it via a hook (or event).

A quick browse through the code shows that the UserIdentity::authenticate method is where most of the action takes place (called from the UserSessionService::login method), and that's very much tied to using either a username or an email address.

Your only option is to implement a custom plugin, with its own controller endpoints, which handles login requests. You would then submit the login form to your plugin, rather than to Craft.

Such a plugin will, of course, need to follow all of the same security best practises as the current Craft "login" implementation, and be actively maintained in case any vulnerabilities come to light.


Query entries by custom date field (for a particular year)

I think your problem is you're converting the date to a year string then converting that to an atom value. Just convert the date straight to an atom value:

{% set yearStart = "#{year}-01-01"|atom %}
{% set yearEnd = "#{year}-12-31"|atom %}

{% set entries = craft.entries({
    section: "programme",
    isOngoing: 0,
    startDate: ["and", ">= #{yearStart}", "< #{yearEnd}"]
}).all %}


Sorting by date field across sections not working

Your second attempt is sound. I don’t really have an idea why it doesn’t work, but I bet it has to do with the SQL that is caused by setting the section param to an array.

What I would try next is the following, kind of a merge of your ideas.

{% set profileIds = craft.entries.section('profiles').limit(null).ids() %}
{% set eventIds = craft.entries.section('events').limit(null).ids() %}

{% set idParam = profileIds|merge(eventIds) %}

{% set timeline = craft.entries({
    id: idParam,
    order: 'GREATEST(eventDate, profileBorn) desc',
}) %}


Craft renders unwanted quotation marks on some tags

I believe the quotation marks are misleading... What you're seeing in the Safari developers panel is simply a blank space, and Safari is putting quotes around it because it's being interpreted as a "string" by the browser.

Equally, your visual layout is probably just getting screwed up because of empty space between your HTML tags. If you tightened up your HTML tags and removed any spacing in between, the layout might look as you expect it to.

You can easily trim whitespace around Twig tags by using spaceless, or adding dashes.

{% spaceless %}

{% endspaceless %}

Remove whitespace before:

{%- for entry in entries %}

Remove whitespace after:

{% for entry in entries -%}

Remove whitespace before & after:

{%- for entry in entries -%}


I had the same problem and all PHP settings were set OK. I couldn't upload a 2MB file, but uploading a 20KB file was fine.

The problem was that the /tmp folder was almost completely full (because PHP stores the temporary file in /tmp before moving it to web/user space i.e. your assets folder). Freeing up space in this folder solved the issue.


Laravel Forge not honoring Craft 3 maxUploadFileSize config setting

After doing some digging, this article helped solve my issue: https://stackoverflow.com/questions/36582004/increase-upload-max-filesize-via-forge.

By increasing the post_max_size in the PHP FPM Configuration and the PHP CLI Configuration I was able to resolve the issue and increase my upload limit to 256M.


The format of the include tag is

{% include 'template' with {var1: value1, var2: value2} only %}

What you need after the with is an associative array (an array with keys and values).

In your specific case you want this:

{% include "_macros/elements/listing" with {config: config} only %}


active state macro how to check if segment 2 is empty

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

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


filter entries by id retrieved from matrix block entry

If I do a similar test:

{% set myVar = ['10032'] %}

{{ dump(myVar) }}

That gives:

array (size=1)
  0 => string '10032' (length=5)

Just like yours.

{% set entryId = 10032 %}

{% if entryId not in myVar %}
    {{ entryId }} not in myVar
{% else %}
    {{ entryId }} is in myVar
{% endif %}

Outputs:

10032 is in myVar

As expected.  Changing entryId to something other than 10032 gives the expected "is not in myVar".

It should be noted that this line:

is in myVar {{ myVar }}

Will cause an array to string conversion error because you're telling Twig to output an array to the browser and it doesn't know how.


CDbCommand failed to execute the SQL statement

A 2006: MySQL server has gone away error generally means that (for any number of reasons) the connection between Craft/PHP and the MySQL server has been dropped.

Common causes are from connection timeouts and misconfigured MySQL settings like max_packet_size.

There are lots of debugging tips in the above link from MySQL's official documentation that would be a good place to start.  Additionally you might want to involve your host and let them know what you're seeing.


How would one go about migrating fields?

The Migrations

This is an ongoing issue. My best call is currently, to do the changes on production and to sync the DB locally.

I see a lot of folks, using plugins to "lock" the editing for the time, changes are being made. Sync to local, edit, resync to production.

As this is not satisfying, there was discussion with the Craft Team and the result is, for now, migrations coming to Craft 3.

https://craftcms.com/news/craft-3-content-migrations

This way you basically can create your own migrations from the command line. This should solve your problem, BUT: you should not use Craft 3 in production, yet.

Theming (off topic)

Something like theming is not possible and I think also won't be really in the future.

I solve this by having a Craft CMS dummy on github, which has most setup stuff I usually need (gruntfile, basic partials for matrices I use often). This dummy evolves over time and only includes some dummy files and folders like db.sample.php, general.sample.php and for the app a app.sample folder.

For basic content stuff I also use plugins like architect or the import/export plugin, to set up basic SEO fields and globals I usually use.

But most are missing a way to export groups etc. perfectly, but they do their job.

Hope that helps.


Paginate entries with 'page' query parameter?

I think this is what are you searching for:

http://buildwithcraft.com/docs/config-settings#pageTrigger


How to output transforms for retina images from one upload?

I'd like to use image transforms to output the retina images but need
  to preserve the width and height of the original as they vary in look
  and dimensions.

This statement kind of contradicts itself. :) You want to create different sizes, but keep the width and height of the original? My interpretation is that you'll always be uploading an image that's a number of times bigger that the @1x size? Let's say you always upload these images @3x, try something like this:

{% set myImage = entry.myImage() %}
{% set baseWidth = myImage.getWidth() / 3 %}
{% set baseHeight = myImage.getHeight() / 3 %}

<img
  src="{{ myImage.getUrl({ width: baseWidth, height: baseHeight }) }}"
  srcset="
    {{ myImage.getUrl({ width: baseWidth, height: baseHeight }) }} 1x,
    {{ myImage.getUrl({ width: baseWidth*2, height: baseHeight*2 }) }} 2x,
    {{ myImage.getUrl() }} 3x"
  alt="{{ myImage.title }}"
  width="{{ baseWidth }}"
  height="{{ baseheight }}">

Hope this helps.


Each session gets it's own CSRF token, so technically it will be valid as long as a session is valid.


Display Relating Entry based on Page Routing

Looks to me like there shouldn't be any quotes around craft.app.request.getSegment(3)

Also I'd use named parameters instead of .getSegment just seems a little bit more readable and robust.


How can I concatenate 2 variables to access array values?

I think you need to try and access the array that user.foo would have.
So your code would be something like:

 {% for user in plugin.data.users %}
  ...
  {{ attribute(user.foo, loop.index0)|raw|nl2br }}
  ...
 {% endfor %}

I haven't tested this though, just going by what I'm sure I remember doing once...


If other languages are not defined show english

You could choose which value to translate your content into using the |t($lang) filter based on some condition. You condition could be a lightswitch field on each entry saying whether it's been translated or not, or check if a content field is empty or not.

So something like

set lang = entry.lang

if entry.isTranslated == false {
   set lang = 'english'
}

{{ content|t(lang) }}


Categories or Structures: Most efficient way to organize FAQ sections

If your clients wants to have control about the order of the entries for each audience,  e.g.

 Trainee
 Advertising
    Ad Entry 2
    Ad Entry 3

 Associate
 Advertising
    Ad Entry 3
    Ad Entry 1
    Ad Entry 2

a good solution might be a entries field. The ability to simply drag and drop entries to change the order is the most intuitive option from my experience. If you have many entries you could combine both logics - e.g. render first all elements that you selected with the entries field and after that add the missing ones according to your categories / structure.


Moving site to new server - admin area not working

I'd start with debugging the control panel. If you enable devMode, and load the dashboard, you might see any error message that display on the screen that would give you a clue what's going on.

If it's not there, then some error message is probably being logged in your craft/storage/runtime/logs files that would help.  Open that files and do a search for [error] and look for any suspicious messages.


Freeform - Grouping fields from the form builder

It sounds like what you would ultimately need here is some sort of grouping of fields feature, which Freeform currently does not have. So I would lean towards saying there isn't a way you can do this purely in Composer, unless of course you had a very stripped down Formatting template, and relied heavily on HTML blocks inside Composer to simulate what you're after. :)


Yes this is definitely possible.
We don't use any of Commerce's in-built shipping stuff - fields or calculation, as it's too limited for our needs (not Commerce's fault - we have very complicated shipping requirements!).
You will want to write yourself a custom module with either a full custom shipping calculator, or an adjuster for shipping.
You'd use an adjuster if you don't need to present any options to the user, and a full shipping calculator if you do.  If the latter, as long as you implement the interfaces for Rules and Methods, you can do just about anything you wants and present it to the user any way you want.  Can be a little tough to get going, but is very flexible once you've got it working.
Docs for this are here:
https://craftcms.com/docs/commerce/3.x/shipping-methods.html


How can I show multiple entry types in the same page

And just to make sure: you are iterating over the results, right? because it actually should be:

{% set entries = craft.entries.section('businessProfile').type(['type1','type2]).all() %}
{% for entry in entries %} ...
... Here {{entry.type}} should be different
{% endfor %}


Craft Commerce cart timing out but allowing order to be processed

This is likely due to the item going out of stock while they were away from the cart, then when they went to pay, the item had to be removed from the cart, but they should have seen an error message when they tried to pay:

  Something changed with the order before payment, please review your order and submit payment again.

The secondary issue is allowing zero value orders. At the moment, zero value orders are allowed and payment gateways are not even called due to the payment due being zero.

On the client side, you could hide the payment buttons if the order value is zero.

We should introduce an allowPaymentOnZeroValueCarts type config option that stops these orders from coming through if dezired. I will add that to the next release.

I might also be a good idea to put some javascript on the page, that forces a refresh after a timeout.


Pull all assets from a specific volume subfolder id

Twig

{% set assets = craft.assets.volumeId(y).folderId(x).all() %}

PHP

$assets = Asset::find()->volumeId(y)->folderId(x)->all();


Duplicate Entry Types into a new section

You need to use a plugin to do this. I've used the architect for doing exactly this in the past. Just export the section and entry types you want to duplicate, rename the section in the json file, delete everything except for the section and entry type definitions, and import.


Check if the first block in a Matrix field matches one of an array of types

When you call entry.newsArticleContent.one().type, what you're getting is an instance of craft\models\MatrixBlockType (https://github.com/craftcms/cms/blob/develop/src/models/MatrixBlockType.php)

It just happens to have a __toString() method that will print out the handle when it's requested, but the if comparison you're doing is using the entire MatrixBlockType instance.

What you're looking for is:

{% if entry.newsArticleContent.one().type.handle  in ['fullWidthImage', 'imageGroup'] %}


The Tag ‘name’ property has been deprecated. Use ‘title’ instead

As mentioned in the comments by Brad, this is a bug and has been fixed in the next release.


Multiple relatedTo conditions using a combination of "and" and "or"

It seems that the relatedTo is by default an or, so you only need to define and once when the rest will be considered or e.g.
$query = Entry::find();

// Convert these IDs into Entries/Category models first.
$foodTypes = [1, 3, 5];
$weathers = [7, 4];

$query->relateTo([
    'and',
    ['targetElement' => $foodTypes],
    ['targetElement' => $weathers],
]);

return $query->all();

This will make sure each array passed into relateTo is considered an and group but the items within that are considered as an or group.


Impersonating a User from a plugin, with specific page redirect

Since this is an action in your own plugin's controller, you can literally do anything you want after the login happens.

if (craft()->userSession->loginByUserId($orderOwnerId))
{
    $this->redirect('https://www.reddit.com/');
}

  if I uncomment the $this->_handleSuccessfulLogin(true); line I get an error.

Because that's a private method you probably didn't copy over from Craft's UsersController.php.  You don't have to use it if you don't want to.

  it says the function is deprecated (https://craftcms.com/classreference/services/UsersService#handleSuccessfulLogin-detail)

Same method name (mostly), but not in the UsersController... it's on the UsersService.  It's also public, not private.


What is the difference between elements.enabled and elements_i18n.enabled?

If your section is enabled in multiple locales, each locale will get its own status lightswitch setting, which maps back to elements_i18n.enabled. It’s how you can have individual entries enabled/disabled on a per-locale basis.


Yes using the onPopulateLineItem event. Something like this should work:

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

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

    $lineItem->options = array_merge(
      $lineItem->options,
      ['customFieldLabel'=>$purchasable->customField]
    );

});


Matrix: get the index number of a certain block

You can use a custom counter instead of using the loop.index value.

{% set step = 0 %}

{% for block in entry.matrixBlocks %}
    {% if block.type == 'stepBlockType' %}

        {% set step = step + 1 %}
        Current step: {{ step }}

    {% elseif block.type == 'otherBlockType' %}

        {# Don't increase step count #}

    {% endif %}
{% endfor %}


Requesting SVGs from a plugins resources directory doesn't work

Actually, the resourceUrl() method doesn't care about the resource file's extension and is able to serve up SVGs (and any other filetype) just fine, so there must be something else wrong. Most likely, the path (i.e. cocktailrecipes/images/gin.svg) to the file isn't correct.

If your plugin has the handle cocktailrecipes (all lowercase; the handle should be identical to your plugin's folder under /craft/plugins), for your particular example Craft will expect to find your file under /craft/plugins/cocktailrecipes/resources/images/gin.svg – first thing to check, is if that file is actually in that location.


How do I retain form input values after submitting error-ridden form containing matrix field inputs

As you've discovered, your Matrix Field behaves a bit differently than many other basic fields.  The Matrix Field, is composed of several Matrix Blocks and, like Entries themselves, Matrix Blocks are Element Types.  So, you can access your value on a MatrixBlockModel in the familiar way that you know how to do already on your EntryModel, however, first you need to get to it which requires an extra step from the EntryModel you get back when a form fails validation.

When your Form fails validation, an EntryModel gets returned to the page.  This EntryModel can't be accessed directly but its attributes and methods can be accessed.  From the example you referenced:

{# Our Title can be found on our EntryModel like so #}
{% if entry is defined %}{{ entry.title }}{% endif -%}

{# And errors can be accessed on our EntryModel too #}
{{ entry.getErrors('title') }}

We can access our Matrix Field like our Title field or any other custom field, but since it's not a simple field, it gives us back an ElementCriteriaModel and we can't output anything without navigating further into the model and accessing each block and the fields within each block directly.

{# This will thrown an error "Object of class Craft\ElementCriteriaModel could not be converted to string" #}
{{ entry.matrixFieldHandle }}

{# But we can access the first block just like we would a single Entry or Asset #}
{{ entry.matrixFieldHandle.first() }}

{# And a field within that block in the same way we would a field on the EntryModel #}
{{ entry.matrixFieldHandle.first().fieldHandle }}

{# And the errors of those fields within a block in the same way we would a field on the EntryModel #}
{{ entry.matrixFieldHandle.first().getError('fieldHandle') }}

To navigate all the retained values and errors for your Matrix Field, you'll need to loop through the MatrixBlockModels of your matrix entry.matrixFieldHandle and output the values and errors within your template.


Ajax pagination not loading last entries if not equal to pagination number

This is just a math/logic error caused by:

// Increment count by 3 entries
count = (count) + 3;

if (count >= totalCount) {
    $("#loadMore").fadeOut();
    console.log('count is larger than total count');
}

Let's say you have a totalCount of 4.  If count was initially 3, then it will now be 6 and greater than totalCount and you bail, never loading the remainder of the results.

100% untested, but something like this should work:

$(function () {

  // load the first page of entries
  var page = 1;

  // set this equal to pagination number
  var count = 3;

  // Get the total count that we set above
  var totalCount = $("#totalRelatedCount").val();

  var diff = totalCount;

  $('#loadMore').click (function (e) {
      e.preventDefault();

      console.log('count is ' + count);
      console.log('total count is ' + totalCount);

      if (diff > 0) {
        $('#loading').fadeIn();

        $.get( "/{{ current_url }}/p"+page , function( data ) {

          $( ".remaining .feat-box-container" ).append( data );

          // this won't hide why not?
          $('#loading').fadeOut();

          // increase page
          page++;

          diff = totalCount % count;

          if (diff === 0) {
              $("#loadMore").fadeOut();
              console.log('count is larger than total count');
          } else {
              // Increment count by 3 entries
              count = count + diff;
          }

        });
      }

    });
});


Does Craft have a discussion forum and ratings add-on?

There is no discussion forum available in craft as of now but people that need that function seem to be using Vanila Forums and just integrating with single sign-on which seems to work just fine.

There is this which could work for ratings: http://plugins.supercooldesign.co.uk/plugin/button-box which is a bit simple but depends on what you need.

There is also this which could allow 'likes' https://dukt.net/craft/like

I thought I had seen something with a bit more advanced ratings but can't seem to find it now. At the end of the day though Craft > ExpressionEngine in pretty much every way. There are very few things EE can do better than Craft and even then it's usually due to a third party add-on being available there that is not yet available in Craft due to it's maturity.


pulling in an image from another section within a matrix loop

I'm not sure what {% for image in craft.assets.kind('image') %} is all about in your code since the image variable isn't being used anywhere.

But here's the basic structure on how you could loop through 3 separate Asset fields in 3 different single sections inside of a Matrix block:

{% for block in entry.homeMatrix %}
    {% if block.type == "homeMatrix" %}

        {% set firstSingle = craft.entries.section('myFirstSection').first() %}
        {% set secondSingle = craft.entries.section('mySecondSection').first() %}
        {% set thirdSingle = craft.entries.section('myThirdSection').first() %}

        {% if firstSingle.myAssetField|length %}
            {% for image in firstSingle.myAssetField %}
                {{ image.url }}
            {% endfor %}
        {% endif %}

        {% if secondSingle.myAssetField|length %}
            {% for image in secondSingle.myAssetField %}
                {{ image.url }}
            {% endfor %}
        {% endif %}

        {% if thirdSingle.myAssetField|length %}
            {% for image in thirdSingle.myAssetField %}
                {{ image.url }}
            {% endfor %}
        {% endif %}

    {% endif %}
{% endfor %}


How to duplicate a matrix field programatically in Craft 3.1?

I've just found this: https://craftcms.stackexchange.com/a/25961/9344.

After reading Robins comments, I can see where I was going wrong.

My working example code now looks like this:

protected static function createNewEntry()
{
    Event::on(
        Elements::class,
        Elements::EVENT_AFTER_SAVE_ELEMENT,
        function(ElementEvent $event) {

            // Ignore any element that is not an entry
            if (!($event->element instanceof Entry)) {
                return;
            }

            // Ignore entries that are new because they have no id
            if ($event->isNew) {
                return;
            }

            // Fetch current entry and assign siteid
            $masterEntry = Craft::$app->entries->getEntryById($event->element->id, $event->element->siteId);

            // Fetch matrix fields by handle
            $masterEntryMatrix = Craft::$app->getFields()->getFieldByHandle('matrixSchedule');
            // get the existing matrixSchedule value
            $masterEntryMatrixQuery = $masterEntry->getFieldValue('matrixSchedule');
            // serialize the data in order to get an array
            $masterEntryMatrixSerialized = $masterEntryMatrix->serializeValue($masterEntryMatrixQuery, $masterEntry);

            // Basic Craft fields...
            $newEntry = new Entry();
            $newEntry->sectionId = $masterEntry->sectionId;
            // more craft fields here...

            // Custom fields
            $newEntry->contentLongtitle = $masterEntry->contentLongtitle;
            // more craft custom fields here...

            // Matrix field
            $newEntry->setFieldValue('matrixSchedule', $masterEntryMatrixSerialized);

            $success = Craft::$app->elements->saveElement($newEntry);
            // Handle success/failure logic here...

        }
    );
}


Session key not timing out when set in a plugin

I think you're confusing Craft's userSessionDuration - which is the amount of time that you can stay logged into the control panel - with PHP's session (which is what craft()->httpSession is a wrapper for).

When you get logged out of the control panel, the former userSession is killed, but you still keep the same underlying PHP session ID and cookie.


How do I use divisibleby() in a for loop to display two columns?

Instead of using the divisibleby-function you can use the batch-filter:

{% for row in entriesInYear|batch(2) %}

    {% for entry in row %}

    {% endfor %}

{% endfor %}

If you have 3 entries in entriesInYear this code would output:


When you specifically group on dateField.day (in your case, the |group('datum.day') part), the group filter won't care about the month or year for the date field – only the day. This means that any entry posted on the 22nd of any month in any year will be grouped together, which is probably not what you want.

In this case, the solution is simply to group on the date field without a postfix (which will create an array index for each unique day/date):

{% set groupVerbund = 'datum' %}
{% set entriesByDay = allSubmissions | group(groupVerbund) %}

Additionally, I can't help but notice the
 tag inside your
, which is strictly speaking non-valid HTML. A better solution might be to do something like this (this would also save you a conditional):

{% for day, entries in entriesByDay %}

{{ day|date('d.m.Y') }}

            {% for entry in entries %}
                {{ entry.datum | date('d. M Y') }} | {{ entry.vorname }} {{ entry.nachname }}
            {% endfor %}

{% endfor %}

One final issue is sorting – you'll probably see the dates mixed up, which is just how the |group filter works – it only groups, and cares less about sorting. Basically, the group filter will return an array that looks something like this:

[
    '2016-10-22' => [array of entries],
    '2017-01-22' => [array of entries],
    '2016-11-13' => [array of entries],
]

...which means that if you want the output to be sorted by date, you'll need to sort that array on its keys (i.e. the dates) – something Twig's native sort filter regrettably doesn't do, but which is easily accomplished with the fantastic SuperSort plugin:

{% set entriesByDay = allSubmissions | group(groupVerbund) | supersort('ksort') %}


Switch Twig condition Case with OR condition (two values in the case)

This currently isn't a supported syntax for the Twig switch statement.

Craft will take that line and compile it down to:

case ("A1" || "A2"):

Which will always evaluate to true, which is why you always get the first result.

In order for it to work, it would need to be either:

case "A1":
case "A2":

To take advantage of PHP's fall-through support or the more ugly:

case ($context["bodyClass"] == "A1" || $context["bodyClass"] == "A2")


it is simple ! only edit php.ini file which is in your xampp folder . increase msql connection time and increase cache i.e limit size and that solve.


My guess is this is the cause:

'cacheMethod' => getenv('CACHE_METHOD'),

getenv('CACHE_METHOD') is probably returning null because that environment variable isn't being set like you expect or its set to an unknown caching driver.


How do I add Alt Image Tags to my photos?

Out of the box, you can use the image "Title" as alt text.  Since it is already configured - you don't need to add any additional fields.  Then you can output this in your twig template as:

{% set image = image.yourImageField.one() %}

For semantics, you may not want to use the "Title" field.  Or, you may be using "Title" for something else.  In that case, you can add a new text field to your asset called "Alt Text".  It will then appear right below "Title" in your image/asset editing dialogue.

{% set image = image.yourImageField.one() %}


Production siteUrl being used in staging environment

I found an existing solution to this. It turns out the order of the file matters and due to the "partial-match", my siteUrl was being set to the staging url and then overriden with the production url.

Proper order of multi-environment config

I'm going to use the solution outlined here
https://craftcookbook.net/recipes/foolproof-multi-environment-config


Allowing non staff users to access CP to post and edit posts?

You're right: there's no technical reason why you couldn't do what you're asking. When users start to add content for a site, they're now content contributors. And it can certainly make sense—depending on the site. When I think of "content sharing site", Craft could be used like a Wiki, for example.

The short answer? If you find yourself reinventing what Craft can already do, just give someone access to the CP.

A longer answer and reasons not to do it? Control. User experience. And trust/security all come to mind.

I just created a site for a client where individual teachers are able to post their class schedules and such and people are able to buy those classes (via Stripe). The client loved the CP. All the teachers were impressed about how easy it was to add their schedules. The CP was definitely a plus in this area.

However, the client properly scrutinizes everyone who wants to use the site (and their credentials) and there's a training period where we show people how to use the site, where to login, etc.  Your use case might be a little more streamlined if you have computer savvy users, etc.

While Craft is straightforward, if not downright intuitive, the CP might be overkill for someone just casually posting content once in awhile.   There still is a lot going on. And it really depends on what content you're managing.

From a traditional web context, the CP is a still little "disconnected" from the actual website. You still have to find the page you want to edit, or create a new one, preview it, and publish.  (That's why, IMO, things like "in-place" editors on are still popular with other CMS.... though I hate those things!)

Having the CP be disconnected is partially due to security. If you trust and properly vett your authors, or there's not much on the line,  I see no reason why you couldn't open up the backend.

As always, take good backups in case you have to roll back to something. That's true of any server, though. No software is perfect; if there's a vulnerability found for, say privilege escalation where a user could somehow become an administrator, the more users that have access to the CP, the more chances someone has to breach the site. Craft is relatively niche so you won't have the brute-force drive-bys that something like WordPress has. But as a site administrator, you can never be too vigilant.


FeedMe Direct Feed Link not showing in CP

Apologies for the confusion, this was updated in the latest Feed Me version, but not reflected in the docs (we're currently re-working them a little).

The direct feed link icon is no more - its not accessible on the first page where you set the name and URL.


How are people organizing their global sets?

Before I create any fields I try to plan them on paper. This helps me to create my first logical groups. It doesn't prevent changes later on, but at least reduces them a little.

Also all my global sets have prefix: global__settings, global__misc...

Now if I have to create a new set and move some fields, I can do a "Search & Replace" on all templates, and thanks to the prefix I don't have to worry about replacing the wrong variables.


Payment form submission is returning a curl error! ([curl] 3:  malformed [url])

For those interested, here was the solution: The payment method for Authorize.net wasn't completely filled in; there was no endpoint set. Thus, it was of course failing when it sent the curl request, because there was no protocol, domain, or anything else other than the query string for the payment form.

Providing the payment method with an endpoint in the CP resolved this issue.


Craft 2: Suspend user results in "Unauthorized You don’t have the proper credentials to access this page."

Is she trying to suspend another user who's an admin user?
I just tested this and your scenario would happen if she's trying to suspend an Admin's account.
A user who's has Admin privileges can only suspend another Admin otherwise you'd have users with lower-level permissions overriding those with higher level ones.
In Craft 3, you get a more clear message if this happens:


Is Craft's Email Service Protected Against Mail Header Injection Attacks?

Does the Craft email service have any protection / validation in place to mitigate against potential Mail Header Injection attacks

Yes.

Attacks like this, for the most part, are really only a concern for PHP apps that roll with their own custom email logic instead of using a widely used/tested email library.  Craft 2 uses PHPMailer and Craft 3 uses SwiftMailer.

And they both provide methods for stripping out newlines to prevent header injection attacks.


You can loop though your "myMatrixBlockName" blocks to get all the retailers' entry IDs. Then use that array of IDs in a craft.entries ElementCriteriaModel to get the entries you're after. Use fixedOrder as a parameter to maintain the Matrix's sort order if you want that.

{% set retailerIds = [] %}

{# Loop `myMatrixBlockName` blocks to get the retailers' entry IDs #}
{% for block in entry.mensPDPLinks.type('myMatrixBlockName') %}

    {% set retailerId = block.retailer %}
    {% set retailerIds = retailerIds|merge([retailerId]) %}

{% endfor %}

{# Convert `retailerIds` array into comma separated list #}
{% set retailerIdString = retailerIds|join(', ') %}

{# Get `retailers` in the same order as listed in the Matrix field #}
{% set retailers = craft.entries.id(retailerIdString).fixedOrder %}

{# Loop `retailers` #}
{% for retailer in retailers %}

    {{ retailer.title }}

{% endfor %}


Image not found with some transforms in english locale

If someone else happens to have the issue, here is what solved it for me: https://github.com/craftcms/cms/issues/1853#issuecomment-582353821


Why is Craft returning a 504 during a system update?

I've had this issue before.

It's usually to do with one of two things for me - either the PHP script timeout value or the FPM proxy timeout value.

Another method of fixing this is to change the update settings in the general Craft configuration:

'backupDbOnUpdate' => false,

Keep in mind though that you will need to back up the database yourself.


When to choose a Structure over a Channel?

Ordering and Hierarchy are the main benefits but they create a couple of side benefits such as the ability to

get the "children" and "parents" of an entry
get siblings including next and previous siblings

The best part is there no real downside, they have all the features and functions of a regular channel PLUS the structure.


Use .env values in Craft 3 plugin settings

You could try declaring the variable $youtubeApiKey with no value set. Instead of using
public $youtubeApiKey = '$YOUTUBE_API_KEY';

try using
public $youtubeApiKey;


It's basically the same as Find entries that use a specific block in their Matrix field?

You can use the base query and left join your Super Table content row

{% set entries = craft
    .entries()
    .section(['your-section'])
    .leftJoin('{{%supertableblocks}} as supertableblocks', '[[supertableblocks.ownerId]] = [[entries.id]]')
    .leftJoin('{{%stc_content}} as stc_content', '[[stc_content.elementId]] = [[supertableblocks.id]]')
    .andWhere(['>=', 'stc_content.field_date', entry.date|date('atom')])
    .groupBy('supertableblocks.ownerId')
    .all()
%}

Note: this is untested, maybe you need certain modifications it should just be some kind of guidance. Please keep in mind to replace your actual table and field names. I just used stc_content as a demonstration as well as stc_content.field_date


I don't recall the specific version/build and my search-fu is weak today, but this was a bug in Craft that should have been fixed in a semi-recent build.  Try updating to the latest and see if you still have the issue.

Update:

Every time we've been able to investigate this issue so far, it has been because of either .htaccess stripping querystring params behind the scenes (i.e. no [QSA] flag on the rewrite rule), or the equivalent in nginx-land.


Locales - New locales not copying assets across

Solved - What was needed was to use the Update Asset Indexes tool in the settings of craft. If I do this just after creating a new Locale, before doing anything else, when my articles are created they know where to look for their assets. So relieved

Also noticed that to get a matrix to copy across locales (as well as setting the matrix field to NOT TRANSLATABLE and the fields within the matrix to TRANSLATABLE) it was necessary to do a slight change to the original matrix after creating a new asset (such as adding a space after the title). This forced the matrix to copy across.

Hope this helps someone else


You'll want to set your cacheMethod config setting to 'redis' and create a rediscache.php file in craft/config/.

That config file is multi-environment aware, just like the other files in craft/config/ and you can see the default settings for Redis in craft/app/etc/config/defaults/rediscache.php.


Accessing Commerce product variant dimensions in the template

Dimensions are set and accessed individually:

{% set variant = product.defaultVariant %}

{{ variant.width }}
{{ variant.height }}
{{ variant.length }}
{{ variant.weight }}


Use of localeEnabled(): bug or misunderstanding?

It's a bit awkward, but you're understanding is correct.  My guess is you probably need to add a .status(null) to take into account the elements global status as well.  localeEnabled, by itself, just checks the element's locale status.


Listing categories with post count in a nav?

Within you nav loop, you would use the method total() with an craft.entries ElementCriteriaModel, to only count the entries that are related to the category you're looping. Pass the CategoryModel to the relatedTo parameter.

{% nav category in craft.categories.group('articleCategories') %}

    {# Get the count of entries related to `category` #}
    {% set entryCount = craft.entries.relatedTo(category).total() %}

    {{ entryCount }}

{% endnav %}


Take a manual back up of your database and then disable Database back up on the feed settings.

If you're using MAMP, this could be your issue.


Front end profile does not save data - form action

The answer is now included in the question. Don't be a dingbat and make sure MAMP or Apache (or whatever webserver you're using) is configured properly.


Solspace Freeform plugin: AJAX without jQuery – how?

From the action you are currently posting to a controller see here

The example shows that in your case it would be looking for a plugin called "Freeform" with a controller named "api" and then within that controller there would need to be a "form" action.  If this isn't there then the page will return a 404 or error as it cannot find the route.

You may be able to create the same thing without using jQuery with something like this method


I've just ran into this myself this morning. It looks to be related to the SmartMaps plugin doing an IP > Geo lookup using an external service.

Specifically it looks like it's using this api :https://geoip.maxmind.com/geoip/v2.0/ which is hanging.

Disabling the plugin fixed my loading issues.


The short answer is no, it is not possible.  The much longer answer I will add to your other question:

Setting Shipping Country and Method for the Cart screen


Feed Me: How to format CSV data for a table field

You can create a feed-me.php file under your /config directory, then you can configure the data delimiter:

<?php

return [
    '*' => [
        'pluginName' => 'Feed Me',
        'dataDelimiter' => '-|-',
    ]
];

On my side, that is not working all the time (if almost never), but the doc says it should!

(https://verbb.io/craft-plugins/feed-me/docs/get-started/configuration)

(https://github.com/verbb/feed-me/issues/449  ---> created just now)


So my issue was very simple to solve once I paid better attention. The 404 was loading perfectly fine the whole time, my problem was that in my 404 file I had it as {% block content %} and not {% block main %} as I had specified in my layout.


Cloudflare's CDN isn't a true CDN like Amazon, Rackspace, or Google.

With Cloudflare you host your assets on the server and Cloudflare then automatically keeps a cached copy of that.

In other words, you don't upload to CloudFlare, CloudFlare downloads from you.

So on Craft, simply use the "Local folder" source type.


Removing a matrix row via front end entry form

In the end I went with a slightly different approach, allowing users to remove multiple rows before submitting the form. Nod to this excellent article: https://caffeinecreations.ca/blog/editing-a-front-end-form-with-matrix/


Trouble getting entries after a certain date

This code works - I double checked. I had a bug further down in my code.

{% set fwd = entry.eventStartDate|date_modify('+30 min')|date('c') %}

{% set upcomingEvents = craft.entries
  .section('schedule')
  .order('eventStartDate asc')
  .eventStartDate('> ' ~ fwd )
  .limit(5)
  .status('live, pending')
%}


Manipulating the map in JS - [GM] Unable to find map

At a glance, it sounds like it's just a matter of waiting for everything to finish loading. You are trying to call a map which has not yet been initialized.
Good news! The tag method includes a callback option which allows you to specify a JavaScript function to be called after the map has finished loading...
{{ map.tag({
    'callback': 'moreJavascript'
}) }}

{% js %}
    function moreJavascript() {
        var map = googleMaps.getMap('mapAlpha');
        console.log(map);
    }
{% endjs %}

Take a look at this practical example of how someone could use the callback option to enable marker clustering... I know that you aren't trying to cluster your markers, but the broader execution is the same.


Getting database error when calling CateogoryService method

You don't show how you're defining the 'live', 'staging' and 'dev' keys for the multi-environment config, but most likely you just need to explicitly set the CRAFT_ENVIRONMENT PHP constant in your categories.php file to tell Craft which database credentials to choose.


Is it possible to include a thumbnail in an element type index view?

(Hopefully it is okay for me to answer my own question)

In the ElementType file, the getSources method needs to have the hasThumbs key set, as follows:

public function getSources($context = null)
{
    $sources = array(
        '*' => array(
            'label'    => Craft::t('All assets'),
            'hasThumbs' => true,
        )
    );
}

In your Model file you have to have a getThumbUrl method defined, as follows:

public function getThumbUrl()
{
    return $this->thumbnailUrl;
}

This results in a small thumbnail next to the title of your element, as seen in the screenshot:

The Craft 2 Class Reference helped put this together for me.


Somehow you would just need to communicate to your template that you are changing the default limit.

A fairly simple/standard way is through a query string, and then looking for the value of the variable.

The two things you need to accomplish are

Setting the query string if someone changes the dropdown box
Checking for a value of the query string key in your code.

To set a query string, you could do it a couple of different ways. The easiest way would actually be to submit your form:

<div class="grid-show">
    <form action="" method="get">
        <select name="limit">
            <option value="12">12</option>
            <option value="20">20</option>
            <option value="50">50</option>
        </select>
        <input type="submit" />
    </form>
</div>

The second step involves checking for the value of the query string within your Twig and if it's not set default to 12:

{% paginate craft.entries({
    section: 'holidayHomes',
    limit: craft.request.getParam('limit') ?? 12,
}) as pageInfo, pageEntries %}

If you wanted this to happen via Ajax it would be a bit more involved, but the principle is the same, ie look for a query string variable and use that as your limit.


Is there any way to hook into saving a plugins settings?

Take a loot at the prepSettings() function of your plugin.

http://buildwithcraft.com/docs/plugins/plugin-settings


While this question is a bit old, for the sake of completeness I'll echo what Brad mentioned in the comment above.

Plugin bugs are best handled by notifying the developer directly. This plugin happens to be on Github and it appears that the developer has responded to all open issues and closed them out.

Additionally, the convention for tagging Stack Exchange posts that are related to plugins is to prefix the plugin's name with the word plugin. In this case, a good tag may be plugin-craftmailer or plugin-mailer.


This is what the function currently does

public function tweetButton($options = [])
{
    $dataAttributes = $this->getOptionsAsDataAttributes($options);

    $html = 'Tweet';

    return $html;
}

So it returns an a tag rather than a link. You should remove your outer tag but you can't place your custom text. You would have to use a string replace function

{{ twitterTweetButton()|replace({'>Tweet<':' >my custom text<' }) }}


404 message after following Craft installation instructions

How did you create the database?
Did you use phpMyAdmin or did you create it manually, or using other tools?

I've had a similar 404 error last week (db was created with phpMyAdmin) then I created database with Sequel Pro and that resolve the problem.


Search with string, entry type and category

A more elegant way to handle it would be to use PHP, rely on a more complex routing system with default values, don't rely on segments but on routing parameters. Use real URLs instead of relative paths and build your URLs dynamically instead of just inserting the string hard coded in order to be able to filter by multiple values without loosing the already set filters.

However - to include your parameters all you need to do

{% set searchResults = craft.entries
    .search(searchTerm)
    .section('resources')
    .type(resourceType)
    .orderBy('score')
    .relatedTo(resourceCat)
%}

I would create a dynamic rule

$event->rules[] = [
    'pattern'  => '/resources/<type:\S+>/<category:\S+>/<search:[a-zA-Z0-9-]+>',
    'route'    => 'module/search/search-elements',
    'defaults' => [
        'type' => '',
        'category' => '',
        'search' => '',
    ]
];

and search in PHP

public function actionSearchElements(string $type, string $category, string $search)

You can then create a Twig function/filter in order to change those

ebooks

to something like

ebooks

And build your URL based on your route params + overwrite the new category. It will make it more re-usable and easier to change in the future if you would like to add an additional parameter or need to change the order you only need to change one place instead of many


There already was a warning about it, but it didn’t really stick out, I guess.

Just gave it the actual Warning style treatment, so hopefully this helps the next guy:


Setting User Permission to hide products of other user

This sounds like a feature request really.  And/or possible a use case for Craft 3s forthcoming multi-site features.  Although C3 + Commerce for it is a ways off yet (6 to 9 months apparently)

You could perhaps use something like a custom field for the 'owner' of each product, and Zenbu to set up filtered views for each of the editors (just guessing, I've not used Zenbu personally)

https://zenbustudio.com/software/zenbu-craftcms


composer.json and composer.lock aren't technically the only files that change; for example some of the files in the vendor folder change each time you update. If you're using Project Config, occasionally the project.yaml file will change if a plugin update makes some data architecture changes or something.

Some Info on Composer and Craft and Updating

The only time composer.json would change on an update is if you ran the update via Craft's updater. When you use Craft's updater, it disregards what is specified in the composer.json; it does its own checking and when it updates a package it locks the packages down in the composer.json to that particular version number. However, when you use composer update to do your updating, it will use what is specified in the composer.json to do see if there are any new versions that match the specified semantic versioning constraints (semver); running a composer update changes nothing in your composer.json file.

Here's an example of what the difference might look like:

1) "nystudio107/craft-seomatic": "3.2.3",   // Craft updates style (note the absolute version number)

2) "nystudio107/craft-seomatic": "^3.1.0",  // Composer semver style (note the '^')

When you run Craft's updater; it won't matter which of these lines you use. Craft will do its own checking and overwrite the current semver as necessary. If you use composer update, #1 won't allow you to install anything other 3.2.3 because that is what is explicitly declared; #2 will allow anything that fits 3.X.X. So if you've used Craft's updater in the past, you'll need to manually add ^ or ~ to your version numbers before composer update has any affect.

The composer.lock file works quite similarly to the way the Craft updater uses the composer.json package version numbers. It's basically a big file that contains the installed version number (as well as a bunch of other stuff) of every single package as well as all the dependencies. It changes any time you update, whether via Craft or composer.

Then you've also got composer install which behaves differently than composer update. composer update takes the semver provided in the composer.json file and checks to see if any newer version that fits the constraints are available, if so it installs it. composer install looks in the composer.lock file and installs whatever is specified there. This means that running composer install on an existing codebase should have no effect provided everything's previously been installed.

A Typical Craft Upgrade Strategy

Here are the typical steps for updating your Craft sites locally and pushing those changes to a live/production server.

Depending on whether you use Craft or composer for your updating:

Run composer update locally. Again, this fetches any newer package versions that comply with the semver, installs them, and makes the necessary changes to the composer.lock file. OR
Run Craft's updater locally. Again, this fetches any newer package versions, installs them, and makes the necessary changes to the composer.json and composer.lock file.

Depending on the nature of the updates, you may need to run a database migration locally. You'll also want to quickly test your site and make sure nothing broke because of the updates.
You'll commit the changes to composer.lock (and if you used the Craft updater, the changes to composer.json) and merge branches / push to your remote Git repo per your typical process.
Usually you'll have some sort of deployment process setup (Buddy, DeployBot, Laravel Forge deployments, etc) that watches your remote Git repo and does a deployment every time you push. This deployment usually looks like a git pull of the latest changes and then, depending on your deployment tool of choice, this next step might be done on the deployment server and the resulting files pushed to the live server or it might be done on the live server itself...
You'll typically need to do several things as part of the final step of the deployment process:

Run composer install - remember, this takes that composer.lock file (which is now different from the files in the vendor folder on the live server) and installs anything it can (i.e. if the lockfile and the vendor folder agree on a certain package, it skips it; otherwise it updates it).
Run your database migration on the live site.
If you're using project config, and the project config file changed during the updates, you'll want to sync any changes there.
Finally you'll want to clear caches so you get the latest and greatest on the frontend of your site.

These steps take some time to do manually, which is why it is a good idea to automate them. You can run them all via the CLI via your deployment tool, but an even better idea would be to add them to the scripts in your composer.json file. For example:

...
"scripts": {
  "post-install-cmd": [
    "@php craft migrate/all",
    "@php craft project-config/sync",
    "@php craft clear-caches/all"
  ],
  ...
},
...

If you add that to your composer.json, any time you run composer install those other three commands will be run directly after.

My apologies on the short answer, I was pressed for time. JK lol


MyPluginVaraible Note the spelling of the highlighted word...


Unknown error occurs on every AJAX call in CP

This will be a environmental configuration issue. The only reason you could get that error is if your web server either isn't setting the global $_SERVER['HTTP_X_REQUESTED_WITH'] variable or it is setting it and it's a value other than XMLHttpRequest.

https://github.com/yiisoft/yii/blob/1.1.17/framework/web/CHttpRequest.php#L679

I'd check the server config and make sure there's nothing odd in your .htaccess files (if on Apache) that might be interfering.


Unable to set slug to value used previously

There probably is still an (maybe corrupted) entry in the db with that slug. Have a look at the entries-content table, sort it by slug and you possibly see an entry responsible for your problem.


Include results in "Object of class Craft\ElementCriteriaModel could not be converted to string"

Well I now see this error was caused by the included template and not the fact that I was trying to include a template.

I thought that the error message would show the error on the included template that was the actual source of the problem, but it was just referencing the include as the error.


To get all .mp4 files:

{% set mp4s = craft.assets.filename('*.mp4').find() %}

To get the first .mp4:

{% set mp4 = craft.assets.filename('*.mp4').first() %}


The problem is that item.defaultVariant will always be true even for products without visible variants (see docs on that), so you can't test for it.

You don't really need to test for it though - just look first for images held against the product, and fallback to images held against the default variant like this:

{% for item in craft.products.all() %}
    {% set imageThumb = item.variantThumb|length ? item.variantThumb.one() :
        item.defaultVariant.variantThumb|length ? item.defaultVariant.variantThumb.one()
    %}
    <img src="{{ imageThumb.url }}">
{% endfor %}


Retrieving entry just after saving it returns null

Searching for an Element by Title, as you describe, is potentially problematic as the Title is not required to be unique. But may not even be necessary in your case.
The $entry object that you pass to the craft\services\elements::saveElement() method will get updated in the same scope that you are running the saveElement code. It appears that you are already accessing that same $entry object when you are using it to throw errors.
See the Objects and References page in the PHP docs for a discussion of the behavior.
Here's a rough update of your code per that expectation:
$entry = new Entry([stuff here]);
$entry->title = 'foo';

if (!Craft::$app->elements->saveElement($entry)) {
  dd($entry->getErrors());
}

// No need to query, you can already access the Entry you just saved
$entry->title

// If you need to query, you could do so via the ID
// from the Entry Element object you just saved:
$entry = Craft::$app->elements->getElementById($entry->id);
$entry->title

Is there a reason you need to query the Element again right after you save it?


In Craft Commerce, is it possible to make the product variant weight a required field?

Yes you can, using the Model::EVENT_DEFINE_RULES Put this in your customer module or plugin.
        use craft\commerce\elements\Variant;
        use craft\base\Model;
       use craft\events\DefineRulesEvent;

        Event::on(
            Variant::class,
            Model::EVENT_DEFINE_RULES,
            function(DefineRulesEvent $event) {
                $rules = $event->rules;
                $rules[] = [['weight'], 'required'];
                $event->rules = $rules;
            }
        );


I'm not aware of any articles or best practice documents.

There is a sample/simple PowerNap plugin that shows the basics of creating and running a task as well as the TaskService class reference documentation which you've already found.


How can I return data from a Matrix field in random order?

You can either have MySQL select the blocks in a random order using RAND():

{% set blocks = entry.myMatrixField.order('RAND()') %}

Or you can shuffle the blocks from Twig instead, using Craft’s shuffle() function:

{% set blocks = shuffle(entry.myMatrixField) %}

There’s not a major performance difference either way in most cases, however if you also want to limit the number of blocks, each method will give you different results.

For example, this will pick 3 blocks at random out of the entire set:

{% set blocks = entry.myMatrixField.limit(3).order('RAND()') %}

But this will always pick the first 3 blocks, and those 3 blocks will be displayed in a random order:

{% set blocks = shuffle(entry.myMatrixField.limit(3)) %}


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

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


Missing Position Field Type in Matrix (Craft 3)

The "Position" field type is retired in Craft 3.

You can use this: http://plugins.supercooldesign.co.uk/plugin/button-box, or this https://github.com/Rias500/craft3-position-fieldtype instead, or just use plain old dropdowns.


When you take a look at the documentation the interface for the update function is the following.

public integer update(string $table, array $columns, mixed $conditions='', array $params=array ())

Thus your code should look like:

public function updateUserName($userId, $updateUser)
{
    $update = craft()->db->createCommand()->update(
        'contest_user',
        array('name' => $updateUser),
        'id=:id',
        array(':id', $userId)
    );

    return $update;
}

You can see a working example here:

// build and execute the following SQL:
// UPDATE `tbl_user` SET `name`=:name WHERE id=:id
$command->update('tbl_user', array(
    'name'=>'Tester',
), 'id=:id', array(':id'=>1));


I'm going to guess that the id for the new product entry doesn't yet exist when the sku is being generated....it's probably created at the end of the save process once Craft is sure the save will complete.

Do you really need to use the ID in the sku?

(I don't immediately see an obvious in built way around it either, but perhaps someone cleverer than me will come along with a good idea).


Commerce: How can I check if I am on a specific product page?

You can use the same approach as the link provided in your question. Only, instead of an entry, you're working with a product.

For example:

template.twig

{# Get the current section - set fallback(s) for entries or products or ?? #}
{% set section = entry.getSection() | default(entry.getSection() ?? product.getType() ?? null) %}
{% if section %}
    {% set handle = section.handle %}
    {{ handle }} {# myProductType #}
{% endif %}

Here we are checking if we're on an entry. If not, we've set a fallback to check if we're on a product page. If nothing, the we return null.

Once we've got our section, we can check the handle. Then it's a matter of checking for the type you are looking for.

...
{% if handle == 'myHandle' %}

We've got a winner!

{% endif %}


Plugin Routes: Asterisk Token effect from CP Routes

You can't have tokens in your plugin routes, but you can easily add a segment variable that recreates the asterisk token's functionality with some regex. According to the the official docs on routing, the asterisk represents

  (...) any string of characters, except for a forward slash (/)

Here's what the defintion for a route with a "asterisk-like" segment could look like:

public function registerSiteRoutes()
{
    return array(
        'myroute/(?P<asteriskToken>[-\w]+)' => array('action' => 'myPlugin/myAction')
    );
}

Note that the string "asteriskToken" will be the variable name for this route segment's value when it is passed to your controller. It could be named anything.

The above route will match any URIs such as

/myroute/whatever (asterisk token will be "whatever")
/myroute/123 (asterisk token will be "123")
/myroute//foobar (asterisk token will be "foobar")

Coming to your controller, here's how you could look up the asterisk token variable's value:

public function actionMyAction( array $variables = array() )
{
   $asteriskToken = $variables[ 'asteriskToken' ];
}

Be aware that any calls to /myroute (i.e. without the second segment) will now 404. If this is unwanted – or if you want to define a default value for your asterisk variable – you can make the asterisk token segment optional. This is done by wrapping the segment variable in parentheses and appending a question mark at the end (kudos to @carlcs for this trick, originally given as an answer to my question here:

'myroute(/(?P<asteriskToken>[-\w]+))?' => array('action' => 'myPlugin/myAction')

With the latter regex, your route will now also match the following:

/myroute (asterisk token will be undefined)

...and in your controller, here's how you could define a default value for the asterisk token variable:

$asteriskToken = isset( $variables[ 'asteriskToken' ] ) ? $variables[ 'asteriskToken' ] : 'myDefaultAsteriskValue';


How to change the Entry status to enabled from Disabled

I think so, if they are required fields. You'd just add them as hidden fields and there wouldn't be any additional database queries because it's already fetched the entry anyway.


Can a Table Column be Rich Text / WYSIWYG?

I think that's actually a table field type you are referring to, not a Matrix Field Type.

Matrix field types can indeed have Rich Text. There are a lot of instances where a Matrix field can be used in place of a table field.


So I've been playing around with this and got stuck a few times, but I think I have a solution that could work for you.

I think the problem is actually because craft()->templates->render() simply just gives you the compiled template back, it doesn't try and render it in the browser. So your plugins init method is being hit, everything is working just fine, then it just goes past it and just keeps going until the end.

There is a controller method for rendering a template which is called like $this->renderTemplate which according to the docs:

  This is a shortcut for TemplatesService::render(), but rather than returning the rendered template, it will output it to the browser and end the request. It will also include any CSS and JS that is queued up via includeCssFile(), includeJsFile(), et al., and it will set the appropriate MIME type header based on the template file’s extension.

You can see the method from the Class reference here

Now I don't think you can or should try and call controller methods from within your plugin's init, so I think you need to do something inspired by this method i.e just echo the content and end the request.

So this is what I have used and it worked for me just fine, it might need some tweaking and more inspiration from the renderTemplate method, but it works as a start.

if (craft()->request->isSiteRequest()) {

  // Get your entry however you wish
  $entry = craft()->entries->getEntryById(264);

  // Render the template with $entry and set it to output
  $output = craft()->templates->render('arena', ["entry" => $entry]);

  // ** From renderTemplate **

  // Output it into a buffer, in case TasksService wants to close the connection prematurely
  ob_start();

  echo $output;

  // End the request
  craft()->end();
}

From this i got a rendered template in the browser, output the entries title using {{ entry.title }} and also all the {% extends %} {% block %} tags and everything else seemed to work.

If there is a better solution then i'm all ears, but this is what I could come up with from looking around the source/docs/stackexchange.

Hope that helps :)


You can define different permissions in Craft CMS, if you are not admin its likely someone restricts your access.

Furthermore you can't delete entries in a section of type single - those entries will always exist


Twig Runtime Error on settings/general (value: system.name)

You might need to fix this manually.
Open your config/project/project.yaml and make sure that the system object has all the following keys in there (you seem to be missing name):
system:
  edition: pro
  live: true
  name: Site Name
  retryDuration: null
  schemaVersion: 3.6.6
  timeZone: Europe/Paris

Once you have done that, run ./craft project-config/apply and the error should go.
Note that the schemaVersion is for Craft 3.6.11.1.


Count table field values in certain section

You can get the total amount of rows like this:

{% set totalcount = 0 %}
{% for entry in entries %}
    {% set totalcount = totalcount + entry.artikelnummer|length %}
{% endfor %}

Edit

In the loop you add the length to the totalCount.


Conditional variables within a certain matrix block type

Why don't you do something like this? You can use switch and case to change the output of each part of the matrix (we call them blocks).

This is part of a snippet to output a documentation matrix that contains code, titles, content etc.

{% for block in entry.documentation %}
    {% switch block.type %}

         {% case 'subsectionTitle' %}

{{ block.subsectionTitle }} #

        {% case 'description' %}

{{ block.description }}

    {% endswitch %}
{% endfor %}


Please try the following code:

{% set dynamicMenu = menutype~".menuGlobal" %}

{% for block in dynamicMenu %}
.
.
.
{% endfor %}


Checking permission for editing entries from inside template

In Craft 3.1, permissions checks are done based on uid now, not id.

This should work:

{{ currentUser.can('editEntries:'~entry.getSection().uid) }}


How to manually run pending tasks in Craft CMS 3

Craft 3 default action to run the queue is

public function actionRun(): Response
{
    // Prep the response
    $response = Craft::$app->getResponse();
    $response->content = '1';

    // Make sure Craft is configured to run queues over the web
    if (!Craft::$app->getConfig()->getGeneral()->runQueueAutomatically) {
        return $response;
    }

    // Make sure the queue isn't already running, and there are waiting jobs
    $queue = Craft::$app->getQueue();
    if ($queue->getHasReservedJobs() || !$queue->getHasWaitingJobs()) {
        return $response;
    }

    // Attempt to close the connection if this is an Ajax request
    if (Craft::$app->getRequest()->getIsAjax()) {
        $response->sendAndClose();
    }

    // Run the queue
    $queue->run();

    return $response;
}

So all you need is Craft::$app->getQueue()->run(). Every Craft 3 project comes with a default module so you can Enhancing a Craft CMS 3 Website with a Custom Module or if You Wanna Make a Craft 3 Plugin?


Add Database Relationship to craft_user table from a Plugin

So it looks like I had a couple of things wrong here.

The type of relationship I was trying to use.
The fact that I was trying to add an extra unique index.

To solve the problem, what I ended up doing was this:

Remove my user_id column.
Remove the defineIndexes() definition altogether (you'll see why in a minute).
Change my Relationship definition to this:

public function defineRelations()
{
  return [
    'user' => [static::BELONGS_TO, 'UserRecord',  'id', 'required' => true,
                    'onDelete' => static::CASCADE],
  ];
}

So what this ended up doing was using the id column that is automatically created as both a Primary Key and a Foreign Key related to the craft_user table.

The reason I wanted to do this, is my new table which I'm creating is actually just an extension of the craft_user table anyway. There will be only ever one row per User (which is made unique by the Primary Key index) and the Foreign Key makes sure that only values that exist in the craft_users id column are allowed in the id column of my new table.

For completeness, the reason I was getting the error mentioned in the question was because I'd set the user_id column to 'required' => true. As I'd not used the onDelete property on the relationship, it was defaulting to ON DELETE SET NULL. It can't be both, either it must always have a value or it can be set to NULL.


Internal Server Error - getDateFormatter() on null

Craft support had suggested looking into the locales table, which had a singular entry for en_us.

What allowed me to update was to copy the following folder and its content: app/framework/i18n/data. It was entirely missing from the Craft-2.7.8.zip file I had downloaded.


Using search criteria in modifyEntrySources plugin

My solution, thanks to @carlcs:

public function modifyEntrySources(&$sources, $context)
{
    $sources[] = array('heading' => Craft::t('Themes'));

    $themes = array(
        'THEME_FOO' => 'themeFoo',
        'THEME_BAR' => 'themeBar'
    );

    $criteria = craft()->elements->getCriteria(ElementType::Entry);
    $criteria->section = 'article';
    $articles = $criteria->find();

    foreach ($themes as $theme => $label)
    {
        // Loop through all articles and check if they contain the current theme.
        // If they do, add it to the ids array which we will later use to filter
        // just the articles with this theme.
        $ids = [];
        foreach ($articles as $article)
        {
            foreach ($article->theme as $articleTheme)
            {
                if ($articleTheme == $themes[$theme])
                {
                    array_push($ids, $article->id);
                    break;
                }
            }
        }

        $sources['theme:' . $label] = array(
            'label' => Craft::t('Theme') . ': ' . Craft::t($theme),
            'criteria' => array(
                'section' => 'article',
                'id' => $ids
            )
        );
    }
}

The PHP itself could be cleaned up, but this works for now.

Categories would probably have been a simpler solution had I gone for that originally.


Extracting an attribute from top level node of a Feedme XML feed using template

It appears now that this is an issue with the plugin being unable to read attributes of a node which has sub-nodes. The developer has noted this, and will hopefully post a fix. In the meantime as work around I used a short php script on the server to call the XML file first and rework the data into a format that the plugin can read.


Craft 3.6 Upgrade errors - can only install one of yiisoft/yii2 (and other errors)

I found the fix here
composer install --ignore-platform-reqs


Craft Commerce: Soft Delete on Payment Methods?

Commerce soft deletes payment methods instead of hard deletes them because even if a payment method is no longer in use, you still need to be able to have a reference to them for existing orders.

You can "un-delete" the payment method by going into the craft_commerce_paymentmethods table in the database and changing the isArchived column from 1 back to 0.


How can I return only 1 random block in a Matrix in Craft using Twig?

You can create a random order by including rand() in your OrderBy function.

{% set randomBlock = entry.carouselMatrix.orderBy('rand()').one() %}
{% if randomBlock is not null %}
    {% set randomSlide = randomBlock.slides.orderBy('rand()').one() %}
    {% if randomSlide is not null %}
        {{ randomSlide .caption }}
        {% set image = randomSlide.image.one() %}
        {{ image is not null? image.getUrl() : '' }}
    {% endif %}
{% endif %}


What is the least intrusive way to allow a user to change their email address on the front-end?

On the front-end of the site, if you're going through Craft's UsersController->actionSaveUser(), then you're correct... we do require the current user's existing password to create an elevated session for several security purposes.  How you present that to the user is completely up to you (as with anything else front-end related in Craft).

If you absolutely, 100%, don't want that workflow and are willing to accept the security risks of bypassing that behavior, then you can create your own plugin that exposes its own controller action, point your form to it and do whatever necessary business logic needed (modifying email directly in the database, etc.).


How to display a specific image from Assets field

I can do something like this and it will display all featured images but will require looping through the entire image set for each entry.

{% for image in entry.image %}
    {% if image.featured | length %}

    {% endif %}
{% endfor %}

Also came up with another solution that goes through the images until it finds a featured image and then stops. If no featured image is found it displays the first one.

{% set break = false %}
{% for image in entry.image if not break %}
    {% if image.featured | length %}

      % set break = true %}
    {% endif %}
{% endfor %}

{% for image in entry.image.limit(1) if not break %}

    {% set break = true %}
{% endfor %}


GraphQL two image transforms for same field

Untested, but should work:

image {
   foo: url @transform ([width: 300, immediately: true])
   boo: url @transform ([width: 600, immediately: true])
}

You can rename fields by just adding a new field name (ex foo:) before it in graphQL. The field name should not be one the object already has as it would overwrite the original field in this case.


Setting Shipping Country and Method for the Cart screen

I agree with the basic underlying premise that showing full cost - i.e. with shipping - is essential on the cart index page for a modern checkout.  Customers loathe what they see as a hidden surprise if they hit shipping costs later in the process and your completion rate plummets in my experience.

Luke's answer is right about the root cause of the issue - Commerce currently requires a customer with a valid 'address' before you can set shipping on the cart, and a 'valid address' is (out of the box) at least a firstName and a lastName .  You can definitely throw a countryId in a hidden field as a default, but only in addition to setting the address details.

This has become without doubt my least favourite thing about Commerce as it currently stands, and I have spent WAY more time on solving this problem than anything else in Commerce.  To be fair I really should have discussed this a lot more with Luke (Holder, not Pearce above!) - as I really think this needs to be solved (by Commerce) sooner rather than later for a sophisticated checkout flow to be achievable without too much hassle.  But at a certain point I was too far along to contemplate going back to scratch with it (as I will have to once a proper fix comes I guess!).  So I've hacked away at it and have it all working pretty well.

So what ARE your options (I've tried all three, and none of them are great):

From easiest to hardest:

Create a fake 'address' for your customer (I used Mr. Shipping Quote for this) - i.e. set firstName Shipping, lastName Quote, and have a select for your countries I guess -> so that you can then use standard methods to set shipping on the cart, and then on your shipping page basically update this with the actual details when you get them
(as per Luke above) - Write an adjuster to add this shipping until such a point as you do get an address, then once you do make the adjuster adjsut to $0...as you'll then have shipping set on the cart appropriately 'for real'
(And this is what we do on imagescience.com.au for a variety of reasons) - write a shipping plugin of your own and ALSO give this an option of being called by controller separate to all the regular shipping stuff in Commerce- so that you can then do a bit of fancy JS on the front end to add the result of the controller to the cart totals on your cart page.  That is, fake it totally until late in your checkout when you really do have an address.

Of these, I think option 1 is about as far as you want to hack in most situations.  Depending on your checkout flow, and how fancy you want to get with address handling/customer address libraries, this can potentially be a relatively simple fix for the issue.  It works for basic scenarios, you basically just need, on your address input form, to test for the Shipping Quote values for those fields and if those are set, display blank fields for user input.

Option 2 was where I started and could also work, but it gets fairly fiddly fast and it seems a shame to just abandon all of Commerce's shipping stuff - seemed more future proof to not do it this way, to me.  But in retrospect I'm not sure about that, this may have proved easier than option 3 in the end...

Option 3 is actually diabolical to get right.  But, it can solve pretty much all the problems.  However, there are MANY complications with it because if you allow a flow back and forth between your cart/shipping/payment pages, there are a bunch of scenarios that arise to do with the possibility that the cart MAY or MAY NOT not have shipping on it, and/or DOES/DOES NOT have coupons, discounts applied - to make it work consistently you have to do stuff like manually summing the lineItem totals etc.  It works, but it's a right mess if you want a really flexible checkout flow - and it's a lot more complicated than it initially looks.  Add to that address handling such as deleting addresses, adding new ones for billing/shipping etc along the way, and you'll end up writing well more JS than you like (well, I have).  Whilst I have it working, I honestly can't recommend it as an approach.

In retrospect, I wish I had persisted with option 1 as an approach for longer, although it soon gets complicated by the same issues as option 3 really, if you allow back and forth flow between your cart pages (and how can you not?).

(Oh, and shipping currently doesn't deal with tax, which further complicated getting your totals/tax right with these approaches)

To really solve this area I'd love to see:

(The biggie!) Set shipping on the cart without requiring irrelevant
data at that point like names - shipping should only need what it
actually needs for each shipping option (including custom plugins).
Some basic address controllers - that are separate from the cart - add/remove (and addresses should be elements with fields etc!)
Tax support with shipping

I wish I could give you a 'this is how you do it' answer but it's really pretty complicated and far from ideal at this point.  If you CAN live without shipping being shown in the cart (and just use e.g. a chart as Luke suggests) - your life will be vastly simpler, that's for sure!