How can I get entries where a date is within a dynamic date range?

Ok, so in the end you’d want your “startDate” custom field parameter to be a string in this format:

'and, >= 2017-08-04T05:00:00+08:00, < 2017-08-11T04:59:59+08:00'

I’m outputting a format for the dates that includes the time and timezone, so that we are able to define when exactly events are being refreshed. To do that I’m using the date filter (otherwise Twig outputs dates in Y-m-d format).

Here’s how you compose the final string including the value from the Global Set, that I am simply concatenating to a string that I pass into the date_modify filter.

{% set var = myGlobalSet.myNumbersField %}

{% set rangeStart = now|date_modify('5:00')|date('c') %}
{% set rangeEnd = now|date_modify('5:00 +' ~ var ~ ' weeks')|date('c') %}

{% set startDateParam = 'and, >=' ~ rangeStart ~ ', <' ~ rangeEnd %}


In order to change the content for each site individually you need to set the field settings accordingly to "translatable for each site"

Otherwise the content for each site will be the same


To update plugins like SeoMatic, just download the latest (either clicking on the direct download link from the /admin/updates/ page in your admin area or from github).

Then you just then need to upload the new folder, overwriting the old one, to your server in the /craft/plugins directory (make sure you rename the download to seomatic as before, removing the '-master' that github adds).


Plugin-settings form field for chosing a user?

Copying from the widgets settings I made something that sort of works:

Define the setting to be type mixed:

protected function defineSettings()
{
    return array(
                 'jobsemail' => array(AttributeType::Mixed, 'required'=>false),
                 );
}

Then create a settings.html like this:

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

{% set userInput %}
    <div class="select">
        <select id="jobsemail" name="jobsemail">
          <option value="">No one</option>
            {% for user in craft.users.group('Admin') %}
          <option value="{{ user.id }}"{% if user.id == settings.jobsemail %} selected{% endif %}>{{ user.name|t }}</option>
            {% endfor %}
        </select>
    </div>
{% endset %}

{{ forms.field({
    label: "Email recipient"|t,
    instructions: "This person gets emailed when new jobs are added"|t,
    id: 'jobsemail',
}, userInput) }}

This gives you a basic SELECT drop-down list. It's ok here, because the number of admin users is low. It would be less suitable if there were 100s of users.

Is a better solution with a real pop-up element picker would be nice!


Display field from one section in another section

This is untested but, give it a try:

{% extends "_layout" %}
{% set title = "Games" %}
{% set entries = craft.entries.section('games').limit(10).order('title') %}
{% block content %}

    {% for entry in entries %}

            {% for category in entry.GamesGenre %}{{ category.title }}{% endfor %}: {{ entry.title }} {% set publishers = entry.GamesPublisher %}{% for publisher in publishers %}({{ publisher.title }}{% endfor %}, {{ entry.GamesReleaseYear.format('Y') }})

    {% endfor %}

{% endblock %}

If need be, have a look at An introduction to relations and reverse relations in Craft CMS, with examples


I needed to define the namespace. In composer.json:
"autoload": {
    "psr-4": {
        "myname\\tests\\fixtures": "tests/fixtures"
    }
}

and then
composer install

That uncovered some other problems with the above code (to anyone else who's trying to figure out fixtures, looking through the Craft repo's own tests directory is helpful), but that's separate from this question.


Problems Securing Database Connection Over SSL

Silly mistake. I forgot to update AppBehaviors.php to the newest release after moving the attributes logic to db.php:

$dbConnection = new DbConnection();

$dbConnection->connectionString = $this->_processConnectionString();
$dbConnection->emulatePrepare   = true;
$dbConnection->username         = craft()->config->get('user', ConfigFile::Db);
$dbConnection->password         = craft()->config->get('password', ConfigFile::Db);
$dbConnection->charset          = craft()->config->get('charset', ConfigFile::Db);
$dbConnection->tablePrefix      = $dbConnection->getNormalizedTablePrefix();
$dbConnection->driverMap        = array('mysql' => 'Craft\MysqlSchema');

// Support for Yii's $initSQLs
if ($initSQLs = craft()->config->get('initSQLs', ConfigFile::Db))
{
    $dbConnection->initSQLs = $initSQLs;
}
// See if we have any extra PDO attributes passed in.
if ($attributes = craft()->config->get('attributes', ConfigFile::Db))
{
    $dbConnection->attributes = $attributes;
}

$dbConnection->init();

After adding the new lines of code, I was able to connect :)


How can I escape Twig code to prevent it from being parsed?

Escape single lines as strings:

{{ '{% set foo = "bar" %}' }}

Use autoescape to escape multiple lines, optionally specifying a syntax (see docs):

{% autoescape %}
     {% if foo != "bar" %}
         {% set foo = "bar" %}
     {% endif %}
{% endautoescape %}

Use verbatim to treat multiple lines as raw text:

{% verbatim %}
     {% if foo != "bar" %}
         {% set foo = "bar" %}
     {% endif %}
{% endverbatim %}


The problem was my attempt to ajaxify the page.

I had my block content wrapped around
{% if not craft.request.isAjax %}

the page also gets loaded in via Ajax into the control panel, I changed the code to:
{% if not craft.request.isAjax or craft.request.isLivePreview %}

Now it works.


Content creation and translation workflow

Never used it, but probably worth looking at this plugin: https://github.com/boboldehampsink/translate

There are some related feature requests about adding this to Craft core you might want to chime in on as well:

https://github.com/craftcms/cms/issues/970

https://github.com/craftcms/cms/issues/1173


Don't output specific category on entry page

I might be mistaken, but you can just insert an if block into your loop:

{% set excludedId = 1234 %}

{% for category in entry.categories.all() %}
  {% if category.id != excludedId %}
    {{ category.title }}
    {{ not loop.last ? '|' }}
  {% endif %}
{% endfor %}

That said, this will no longer know whether the "last" item in the loop was excluded. A better solution might be to trim down the collection before beginning the iteration:

{% set excludedId = 1234 %}

{% for category in entry.categories.all() | filter((c) => c.id != excludedId) %}
  {{ category.title }}
  {{ not loop.last ? '|' }}
{% endfor %}

This makes use of the filter filter, which you can pass a "function" of sorts to compare each ID to your excluded one. If the comparison is false, it'll remove it from the collection before the loop starts.

One last option (and possibly the best one) is to adjust the query itself, before it's run:

{% set excludedId = 1234 %}
{% set onlyDesiredCategories = entry.categories.id("not #{excludedId}").all() %}

{% for category in onlyDesiredCategories %}
  {{ category.title }}
  {{ not loop.last ? '|' }}
{% endfor %}

Instead of filtering down from the natural relations, this method attempts to adjust the ElementQuery instance provided by the relation field (entry.categories) by setting the id param to not 1234, meaning that ID will be excluded when the query is executed. I haven't actually tried this lat method, myself, so your mileage may vary.


The currentSite property from the Sites service is what you're looking for. Here's how you would use it:
'api/search.json' => function() {

    $siteHandle = Craft::$app->getSites()->currentSite->handle;

    ...

    $criteria = [
        'site' => $siteHandle,
        ...
    ];

    return [
        ...
    ];
},


Using a Redirect plugin in conjuction with a wildcard route

I ended up making a 404 template (which in atuality is the SPA index file)

This causes the Craft redirects to take effect, and have the SPA as a fallback route.

This means in Production i don't need any such route. For development purposes i do, so i made a conditional route file (to avoid the debug 404 of Craft):

 if(getenv('ENVIRONMENT') === 'dev') {
   return [
     '<url:(?!api).*>' => ['template' => '404']
   ];
 } else {
   return [];
 }


Craft’s assets functionality is getting refactored in Craft 3, so anything you do with those APIs today will need to be updated when 3.0 comes out.

The silver lining for you is, literally every plugin will need to be updated for Craft 3 (due to us moving to Yii 2), so we are planning on having a several month-long beta period where we will work with plugin developers to get their plugins updated, before the official public release. So we will be happy to work with you on updating your plugin during that period.

As far as an ETA, I couldn’t say. Craft 2 still has a lot of shelf life ahead of it.


Order entries by related "Year" category and paginate?

You could sort using the multisort filter (docs) then paginate using Yii's ArrayDataProvider - see this post for reference.
{# Fetch your entries and order by theYear descending #}
{% set allEntriesByYear = craft.entries()
    .section('library')
    .orderBy('postDate DESC')
    .theYear(':notempty:')
    .with(['theYear'])
    .all() | multisort(e => e.theYear[0], direction=SORT_DESC) %}

{# Create your custom pagination #}
{% set dataProvider = create({
    'class': 'yii\\data\\ArrayDataProvider',
    'allModels': allEntriesByYear,
    'pagination': {'pageSize': 4}}) %} {# Change this to the number you need per page #}

{% set results = dataProvider.getModels() %}

{% set currentPage = dataProvider.getPagination().getPage() + 1 %}
{% set totalPages = dataProvider.getPagination().getPageCount() %}

{% if currentPage > 1 %}
    {% set prevPage = currentPage - 1 %}
{% endif %}
{% if currentPage < totalPages %}
    {% set nextPage = currentPage + 1 %}
{% endif %}

{% if results | length %}
    {% for entry in results %}
        {{ entry.title }} - {{ entry.theYear[0] }}

    {% endfor %}
{% endif %}

    {% if prevPage is defined %}
        < Previous page
    {% endif %}

    {% if nextPage is defined %}
         - Next page >
    {% endif %}


Grabbing an asset field from Page A to display on Page B

First you need to get the entry for the main page. There are a number of ways you might do that (check the craft.entries documentation). One would be to fetch it by section handle, so assuming the main page has section handle of mainPage, you can do this:

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

And then you can get the from the main page asset as before:

{% for asset in mainPage.donateHeaderImage %}

{% endfor %}

To be safe, you should always handle the possibility that craft.entries won't return anything (maybe the mainPage section handle changed).

So either test it:

{% set mainPage = craft.entries.section('mainPage').first %}
{% if mainPage %}
  {% for asset in mainPage.donateHeaderImage %}

  {% endfor %}
{% endif %}

Or use the powerful null-coalescing operator:

{% for asset in craft.entries.section('mainPage').first.donateHeaderImage ?? [] %}
  ...


Plugin routing casing: camel, lower, Pascal

This is the general rule of thumb...

Lower (myplugin) - When creating links for the browser to follow ("href" & "src")
Camel (myPlugin) - When creating a path for PHP to interpret (like calling an action)
Pascal (MyPlugin) - Almost never. Only for naming plugin components. (ie: MyPluginService)

Here's the logic behind lower vs. camel... If it's an "href" or "src" for your browser to follow, you're basically referring to the folder name which contains your plugin. If it's a reference for PHP to interpret, that information is used to trigger a part of your plugin by class name.

In the case of a controller action (/actions/myPlugin/foo), that path starts as a normal browser path, until actions gets interpreted by your root index.php file. Once the index file parses out the actionTrigger, the rest of the path is handled via PHP.


Displaying disabled posts only to post author

There are a couple of aspects to consider in your question.

Display entries to the author who created them
Display entries which are disabled

I'll assume your Channel/Structure is named "Gallery Image"...

First, establish the User ID of the logged in User:

{% set loggedInUserID = currentUser.id %}

...then find Entries authored by the Logged in User:

{% set galleryEntries = craft.entries.section('galleryImage').authorId(loggedInUserID) %}

(Entry Author ID parameter info...)

... then loop through any entries which have a Status of "Disabled"

{% for entry in galleryEntries.status('disabled') %}

Your draft Gallery entries

    ...(template code)...
{% endfor %}

(Entry Status parameter info...)

Another variation which you could use, which moves the Status parameter out of the For-Loop, is:

{% set galleryEntries = craft.entries.section('').authorID(loggedInUserID).status('disabled')%}
{% for entry in galleryEntries %}

Your draft Gallery entries

    ...(template code)...
{% endfor %}


{% for image in entry.imageGallery.offset(1).all() %}

Don't search for an example "how to apply offset". All properties work the same - there is nothing special/ no difference between offset, limit, a field value or anything else.


Sprout Forms - include hidden fields in notification emails

By default, several fields do not display in the default Email Template such as the Hidden Field, Invisible Field, Section Heading Field, Private Notes Field, and Custom HTML field.

If you'd like to display any or all of those fields, you can override the default email template by in your Notification Email settings. Select the "Custom Templates" option and add a path to a folder in your template folder where you will place your email.twig override file. More info on Notifications and Email Template overrides in our docs.

You can copy the default Email Template as a starting point and the line that you'll want to update is {% for field in fields if not field.isPlainInput() %} which you can see here.

You can remove the if not field.isPlainInput() condition in that for loop to display all fields in your email. And conditionally hide or handle other fields uniquely in your templates by targeting them by their unique folder name: field.getFieldInputFolder().


craft-imageoptimize plugin cropping position

FWIW, I would not recommend doing image resizing via your Twig templates, because it will do them on page load time. Rather, I’d recommend doing them via an Optimized Images field as per: https://github.com/nystudio107/craft-imageoptimize/blob/v1/README.md#dynamically-creating-optimized-image-variants

But if you really want to do it, the parameter there is the same as you’d use for regular Craft transforms: https://docs.craftcms.com/v3/image-transforms.html#defining-transforms-in-your-templates

So you could do 'top-center' or such

But especially since you’re just creating one image variant, there’s no real advantage to doing this via ImageOptimize in your templates. Just use a regular Craft transform. With ImageOptimize installed, the resulting image will be optimized when done via Craft transforms, too.

The real benefit of using ImageOptimize to create image transforms is to make creating responsive image srcsets easier.


Simple user query with orderBy not working

Just did a simple test on a fresh install of the latest Craft with 3 users in a user group using this code and the output was what I'd expect:

{% set users = craft.users.groupId(1).orderBy('lastName asc') %}

    {% for user in users %}

{{ user.lastName }}, {{ user.firstName }}

    {% endfor %}

Gives:

Aardvark, Adam
Meadows, Marc
Zimmerman, Bob


Validation not running on empty custom fields on an entry (when creating programmatically)

You would need to set the entry's scenario to live just before saving the element.
$section = Craft::$app->sections->getSectionByHandle('contactSubmissions');

$entry = new Entry();
$entry->sectionId = $section->id;
$entry->typeId = 2;
$entry->authorId = 1;
$entry->enabled = true;

$entry->setFieldValues([
    'contactName' => ucwords($data['contactName']),
    'contactEmail' => $data['contactEmail'],
    'contactCompany' => $data['contactCompany'],
    'contactMessage' => $data['contactMessage'],
    'contactHeardAbout' => $data['contactHeardAbout'],
    'contactWebsite' => $data['contactWebsite'],
    'contactTitle' => $data['contactTitle'],
]);

$entry->setScenario(Entry::SCENARIO_LIVE);

if ( Craft::$app->elements->saveElement($entry) ) {
    //$this->sendMail($entry);
}

die(var_dump($entry->getErrors()));

return $entry;

Alternatively, If you want to save entries from the front-end, unless you have very specific requirements, you could use:

Guest entries plugin (if users are not logged in)
Make a front-end entry form (if users are logged in)


Error when calling methods between two services (triggered by init)

Your service’s init() function gets called immediately after it is loaded – and before Yii has had a chance to remember that craft()->myPlugin should return the service instance.

Take a look at these two lines from CModule::getComponent() (the method that the magic getter invokes when you call craft()->somePluginName):

$component->init();
return $this->_components[$id]=$component;

So when MyPlugin_OtherService::methodInOtherService() tries to refer back to craft()->myPlugin, craft()->myPlugin has not yet been assigned to the service instance, which results in the PHP fatal error you’re getting.

I can propose a change that would fix this:

$this->_components[$id] = $component;
$component->init();
return $component;

…but I’m not sure what the implications would be for that.

You might just need to question whether it’s so important for this code to be running from init() as opposed to another function that you’d have to invoke manually. Having it in init() could lead to other unexpected consequences as well.


Possible to assign fields (or an image) to a category?

The Craft Categories page is very useful.

To assign an entry to a category, create a category field, and require it in the entry type (you are probably already doing this).

When you create a Category Group you can edit the field layout, and add an image field and a text field for the category. Then to edit that content, double click on the category itself (from the right-side category menu), and you will get a modal dialog where you can edit the text and image.

To list the categories in myCategoryGroup you do:

{% set categories = craft.category.group('myCategoryGroup') %}
{% for cat in categories %}
  {{cat.title}} - {{cat.image}} {# assuming image is the name of the image field #
{% endfor %}

Craft site has an article on How do I list the entries related to a category?.


Custom field type file upload error [Uploaded File Class]

Yii’s CUploadedFile class actually doesn’t support retrieving uploaded files that came from a file input whose name was “namespaced” (e.g. name="fields[handle]" rather than just name="handle").

However, Craft has its own UploadedFile class which extends CUploadedFile, and the whole point of it is to add that namespaced input name support. It uses a dot syntax rather than square brackets, so if a file input had the name fields[handle], you would fetch that file like this:

$file = UploadedFile::getInstanceByName('fields.handle');

Problem is, you can’t actually rely on the file input name having a fields namespace – it will vary depending on the form. In fact many element forms within Craft have randomized namespaces (e.g. the Quick Post dashboard widget, or the modal windows that come up when you double-click on an element within a relational field).

That’s why field types have a getContentPostLocation() method, which returns the input name that would have been used for the current field, namespace and all, converted into dot syntax. So you can plug that value directly into getInstanceByName() and get your uploaded file.

$contentPostLocation = $this->getContentPostLocation();

if ($contentPostLocation)
{
    $file = UploadedFile::getInstanceByName($contentPostLocation);

    // ...
}


What is $source and $sources in BaseRelationField?

In case of the element type Asset sources are the available volumes. In case of Category the available sources are the different groups. Sources for Entry are your sections, Tag have the different sets/groups as well.

It contains an array or the type section, folder, group and the ID of the corresponding model, separated with an :

You can just do

$field = Craft::$app->getFields()->getFieldById(>>your field id<<);
Craft::dd($field->sources);

to get to know how it looks like. It could be like this:

array(1) {
  [0]=> string(10) "section:16"
  [1]=> string(10) "section:18"
}

or for an Asset

array(1) {
  [0]=> string(8) "folder:1"
}


How fixed are the ICC profile in core app?

Not sure I'm following 100%, but they're part of the Imagine library so as long as Craft is using that library, they will be included in Craft.


How do I redirect from a legacy category URL to a new catgory URL using Retour

Despite having used regex's for years, I still almost never get them right from memory. A great tool for testing them out is: https://regexr.com/

What you'll need to use is a capture group. Something like this for the source:

/category/(.*$)

And then the resulting URI would be something like this:

/news/category/$1

Each set of () is a capture group; they are numbered sequentially, so $1 will output the first capture group.

If you go to https://regexr.com/ it will even explain every part of the regex, and what it does:


Its probably not a good idea to go in and change the fonts for Craft yourself.

Please submit a bug report to support@pixelandtonic.com, and they will have a look into the issue.


Getting image for product in Cart Screen

This actually depends where the image is stored - if the asset (image) field is on the product, and is called myImage, then as per Brad's example you'd use:

lineitem.purchasable.product.myImage

...BUT if it's in rather a field on the variant you would instead reference it as:

lineitem.purchasable.myImage

(This is because lineitem refers to a variant....in the case of a product without variants it references the implicitly created defaultVariant).


How can I pass a Craft Field into a JavaScript function?

Is the JavaScript inline in your template file? e.g. using {% includeJs %} or even just a <script> tag? If so you should be able to do it as you suggested by outputting Craft variables directly into the JavaScript within your template.

If the function is in an external script, you could call a function from within your template, something along these lines:

{% includeJsFile "/path/to/myfile.js" %}
{% set myJs %}
   myFunction('{{entry.country}}','{{entry.visits}}');
{% endset %}
{% includeJs myJs %}

And then in your JS file you can have something like

function myfunction(country, visits){
   //do something
}


First and Last day of Week + Month in Twig

That code in Twig would be:

{% set day = now|date('w') %}
{% set weekStart = now|date_modify("-#{day} days")|date('m-d-Y') %}
{% set weekEnd = now|date_modify("+#{6-day} days")|date('m-d-Y') %}


Taxcloud.net integration for Craft Commerce?

As of Sept. 27 2016, I'm not aware of any existing taxcloud.net integrations with Craft Commerce and I'm not seeing any on https://straightupcraft.com/craft-plugins/ as well.


We did something similar with Charge when we were accepting payments for a Craft Virtual Training course. It does involve writing a plugin, but thankfully all of the heavy lifting for saving entries and charging credit cards is handled by the services provided by Craft and Charge, so the only thing the plugin has to worry about is collecting post data and passing it to some APIs.

Start off by creating a primary plugin class (see Setting Things Up in the Craft plugin docs), and then giving your plugin a controller with the following code:

<?php
namespace Craft;

class FooController extends BaseController
{
    public $allowAnonymous = array('actionCreateBooking');

    public function actionCreateBooking()
    {
        // Require this to be a POST request
        $this->requirePostRequest();

        // Require that the user is logged in
        craft()->userSession->requireLogin();

        // Get the user
        $user = craft()->userSession->getUser();

        // Do any custom validation here
        // ...

        // Charge the card
        $charge = new ChargeModel();

        $charge->cardToken     = craft()->request->getRequiredPost('cardToken');
        $charge->cardLast4     = craft()->request->getPost('cardLast4');
        $charge->cardType      = craft()->request->getPost('cardType');
        $charge->cardName      = craft()->request->getPost('cardName');
        $charge->cardExpMonth  = craft()->request->getPost('cardExpMonth');
        $charge->cardExpYear   = craft()->request->getPost('cardExpYear');

        $charge->customerName  = craft()->request->getPost('customerName');
        $charge->customerEmail = craft()->request->getPost('customerEmail');

        $charge->planAmount    = 10000; // In cents

        if ($charge->validate() && craft()->charge->handlePayment($charge))
        {
            // Save the booking entry
            $entry = new EntryModel();
            $entry->sectionId = craft()->request->getPost('sectionId');
            $entry->typeId    = craft()->request->getPost('typeId'); // Not necessary if there's only one entry type
            $entry->authorId  = $user->id;
            $entry->enabled   = true;

            $entry->getContent()->title = 'New Booking: '.$user->username;
            $entry->getContent()->chargeId = $charge->id; // Custom number field
            $entry->getContent()->someOtherCustomField = 'xyz';

            craft()->entries->saveEntry($entry);

            // Redirect the request based on the 'redirect' param
            craft()->userSession->setNotice('Booking saved.');
            $this->redirectToPostedUrl();
        }
        else
        {
            craft()->userSession->setError('Couldn’t charge the card.');

            // Send the charge model to the template
            craft()->urlManager->setRouteVariables(array(
                'charge' => $charge
            ));
        }
    }
}

You might want to hard-code the sectionId and typeId rather than leaving it up to the POST data, and there might be other slight changes you want to make, but that’s the gist.

With the plugin in place, you would just need to create a form that captures all of the info the controller is looking for, and posts it to the foo/createBooking action:

<form method="post" accept-charset="UTF-8">
    {{ getCsrfInput() }}
    <input type="hidden" name="action" value="foo/createBooking">

    <!-- ... -->
</form>


What would prevent my assets from reindexing on a local MAMP install

If the Update Asset Indexes fails on a MAMP install, double check to make sure ALL assets source paths are correct and exist on the file system.

I had defined a asset source to a folder which I had planned on using but had not yet created on the file system, and this caused the Update Asset Indexes to fail w/o any warning messages, save for a JS error in the console.


ElementAPI : Excluding terms from search criteria

Here is what I ended up changing my code to exclude search items.

//Get excluded ingredients query
$excludedQuery = Craft::$app->request->getQueryParam('xq');
if ($excludedQuery) {
    if (!isset($criteria['search'])) {
        $criteria['search'] = '';
    } else {
        $criteria['search'] = $criteria['search'].' ';
    }
    $criteria['search'] = $criteria['search']."-title:'".$excludedQuery ."' -recipeIngredients:'".$excludedQuery ."' ";
}


Relation fallback if no category has been selected

I had to use a bunch of conditionals to accomplish this - it's not ideal but here's what I came up with

{% set category = craft.app.request.getParam("category") %}
{% set function = craft.app.request.getParam("function") %}
{% set industry = craft.app.request.getParam("industries") %}

{% if not category | length %}
        {% set category = "blog,caseStudies,videos,webinar,whitePapers" %}
{% endif %}

{% set category = category | split(',') %}

{% set posts = craft.entries({
    section: category,
    orderBy: "postDate desc"
}) %}

  {% if function | length %}
    {% set functionSection = craft.categories.group('businessFunction').slug( function|split(',') ) %}
    {% set posts = posts.relatedTo(functionSection) %}
  {% endif %}

  {% if industry | length %}
    {% set industrySection = craft.categories.group('industry').slug( industry|split(',') ) %}
    {% set posts = posts.relatedTo(industrySection) %}
  {% endif %}


Apparently SEOMatic provides an automatic hreflang to your source.
So changing the language in the settings tab helped for me.


Editing a users custom fields from a plugin action Craft 3

You should just reference the field as an object property of the user instead of using setFieldValue. I also use the getElements function instead of using the property, but I don't think that makes much difference. The code below should work.
public function actionUpdateuser() {
    // Update user data
    $userId = 67852;
    $user = Craft::$app->users->getUserById($userId);
    $user->userCompanyName = 'New Name 2';
    $result = Craft::$app->getElements()->saveElement($user);

    return $result;
}

Also make sure to add the Craft Users class at the top of the page with:
use craft\elements\User;


Craft CMS logo still showing on CP Login page

As of Craft 2.5, by default you will see your Site Name in plain text above the login form, and a light Craft CMS logo below it. If you have Craft Client/Pro and upload a custom Login Page Logo from Settings → General, the plain text Site Name will get replaced with that logo, but the Craft CMS logo will remain.

The Login Page Logo was never meant to be used to white-label the CMS - even pre-2.5 if you uploaded a custom logo, there would still be Craft and P&T references in the CP footer (which hasn’t changed).


Load entries based on category field value while multiple categories are selected

After looking for some more options I found the solution.

At first I was looking for a solution on how to check if the handle was inside of the array but, didn't manage to output the entire array as a conditional. I ended up changing the filter to filter on the category id (should have done that in the first place).

Now I'm filtering by ID so I could just use:

{% for entry in entries if selectedCat in entry.categories.ids() %}

I got some help from this answer after I figured out to use ID's instead of handle's

Converting array of entries to an array of ids


Yes, a date field is a good idea. For the following example I'm using a date field "startDate" in a global set "classes". And for the classes entries I set up a dropdown field "weekday" with values "monday, thuesday, ..." and localized labels "Montag, Dienstag, ...".

Twig's date_modify filter does all the calculation for this:

{% set weekday = entry.weekday %}
{% set classDate = classes.startDate|date_modify(weekday) %}

{{ classDate|date('l, F j, Y') }}


I assume, that title is a subfield of a matrix field, because title is a reserved name in craft. So as far as I understand your Question, you want to get some results out of a matrix field thats in one of your pages ('pageOne', 'pageTwo', 'pageThree'). That means you have to loop over this field as well.

{% if entries|length %}
   {% for entry in entries %}
       {% for block in entry.matrixFieldHandle %}
          {{ entry.title }} - {{ block.matrixTitle }}
       {% endfor %}
   {% endfor %}
{% endif %}


How do I get a URL link to open in a new window once clicked

Add target="_blank" to the link.

Like so: Opens in new window


Remove the anchor in nav loop based on another field conditional

Instead of using {% if page.pageIntroText|length %} have you tried

{% if page.pageIntroText is not empty %}


For loop through custom field in JavaScript

You could output the numbers in a data attribute on a wrapping HTML element:

{% set numbers = '' %}

{% for stats in entry.statsPanels %}
    {% set numbers = numbers ~ stats.statsNumber %}
    {% if not loop.last %}
        {% set numbers = numbers ~ ',' %}
    {% endif %}
{% endfor %}

<div class="myComponent" data-numbers="{{ numbers }}">
...
</div>

Then you can read them in your JavaScript file:

var endCounterVar = $('.myComponent').data('numbers');

if (endCounterVar.length) {
    endCounterVar = endCounterVar.split(',');
}

This might not be the cleanest/shortest way to achieve this in Twig, mind you!


You want to take a look at the CacheService class which is the service that allows you to programmatically interact with the internal cache.

This is an example of how to set some cache that expires in 3600 seconds (one hour). Set the expiration to 0 if you never want it to expire.

craft()->cache->set('some_key', 'some_value', 3600);

Just checkout CacheService for more details, as there are more methods and parameters to make use of, but this should be the basic use case.

CacheService Class Reference


Have some categories NOT linked to a category entry

I think I might have found a solution, although it might not be very elegant :/

So, i'm basically looking to see if a category field has content and then taking out the anchor in the template.

{% if category.practiceIntroText|length %}

{% endif %}
{{ category.title }}
{% if category.practiceIntroText|length %}

{% endif %}

Same code but making use of the ternary operator:

{% set catWithContent = category.practiceIntroText|length %}

{{ catWithContent ? '' }}
{{ category.title }}
{{ catWithContent ? '' }}


How to cache and serve different data to different users using Blitz?

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


Populating tables and matrix fields using GuestEntries

See here for example front-end HTML code for all of Craft's default field types:  https://straightupcraft.com/articles/craft-cms-field-guide-twig?view=input

Matrix:

{# You need to include the 'type' input to identify the matrix block type you are submitting #}
<input type="hidden" name="fields[fieldHandle][new1][type]" value="contacts">

{# All of your custom fields must be within a 'fields' array. #}
<input type="text" name="fields[fieldHandle][new1][fields][field1Handle]">
<input type="text" name="fields[fieldHandle][new1][fields][field2Handle]" >
<input type="text" name="fields[fieldHandle][new1][fields][field3Handle]" >

{# For New Entries, you'll want to use the naming convention

'new1', 'new2', 'new3' for each of your blocks.  For existing entries you
can update those values to be the block IDs #}

Table:

<input type="hidden" name="fields[fieldHandle]" value="">
<textarea name="fields[fieldHandle][0][col1]" rows="1"></textarea>
<textarea name="fields[fieldHandle][0][col2]" rows="1"></textarea>
<textarea name="fields[fieldHandle][0][col3]" rows="1"></textarea>
<input type="hidden" name="fields[fieldHandle][0][col4]">
<input type="checkbox" name="fields[fieldHandle][0][col4]" value="1">

<textarea name="fields[fieldHandle][1][col1]" rows="1"></textarea>
<textarea name="fields[fieldHandle][1][col2]" rows="1"></textarea>
<textarea name="fields[fieldHandle][1][col3]" rows="1"></textarea>
<input type="hidden" name="fields[fieldHandle][1][col4]">
<input type="checkbox" name="fields[fieldHandle][1][col4]" value="1">

Lightswitch:

<input type="hidden" name="fields[fieldHandle]" value="1">


Commerce: How to update an order status via the frontend

A customer can not update the order status from the front end. Only a user in the CP with the right permissions can do so from the Edit Order page.
To add this functionality you would need to make your own controller action endpoint (in a plugin or module) that does the following:
<?php

namespace modules\mymodule\controllers;

use modules\mymodule\MyModule;

use Craft;
use craft\web\Controller;

/**
 * @author    You
 * @package   MyModule
 * @since     1.0.0
 */
class UpdateOrderStatusController extends Controller
{
    protected $allowAnonymous = ['index'];

    /**
     * @return mixed
     */
    public function actionIndex()
    {
        $this->requirePostRequest();
        $this->requireAcceptsJson()
        // validate the current user is allowed to edit the order?

        $newStatusId = Craft::$app->getRequest()->getRequiredParam('statusId');
        $message = Craft::$app->getRequest()->getRequiredParam('message');
        $orderNumber = Craft::$app->getRequest()->getRequiredParam('number');
        $order = Order::find()->number($orderNumber)->one();

        if($order){
          $order->orderStatusId = $newStatusId;
          $order->message = $message;
          Craft::$app->getElements()->saveElement($order, false);
          return $this->asJson([
              'errors' => $order->getErrors(),
              'success' => !$order->hasErrors(),
          ]);
        }

        return $this->asJson([
            'errors' => ['No order found'],
            'success' => false,
        ]);
    }
}


As of 3.1.2 you can now index assets via the cli tool:

./craft index-assets/all

OR

./craft index-assets/one {handle}


Is there a way to to fire some code before user validation?

Currently Craft doesn't have any events related to validation.  You can see the full list of events available here.

You can always add it as a feature request, though. Be sure and add examples of your specific use-case.


Debugging an error ("An unknown error occurred")

The error you're showing from the logs is a simple 404 error that occurs whenever someone or something requests a URI on your site that doesn't resolve to anything.  In this case it is /(X(1)S(q325ycazg05lq11ktn1hqjtx))/copyright, which is likely a script probing for vulnerabilities, which is very common for any public website.

We've moved those 404 messages into their own 404.log file in the upcoming Craft 3 so they don't clutter the main log file.

The underlying error message for An unknown error occurred will be elsewhere in your log files.  Sometimes it's helpful to nuke all of your logs (or move them somewhere else), then reproduce the issue as you'll have left to sift through.


Without an entry with slug contact/thanks then the page just returns an error Variable "entry" does not exist. But still it doesn't draw any content from the entry.

You do not need to create an entry for the Thanks page - in most cases it is easier to just add the actual text to your template file. If you do want to make it editable, then create a Single Entry, name it whatever you want, then go to Settings > Sections > yourSection and edit the uri and path variables. The URI should be contact/thanks, and the template path would likely be something like thanks.html


You can add the psd extension to extraAllowedFileExtensions in your config file.

'extraAllowedFileExtensions' => 'psd'

https://craftcms.com/docs/config-settings#extraAllowedFileExtensions


How do you deploy Craft 3 on Heroku with Postgres?

Found out that there are a variety of Config vars in Heroku you need to set that match your local .env file. In particular:

ENVIRONMENT
SECURITY_KEY
DB_SCHEMA

Edit 10.1.19 Wrote this tutorial on how to get Craft 3 up and running on Heroku.


Can't add anymore fields / blocks to Matrix Field

There's nothing in Craft limiting the amount of Matrix Blocks and fields you can add, it's purely environmental.

The most common values to increase are max_input_vars, post_max_size and memory_limit, so you'd need to bump one or more of those to higher values to be able to add more.

If you're running things like Suhosin or mod_security, they provide their own additional settings that sit on top of php.ini settings that you might need to adjust as well.


Craft search only shows results matching 'title' of entries

Search via search() can be used only for text fields, if you want to search by categories or records you need to use the relatedTo() method, also do not forget to specify search keywords when creating the field.

Links: https://craftcms.com/docs/3.x/relations.html#terminology, https://craftcms.com/docs/3.x/searching.html#supported-syntaxes.
Practical example:
{% set searchResults = [] %}

{% set queryParamsText = queryParamsText|merge({
        search: {
            query: 'title:' ~ searchWord
        }
     })
%}

    {% set category = craft.categories.group('category').search(searchWord).one() %}

    {% set relatedParams = relatedParams|merge([{ targetElement:category }]) %}

    {% if relatedParams|length > 1 %}
        {% set queryParamsRelated = queryParamsRelated|merge({'relatedTo':relatedParams}) %}
    {% endif %}

{% set searchResultsText = craft.entries(queryParamsText).section('canAddSectionHandleOrId') %}

{% set searchResultsRelated = craft.entries(queryParamsRelated
).section('canAddSectionHandleOrId') %}

{% set searchResults = searchResultsText|merge(searchResultsRelated)|unique %}


Hook calls within a loop always get the Entry, not the loop context?

If I understand correctly, the $context variable passed to my hook should be a reference to that summary object.

Nope... $context is a reference to the entire Twig rendering context of which your bookings objects will be a part of.

You can use xDebug or var_dump to see where your bookings objects are stored and loop though them as necessary from PHP.


P&T Contact Form plugin: How can I copy "name" and "email address" in the body of the mail?

I ended up hacking the ContactFormService.php file with some extra code for the body

It's actually quite simple:

$email->body = "Sender: ".$message->fromName."\n\nEmail-addreas: ".$message->fromEmail."\n\nMessage: ".$message->message;

Same thing for cc mail

I understood 2.2 will have a plugin hook for this kind of added functionality (emails.onBeforeSend event)


"Conditional" field layout - hiding or showing fields based on another field

The feature request for this has been very popular since day one, so hopefully it's something P&T adds to the core some day.

For the interim I just published a small plugin called Reasons, which will add simple field/value based conditionals to entry type field layouts - pretty much exactly like the OP describes it.

Download from GitHub: https://github.com/mmikkel/Reasons-Craft

Edit
P&T retired the UserVoice page; here is the new home for the feature request


I can't see why Craft would be breaking a CSS rule, you're outputting three items and is it outputting the 3 items on the page?

If yes, then the CSS rule might need to be fixed. If not, then I don't understand your problem.


How to add a unique number for each reiteration and render it multiple times?

Set it as a variable inside your loop and you can reuse it all you want.

 {% for entry in craft.entries.section('yourSection') %}
    {% set loopIndex = loop.index %}
    <li>"rs-{{loopIndex}}" id="slide-{{loopIndex}}-layer-2"</li>
 {% endfor %}


For each entry type, there is now an easy way to manage what columns are shown. From the admin, if you choose Entries from the main navigation, and then go to the entry type in question, you should see a small cog in the bottom left:

Click that and you'll be shown a number of checkboxes with columns that can displayed. Click the URI checkbox to enable that column, and then click Save. You can also drag and drop the column names here to re-arrange them.

You should now see that column in the entry list:


Guest Entries plugin with Paypal integration?

Hope that its not too late. I would not use paypal. Use stripe instead. You can then redirect the user to the Charge plugin by Squarebit.co.uk after the entry has posted. Once payment is made, change the status of your entry to enabled. Much cleaner and stripe is easier to work with.


How to wrap a matrix blocktype occurrence loop inside a ul?

A possible solution could be this:
Instead of outputting your blockType3 immediately, save all blockType3 ID's in an array. When your loop has finished (check for loop.last) output all the blocktypes from the array at once.

This code is just as an example (untested):

{% set arrBlockType3 = [] %}
{% for block in entry.matrixField.all() %}
    {% switch block.type %}
        {% case 'blockType1' %}

                {{ block.field }}

            {% case 'blockType2' %}

                {{ block.field }}

            {% case 'blockType3' %}
                {% set arrBlockType3 = arrBlockType3 | merge([block.id]) %}
    {% endswitch %}
    {% if loop.last %}

        {% for id in arrBlockType3 %}
            {% set block = entry.matrixField.id(id).first() %}

{{ block.field }}

        {% endfor %}

    {% endif %}
{% endfor %}


As far as 'setting availablity' goes, one could choose to make a 'services' section with a Matrix field that contains a DateTimeField. That way, the client can create a new Matrix Block for each available time span. The {% cache %} tag will help you in speeding this up on the frontend.

For booking, you could:

A: Make a 'bookings' section, with a related content field 'service'. Fill this section with a frontend Entry form, set post and expiry dates to the time span of the visitor's choice. You could now display a list of bookings on the frontend (behind a login), or have your client manage bookings through the CP's content tab.
B: Make a plugin to handle bookings. This would be my preferred approach.

To handle payments, you could use an existing plugin (Charge, for example) or build your own.


You should create a new single in the "Section" area of the settings page. It should just create the single after you have created the section.


How do you import hierarchical data that uses the adjacency list model into Craft Structures or Categories?

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


Is there any way to set a default status for Entries, either globally or per Section?

Your two options are the only ones thus far. If you would like this feature you can leave a post on the G+ group, or email them at: support@buildwithcraft.com


Craft 3 Custom Field Type with a File Uploader

Just as a little example how to store files in a custom field

/**
 * @inheritdoc
 */
public function normalizeValue($value, ElementInterface $element = null)
{

    $namespace = $element? $element->getFieldParamNamespace() . '.' : '';
    $file = UploadedFile::getInstanceByName($namespace . $this->handle);
    if($file !== null){
        // replace this
        $somePath = __DIR__ . DIRECTORY_SEPARATOR . $file->name;
        $file->saveAs($somePath);
    }
    return $file;
}

/**
 * @inheritdoc
 */
public function getInputHtml($value, ElementInterface $element = null): string
{
    Craft::$app->getView()->registerJs('Craft.cp.$primaryForm.attr(\'enctype\', \'multipart/form-data\');');
    return '<input type="file" name="' . $this->handle . '">';
}

Edit:

If you want to store the file path in your Database you would check if $value is an instance of File and if so return the path. Otherwise just declare your field has contentColumn = false


The better approach would be to pass the icon as a parameter to your macro. So I would do something like

{% macro renderIcon(type) %}
    {% switch type %}
        {% case 'video' %}
            {% include 'video.twig' %}
        {% case 'audio' %}
            {% include 'audio.twig' %}
        {% default %}
            {% include '_generic.twig.twig' %}
    {% endswitch %}
{% endmacro %}

And in your template you can do

{% import 'macro.twig' as icon %}
{{ icon.renderIcon(product.getType().handle) }}


Well, that's awkward.

The SetStatusEvent was removed way back in the Craft 3.0 launch, but the class itself was never removed (will fix that for the upcoming 3.4 launch).

There isn't really a clean replacement for it.

One way would be to listen to the EVENT_BEFORE_SAVE_ELEMENT event, run a separate database query to get the current status from the database and compare the status to the element that was passed in to see if it changed.

3.4 will give you another option - you could listen to EVENT_AFTER_SAVE_ELEMENT, then check the dirtyAttributes array to see if the status has changed, since elements now keep track of what attributes have changed on a given request.


ContactForm Plugin - Where does the email source come from?

The email's "from" field is set to the system email that is under Settings->Email in the control panel.

The email's "reply to" field is set to the "fromEmail" hidden input you set on the form.

This is done because many email servers will see that the "from" domain is different than the domain the email originated from and mark it as SPAM.


The reason the attribute for your Super Table is null is because the field is an element, which doesn't have 'simple' content. You'll find this is the exact same case for any other element like an Entries field, or a Matrix field.

I believe the reason for this is that this simply fetches the content from the actual craft_content table. Being complex (relational) data, there's technically nothing in the content table. Getting the content is a little more complex.

In the case of Super Table (and other elements), when querying the field's content on an attached element, you'll get an ElementCriteriaModel (for Craft 2) returned, which allows you to do all sorts of things when outputting the content of a Super Table (limit, order, etc).

To illustrate, you can do:

var_dump($response[0]->lifeBeforeColumnOne);

Which will output the ElementCriteriaModel, which will be not overly useful for actual content output. In addition, you'll want to call find() on the criteria (just like you're doing above in your code to fetch the entries) to return an array of SuperTable_BlockModel's.

$blocks = $response[0]->lifeBeforeColumnOne->find();

foreach ($blocks as $block) {
    var_dump($block->featuredImage);
    var_dump($block->textContent);
    var_dump($block->source);
}

You can then output the content by targeting the inner fields'.

You might also find this slightly related conversation useful - Getting all content, including Matrix fields from an EntryModel

There's also an example of this sort of functionality on the docs - https://verbb.io/craft-plugins/super-table/docs/guides/developer-examples#fetching-content-from-a-super-table-field


How to see which database Craft is currently connected to?

You could do something like this to at least see which environment from your multi-environment config that Craft is matching:

$craft = require 'path/to/craft/app/bootstrap.php';
echo $craft->config->get('server', ConfigFile::Db);


CloudFlare Shared SSL certificate forbids CraftCMS control panel sign in

I'd give Patrol plugin a try, just activate secure connections.


Craft Commerce: Addresses not showing in profile

Its likely that the order was made while a guest user, then signed up, so the guest order was then associated with the new user - but the addresses used in that guest order don't get copied to the address book of the new user.


Is it possible to disable dev output in a template when devMode is true?

You can create a simple plugin with an init() method like so:

public function init()
{
    craft()->log->removeRoute('WebLogRoute');
    craft()->log->removeRoute('ProfileLogRoute');
}

That will prevent the extra logging and profiling information to be output in the browser's console when devMode is enabled.


Front End Asset Management - Upload New Photos without Deleting/Overriding Existing

You're right that your template needs some adjustments. Whenever you're saving an Assets field, you need to have all of the Asset id's not just the new ones. You're looking for something like

{% if entry.photos|length %}
    {% for photo in entry.photos %}
        <input type="hidden" name="fields[photos][]" value="{{ photo.id }}" />
    {% endfor %}
{% endif %}

<input type="file" id="photos" name="fields[photos][]" class="upload" multiple>


I don't think you can do it like that - in Commerce, the order gets completed when a payment is made.

Fortunately, you can use the manual payment mechanism, which automatically completes the order, as the fake 'payment' type to get this to occur.  Just go in to Commerce settings and create a new payment type of 'manual' set to 'authorize only', and give it a name like 'Get Quote'.

To actually complete the order, you'll need to post the manual paymentMethodId to a call to commerce/payments/pay.  If you're doing this in a contact form, you'll have to intercept the form submit and post this via AJAX I guess.

Alternatively you could write your own controller to complete the order with some plugin code, but the above solution is essentially built in an intended for this sort of thing.


I believe A&M Forms stores its fields separately, it does not use the Craft fields that you would use elsewhere. You'll probably need to re-create those fields through A&M Forms to be able to access them in your forms.

To be honest, you should probably stop using A&M Forms if you are not in too deep. It was never ported to Craft 3 (and never will be), so your site will be stuck on Craft 2 unless you put in significant effort later to switch form plugins.


If you know your q variable should be a slug, you can use the .slug query parameter:

{# Get the requested entry slug from the URL #}
{% set requestedSlug = craft.app.request.getSegment(3) %}

{# Fetch the entry with that slug #}
{% set entry = craft.entries()
    .slug(requestedSlug|literal)
    .one() %}

More on how to use this in the Craft 3 docs.

I have personally had some unexpected results using Craft's built-in search.


Display variant title on cart page only for items with more than one variant

If you are using separate product types - some with variants, some without:

Then what you're looking for is basically:

{% for lineItem in cart.lineItems %}
    {% if lineItem.purchasable.product.type.hasVariants %}
       {# the purchasable is the chosen variant - display the product AND variant title #}
       {{ lineItem.purchasable.product.title }} <br>
       {{ lineItem.purchasable.title }}
    {% else %}
        {# no variants, just use the title from the product #}
        {{ lineItem.purchasable.product.title }}
    {% endif %}
{% endfor %}

If you're using just one product type, some entries of which have one variant and others more:

Basically you need to get back from the lineItem to the product so that would be something like this:

{% if lineItem.purchasable.product.variants|length > 1 %}
    {{ lineItem.purchasable.title }}
{% else %}
    {{ lineItem.purchasble.product.title }}
{% endif %}

...
(I've not tested these directly, just coded here in the browser but that should be pretty
close!)


I'm not sure that .entry is a valid parameter? I think that craft.entries.section('kontakt') contains an array with entries, so maybe you you could do .first on it, so basically I think you wanted to do this:

    {% for kontaktEntry in craft.entries.section('kontakt').first.kontakter %}

                {% set image = kontaktEntry.bilde.first() %}
                {% if image %}

                {% endif %}

{{ kontaktEntry.navn }}

                {{ kontaktEntry.stilling }}

    {% endfor %}


I don't think you can disable categories with the current version of Craft. But you're right, it currently looks like that categories are prepared to get disabled.

Update:

Categories now have their own edit pages in Craft 2.3, where you can set the status. And you can even set it on a batch from the category index page!


How would I show a message and define where the user is redirected after changing their email through a front end form?

Based on Brad's response I created the following controller in a plugin:

<?php
namespace Craft;

class Myplugin_SaveUserController extends BaseController
{
    protected $allowAnonymous = true;
    /**
     * Handle the save user form request.
     */
    public function actionSaveUser()
    {
        $this->requirePostRequest();
        $email  = craft()->request->getPost('email');
        $userId = craft()->request->getPost('userId');
        $user   = craft()->users->getUserById($userId);

        if ($email !== $user->email)
        {
            craft()->userSession->setFlash('changedEmail', 'changed email');
        }
        $this->forward('users/saveUser', false);
    }
}

I then check for it in my template:

{% if craft.session.getFlash('changedEmail') == 'changed email' %}

This seems to do the job.

For anyone who may be using this in the future, it's worth noting that I also had to change the "action" hidden input in my form:

<input type="hidden" name="action" value="myplugin/saveUser/saveUser">


Live preview option not working for multi-site functionality

Essentially you're looking for this feature request: https://github.com/craftcms/cms/issues/1160

That has been resolved in https://github.com/craftcms/cms/commit/1ab6b6e6e3cd5a13c949d113c8367e7faf930ee4 which will be released in Craft 3.1.


How do I create an “Archive” page for my entries? covers this.


How to save a Matrix with Super Table in it

In the super table array, there has to be a type there:

"superTableHandle" => array:5 [
    0 => array:3 [
      "type" => 1//the field's id
      "fields" => array:10 [
        "relatedArticle" => 325051
        ...
      ]
    ]
    1 => [...]

For me, this id is 1. It can be found in database by running this SQL

select * from supertableblocktypes;

But I ran the code below before and found out the field's id is 81 which is not working for me, I don't know why

dd(Craft::$app->fields->getFieldByHandle('matrixHandle')->blockTypeFields);


Whatever template path you decide to go with, make sure you set that in the section’s settings. So if it’s house/_entry.html, make sure you put house/_entry in your section settings.


Can someone explain to me the difference between 'not' and without?

Your first example (.id('not' ~ entry.id)) will exclude that entry ID from the results on in the actual database query.

Your second example will grab all of the entries that satisfy the criteria, then from the PHP/Twig side, then use the |without filter to loop through the array results and remove the ones that match the criteria.

Pretty sure your 2nd one won't work as you're expecting though, since you're telling it to remove an entry.id, which is an integer, but the results are an array of Entry elements. It might work just using entry instead, but I'm guessing the |without filter isn't smart enough to work on entire objects.

Long story short, use the 1st example.


Multi locale, multi-domain Live Preview failing

Only setting headers in .htaccess doesn't fix the problem.
As Marion Newlevant points out in her answer the cross domain works with the headers set. But you still get a white page as a preview.

Looking further into the problem, I've found that the page tries to do a post request to the other domain.
It calls upon the action function actionPreviewEntry() in the EntriesController.php file (Location: /craft/app/controllers/ )

But because the user isn't logged in on the other domain and anonymous access isn't allowed for this action. You get redirected to /login to login on that domain.

I came up with a quick solution for the problem. It's a bit dirty for now, but the authors of Craft aren't coming with a solution either.

Solution

Delete (If you have set them) the headers for Access-Control-Allow in your .htaccess file. We don't need them.
Open the file EntriesController.php in the folder /craft/app/controllers/
Replace the code.

protected $allowAnonymous = array('actionViewSharedEntry');

With:

protected $allowAnonymous = array('actionViewSharedEntry','actionPreviewEntry');

Add the following code in the public function actionPreviewEntry():

// Set a boolean for logout admin user if cross-domain access
$crossDomainAccess = FALSE;

// Check if the user isn't logged in. Likely meaning that the action is called from another domain.
if ( !craft()->userSession->isLoggedIn() ) {

  // Get allowed origins
  $locales = array('en','nl');
  $allowedOrigins = array();
  foreach ( $locales as $locale ) {
    $allowedOrigins[] = craft()->config->getLocalized('siteUrl', $locale);
  }

  // Check origin and give access if allowed
  $httpOrigin = $_SERVER['HTTP_ORIGIN'];
  if ( in_array($httpOrigin, $allowedOrigins) ) {
    header('Access-Control-Allow-Origin: ' . $httpOrigin);
    header('Access-Control-Allow-Credentials: true');
    craft()->userSession->loginByUserId(1);
    $crossDomainAccess = TRUE;
  }
}

Explanation of the code:

As you can see I set the locales to en and nl. Because that's the only locales for my website.

$locales = array('en','nl');

The domains that are allowed to communicate with each other are set in the general config file under siteUrl. See step 4 of the localization guide for more information.
We will fetch them here and put them in an array for checking.

$allowedOrigins = array();
foreach ( $locales as $locale ) {
    $allowedOrigins[] = craft()->config->getLocalized('siteUrl', $locale);
}

We check the origin of the request and if it's allowed to communicate with this domain. If so, then set the header to allow cross-domain access.

And automatically login as the admin user to get full access for the preview page to load as if you are logged in on the other domain.

$httpOrigin = $_SERVER['HTTP_ORIGIN'];
if ( in_array($httpOrigin, $allowedOrigins) ) {
    header('Access-Control-Allow-Origin: ' . $httpOrigin);
    header('Access-Control-Allow-Credentials: true');
    craft()->userSession->loginByUserId(1);
    $crossDomainAccess = TRUE;
}

Next we need to logout the admin user on the other domain. Add the following code:

if ( $crossDomainAccess == TRUE ) {
  craft()->userSession->logout();
}

Before the line (In the same function, public function actionPreviewEntry()):

$this->_showEntry($entry);

And that's it. A quickfix for anyone that has come across this problem and wants to fix it quick but dirty for now.

Note: If you update your craft cms, then this code will get deleted, so you have to add it again after you updated.

If you're using baseCpUrl

Slight modification if you're using the baseCpUrl setting and/or have paths in your settings file:

if ( !craft()->userSession->isLoggedIn() ) {

  // Get allowed origins
  $allowedOrigins = array(
          parse_url(craft()->config->get('baseCpUrl'), PHP_URL_HOST),
          parse_url(craft()->config->getLocalized('siteUrl', 'en_us'), PHP_URL_HOST)
  );

  // Check origin and give access if allowed
  $httpOrigin = parse_url($_SERVER['HTTP_ORIGIN'], PHP_URL_HOST);
  if ( in_array($httpOrigin, $allowedOrigins) ) {
          header('Access-Control-Allow-Origin: ' . $_SERVER['HTTP_ORIGIN']);
          header('Access-Control-Allow-Credentials: true');
          craft()->userSession->loginByUserId(1);
          $crossDomainAccess = TRUE;
  }
}

Here I've hard-coded the language in, but it can be combined with the answer above instead.


Craft's control panel search function returning inconsistent results

MySQL uses a list of stopwords when performing full-text searches. As you can see, about and still are in there... At the top of the page they say:

  False hits or misses might occur for stopword lookups...

I think this is the issue here. One way to get around it in your case is to add the below in your config/general.php (docs):

'defaultSearchTermOptions' => [
    'subLeft' => true,
],

If the above helps, another thing you can try is to change the storage engine your searchindex table from MyISAM to InnoDB. That would allow you to remove what you've added in your config/general.php but would require you to have at least MySQL v5.6+.


Nesting level too deep - recursive dependency?

I figured this out, with help from a GitHub thread or too. It appeared that using the sort filter on an array of objects was problematic. I was able to fix this by sorting the keys in speakers instead of directly sorting speakers.

Working code:

{% for speakerKey in speakers|keys|sort %}
  {% set speaker = speakers[speakerKey] %}

  <li>{{ speaker.title }}</li>
{% endfor %}

I'm not 1000% sure exactly what was breaking, but I think by using |sort on a collection of objects, PHP ended up recursively looping through the speakers array in an attempt to sort it.

Here are some related threads that I pieced together to guess that |sort was the problem:

Nesting level too deep when looping through matrix blocks
https://stackoverflow.com/questions/3834791/fatal-error-nesting-level-too-deep-recursive-dependency
https://github.com/craftcms/cms/issues/5794


My site is down and I can't access the admin panel after attempting an automatic update


Does it make sense to use Craft with relative links?

I would question the need to have relative URLs to begin with.

As Brad mentions, Craft neatly solves the multi-environment problem for you.

If you come from an environment like WordPress where it makes absolute URLs for you and then you end up having to do a find-replace on the content when switching environments (since there's no "built-in" way to do it), I can see where your co-worker might think relative is the way to go. However, even WP has good reason to do so.

Back before content management systems, relative URLs were probably the way to go because they are easier to code by hand; if you used conventions like "../" your pages also worked locally. Now with systems like Craft and local testing servers, creating links within content is much more consistent.

Craft even has a find/replace tool in the CP if you want to make sure those staging/production URLs absolutely get switched over in the database as well.

Speaking of consistency, google wants you to be as efficient as possible. From an SEO perspective, this moz post goes over the pros and cons of relative vs absolute but a few points worth summarizing:

Scrapers can be a big problem stealing your content. Absolute URLs make it a bit more difficult for the laziest of them.
By using things like rel="canonical" and letting Craft spit out your main base URL consistently, you can help avoid duplicate content issues.

Yoast gives some thoughts on this as well but I'll leave you with one takeaway:

  The few minutes a developer might save by using relative URLs are offset by countless hours an SEO might be spending to solve the issues caused.


How to get Current Entry ID in Plugin Variable?

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

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

    $criteria->elementId = $elementID;

    return $criteria->find();
}

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

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


Is it possible to get the md5 hash of Craft's latest version from the download server?

Currently not, but that's not a bad idea and probably worth adding to https://feedback.buildwithcraft.com.

During an auto-update, the file name of the patch file that is downloaded happens to be the MD5 sum of the file so the Craft client can verify the integrity of the downloaded file, but there isn't a mechanism like that in place currently for full Craft downloads.


So having tried bringing it locally and getting a multitude of errors, I realized the live site was version 2 and I was installing version 3.

Following the upgrade guide solved it for me (among some minor plugin tweaks).


What would be the best way to track downloads by user?

You can track the number of times a file has been downloaded using the Asset Count plugin by Verbb.

As the readme shows, rather than linking directly to your files, you’d point the link to the plugin’s controller action:


How can I add field content to an asset in code?

It propbably works to store the custom field directly with your new element model:

$assetFileModel->setContentFromPost(array(
    'captionFieldHandle' => $myCaption,
));


Showing and playing video's in Twig templates

You're close!
Because an asset field can potentially contain multiple items you need to explicitly select the first one, so:
{% set video = component.video.one() %}
But that doesn't get the actual url of the video, to get that you need to request it:
{{ video.url() }}
So in your case:
{% set video = component.video.one() %}
{% if video %}
   <video width="800" height="500" controls>
      <source src="{{ video.url() }}" type="video/mp4">
   </video>
{% endif %}

If you do find yourself needing to show multiple files, then you'd wrap it within a loop:
{# Get all the files #}
{% set videos = component.video.all() %}

{# Check to see if videos has anything in it with '|length' #}
{% if videos|length %}
    {% for video in videos %}
       <video width="800" height="500" controls>
          <source src="{{ video.url() }}" type="video/mp4">
       </video>
    {% endfor %}
{% endif %}


You don't wish to just pull down the production environment to your development server? This is how we solve this problem at work, by only editing the production server's database and then pulling it when it is updated.

There are quality scripts for syncing environments from the command line. You can simply run ./pull_db.sh and it will do everything for you.
https://github.com/nystudio107/craft-scripts

There are also new craft 3 plugins for export/import but I have not had much success so far.


We just fixed this yesterday with Contact Form 1.8.1.


Is this something that can be done with the Craft page when saving an entry?

In 2.2, there isn't an easy way.  In the upcoming 2.3 release, we added a $performAction property to the event, so your can do something like:

$entry->addError('attribute', 'MyErrorMessage');
$event->performAction = false;

And Craft will not save the entry and return to the edit entry page to display any validation errors.

You should post your second question as an entirely new question.


some assets have volumeId set to NULL in database

Is it normal?

Yes. It's a nullable column in the database.

  Should I attach them manually to some volume?

Nope. There are many scenarios where Craft creates temporary volumes and temporary assets where they won't belong to an "official" volume.


Get all entries attributed with category

Found an answer to this here: https://craftcms.stackexchange.com/a/4132/3890

The important thing to note is when you're using relatedTo you're not passing a slug, you're passing a whole object. So just .relatedTo('category-name') won't work.


I just figured out the answer so I'm going to post it if anyone else is asking this question. Yii accepts aliases as well as function/class names when evaluating the rules function. When using number you're really using an alias that points to the yii\validators\NumberValidator class. See yii2/validators/Validator.php to see a list of default aliases created by Yii.


There is no way out-of-the-box so your only options would be to either create a module that passes multiple XML files into feed me using the direct feed url or to create a script/use software that merges all the files into one.


How can you crop an image and output from a Matrix field?

When you call .first on an Asset field, that's going to return an AssetFileModel.

Change the relevant part of your code to this:

{# grab the first image #}
{% set image = block.image.first() %}

{# link to the full sized version #}

    {# generated the transformed thumbnail version #}

{{ block.imageTitle }}

{{ block.imageContent }}


You want something like this:

{% set seo = craft.seo.custom(
    'Welcome back, ' ~ category.title ~ ', Test Meta Description!'
) %}

Or even more clear (to me anyway):

{% set seo = craft.seo.custom(
    "Welcome back, #{category.title}, Test Meta Description!"
) %}

More here: https://twitter.com/nystudio107/status/938018528527036416?s=21


How to create a relation to multiple assets in my Plugin Model/Record?

I think what you're asking is how to define the relationship using Active Record in the other direction - going from Craft's AssetFileRecord to your plugin's EstateRecord.

And the answer is that you can't without hacking the AssetFileRecord and manually adding a BELONGS_TO relation back to your Estate Record.

You're going to be much better off ditching records and active record for this all-together, I think.  Have your service layer use the Query Builder craft()->db->createCommand() directly, then you can join in any data you want from any tables outside of the context of active record.


For anyone interested, I had set web/index.php to production.

The reason why both staging and production were working was due to me using the same username and password for the database.

Once I had changed this to dev, it now works so I no longer need the .env file.


Brad, Thank you again for your help.

I found the problem, although I'm not sure of "why". In my service file, I have this line:

$email->body = craft()->templates->renderString($settings->welcomeEmailMessage, ['firstName' => $contact->firstName]);

After digging though log file(s), I found the error. "Unexpected '['"

It needed to be this:

$email->body = craft()->templates->renderString($settings->welcomeEmailMessage, array('firstName' => $contact->firstName));

Because everything was working perfectly on my local machine, (newer version of php) I wonder if that's the root cause.


Simple Search form with a few drop-down choices

I would probably create some categories for make,  color and transmission and relate every entry to it. Then you have the ability to use craft.entries... to fetch the entries as you need them. You can find all specs of the entries method in Craft's docs -  just fetch all entries that are related to the category you want.

Depending on the total number of entries you could just fetch (and cache) all entries every time and use a javascript filter mechanism. I worked with isotope before.

Using js you can achieve a smoother UX once all entries are loaded. However, best practice would be to start coding without js and make it work and then enhance the experience with js. Depends on your budget.


Recommended CPU/RAM VPS settings to query 50,000 entries

The CPU won't be the issue more the RAM if you expect to pull in all those results. But it's not much anyways.... A 1 CPU/1GB RAM on Digitalocean will be enough.


PHP Fatal error: Uncaught Error: Class 'Craft\DbConnection' not found

This project was missing the craft/app/etc/db/directory and all files within that directory (my .gitignore file had meant to ignore the project root db directory, but caught all directories named 'db'). Removing 'db' from my .gitignore and re-pushing to my server solved this error.


How can I tell if a field exists in a block of a matrix?

You can use {% if block.stepAccordionContent|length  %}...{% endif %} to test if any rows are defined in your table field.

Note: When you create a table field it will have an empty row defined under 'Default Values', which should be removed; otherwise all new instances of the table will have an empty row defined by default causing block.stepAccordionContent|length to return 1, instead of 0 as expected.


I'd probably have products as a channel and then a product being tied to a category so and then category urls would be something like /products/category


Yeah the server is probably misconfigured. Craft relies on a 404 happening to do some of what it does, but the status code should be changed before the response is returned.

I don't have enough information to tell you how it is misconfigured. Would depend on the webserver (Nginx/Apache/whatever) and we'd need to see the specific config.

There also is no /sitemap.xml on the site.


User registration form with checkbox field

Just in case anyone else has this issue i got it working with these modifications.

I think the hidden field was required for the possibility of null values.

<input type="hidden" name="fields[myCustomField]" value="no">

It also required the extra [] brackets after the field name in the checkbox option (as checkbox fields are an array).

name="fields[myCustomField][]"

Here's my code thats working:

            <input type="hidden" name="fields[termsAgreement]" value="no">
            <input type="checkbox" id="termsAgreement" name="fields[termsAgreement][]" value="yes">

             I agree to terms and conditions above
            </label>
            {{ account is defined and account ? errorList(account.getErrors('termsAgreement')) }}


It's pretty much impossible to be sure just by looking at the site. But there's a good chance the links are coded into the templates.

Again, the exact template could be anywhere. It's common to create a partial include it in a layout template but could equally just be within the layout template itself.

You don't say if this is Craft 2 or Craft 3 but you'll need to look in either /craft/templates for Craft 2 or /templates for Craft 3

You may also find you have an add on such as NavEE or A&M Nav installed. This allows the creation of navigation blocks which can be included in templates. So you might find the links in there.


Sounds like you didn't completely roll the database back to 3.1 before re-trying the update. That table probably got created the first time you tried to update to 3.2.

Make sure the database is wiped 100% clean before rolling back to your 3.1 database. Then try updating again.


Migrate Craft CMS installation from PgSQL to MySQL - any hints?

For others finding this post: we never made it. We invested > 2 days and then decided to stay with postgresql for this project.


You're getting that error because CSRF validation is failing.  Whether that's a bug in the Dev Preview of Craft 3 or something environmental on your end is hard to tell with the given information.  I can't reproduce it locally, though.


Can I add an enabled-by-default lightswitch field to existing entries?

If there was no default set beforehand, then your previous elements will have a value of null for that field. You should be able to include those in your "on" queries by querying for that null value as well as the "on" value in your templates:

{% set onEntries = craft.entries.yourLightswitch([null, '1']).find %}

This won't actually change the value of your previous elements though. One way to do that would be using a SQL query against the craft_content table to update rows (elements) that have null in that column:

UPDATE `craft_content` SET `field_yourLightswitch` = 1 WHERE `field_yourLightswitch` IS NULL;


This should do what you're looking for:

{% set someEntries = craft.entries({
    level: 1,
    id: '1,2,3,4,5',
    myOtherField: 'and, not blue, not green'
}) %}


Is it possible to get a tweet image when using Twitter plugin

There should actually be a entities.media property available in the JSON, when there are images attached to the tweet.

This is what works for me:

{% set tweets = craft.twitter.get('statuses/user_timeline') %}

{% for tweet in tweets %}

{{ tweet.text }}

        {% if tweet.entities.media is defined %}
            {% for item in tweet.entities.media if item.type == 'photo' %}

            {% endfor %}
        {% endif %}

{% endfor %}


Store form data with file upload in an asset source using Freeform

You could try to use Craft and/or freeform hooks https://solspace.com/craft/freeform/docs/events-and-hooks/#events-freeform-forms and fetch the assets related to the entry during the beforeSaveprocess, add field values of the submission to it and save it again. There are examples how to do this in Crafts documentation

Or the most flexible (and for me easiest) thing: create a custom controller that extends the freeform controller and add a few lines to attach those information to the asset.


How can I iterate through an array of field handles for an entry?

I figured it out! I ditched the macro and just included the following in my template:

{% for field in courseFields %}

{{ field.title }}

    {{ entry[field.handle] }}

{% endfor %}


Channel Section with individual entry template and index templates?

The way I've done this in previously is in your templates have a directory titled Resources and inside that directory another directory titled _types

Within the _types directory I will have the code to output the content based on the entry type. I would name each of those templates ENTRY-TYPE-HANDLE.html

The on your Resources index user the following:
{% include "resources/_types/" ~ entry.type %}


Main email address for "Contact Us" in settings is not changing

If you are using the popular 'Contact Form' plugin, try Settings > Contact Form (under Plugins heading) and the field you want is the first field, 'To Email'.
The variables in Globals are 100% custom but usually change the email address that is displayed sitewide such as in your footer or contact page. They can be, but are not necessarily, wired into your contact form.
If you can't see Settings in the left side nav, or the Plugins section in Settings, you may need to request greater permissions from your CMS admin.
Be gentle (mods), this is my first answer in a long time ;)


Completely untested, but something like this should work:

{{ !object.id ? (object.locale == "jp" ? "Japanese title" : "English title") : object.title) }}

Basically only run your logic if the entry doesn't have an ID yet (which new entries won't until they are saved).


Only allowed 100 queries with relatedto?

The reason this happens is Craft has a default limit of 100 for all ElementCriteriaModel objects (this includes assets, categories, entries, tags, and users, also relations as you encountered).

This isn't made terribly clear in the documentation, but you can see it under the defineAttributes() method on the ElementCriteriaModel class reference page.

As you discovered, adding a .limit(null) parameter overrides that limit.


Ignoring "The " and "A " when sorting entries

How to achieve the same functionality on Craft 3?

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

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


Database Exception Column not found: 1054 Unknown column 'configVersion' in 'field list'

After executing: craft migrate/up --type=app it works again.


Display Backend User Entries on Front end

Assuming completed is an Entries field, and you want to test if a particular entry has been added to the currently logged in user's completed field, something like this'd work:

{% set isEntryCompleted = currentUser and entry.id in currentUser.completed.ids() %}

{% if isEntryCompleted %}
    ...
{% endif %}

The idea here is to first check if currentUser is set (it'll be null if the current user isn't logged in), and then pull an array of all selected entries' IDs with currentUser.completed.ids(). Finally you can use the in operator to check if a particular entry's ID is in that array.


Contact Form email address set in the plugin's setting being changed by Linode server?

Generally I've been dissatisfied with the craft cms contact form plugin. Fortunately, this doesn't need to be handled with the CMS. I've been using third party tools such as Formbucket to handle form submissions for several reasons.

Reliability is extremely important. Most clients will not tolerate any mistakes regarding lead generation in contact forms.
Feature rich. Craft's contact form plugin is very barebones and ugly. With formbucket and other form submission collection tools, you can add as many fields as you want instead of segmenting message. There is also honeypot and recaptcha fields to keep out spam.

I know this is probably not the answer you were looking for, and I wish you the best with getting it to work, just wanted to let you know how i've been doing it.

PS: I don't work for Formbucket.


Craft\SproutForms_EntryModel and its behaviors do not have a method or closure named

Make sure those "missing" fields aren't used in the title format (under the advanced tab) or in your notifications -  both in the control panel. Ran into something similar just now.


Get username and email on setpassword form

Craft currently doesn't expose that user info to the setpassword template.

You could write a plugin that mimicked that portion of Craft's UsersController except returns the UserModel (or part of it) to the template and/or make a feature request to expose more of info to that template.


I guess that each of these PDFs are related to an entry using an assets field.

If this is true, you could add an extra field "Random Path" to that entry and use that field's value as a segment of your PDF's URL.

You can achieve this by setting the upload location for the PDFs to a subfolder named after that field's value. You set the subfolder path (i.e. to {randomPath}) in Settings → Fields → "myAssetField" → Default Upload Location.

If the randomPath field has a value of mUampRNYxcwXampC9QX, an PDF file mySecureFile.pdf is saved like so: /myPdfFolder/mUampRNYxcwXampC9QX/mySecureFile.pdf (in fact it is moved after the entry is saved).

To generate random strings for that field, use the fantastic Craft plugin "Randomm" by Fred Calsen.


Under the PhpStorm preferences, go Editor->File Types->Twig and add *.html as a Registered Pattern.


What's the correct way to uninstall a plugin which MUST NOT be enabled?

You will need to enable it to uninstall it but you can do everything via CLI.
First ./craft plugin/enable plugin-handle then ./craft plugin/uninstall plugin-handle then composer remove namespace/package-name.
If you really can't enable it as above, you'd need to composer remove namespace/package-name and manually remove any references in your plugins table, project config as well as any tables the plugin may have created on install.


Getting an zero index and count for an entry list

There's an easier way... Twig has a built-in variable in for-loops called loop, which has loop.index and loop.index0 properties which output exactly what you're looking for:
https://twig.symfony.com/doc/3.x/tags/for.html#the-loop-variable
{% for project in sliderWork %}

{{ loop.index }}{{project.title}

 {% endfor %}


Charge 2 - Stripe form fields not showing

After looking into the source code of the encrypt function, the craft.charge.setPaymentOptions() function calls mcrypt_module_get_algo_key_size and because my vagrant box (ubuntu 14.04) didn't have php5-mcrypt installed, it failed there.

To fix it: run apt-get install php5-mcrypt && sudo php5enmod mcrypt.


Disable image cleansing for public facing form uploads

The imageDriver setting just determines which driver Craft should use when working with images (GD or ImageMagick) for things like image cleansing and image transforms. So changing its value will not affect whether images are cleansed on upload; just which driver would be used for that process.

If you want to disable image cleansing on the front end, you will need to write a plugin that handles the upload. You can find out how to do that from this answer: https://craftcms.stackexchange.com/a/9675/9


You can use UrlHelper::getSiteUrl() instead, which does have a $localeId argument, for generating a URL relative to a given locale’s base URL (per the siteUrl config setting).

So if your siteUrl config setting is set to:

'siteUrl' => array(
    'en' => 'http://example.com/',
    'de' => 'http://example.com/de/',
)

and you do this:

UrlHelper::getSiteUrl('foo/bar', null, null, 'de');

it will return this:

http://example.com/de/foo/bar

(Regardless of which site you call it from.)

UrlHelper::getSiteUrl() is also available to Twig templates via a siteUrl() global function:

{{ siteUrl('foo/bar', null, null, 'de') }}


The documentation posts this link:
Upgrading from Craft 2

Mijingo has a tutorial: Upgrading Craft 2 to Craft 3

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

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


Bulk upload images, generating a seperate page for each image

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

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

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


I second Brad on this, if there is a composer package, use that.

Whether you use a composer package or a library not found on packagist.org you'll still need to load it so that your plugin can make use of it.

Generally speaking, there are plenty of places where you can import/require third party libraries from but my recommendation would be to do so from the init() method in your main plugin class. As far as where to put it, I would go with one of these 5 acceptable directory names used most often in no particular order library, common, third, lib, or src. I'll use library in the following example.

Once you've downloaded/installed your third party library, your directory structure might look something like this...

plugin
    PluginClass.php
    controllers
    templates
    ...
    library
        campaignmonitor
    OR
    library
        vendor
            composer
            campaignmonitor
            ...

Given the outlined directory structure above, your init() method might look something like this...

// PluginClass.php
public function init()
{
    require_once './library/campaignmonitor/SomeClass.php';
    require_once './library/campaignmonitor/SomeOtherClass.php';
    ...
    // If using composer
    require_once './library/vendor/autoload.php';
}

I'd also like to point out that Craft::import() can theoretically import using glob as in Craft::import('plugins.pluginname.library.*) which is cool because those don't get required right away but lazy loaded when needed. However, this only works for class in the Craft namespace so you'll have to stick to a method described above: )

Hope that helps!


Seems to be a browser bug. Dashboard is not working with Firefox 20. With Firefox 31 admin is working.


How to enable changing the status of my own Element Type

That's because those buttons are ActionButtons and they have actually nothing to do with statuses in general since the status is not a single field value nor is there a value in the DB that's called status. For example: the status of an entry depends on several different attributes like expiryDate or the date when it's published so there is no way to set those statuses via button there.

You'll need to register the action buttons for your element type. Just take a look at an entries defineActions function.


Running Craft Console Commands on Webfaction

Turns out this was a problem with running the right version of PHP. I was able to fix the issue by changing my command from php to php74, directly specifying the version of PHP that I want to run. This should work with php71 php73 and future versions like php80 too.
Here's what my commands look like now:
php74 craft migrate/all
php74 craft project-config/sync


The way you want to achieve this won't work. Twig is just a render engine for php so you can't execute it during your runtime. You could load all entries during the page load and create a twig filter to json_decode them in order to gain access with javascript or you can do something really really nasty like

{% set allEntries = craft.entries.section('comics').order('id asc') %}
<script>
    var entries = [];
    {% for entry in allEntries %}
        entries.push({
            title: "{{ entry.title }}",
            body: "{{ entry.body }}",
            url: "{{ entry.getUrl() }}"
            // .....
        });
    {% endfor %}
</script>

To get an array of objects in javascript. But I would not suggest this. The clean way would be to create an ajax request and fetch the entry with php

Have a look at this to learn how to create an ajax request to a controller. You would have to change your controller to:

public function actionSearchEntry()
{
    $id = craft()->request->getParam('id');
    $element = craft()->elements->getElementById($id);

    $criteria = craft()->elements->getCriteria(ElementType::Entry);
    $criteria->section = "comics";
    $criteria->orderBy = "id asc";
    if(!$nextElement = $element->getNext($criteria)){
        $this->returnJson([
            'success'   => false
        ]);
    }

    $this->returnJson([
        'element'      => [
            'title' => $nextElement->title,
            'body'  => $nextElement->body,
            // ....
            'id'    => $nextElement->id
        ],
        'success'   => true
    ]);
}

In your javascript you'll create an ajax request and change the values to the one you received if it was successful (if not there will be probably no other entries.


Without having to use a separate Plugin this is a good basic practice on setting up basic SEO for your site.

First create three new fields called "seoTitle", "seoDescription" and "seoKeywords". Put these three fields in a Global group called "globalSeo".

In your layout template "layouts/_layout.html"

    {% set seoTitle = globalSeo.seoTitle %}
    {% set seoDescription = globalSeo.seoDescription %}
    {% set seoKeywords = globalSeo.seoKeywords %}
    <!DOCTYPE html>
    <html>
        <head>
            <title>{% if title is defined %}{{ title }}{% else %}{{ seoTitle }}{% endif %}</title>
            <meta name="description" content="{% if description is defined %}{{ description }}{% else %}{{ seoDescription }}{% endif %}"/>
            <meta name="keywords" content="{{ seoKeywords }}"/>

            {# You can then use the same fields for Facebook tags etc.. or create separate fields. #}
            <meta property="og:title" content="{% if title is defined %}{{ title }}{% else %}{{ seoTitle }}{% endif %}"/>
            <meta property="og:description" content="{% if description is defined %}{{ description }}{% else %}{{ seoDescription }}{% endif %}"/>
        </head>
    <body>

You can now per template override these standard variables with your own for that particular page and/or template.

For a template:

    {% extends "layouts/_layout" %}
    {% set title = "This is a my custom Page Title" %}
    {% set description = "This is a my custom Page Description" %}

For a entry:

    {% extends "layouts/_layout" %}
    {% set title = entry.title %}
    {% set description = entry.descriptionField %}

.. or if you want to user to have custom control over the entry SEO as well you can always add the same "seoTitle" fields to the entry's Channel/Structure/Single and do:

    {% extends "layouts/_layout" %}
    {% set title = entry.seoTitle %}
    {% set description = entry.seoDescription %}


How to change the display of asset fields in the control panel via plugin?

Short answer: no. The thumbnail size (30x30) is hardcoded into the method you found (_getCpElementHtml), so there's no way you can change that.

You could try extending the control panel's CSS (using this plugin) to enlarge and/or hide certain elements, but that won't get the thumb any bigger.


Database Exception: Column not found: 1054 Unknown column 'position' in 'order clause'

Command ./craft migrate/all fixed this issue.


Craft 3 setPasswordPath config not working for front end users

If you really want to change the password action url (not the password path) you can only do that in your Twig template and use the |replace('actions/users/set-password', 'account/set-password') filter.

The action url is hard coded in PHP and I would suggest you not to change it unless you know what you are doing. It would by default route to an action that does several important things and then redirects to the passwordPath.

So when you replace the route you should include the logic into your custom controller or create a site url rule to the default action


You could wrap this in another for loop and put a condition on the inner fors,

something like

{% for option in myPositionDropdown %}

{{ option.value }}

  {% for position, playersInPosition in playersGrouped if position == option.value %}

    {% for player in playersInPosition %}
      {% set playerData = craft.entries.section('myPlayersChannel').relatedTo(player).first() %}

        {{ playerData.fullName }}
        {{ playerData.age }}
        ...

    {% endfor %}

  {% endfor %}

{% endfor %}

(untested code)

That sort of idea though, loop the dropdown in order and show the grouped results. Heck, you probably don't need to group them at all since you're filtering them out in each loop.

HTH


How can i detect that an asset has been published from a plugin?

You could use the entries.onSaveEntry event to get entries as they're saved, check the publish date, then loop through its properties, and check the paths on any assets.

You'd probably also want to hook into entries.onDeleteEntry to de-index any assets from entries that get deleted.

Please note: this won't auto-index entries that were scheduled to publish at a later date.


The problem you have here is you are calling saveElement from EVENT_AFTER_SAVE_ELEMENT which is causing an infinite loop.

You need to set:

$entry->propagating = true;

Before calling the saveElement method.

Dates should be a PHP DateTime class, e.g:

$entry->rangeStart = new \DateTime('2019-04-10 19:00:00');


You would loop through the Matrix field within each tab the same way you’d do it for any other element.

{% set tabs = entry.descendants %}
{% for tab in tabs %}
    {{ tab.title }}
    {% for block in tab.myMatrixFieldHandle %}
        {% if block.type == 'about' %}
            ...
        {% elseif block.type == 'team' %}
            ...
        {% elseif block.type == 'clients' %}
            ...
        {% endif %}
    {% endfor %}
{% endfor %}