The difference between "raw" and "escape" is sometimes confusing... Try this instead:

{{ element.blockContent|e }}

escape:

  The escape filter escapes a string for safe insertion into the final output.

raw:

  The raw filter marks the value as being "safe", which means that in an environment with automatic escaping enabled this variable will not be escaped if raw is the last filter applied to it.


Freeform Plugin: Success Page and Submission ID - Template not Found

Did you set up a route and assign a template to it?

contact/success/{{ number }}


Permission error on session_start() after 3.5 upgrade

Easy fix. Removed all session data which had www-data:www-data ownership.


Custom status based on chosen payment gateway

Listen for the onBeforeOrderComplete event and do something like this (replacing values to match your setup).

craft()->on('commerce_orders.onBeforeOrderComplete', function($event){
    $order = $event->params['order'];
    if ($order->paymentMethodId == 2)
    {
        $order->orderStatusId = 3;
    }
});


Craft Commerce Currency - Email template not showing currency

You need to pass the currency to the conversion filter.

The order is always made in the primary currency, but the payment currency that they made the payment in might be different, so you need to pass order.paymentCurrency to the conversion filter.

You can read about using different currencies here:
https://craftcommerce.com/docs/payment-currencies

In addition to just changing the filter to |commerceCurrency take a look at the docs for the filter for the optional formatting and conversion options:
https://craftcommerce.com/docs/twig-filters


Implementing two factor authentication / TOTP for CP logins

I know this is a little late, but i've just build a plugin for TOTP. It is in beta, so beware before using it in a production environment.
https://github.com/born05/craft-twofactorauthentication


loop.index is not returning correct number inside nested loop with inline if conditional

I'm guessing you want to display the loop index of the outer for loop.

To do that, Twig provides a loop.parent context.

{% for order in orders %}
    {% for refund in order.transactions if refund.type == "refund" %}
        {{ loop.parent.loop.index  }}
    {% endfor %}
{% endfor %}

If you're looking to get the total number of times the inner loop gets hit, then something like this should work:

{% set loopCount = 0 %}

{% for order in orders %}
    {% for refund in order.transactions if refund.type == "refund" %}
        {% set loopCount = loopCount + 1 %}
        {{ loopCount  }}
    {% endfor %}
{% endfor %}


You can achieve progressive JPGs if your server has Imagick installed, but it doesn't look like the image processing library that Craft is using has added support for it, yet.


If you're looking for a purely Twig/template solution, then your best bet would be to either enable devMode and use Twig's dump() method or install something like the Craft Kint plugin.

Keep in mind that both of them are going to give you much more information than just attributes available on a model (like the array of OrderModel's your example is going to return), but that info will be included.


This works but using this code can be a problem if you are dealing with a huge number of rows.

To access the n-th row, you can use:

{{ entry.blockRepeater.findElementAtOffset(n-1).heading }}

I found this method in the ElementCriteriaModel class. You can test if a certain row exists using entry.blockRepeater.offsetExists(n).


Assets S3 Cache Duration and CP Thumbnails

With the correct cache busting, files can remained cached for as long as possible. Craft handles a lot of this for you.
I typically cache items for a year but do take caution to ensure every reference to assets within the site has a cache busting string on it. It's important to note that Cloudfront needs to be setup to use these query strings.
On the frontend, Craft appends an mtime attribute to the query string. If you ever replace an asset, the mtime is updated and subsequently a new cache is created.
Within the Craft CP, thumbnails of your remote images are generated rather than serving them from a CloudFront URL, generally there are no worries with caching here as Craft handles that.
Volumes with an expiry set will automatically load the mtime parameter when fetching the URL from Craft. Alternatively, you can implement your own cache busting with the url() function shown here.


As it happens, this solved my issue: {{ personfirstandlastname|replace({'\'':''}) }}

EDIT

To clarify, this isn't a valid Twig object:

{'\'',''}

... while this is:

{'\'':''}


Only see 3 textarea field on Plugin Setting Page

After shuffle all textareaField, I found the 4th one custApptReminder1 misspell in function defineSettings() at my plugin.php. After corrected it, the field is show up.

protected function defineSettings()
    {
        return array(
            'custAccountCreation' => array(AttributeType::String),
            'custAccountCreationSubject' => array(AttributeType::String),
            'custApptReminder'=> array(AttributeType::String),
            'custApptReminder1'=> array(AttributeType::String),
        );
    }


How do you set a user's group on a registration form?

If you're looking for a Craft 3 solution, I just got this set up on a project and hope it helps someone else out.

First you'll need to add a custom field to your form.  If you want your user to choose which field, then go with a dropdown or radio button and adjust the plugin logic below. My scenario required me using a hidden field and auto-filling in the value based on a query parameter in the url.

<input type="hidden" name="myHiddenInput" value="1">

In your custom plugin's primary class, use this service at the top of your file:

use craft\services\Users;

and then in the init() function add this event and adjust the code to your liking:

Event::on(
    Users::class,
    Users::EVENT_AFTER_ASSIGN_USER_TO_DEFAULT_GROUP,
    function(UserAssignGroupEvent $event) {

        // get your hidden input value, 1 for true, 0 for false
        $isInDifferentGroup = Craft::$app->getRequest()->post('myHiddenInput');

        if ($isInDifferentGroup) {
            $differentGroup = Craft::$app->userGroups->getGroupByHandle('differentGroupHandle');

            $userId = $event->user->id;
            $customGroupId = $differentGroup->id;

            // add more group ids to array in 2nd param to add user to multiple groups
            Craft::$app->getUsers()->assignUserToGroups($userId, [$customGroupId]);
        }
    }
);

Shout-out to Oliver Stark from fortrabbit for helping me with this.


All images uploading... except JPG files

I had this same issue and resolved it (at the suggestion of Craft CMS support) by enabling ImageMagick in the php.ini and restarting MAMP PRO.

Per the MAMP PRO 3.0 user guide:

The ImageMagick PHP module is included by default, but you must enable it inside the php.ini template file. Remove the ‘;’ from the following line.
;extension=imagick.so


Seems like what you're looking for is under Commerce Settings->Payment Methods, set the "Credit Card Payement Type" to "Authorize Only (Manual Capture)", then set the "Payment Gateway" to "Dummy".


Craft and AJAX page transitions - how to exclude local hash links from executing AJAX?

The function you mention isn't the problem. It isn't being called because, as you say, the exclusion clause is working perfectly.

But you also have a hook on the window.popstate which is triggered when you change the URL (by adding #contact to it for example).

This hook, as below, subsequently fires the loadPage function you have coded:

$(window).on("popstate", function(e) {
    // -------------------------------------
    //   If there was an AJAX page transition already,
    //   then AJAX page load the requested page from the back or forwards button click.
    //   Variable initially set after the $main variable.
    // -------------------------------------
    if (changedPage) loadPage(location.href);
  });

See more on the popstate event:

https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate

As others have mentioned though, this is Javascript specific rather than Craft, so should probably be moved or archived?


Declare a private variable inside your class, private $userId = NULL

After you've saved the user in the first method, update the variable $this->userId = $user->id

In the second method grab the user by using the variable $user = craft()->users->getUserById($this->userId);

I haven't actually tested the code, but it might do the trick :)

EDIT: You might want to make a null-check before attempting to fetch the user, to ensure that it doesn't break if it tries to run it while the variable is still NULL


While we wait for an official update, you can patch this pretty easily. Just open up craft/plugins/twitter/TwitterPlugin.php and find this function:

public function getSettingsHtml()
{
    // ...
}

Delete the function entirely, and replace it with this:

public function getSettingsUrl()
{
    return 'twitter/settings';
}


Is there an easy-to-follow tutorial to learn Craft CMS basics?

Craft has an official getting started tutorial now! https://craftcms.com/docs/getting-started-tutorial/
Original Answer:

Welcome to Craft!  Here's a collection of developer resources to help get you up to speed on Craft quickly.
The most important thing to note about Craft CMS and Craft Commerce is that they are platforms used to build bespoke solutions for clients. They are light on traditional "out of the box" features and instead invest heavily on providing developers with a modern toolset and content teams with a great author experience. In practice this means that every Craft site is made specifically for the client which is great and what clients and developers appreciate about it. The downside is if you are brand new to Craft and have no context to the original build out or developer, it can be a challenge to get up to speed.
Craft Official Docs & Support

Craft CMS docs - Pretty comprehensive and worth reading if you're new to Craft.
Craft Commerce docs
Craft Slack group - All of the Craft dev team is on Slack every day with 5,000+ other Craft developers and users from all over the world.
Craft StackExchange - You'e obviously found this one, but this is the best place to ask "how do I" implementation questions.

Learn Craft
Free and commercial.

Mijingo Craft's Tutorials — Mijingo is an official Craft education & training partner. They have a number of excellent free and paid resources for Craft & Craft Commerce. Ryan Irelan, Mijingo's founder, also offers customized training online or on-site.
Tuts+ Tutorials — Not official but very good and low cost (most are $9).
Craft Straight Up Hangouts — Hosted by Ben Parizek, these are live learning sessions with Ben and a member of the Craft team.
Studio 107 Blog — Andrew Welch is a prolific Craft developer and the creator of the SEOMatic plugin. He has some excellent developer-oriented posts on Craft that are worth reading.


I managed to get access to the slug in the transformer function by using use. I'm not sure if it's the correct way but it works for now.

'api/series/<slug:{slug}>.json' => function($slug) {
  // get category by slug
  $category = craft()->elements->getCriteria(ElementType::Category);
  $category->group = 'series';
  $category->slug = $slug;
  $category->first();

  return [
    'elementType' => ElementType::Entry,
    'criteria' => [
      'section' => ['lessons'],
      'relatedTo' => ['targetElement' => $series]
    ],
    'transformer' => function(EntryModel $entry) use ($category) {

      $firstCategory = $category->first();

      $cat = [
        'id' => $firstCategory->id,
        'slug' => $firstCategory->slug,
        'title' => $firstCategory->title
      ];

      return array_merge(structureEntry($entry), structureCategory($cat));
    }
  ];
}


Newbie: Trying to understand includeCssFile

Whenever Craft receives an URL request, it tries to figure out what resource to serve the client. Among other things, it'll look inside your templates folder and try to find the requested resource there – which is why a request to styles/index.css works if that file exists inside your templates folder. However, Craft only looks at files in your templates folder when it evaluates the request URL, nowhere else – which is why ../styles/index.css doesn't work.

In any case, it's usually a bad idea to serve external resources (CSS, JS files etc) from outside your public web root. If you can, put your CSS and JavaScript files somewhere in your public root directory, and make sure you're not using relative URLs for {% includeCssFile %} – i.e. you should use {% includeCssFile '/styles/index.css' %} if you have a folder called styles in your public web root (alongside your index.php file).

Another option is to inline your CSS files, in which case you can put the files whereever you want. I recommend the Inlin plugin for all your inlining needs:

<head>
    <style>
        {{ craft.inlin.er('styles/index.css') }}
    </style>
</head>

If you want to inline files without a plugin, you can use the Twig source function – outlined in this answer.


My guess is you're running PHP 7.4.0.  I could reproduce it on 7.4.0 on Windows, but when I updated to PHP 7.4.2, the issue went away.

This appears to be a PHP 7.4.0 bug on Windows as evidenced by this Github issue for Yii: https://github.com/yiisoft/yii2/issues/17782


Multi-environment database config being ignored

The environment-specific array that Craft uses is determined by the $_SERVER['SERVER_NAME'] variable (usuall your domain name), not the database hostname. Instead of using localhost to trigger the env-specific settings, you should use your domain. Your db.php should looks more like this:

return array(

  // default
  '*' => array(
    'server' => 'localhost',
    'user' => 'av01759',
    'password' => '*******',
    'database' => 'av01759_maltaministries',
    'tablePrefix' => 'craft',
  ),

  // production-specific (use your domain instead of example.com)
  'example.com' => array(
    'server' => 'localhost:3307'
  )

);

UPDATE: Since in this case, $_SERVER['SERVER_NAME'] actually is "localhost" for you and I understand you are connecting to a remote db, you could try using this for your db.php (swapped the value for server in my above example, this way you make the exception for production).

return array(

  // default
  '*' => array(
    'server' => 'localhost:3307',
    'user' => 'av01759',
    'password' => '*******',
    'database' => 'av01759_maltaministries',
    'tablePrefix' => 'craft',
  ),

  // production-specific
  'production-site-domain-here.com' => array(
    'server' => 'localhost'
  )

);


How to use Sprig's "Load More" Recipe After Update

The problem is that you are doing .relatedTo(category) but the variable you are passing is called relatedTo, not category.
Just like with limit, based on your code, it should be .relatedTo(relatedTo). Also, it should be part of the same hash as your limit.
However, you can't pass a category object to a component and will need to pass its id instead (docs).
Depending on what category is in your case (and I guess it's an object), you could do:
{{ sprig('_components/load-more', {
    'limit': 6,
    'categoryId': category.id
}) }}

Then in your component:
{% set offset = offset ?? 0 %}

{% set query = craft.entries().section('caseFiles').offset(offset).limit(limit) %}

{# Make sure a categoryId is being passed #}
{% if categoryId %}
    {% set query = query.relatedTo(categoryId) %}
{% endif %}

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

{% for entry in entries %}
   ------Entry Content-----
{% endfor %}

{% if entries %}
  {# Increments `offset` by the value of `limit` and swaps itself out on click #}
  <button class="orange-button" sprig s-vars="offset: {{ offset + limit }}"
    s-target="this" s-swap="outerHTML">

Load More

  </button>
{% endif %}


htaccess www to non-www redirect (and config.php)

Providing you have the necessary permissions to do this, the following in your .htaccess should do the job:

RewriteCond %{HTTP_HOST} !^domain\.co\.uk$ [NC]
RewriteRule ^(.*)$ http://domain.co.uk/$1 [R=301,L]

In place, the full file will probably look something like this:

<IfModule mod_rewrite.c>
RewriteEngine On

# Redirect to non-www domain
RewriteCond %{HTTP_HOST} !^domain\.co\.uk$ [NC]
RewriteRule ^(.*)$ http://domain.co.uk/$1 [R=301,L]

# Send would-be 404 requests to Craft
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]
RewriteRule (.+) index.php?p=$1 [QSA,L]
</IfModule>

The following seems to work for me as a generic option:

<IfModule mod_rewrite.c>
RewriteEngine On

RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]

RewriteCond %{HTTPS} on
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]

# Send would-be 404 requests to Craft
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]
RewriteRule (.+) index.php?p=$1 [QSA,L]
</IfModule>


The natural sort order for related entries is the order defined in the control panel (not the post date of the related entries), unless you otherwise specify the sort order. Here is an example taken from one of my projects, where related articles are defined within an entries field-type in an article entry:

{% set relatedArticles = entry.relatedArticles %}

    {% for article in relatedArticles %}

{{ article.title }}

    {% endfor %}

On the backend, craft uses the table craft_relations to create the relationship with the columns sourceId, targetId, and sortOrder. This sortOrder column defines the default sort order when accessing related entries through the related 'entries' field-type.

If on the other hand, you are accessing related entries using the .relatedTo() method of the EntryCriteriaModel then you will need to specify the sort order using .order('sortOrder').

Update

Here is the original code:

{% set relatedRecords = craft.entries.section('contenuDiscographie').relatedTo(entry) %}
{% for record in relatedRecords %}
    {{ record.title }}
    {% for block in record.discoArtistes %}
        {% set relatedPerformers = craft.entries.section('interpretes').relatedTo(block) %}
        {% for performer in relatedPerformers %}
            {{ performer.title }}
        {% endfor %}
    {% endfor %}
{% endfor %}

Try using the actual relationship field:

{% set relatedRecords = entry.myRelatedEntriesFieldHandle %}
{% for record in relatedRecords %}
    {{ record.title }}
    {% for block in record.myMatrixBlockFieldHandle %}
        {% set relatedPerformers = block.myRelatedEntriesFieldHandleInsideMatrixField %}
        {% for performer in relatedPerformers %}
            {{ performer.title }}
        {% endfor %}
    {% endfor %}
{% endfor %}

Edit I edited the code above to be more generic, rather than trying to guess what the field handles are named in your project. You need to change these to your actual field handles. From the picture above I would guess they might be 'entry.relatedRecords', 'record.discoArtistes', and 'block.nom' for example.


How to I set the location folder of Control Panel resources?

Thank you @Brandon Kelly for the solution:

  That’s because @webroot is only reliable on web requests. To fix,
  update your resourceBasePath config setting to a real path:

  'resourceBasePath' => dirname(__DIR__) . '/web/cpresources'


can't login after move site to local - empty response

Finally i got it.
It was an issue with the .htaccess
I had not a default installation .htaccess, but a special one.
What helped in my case wa putting following into the .htaccess
    # Remove www from URL's
    RewriteCond %{HTTP_HOST} ^www\.(.+)
    RewriteRule ^ http%2://%3%{REQUEST_URI} [L,R=301]

    # Remove trailing slashes
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^(.*)/$ /$1 [L,R=301]

But also got issues similar to this answer afterwards: https://craftcms.stackexchange.com/a/35846/11140


Moved from dev to prod server, admin page blank

I found the problem - the htaccess file was still the old EE file that had been there. Once I uploaded the Craft-provided htaccess file, I was able to get back into the control panel. Thanks for the help guys!


Force redirect from HTTP to HTTPS via htaccess with multisite installation

move these lines

 RewriteEngine On
# Send would-be 404 requests to Craft
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]
RewriteRule (.+) index.php?p=$1 [QSA,L]

to the end of the file


Database migrations on environments - in which env do I apply updates to Craft and Plugins?

You have options, but most people probably do the following...

Apply the updates locally.
Push those changes to the server.
Have Craft run any necessary migrations.

My deployment process ends with the following command being executed on the server:

composer install --no-interaction --prefer-dist --optimize-autoloader --no-dev

And in my composer.json file, it runs this:

  "scripts": {
    "post-install-cmd": [
      "./craft migrate/all"
    ],
    "post-update-cmd": [
      "./craft migrate/all"
    ]
  }

Between those two commands, it ensures that (A) all of the plugins and libraries specified in my composer file are identical on the production server, and (B) any necessary migrations are run after that.


Mutliple logouts required on Multiple App Servers

It sounds like your sessions are not being sticky. How many servers?

Are you having to login multiple times as well to get things done?

Apart from what Brad mentioned, couple things I'd try if you haven't already:

Set an appId in the config settings. You didn't mention AWS but setting an appId seems to have solved it for at least one other poster using multiple servers.
Set overridePhpSessionLocation and feed it your redis server (or auto). (It's possible Craft isn't even using Redis if it's not getting set correctly.)


Session related question - opening browser with multiple tabs

Per default, there is no way to have different sessions in the same browser window. The sessions are always shared trough all tabs. If two different Sessions are enough, you could use a privat/incognito browser window.

A other solution could be to use HTML 5 SessionStorage for your variables. But this works only for your own variables: Craft CMS use normal sessions/cookies. You can find further informations about your topic here: https://stackoverflow.com/questions/368653/how-to-differ-sessions-in-browser-tabs.


Output random blocks from a matrix but without the first

That query would basically tell MySQL to do this:

Shuffle the blocks
Return the second one

Since the shuffling happens before the offset/limit params get applied, they can’t be used to exclude the first block, since the first block will already be put in some random position by that point.

Instead you should get the ID of the first block, and exclude it using that:

{% set firstBlockId = city.cityBlocks.limit(1).ids()|first %}

{% if firstBlockId %}
    {% set randomQuotes = city.cityBlocks.id('not '~firstBlockId).order('RAND()') %}
    ...
{% else %}
    There were no blocks...
{% endif %}


You can do it with Redactor.

You can configure your toolbar to have a view HTML button.

Also, a caveat, Redactor has an html-purifier function, which will eat some bits of code in the name of making it "clean." But that's relatively easy to configure as well. Just make sure to look at the plugin documentation.


Register multiple TwigExtensions in one plugin in Craft 3

There are several things going on here. This will be a general answer that can hopefully help you move forward. This example will use Sprout Active as a reference and you can see the code here for an example of a plugin that implements multiple, simple Twig Extensions.

Define your Twig Extension class and Namespace

In Craft 3, you can register a Twig Extension (or multiple Twig Extensions) in your Plugins init. While the line to register the Twig Extension is straightforward, there are a lot of other details that matter in your file and I'll comment the code below to highlight why:

<?php

// In Craft 3, each class you create has a namespace. You need to
// make sure that this is referenced in any other classes that use this class
namespace barrelstrength\sproutactive;

// We're referencing the namespaces of other classes in this class too.
// We use the Craft Plugin class, to create our plugin
use craft\base\Plugin;

// You'll create this file next. We need to identify the namespace
// of the Twig Extension we'll be importing so Craft knows where it is
// when we reference `new TwigExtensions()` below
use barrelstrength\sproutactive\twig\TwigExtensions;

class SproutActive extends Plugin
{
    public function init()
    {
        parent::init();

        // Register the Twig Extensions file. We could name this anything
        // and put this anywhere in our folder structure now. As long as
        // we reference the namespace properly above, Craft will be able to
        // find it. We can create multiple Twig Extensions within this
        // TwigExtensions Class or create multiple files to manage our
        // Twig Extensions and import those classes too.
        Craft::$app->view->twig->addExtension(new TwigExtensions());
    }
}

Twig 2 updated several things too

Once we get the extensions loaded, you can create extensions similar to before, however, Craft 3 uses Twig 2 which introduces several breaking changes on it's own. You can see some discussion of the Twig 2 front-end changes in the Craft docs but the docs don't discuss the API changes.

In Twig 2, Twig_SimpleFunction replaces Twig_Function_Method and Twig_Filter_Method so you'll need to update any Craft 2 Twig Extensions code to use Twig_SimpleFunction

In the Sprout Active TwigExtensions Class you can see how the class creates multiple Twig functions within the getFunctions method.

public function getFunctions()
{
    return [
        new \Twig_SimpleFunction('active', [$this, 'getActive']),
        new \Twig_SimpleFunction('activeClass', [$this, 'getActiveClass'], ['is_safe' => ['html']]),
        new \Twig_SimpleFunction('segment', [$this, 'getSegment']),
        new \Twig_SimpleFunction('segmentClass', [$this, 'getSegmentClass'], ['is_safe' => ['html']])
    ];
}


You can add your own translations by placing a region-specific translation file in a craft/translations folder. The filename should be named after your locale and return an array of translations.  In your case this may look like a file named:

craft/translations/hu.php

And within that file, returning an array like so:

<?php

return array(
    "Singles" => "Something Better than Egyedülállók"
);

All strings that are identified as translatable in your front-end templates and the Craft Control Panel files, will be checked against these translations when loading a page in your particular locale. Craft's help doc on Static Translations discusses what this could look like in your templates.

If the phrase is really off in your language, you may want to reach out to Pixel & Tonic and let them know as well. I believe they welcome recommendations from community members on how language translations can be improved.


Is it possible to adjust Redactor config on a per-user basis?

Not possible with the native Rich Text field in Craft (or any field in Craft since the settings aren't defined on a per-user basis).

You could probably pull this off with a custom plugin that added a field type that extended Craft's Rich Text field and overwrote (at least) the getIntputHtml() and getSettingsHtml() methods to add per-user settings support.


Product types are really all about data concerns - so if the data you're storing for your canines/equines (hereafter known as dogs and horses to save some typing ;) ) - is the same, then you're right you don't need more than one product type.  So let's say you make one type of product Animal.

The most obvious tool for grouping that Craft provides is categories.  You might make a category group of Animal Categories, and then two categories in that Dogs and Horses.  You then add a categories field to your product type and select that category group as the source.

Then, when entering each product, you just choose the appropriate category at that time (i.e. you don't so much assign product to a category from the category itself, rather the product is related to the category using the field on the product entry).

In terms of then listing those on a listing (rather than individual) page, in the category settings, set your categories to resolve to e.g. animals/{slug} (i.e. an actual url might be animals/dogs and define a template for Craft to use.

When someone hits that url, your chosen template will be loaded, and this template will have an auto-populated variable of category you can then use that to filter your products display

{% set products = craft.commerce.product.relatedTo(category) %}
{% for product in products %}
    etc.

That's the basics of doing a listing

To sort orders, you can do it in any normal Craft way, such as by the title in alphabetic order:

{% set products = craft.commerce.product.relatedTo(category).order('title asc') %}

If you want an explicit order, you can do it at the template level by ids and used fixedOrder('true) and so on.  There is currently no GUI method of sorting products in Commerce.

(It is fair to say though that it would be nice to have a native ability to create a default sort order for products in the back end, by e.g. drag and drop, which does not exist currently.  You can achieve this by using a Commerce Products field (which is really a relations field, just to products) - and simply manually sort all your product in that, and use that field to build your listings, but this is kind of frustrating to be honest - as where you then store that field?  We use a global set for this currently but it's not ideal).


How to display entries filtered from more than one category

Here's something I've got for filtering news by author and by category. You might be able to re-work it for your needs?

From a page URL being: http://project.com/news?&cat=CATEGORY&author=NAME

{% set query = {} %}

{% set categoryParam = craft.app.request.getParam('cat') %}
{% set authorParam = craft.app.request.getParam('author') %}

{% set category = craft.categories.slug(categoryParam) %}
{% set author = craft.entries.section('team').slug(authorParam).first() %}

{% if category %}
    {% set query = query|merge(category) %}
{% endif %}

{% if author %}
    {% set query = query|merge(author) %}
{% endif %}

{% if categoryParam and authorParam %}

    {% set results = targetEntries.relatedTo(['and',
            { targetElement: category },
            { targetElement: author }
        ]
    ).orderBy('postDate desc') %}

    {% set noResultsMessage = "Sorry, there are no articles by " ~ author.title ~ " in that category. Try changing your filters." %}

{% elseif categoryParam %}

    {% set results = targetEntries.relatedTo(category).orderBy('postDate desc') %}
    {% set noResultsMessage = "Sorry, there are no articles in that category. Try filtering by a different category." %}

{% elseif authorParam %}

    {% set results = targetEntries.relatedTo(author).orderBy('postDate desc') %}
    {% set noResultsMessage = "Sorry, there are no articles by " ~ author.title ~ ". Try filtering by someone else." %}

{% else %}

    {% set results = targetEntries.orderBy('postDate desc') %}

{% endif %}

It was written a long time ago, so I'm seeing some places where I can streamline it, but this works for me filtering by two fields. I think the key part for your requirements is:

{% set results = targetEntries.relatedTo(['and',
    { targetElement: category },
    { targetElement: author }
]).orderBy('postDate desc') %}

Hope this helps in some way.


You could use the Redactor's pagebreak plugin. Check out the docs.

If activated in your Redactor config, you will have the option to insert page breaks to your content, via a new “Insert Page Break” toolbar button.

Now you can get the first "page" in your template:

{% for entry in craft.entries.section('blog') %}

{{ entry.title }}

        {{ entry.richTextFieldHandle.getPage(1) }}

        {% if entry.richTextFieldHandle.getTotalPages() > 1 %}
            Continue reading…
        {% endif %}

{% endfor %}


In the CP you can generate a modal using craft's 'garnish' js as explained in this answer. On the front-end I believe you would need to develop you own solution.


Can't be done, don't waste your time.

Only thing that could work is via a static translations file, but the CP gets locale name data directly from that yii language file, so this is your only chance (see dupe question). Other things can be overwritten though, e.g 'Users' => 'Members'.


Craft 3 - Plugin - Override Control Panel column values for field or field types

Depending on how complex your needs, you might do with the following:

Control Panel JS
Preparse Field

I've used this combo to alter field value display in the control panel.

For example, if a myField can contain a value of '1', then in a Preparse Field I do this:

{% if element.myField == 1%}ONE{% endif %}

And then using Control Panel JS, I can check the value of that field in the CP (in this case, checking for '1'), and then add/remove a CSS class, change the value of the HTML, etc. Part of the reason to use Preparse fields is they allow you to shorten the column header.

It's a little fiddly, but it works well.


We're actually working on a plugin for just this at the moment for one of our projects. It's more for populating channels from a feed (like Solspace Importer or DataGrab), but exposing this via a template tag is something we'll look at including.

Interested if anyone else has come across anything though!

Edit: Feed Me plugin added.


I'm assuming that you are trying to create an 'index' page for your channel entries. There are a few ways to do this depending on the requirements of your site, but a very simple way is to create a 'single'. In the template for the single you can request the channel entries, and loop through the response to generate your index navigation.

{% set entries = craft.entries.section('myChannelSectionHandle').limit(null) %}

    {% for entry in entries %}

{{entry.title}}

    {% endfor %}

If you want the uri's to match up nicely then you can set the 'uri' of the single to be mySectionName and the 'uri' of the channel entries to be mySectionName/{slug} in the section settings — such that to the end user, it will simply feel like they are all part of the same section.

For some slightly more complex options, see these answers, here and here.


I figured it out (edited with my FORM mark-up as well):

I'm actually rendering the FORM using the SproutForms method:

<div class="submit-via-ajax">
    {{ craft.sproutForms.displayForm(block.gatedContentForm.first().handle) }}
</div>

and then my JS looks for any form submissions from a ".submit-via-ajax" block

// process the form
$('.submit-via-ajax form').submit(function(event) {

    // get the form data
    var formData = $(this).serialize();

    // process the form
    $.ajax({
        type        : 'POST', // define the type of HTTP verb we want to use (POST for our form)
        url         : 'sproutForms/entries/saveEntry', // the url where we want to POST
        data        : formData, // our data object
        dataType    : 'json', // what type of data do we expect back from the server
        encode          : true
    })
        // using the done promise callback
        .done(function(data) {

            // here we will handle errors and validation messages
            if (data.success == true)
            {
                // show/hide content/elements
            }
            else
            {
                // show an error
            }
    });

    // stop the form from submitting the normal way and refreshing the page
    event.preventDefault();
});


Invalid verification code. Please login or reset your password

If it's just some users, I've seen some email clients split the link with a newline and when users click it, they don't get the full token in the URL producing an invalid one when Craft tries to verify it.

In those cases, it's recommended that the user manually copy and paste the full URL instead of clicking on it.


These are probably coming from the incoming request in the $_SERVER PHP superglobal

Yii2 does its best to figure out the incoming request, but that's relying on information coming from the client, which is insecure. Note the warning about potential cache poisoning in the Craft CMS docs:

  Don’t ever use the @web alias when defining your sites’ Base URLs. It could introduce a cache poisoning vulnerability, and Craft won’t be able to reliably determine which site is being requested.

This is for the same reason; if no explicit siteUrl is provided, it'll try to figure it out from the request.

In your case, craft.rebrand.getLogo().url ends up calling getImageVariable which then ends up calling the Yii2 asset manager to get the published URL. I think your siteUrl or other aliases may not be set properly.

    /**
     * Returns the schema and host part of the current request URL.
     *
     * The returned URL does not have an ending slash.
     *
     * By default this value is based on the user request information. This method will
     * return the value of `$_SERVER['HTTP_HOST']` if it is available or `$_SERVER['SERVER_NAME']` if not.
     * You may want to check out the [PHP documentation](https://secure.php.net/manual/en/reserved.variables.server.php)
     * for more information on these variables.
     *
     * You may explicitly specify it by setting the [[setHostInfo()|hostInfo]] property.
     *
     * > Warning: Dependent on the server configuration this information may not be
     * > reliable and [may be faked by the user sending the HTTP request](https://www.acunetix.com/vulnerabilities/web/host-header-attack).
     * > If the webserver is configured to serve the same site independent of the value of
     * > the `Host` header, this value is not reliable. In such situations you should either
     * > fix your webserver configuration or explicitly set the value by setting the [[setHostInfo()|hostInfo]] property.
     * > If you don't have access to the server configuration, you can setup [[\yii\filters\HostControl]] filter at
     * > application level in order to protect against such kind of attack.
     *
     * @property string|null schema and hostname part (with port number if needed) of the request URL
     * (e.g. `http://www.yiiframework.com`), null if can't be obtained from `$_SERVER` and wasn't set.
     * See [[getHostInfo()]] for security related notes on this property.
     * @return string|null schema and hostname part (with port number if needed) of the request URL
     * (e.g. `http://www.yiiframework.com`), null if can't be obtained from `$_SERVER` and wasn't set.
     * @see setHostInfo()
     */
    public function getHostInfo()
    {
        if ($this->_hostInfo === null) {
            $secure = $this->getIsSecureConnection();
            $http = $secure ? 'https' : 'http';

            if ($this->headers->has('X-Forwarded-Host')) {
                $this->_hostInfo = $http . '://' . trim(explode(',', $this->headers->get('X-Forwarded-Host'))[0]);
            } elseif ($this->headers->has('Host')) {
                $this->_hostInfo = $http . '://' . $this->headers->get('Host');
            } elseif (isset($_SERVER['SERVER_NAME'])) {
                $this->_hostInfo = $http . '://' . $_SERVER['SERVER_NAME'];
                $port = $secure ? $this->getSecurePort() : $this->getPort();
                if (($port !== 80 && !$secure) || ($port !== 443 && $secure)) {
                    $this->_hostInfo .= ':' . $port;
                }
            }
        }

        return $this->_hostInfo;
    }


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

class ClassName{

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

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

        return $this;
    }

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

        return $this;
    }

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

You can then use it like

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


This is a very difficult problem. And to be honest, I'm not sure if 3 dishes will actually cover the possible combinations in the way that you're asking. Just the common dietPreferences alone could result in 63 combinations (6+15+20+15+6+1). If you add allergens into the mix the numbers get very large very quickly.

dietPreferences = ['beef', 'pork', 'chicken', 'fish', 'vegetarian', 'vegan'];
allergens = ['dairy', 'peanuts', 'gluten', 'shellfish', 'etc', 'etc'];

I think that you will need to reduce the combinations to something like ['redmeat(including chicken)', 'redmeat+fish', 'fish+vegetarian', 'vegetarian', 'all']; And then always have a meat, fish and vegetarian dish that do not include any allergens. Vegans would not be supported; nor would those allergic to dairy, gluten, and other ingredients that are difficult to avoid.

As far as a CMS goes however, craft is as capable as any CMS to tackle the problem, but you would need to establish the parameters carefully first.

For more information on relationships check out the documentation for relatedTo. You might also do a search on this site for 'relatedTo', 'advanced search' and 'elementCriteriaModel'.


When you call craft.commerce.products you're asking Craft for an Commerce_ProductModel.

So you could sort by:

title (alpha)
defaultPrice
type
promotable (sale products on top)
postDate (newest products)
.. etc.

To sort by sales (popularity), you might consider something like BonFire's Popular Products plugin which keeps track of how many purchases were made and how many times the product was viewed, very similar to Ben Croker's EntryCount plugin.


How automatic slug generator could replace accentuated letters?

It actually used to work this way when Craft first launched, but we had feedback where it was desired behavior to allow accented characters and even multi-byte characters in slugs, because they are perfectly valid in the URI.  e.g. http://domain.com/會意字

However, enough people have brought it up where they would like the old behavior that we're going to add a config setting for Craft 2.2 where you can choose which you prefer.

Update:

This was added as a limitAutoSlugToAscii config setting that defaults to true in Craft 2.2.


Remove $_SERVER and DB Queries from logs in 3.4+

If you disable devMode in config/general.php, that information won't be logged.


When developing plugins where should you store values that might not strictly be settings?

You could create a Record which will give you a custom table to store your twitter related settings and update them as needed but I think that your use case is still simple enough that you could leave them in the settings array and then use the Plugins Service to update those settings.

This is how I would do it if I chose to use defineSettings()

// MyPlugin.php
public function defineSettings()
{
   return array(
        // ...
        'twitterApiKey' => array(AttributeType::String, 'default' => '5omeRand0mstriNg'),
        'twitterUsername' => array(AttributeType::String, 'default' => 'someone'),
    );
}

// MyService.php
public function saveTwitterSettings(array $settings=array())
{
    $plugin = craft()->plugins->getPlugin('myplugin');
    $savedSettings = $plugin->getSettings()->getAttributes();
    $newSettingsRow = array_merge($savedSettings, $settings);

    return craft()->plugins->savePluginSettings($plugin, $newSettingsRow);
}

Feel free to follow up with questions/comments if you have any.

@selvinortiz


Part of a website only accessible to users

It is! You can use the requirePermission tag:

{% requirePermission "yourPermission" %}

See the full documentation here. Keep in mind this list as built in permissions but you can also add custom permissions through a plugin should you require it.

As far the second question, I'm not 100% sure but I believe you can set "enabled" to "false" when creating a registration form. See further details here.

Update: You can also use isInGroup


You could use the in operator to search for a substring in your markup.

{% set imageExists = '<img' in entry.body.getRawContent() %}
{% set classAttr = imageExists ? 'with-image' : '' %}

<div class="{{ classAttr }}">
    {{ entry.body }}
</div>

Another, probably bit more reliable way to test for <img> elements is to use the Retcon plugin, which uses DOMdocument to parse the markup.

A combination of retconOnly and length filters should get you there.

{% set imageExists = entry.body|retconOnly('img')|length %}


Craft Routing / Variables with Differing URI

Go to Settings → Routes, and create a route like this:

Then create that partners/_partner_news_entry.html template. (You can change the location/name of the template if you want; just make sure it matches the “Load this template” setting within your route.)

In that template, you can get the Partner Reference and the entry slug like this:

{% set partnerRef = matches[1] %}
{% set entrySlug = matches[2] %}

I’m not sure how you have it set up, but assuming you have a “Partners” channel with a “Partner Reference” custom field, which stores all of the styling/logo/branding info you need, you can get those relevant entries like this:

{% set partnerEntry = craft.entries({
    section: 'partners',
    partnerReference: partnerRef
}).first() %}

Make sure it’s a valid Partner Reference like this:

{% if not partnerEntry %}
    {% exit 404 %}
{% endif %}

Do the same stuff for the News entry:

{% set newsEntry = craft.entries({
    section: 'news',
    slug: entrySlug
}).first() %}

{% if not newsEntry %}
    {% exit 404 %}
{% endif %}

If there’s an Entries field that actually ties the News entries to a specific partner and you want to ensure that you’re not viewing a News entry that should have only been associated with someone else, you can tweak that like this:

{% set newsEntry = craft.entries({
    section: 'news',
    slug: entrySlug,
    relatedTo: {targetElement: partnerEntry},
}).first() %}


What is getContent() / the ContentModel, and how do I use it to get and set custom field values?

BaseElementModel::getContent() will return the element’s ContentModel. It has two purposes:

To store the element’s data from the craft_content table table when fetching elements from the DB.
To store the POST data that should be stored in the craft_content table when saving an element to the DB.

In both cases, the ContentModel should not actually be accessed directly when getting/setting custom field values.

When you’re getting an element’s existing custom field values, use $entry->getFieldValue($fieldHandle), or simply type $entry->$fieldHandle, since BaseElementModel’s magic getter will act as a wrapper for getFieldValue() if the attribute you’re accessing happens to be a custom field handle.

You should do this rather than go directly to the ContentModel because it gives the field types a chance to prep the raw DB data (via their prepValue() method). Most field types have something they need to do before their data will be ready to be interacted with, and in the case of Matrix/relational fields, who don’t store any data in the craft_content table, it’s literally the only way you’ll have a chance to know anything about the field’s value. For those fields, if you were to call $entry->getContent()->$fieldHandle you would just get null back, no matter how much data the field actually has.
When you’re setting new custom field values on an element, use $entry->setContentFromPost($newValues).

Like getFieldValue()’s relationship to retrieving DB data, this method will give field types a chance to prep the POST data before it gets saved to the database (via their prepValueFromPost() method). Since Matrix/relational fields don’t actually store data in the database, this is actually a moot point here and their post data will end up on the ContentModel exactly how it was passed in to setContentFromPost(), but still, there’s no harm in using that method, and better to get in the habit of using it.

$element->setContentFromPost(array(
    'myEntriesField' => array(1, 2, 3),
));


You have to type out the complete statement for each condition, i.e.

{% if entry is defined or category is defined %}
    ...
{% endif %}


Look under Globals in the Control Panel, which is the likely place for such links. If you do not see it, either you do not have permissions OR there are no Globals. Assuming you do not see them, Robin's suggestion about contacting the developer is the next step.


Image transform not working with different locales

Ran into a similar problem on a past project, it could be your .htaccess acting up and redirecting the call to cpresources to /benl/cpresources as opposed to /cpresources/.

If you look at your console on the page that the image is broken - you might be getting a 404 error. If that is the case...

Adding this rewrite rule helped my project and may help yours as well.

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^cpresources/transforms/(.*)  /cpresources/transforms/$1 [L,R,NE,QSA]

Add this rule to your .htaccess in your /benl/ directory before the default index.php rewrite.


Looking at the code you posted looks like you should change /cy_gb/index.php to /cy/index.php. /cy/ is the actual subfolder you are requesting here: https://site.domain.net/cy/


Solution was to call

$productOrCategory  =   new \stdClass();


__PHP_Incomplete_Class retrieved from session

Save yourself the headache and don't store an entire Model in session.  More to the point, don't store any complex objects in session.

It's much better practice to store just the information you need in session to create the model when it's needed (i.e. some unique ID).  You won't run into issues like you're seeing and you won't be using unnecessary server resources serializing and unserializing these complex objects.

You can see the reason you're getting the error on this page.


Algolia changed their index quotas, requiring records to be no larger than 10kb for the Community Edition plan.

My issue was solved by upgrading my to the Essential plan, and creating a custom mapping with the Search Plus plugin, to make sure I kept the record size only as large as it needed to be.

I was experiencing issues particularly with Commerce products that had variants and other custom fields.


New entries not appearing on template page

Are there more than 100 entries in the products channel? If so, you'll need to specify the limit. All Craft requests are limited to 100 by default.

{% for entry in craft.entries.products.limit(null) %}

If not, please post your template code :)


How to use form.handle in Custom field.html

I have updated the plugin files to make this work as I needed it to.

In sproutforms/variables/SproutFormsVariables.php, I have updated the $bodyHtml variable at Line 57 to include handle => $formHandle

$bodyHtml = craft()->templates->render(
    'tab', array(
        'handle'               => $formHandle,
        'tabs'                 => $form->getFieldLayout()->getTabs(),
        'entry'                => $entry,
        'formFields'           => $fields,
        'thirdPartySubmission' => !!$form->submitAction,
        'displaySectionTitles' => $form->displaySectionTitles,
        'renderingOptions'     => $renderingOptions
    )
);

This means in my Template Override in _forms/tabs.html I can pass the handle as a variable

{%- if formField -%}
    {% include "field" with {
        form:                 handle,
        field:                field,
        element:              entry,
        required:             required,
        formField:            formField,
        renderingOptions:     renderingOptions,
        thirdPartySubmission: thirdPartySubmission,
    } only %}
{%- endif %}

I can then do as I required with not needing to specifically specify a form name in my submittedEntry variable

{% set ourForm = craft.sproutForms.form(form) %}
{% set submittedEntry = craft.sproutForms.getEntry(ourForm) %}

The use case for this update is if clients can add forms through the Matrix, you need to get form.handle in submittedEntry so that you can populate the form post using value="{{ attribute(submittedEntry, fieldName) }} if the form fails validation (so that the form doesn't return empty on validation failure).

In the documentation the submittedEntry value is always manually set, however in this example you need to be able to set submittedEntry dynamically so that you can use generic Template Overrides in _forms rather than having overrides per form in _forms/formHandle.


Setting Imager crop position dynamically

If the value of imageCrop is a string in the correct format (ie 50% 50%, 0% 0%, or similar), this should do it:

{% set entryImage = entry.pageHeader.first() %}
{% set imageCrop = entryImage.cropPosition %}

{% set transformedImages = craft.imager.transformImage(entryImage, [
    { width: 1680, jpegQuality: 75 },
    { width: 1080, jpegQuality: 75 },
    { width: 680, jpegQuality: 70 },
    { width: 480, jpegQuality: 70 }
  ], { ratio: 21/9, position: imageCrop }) %}


Craft creating dirty transparent background on image transformations / resizing

The reason is the GD image library. If you switch to imagick, the transparent background will be clean:

Resized, clean:


How do I get rid of whitespace when rendering without touching template indentations?

The spaceless tag only removes whitespace between HTML tags. You have to use the whitespace control modifier on your tags to remove leading and or trailing whitespace.

Additionally I'd use the ternary operator for your conditionals (and put the hyphen inside it):

{% for date in entry.d_date %}
    {{  date.showMonth == 1 ? date.date.month ~ '-' : '' -}}
    {{- date.showDate == 1 ? date.date.day ~ '-' : '' -}}
    {{- date.date.year }}
{% endfor %}


Changed section from Channel to Structure, but can't re-order entries

Have you switched sorting to "Structure"?

When you're not sorting by Structure, you won't be able to rearrange the entries.


How do I make it required to enter password when changing user data?

Craft has a similar concept in the Control Panel for changing sensitive data like passwords/emails you could model called "elevated sessions".

You could write a custom plugin and your form could post to an action in a controller in your plugin, which could check if the phone number for that user has changed.

If so, you'd prompt the user to enter their current password and either do something similar to Craft's UsersController->actionStartElevatedSession, if you need it to last for period of time, or just validate the password and let it go through once.


What does the 'modifyEntrySources' hook do?

"Source" is in the context of "where an element is pulling its data from".

The easiest example is with Assets, because they have easily defined Asset Sources settings portion of the control panel, but all elements (entries, tags, categories, users, etc.) have sources behind the scenes.

See the CategorySources plugin for an example of how it might be used (including a screenshot).


You can simply get all the relevant categories at once and combine your relatedTo parameters with a single and operator:

{% set issue = craft.entries({ section: 'issues', slug: 'october-2014' }).first() %}
{% set categories = craft.categories({ group: 'articles', slug: 'category-slug-one, category-slug-two, category-slug-three' }) %}

{% set entries = craft.entries({
    section: 'articles',
    relatedTo: [
        'and',
        { targetElement: issue },
        { targetElement: categories }
    ]
}) %}


400 error logging into local Craft 3 project

I haven't seen this particular issue but generally I've found that from time to time MAMP doesn't like running Craft in CGI mode, i.e. with different PHP versions per host.

Try switching it to module mode (under the PHP tab of MAMP Pro). If that works, then try reverting to CGI mode. You may find it continues to work.


I had the same issue on macOS Sierra, running on with the following installed using homebrew:

Craft CMS (2.6.2989)
nginx (1.12.1)
php-fpm 7.1 (7.1.8)
php71-imagick (3.4.3)

After a number of hour of digging around I found the following.

By default (don't ask me why), the configuration file for Imagick has image format configuration commented out....Thanks for that guys.

The Fix

Uncomment file format configurations in /usr/local/etc/ImageMagick-7/magic.xml

<magicmap>
  <magic name="GIF" offset="0" target="GIF8"/>
  <magic name="JPEG" offset="0" target="\377\330\377"/>
  <magic name="PNG" offset="0" target="\211PNG\r\n\032\n"/>
  <magic name="TIFF" offset="0" target="\115\115\000\052"/>
</magicmap>

Then restart php-fpm (on macOS it was for me brew services restart php71)

Don't forget!

Once you've done the above, don't forget to run the Update Assets Indexes in Craft CP. This will generate all of the thumbnails for the images.

Hope this helps someone.


Craft 3 installation issue on account creation

Hello and thanks Brad !

I was actually using Firefox. When I tried to install Craft 3 via Chrome (which has never gone to the website before) the issue was solved and I could access to the next page. Should be a cache issue !

Thank you !

Olivier.


"Unknown "craft" function" Error in Plugin Service Call

There are multiple issues happening here...

The Twig code should look like this:

{{ craft.businessLogic.exampleVariable() }}

As noted in that example, Twig can't communicate directly with a Service level method. You'll need to ping the Variable class, and use your Variable method to call the Service method.

Optional...

The Business Logic plugin template currently only works with Craft 2. If you're attempting this on a Craft 3 site, several things would need to be changed.


You can still use plain text, you just need to use a filter after

{{ entry.text | nl2br  }}


Converting images to WebP - Overcoming Timeout Errors?

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

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

I'm pending information at the moment.

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


Are there any Craft specific migration tools that extend Yii's built-in functionality?

Craft has it's own version of Yii's console app, yiic, in craft/app/etc/console/yiic.php and we have a migrate command that lets you create, view history, see new migrations, etc. for plugins as well as Craft itself.

We've extended the default migrate command to add Craft-specific features and remove some default Yii functionality that we don't want to support (i.e. down migrations).

You can see the available commands to run here: http://buildwithcraft.com/docs/plugins/migrations


How possible is it to set write permissions on storage folder on symlinked install?

Symlinks don't really have permissions themselves.

If I had to hazard a guess, it sounds like your deployment script isn't setting the correct permissions on the craft/storage directory, maybe because they're being recreated every time you deploy?

I think you have a couple options:

set the permissions on that directory correctly (see the above link) after you deploy
change your deployment strategy a bit.

If it were me, I'd tell the build/deploy script to ignore the craft/storage directory altogether. Setup your own storage folder that won't be touched by your deploy script (say above the releases folder) after you deploy. Then just tell Craft to use that location.

What is the symlink actually pointing to?

You could really deploy anywhere on the server too, not just in the typical nginx web root. (I prefer not to even touch the default distro locations because any update could modify your web files.)

If you want to go down the path of permissions, it gets a little murkier. I don't have a ton of experience with something like Capistrano (or whatever deployment system you're using) but your deploy user needs to have sudo permission to be able to change the permissions so your PHP user—likely the same user as the nginx user but not the same as the deploy user—can write to it.

One way around this is PHP-FPM. Setup a new fpm pool with the user/group of the deploy user then add whatever user you're running nginx as to that user's group (eg usermod -a -G deploy-user www-data)

That will let nginx read files from the deploy user but let FPM write to the folder because it owns it. Then you won't have to worry as much about after-deployment permissions.

It's also cheap jail if you set it up properly.

(If you're running Apache as mod_php with nginx in front of it, it'd be a similar setup.)


nesting functionality missing in section type structure after feed-me import

Check the sort order dropdown at the top right of the index page to make sure you're on "Structure".


Has anyone tried a port from Expression Engine to Craft using Verbb's Feed Me plugin?

If you import the related items first then you should be able to make the relationship when you import the parent entries.

However, it's really down to the complexity of the relationships.

You may find it simpler to do the import in stages. Start with the bare bones to create entries with the appropriate names/slugs and then bring in the other data bit by bit.

I would favour using XML or JSON for my import format.

I also find it useful to also include some craft fields into which I import the legacy EE id (and any other pertinent information).


Why does a Element Criteria Model Query with Strings on a custom element type not filtering?

Found the answer, simple mistake.

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

was needed along with

public function defineCriteriaAttributes() {

    return array(
        'templateId'    => AttributeType::Mixed,
        'code'          => AttributeType::String,
    );
}

Hopes that helps anyone else who comes across something like this.


Best practices in debugging an 'Unknown error'

Unknown error messages in the control panel almost always happen over an AJAX request and are usually 500 response code Internal Server Errors, so there isn't an convenient way to display a meaningful error message with a full stack trace to help debug.

But you've found the next best thing... the error logs in craft/storage/runtime/logs.

Usually if you see it on every page in the CP, it's from something like Craft trying to write a license file to the craft/config folder, but it can't. The error you shared is a 503 response, which means "Service Unavailable".  You'd typically only see that if a request comes into the front-end of the site while Craft is in the middle of an update, or the front-end of the site is offline.

So I'm not 100% sure the error you posted is the one that's causing the "unknown error".  I'd enable devMode, clear out all your log files, reproduce the problem and scour the logs again to see if anything else pops out.


How can I print the name of every template being rendered in HTML comments, when in devMode?

So this sounded like a fun problem to solve... so I wrote the Template Comments plugin that does what you want:

This free plugin adds a HTML comment to demarcate {% block %}s and each Twig template that is included or extended.


Convert textfield to be used in html class or id?

You can do this with the Luke Holder's Inflect plugin. Which method to use would depend on how you want the resulting text to look. I'd use {{ myTextField|slugify }} to get a string that looks like this "this-is-my-class", since I only use lowercase and hyphenate class/id names.


How can I set up sources based on my custom field data?

Setting up the sources in the sidebar isn't difficult. Add the modifyEntrySources()(link) hook to MyCustomPlugin.php.

public function modifyEntrySources(&$sources, $context)
{
    if ($context == 'index')
    {
        $sources[] = array('heading' => 'My Custom Heading');

        $sources['mypluginhandle:mysectionname'] = array(
            'label' => 'My Section Name',
            'criteria' => array('myPluginHandle' => 'SQL CODE HERE')
        );
    }
}

At this point you should have a new entry heading and source in the Entries Listing page. Clicking on it isn't going to filter your data as you may expect... yet.

Notice the 'criteria' => array('myPluginHandle' => 'SQL CODE HERE')? This is what you are going to use to filter the entries according to what you want to see. Everything that is in the value of the 'myPluginHandle' array will be passed over to the modifyElementsQuery() (link) method in the MyCustomFieldtype.php file. This is where you can build out your SQL statement accordingly.

public function modifyElementsQuery(DbCommand $query, $params)
{
    if ($params != null) {

        // whatever you need to do to dig in to your custom fields' data...
        // using the code above, $params would be equal to 'SQL CODE HERE'

        $query->where($params);
    }
}

This should be all you need to filter your entries by your custom field!


Template not found: $PRIMARY_SITE_URL/$PRIMARY_SITE_URL/blog/this-is-my-blog

You have to go to your Admin Dashboard > Settings > Sites > Your site and delete Base URL field, then save it and try to navigate.


Update multiple database entries via controller

OK, I managed to figure it out and I'll post the solution for those who run into similar problems.

Essentially, what's happening is Twig template->Plugin controller->Plugin Service->Laravel API->Laravel Controller->Database

The code:

//Plugin controller
public function actionPositionGuide() {
    $this->requirePostRequest();
    $attr = json_decode(craft()->request->getPost('guide.json'), true);
    $neworder = array();
    foreach($attr as $row) {
        $guide = array(
            'id' => $row['name'],
            'position' => $row['value']
        );
        array_push($neworder, $guide);
    }
    $request = craft()->myplugin_guide->positionGuides($neworder);

}

Then

//Plugin service
public function positionGuides($attr) {
    $url = $this->getBaseUrl() . "/guides/position";
    return craft()->mylaravel_api->send('post', $url, $attr);

}

Then add a route to the Laravel routes.php file

Route::post('guides/position', 'GuidesController@position');

Then the Laravel controller:

public function position() {
    $data = Input::all();
    $response = ["msg" => "success", "status" => 200];

    foreach($data as $guide) {

        $oldguide = Guide::find($guide['id']);

        if (is_null($oldguide)) {
            $response = ["msg" => "error", "status" => 500];
        }

        $oldguide->position = $guide['position'];

        $oldguide->save() ? $oldguide : Log::debug($oldguide->getErrors());
    }

    return Response::json($response["msg"], $response["status"]);
}

Error handling is not great but if anyone has suggestions for improvement, I'm all ears.


Description and logo at the very top of browser?

Site title - This is set with HTML meta tags and not really anything to do with Craft specifically. It depends how you "switched" from wordpress to Craft. Inside your document head, you need to include a title tag, like:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
<head>
    <title>Website title goes here</title>
</head>
<body>

You can set this automatically by doing the following:

<title>{{ entry.title }}</title>

Favicon (logo) - Upload your .ico file to the /public_html directory.


Show/display entries next/prev except entries with lightswitch field active

I got it by simply adding a condition where I was displaying my previous entry.

{% if prevEntry %}

    {% if prevEntry.comingSoon %}

        {# if comingSoon field is active, hide the link #}

    {% else %}

            Previous
            {{ prevEntry.client }}

    {% endif %}
{% endif %}


Similar entries with the greatest coincidence tags

Please correct me if I am making an incorrect assumption. From your example, it looks like you're passing multiple tags to the search query, and by greatest coincidence you mean that you want the Entries that have the most matching tags that are part of your search, to appear higher in the results than Entries that may just have a single matching tag.

I don't believe this is possible without an additional plugin that helps with modifying the scoring and order of the search results.


Many db requests with relationship fields

This is how relationships work in Craft at the moment. Each relation equals +1 query. If you don't access your relation on an entry the query isn't executed. So by only fetching title and/or id you don't run any extra relationship queries.

Caching is your best option at the moment to make the query count go down. Make use of caching to cache large chunks of you code.

Brandon has hinted on Slack that Craft3 might incorporate Yii2 lazy loading of relations using the ->with() command. This will solve a lot of the N+1 queries with relationships.

Update

The release of Craft 2.6 included the functions for Eager-Loading of elements. See this link for documentation on the subject: https://craftcms.com/docs/templating/eager-loading-elements


How do I create a page with a dynamic id?

Depending on how your redirect works, you can redirect and get the param in the template where the form is via:

{% set param_name = craft.request.param('param_name') %}

You can then set this param in your form template and post it to your action controller.

<input type='hidden' name='param_name' value='{{ param_name }}' />

In your action controller you can retrieve it by getting it from the post.

$param_name = craft()->request->getPost('param_name');

Is this anything you can use? Or need? Good luck!


Saving entries with FeedMe doesn't trigger Sprout notification email

To confirm the behavior here, Sprout Notification Emails only get triggered on web requests and are suppressed for console requests and during updates and migrations. Notification Emails could get triggered in other contexts but you would need to do so programmatically.

Notification Events don't run for console requests

$request = Craft::$app->getRequest();

// Only handle notifications on web requests
if ($request->getIsConsoleRequest()) {
    return false;
}

Notification Events don't run during migrations

if ($request->getIsActionRequest()) {
    $actionSegments = $request->getActionSegments();
    if (
        ArrayHelper::firstValue($actionSegments) === 'updater' ||
        $actionSegments === ['app', 'migrate'] ||
        $actionSegments === ['pluginstore', 'install', 'migrate']
    ) {
        return false;
    }
}

Code examples from Sprout Base Email v1.2.7


It looks like Redactor has a plugin called “Clips” that allows you to:

  Create a dropdown of frequently used "snippets" of code, text, icons,
  emoji, you name it.

Pixel and Tonic made it into a plugin for Craft too.
I haven’t tried either but it looks like it should do the trick. I just tried the Craft plugin and it worked out pretty good. It doesn't have a preview of the emoji like Slack’s emoji menu though.

The plugin has settings where you can define the clips and the following HTML with each clip. Pretty straightforward.

After installing it I edited one of the .json config files in craft/config/redactor/ directory by adding

"plugins": ["clips"]

It then gives you a button on the tool bar called Clips. Make sure your Rich Text field is set to use the config that you added this plugin to.

Clicking that button gives you the following list. Clicking on a clip will insert the corresponding HTML

Not as polished as Slack’s emoji menu. Might be a way to edit the plugin to get it to do that though.


How to save data from a form in Craft? Explain with an example?

You'd do this wiht a Craft plugin or module.

Try giving the plugin docs a once over: https://docs.craftcms.com/v3/extend and if you have some specific questions, feel free to post back.

You can also generate Craft plugin boilerplate code at https://pluginfactory.io that already has a lot of this setup for you.


Correct timezone for AttributeType::DateTime in CP

It's a bit confusing at the moment (should be cleaner in the upcoming Craft 3), but for now, if you use {{ entry.dateCreated|date }}, it should take the timezone into account and display the correct time.


You can use the group filter

{% set allEntries = craft.entries.section('blog').all() %}

{% set allEntriesByYear = allEntries|group('postDate.year') %}

{% for year, entriesInYear in allEntriesByYear %}

{{ year }}

        {% for entry in entriesInYear %}

{{ entry.title }}

        {% endfor %}

{% endfor %}


How can I loop through the values of a drop down within a SuperTable?

You'll likely want to do something like this:

{% for fieldtype in blocktype.getFieldLayout.fields %}
    {% set field = fieldtype.field %}

    Handle: {{ field.handle }}

    {% if field.type == 'Dropdown' %}
        {% for option in field.settings.options %}
            Label: {{ option.label }}
            Value: {{ option.value }}
        {% endfor %}
    {% endif %}
{% endfor %}

Essentially, this loops through all the sub-fields in your Super Table field, and for each field, you can make any sort of conditional you like in order to handle each fields content.


How to change the message on the homepage

that's the content of the default 'Homepage' entry, which you'll find in the Entries section of the control panel. That's what is being inserted with the {{ entry.body }} variable in the index.html template.


element-api plugin / get entry total in section in Craft 3

Ok i think i stumbled on the answer -

$signees = Entry::find()->sectionId(4)->count();


Create new entry from related Entry field

Not sure when this was added, but this is now available in Craft core. The select modal has a button to create a new entry of that type.


There are two very different questions here, but I will try my best to answer them both!

The first being "How do I hide a page from the navigation?"

The simplest way I can think of for this, that is also controllable through Craft, is to create a simple "Hide from navigation" Lightswitch field, and add this to your entry types.

When looping through entries for the navigation, you can check whether the lightswitch has been checked, and if it has, don't show that entry in the nav:

{% for entry in craft.entries.section('lorem').hideFromNavigation(0) %}
    --
{% endfor %}

The second question is "How do I redirect to the homepage if someone visits /services?"

This can be achieved with the redirect tag. In your services/index.twig template file, you can simply add:

{% redirect siteUrl %}


First, make sure you have devMode enabled so any errors will be show. Then, I would consider writing the template code in a way that will ensure something will output when looping through the block types to help troubleshoot.

For example

{# Loop through each block #}
{% for block in entry.comparisonChart %}
    {# Output templating based on the block type #}
    {% switch block.type %}
        {% case "compareChartHeadingBlock" %}

{{ block.compareChartHeading }}

        {% case "compareChartTwoBlock" %}
            {% for row in block.compareChartTwo %}

{{ row.chartTwoLeft }}

{{ row.chartTwoRight }}

            {% else %}
                Compare chart two has no content
            {% endfor %}

        {% case 'compareChartThreeBlock' %}
            {% for row in block.compareChartThree %}

                        {{ row.chart3Left }}

{{ row.chart3Center }}

{{ row.chart3Right }}l

            {% else %}
                Compare chart three has no content
            {% endfor %}

        {% default %}
            {# The message below will be displayed if the type doesn’t match those handled above #}
            This {{ block.type }}’s templating has not been handled

    {% endswitch %}

{# If the Matrix has no blocks, output a message #}
{% else %}
    This Matrix has no content
{% endfor %}

An approach like the above should help narrow where the problem is occuring. If you do get error messages, please post them as it can help identify where the problem is occuring as well.


What's the easiest way to generate a link to edit a given entry in Craft?

profile.cpEditUrl is what you're looking for.


Craft has a pretty extensive relationship system, which is what you'd probably want to take advantage of here.

You could make another channel called "Offers" and each offer would be an entry in that section.

Then you could create an entries field called "Ad" and save it in your "Offers" section's field layout and have its source set to "Ad".

Then, when saving an offer, you'd select the ad(s) in the ad field the offer belongs.

You'd be able to query those relationships from the template side like so: https://craftcms.com/docs/entries-fields#examples


There is no plugin that provides this type of functionality but there really isn't any need for one either. Depending on how many pages their mini-sites needs to be, this really can all be handled with front-end entry forms and how complicated it can get is entirely up to you.

You should create their control-panel's using routes (possibly not even necessary depending on how you structure it). There you'd allow for any of the entry forms, etc.

In order to give more advice on how to go about this we'd really need more detail on exactly what each of these multi-sites needs to be capable of but this just seems like a standard site allowing unique front-end entry creation which is all able to be done without the use of any plugins, even while allowing it to get quite advanced and complicated.


Removing old Block Handles in Matrix Field?

Tried it here and seems ok. Once you have deleted your field, are you saving your matrix block (top right button)?

If you delete the field then try to recreate it straight away (or any other field for that matter), it gives you the Handle "videoUrl" has already been taken. until you save the block. Once you save, you should be ok to recreate.

It does seem a bit buggy though as you need to save in between each action... Might need to see what the craft guys think.


Your targetElement needs to be the category object or the ID of your category.
So if the id of your category is 5 you need

'relatedTo' => ['targetElement' => 5],

If you really want to be able to fetch your category by slug (which I would not suggest since your slug can be changed in the cp but the ID can't, if someone changes the slug by accident your entire logic will break) you can create an ElementCriteriaModel to search for the category with the slug and insert the object there.

$criteria = craft()->elements->getCriteria(ElementType::Category);
$criteria->slug = $slug;
$category = $criteria->find();

And inside your array

'relatedTo' => ['targetElement' => $category],


Permissions when crossing over from Windows to Mac

I've got a nearly identical setup... a Windows 8.1 box using IIS and an OSX laptop using MAMP with Craft installs that are sync'd with Dropbox between them.

If I recall correctly, the only thing I did was give "Everyone" full recursive access to things like craft/storage on Windows and chmod -R 777 craft/storage on the OSX box.

Haven't ran into any permission issues.

I will warn you not to use symlinks in that setup, however, as Dropbox doesn't know how to resolve those cross platform.


Eager Load Matrix Field with Assets Field Type

The line {% set img = entry.primaryImage[0] ?? null %} is looking for the primaryImage field on the entry inside your for loop. It is not looking for primaryImage for the current matrix field.

If primaryImage is a field within your matrix blog you will need to change the line to

{% set img = block.primaryImage[0] ?? null %}


Craft supports hierarchical, nested categories out of the box.

It also supports hierarchical entries, assuming you used the Structure section type (and not a channel or single).

Where Craft and Joomla differ is the output on the front end is completely up to you. There's no default "widget" or anything in Craft that is going to do exactly what you want.

Craft's {% nav %} tag would help you output categories and sub categories. This example uses a structure section but it's also applicable to nested categories as well.

There's a few recipes in the Craft Cookbook that you might find helpful in this instance as well.


Craft 3 - Cache tag increasing number of database queries

When you first load the template using the {% cache %} tags, the number of queries will likely be higher because it still has to retrieve the correct data from the database.

Subsequent loads of that template should show a lower amount of queries because it's returning actual cached content at that point.

The same thing will happen once the cache is busted from expiration on the next template load as well.


Ended up the document root was looking for var/www/html instead of just var/www

This fixed it for me https://stackoverflow.com/a/23175981/851669


How do I push contact form data to SugarCRM? (currently using Sprout Forms)

I was able to accomplish this by grabbing Craft Business Logic, stripping out most of the examples, and simply listening for a form submission:

craft()->on('sproutForms.onSaveEntry', function (Event $event)
{
    $entry = $event->params['entry'];
    $content = $entry->getContent()->getAttributes();

    // Let's not pass fields we don't need
    $fields = array();
    $ignore = array('id', 'slug', 'title', 'handle', 'locale', 'element', 'elementId');

    foreach ($content as $field => $value)
    {
        if(!in_array($field, $ignore))
        {
            $fields[$field] = $value;
        }
    }

    $fields = http_build_query($fields);
    $ch = curl_init('https://url-to-sugar.crm/index.php?entryPoint=WebToLeadCapture');
    curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);

    $response = curl_exec($ch);
    curl_close($ch);
}

I just created an init function in the plugin and added this there. I didn't need to use an API because the data is only flowing in one direction. I just used curl to push the data.


getAncestors() gets all entries that are ancestors. Since you're looping through them what rootEntry is set to last time through is the closest ancestor.

You can avoid the loop and just get the first one:

{% set rootEntry = entry.getAncestors().first() %}


Failed Stale Template Cache Delete Error...Analyzed...But No Answer

OK, I found the answer to this. Here is the correct answer.

Basically change dateCreated to elements.dateCreated in my template.


Disregard, I loaded redactor in the wrong directory!


Live Preview in different languages on different top level domains

With the current implementation of Live Preview in Craft, using Live Preview across different top-level domains isn't possible due to the cross-domain policy (as you found out) along with a few others.

We've got a few ideas on how we might address this in the future, but it will definitely be after Craft 3 comes out.


The short answer is no... but that kind of thing is not really Freeform's responsibility - Craft gives you the flexibility to output whatever you want wherever you want, but in order to do so you need to create templates and/or routing to suit your requirements.


Craft-Scripts will do this for you: https://github.com/nystudio107/craft-scripts#clear_cachessh

You can see what it does via the source: https://github.com/nystudio107/craft-scripts/blob/master/scripts/clear_caches.sh

As for cache/clear this clear's Yii2's cache... which Craft CMS uses for almost nothing. Template Caches are always in the db, compiled templates are always cached on disk as files, and so on.


Gitignore pattern to remove image transforms

Those image transform folders all start with an underscore. The following pattern should work, if you don't set up underscore folders yourself:

public/assets/**/[_]*/


Return all Matrix blocks with a drop down set to a specified value

How about:

{% for block in entry.myMatrix if block.subsection == 'intro' %}
    ...
{% endfor %}


nystudio107 just released a nice guide yesterday for setting up a Craft 3 site via composer.  No mention of Mamp Pro, but I don't think that should really be a problem if you're already used to using it, as you would just make sure your hosts file is pointing to the /web/index.php file.  The article does a great job of explaining what a lot of the terminal commands actually refer to instead of just telling you what to type in.

https://nystudio107.com/blog/setting-up-a-craft-cms-3-project


We tried a lot of things to fix this but could not as yet. We tried Nginx config chnages, and on a different server htaccess setting changes, having settings in the config like enableCsrfProtection off, usePathInfo' => true etc. The requireElevatedSession works ok for us on change a users password etc so this did not seem to be the problem as some other users have had.

The only way we could get around this for now was by editing the Charge plugin to stop the requireElevatedSession (Asks for a password before doing anything). I hope everything is ok with Joel at SquareBit as his support before on this plugin was excellent, but have had no reply from the last few months.

We changed:
'craft/plugins/charge/controllers/Charge_ChargesController.php'
lines 113 and 175 and Comment out/remove

//$this->requireElevatedSession();

And then in 'craft/plugins/charge/templates/payment/_view.html' removed JS calls

//new Craft.ElevatedSessionForm('.charge-refund-action');
//new Craft.ElevatedSessionForm('.charge-recur-cancel-action');

Hope this helps, or if anyone knows of a better fix?


Is there a thumbnail generator plugin for video assets?

There is a plugin called 'Transcoder' But it's not free:
https://github.com/nystudio107/craft-transcoder/blob/v1/README.md


Omitting unused letters from A to Z list

[untested]

Something like this should do the trick:

{% for letter, members in craft.entries.section('members').order('surname', 'firstname') | group('surname|slice(0,1)') %}

{{ letter }}

    {% for member in members %}

{{ member.surname }}, {{ member, firstname }}

    {% endfor %}

{% endfor %}


If you're looking to only allow certain IP addresses to access the entire control panel, you're best bet would be to whitelist them via an .htaccess file.

Something like:

<Limit GET POST>
    order deny,allow
    deny from all
    allow from 1.2.3.4
</Limit>

If you're looking to just allow certain Craft-specific actions by IP address, then you'd have to write a plugin.  For example, if you only want certain IP addresses to be able to create an entry, the plugin would listen for the onSaveEntry event, make sure it's a new entry, check if the user has createEntry permissions, if so grab their IP address and make sure it falls in your whitelist.

Just be aware that IP address detection can be spoofed, so you shouldn't be relying on this for any critically sensitive data.


permissions userphotos "an unknown error occurred"

Changing the userphotos folder's owner to be the same as the user:group Apache was running as solved the issue.  i.e.

chown -R www-data:www-data userphotos


Extending Craft Commerce admin templates

It's not documented on the Commerce site (yet), but Commerce does have commerce_addProductActions and commerce_addOrderActions hooks that a plugin could latch onto to add its own custom actions to the Order and Product index pages.

Virtually identical to the add(Element)Actions hooks that Craft provides for its elements.


Craft Commerce, variable product prices based on weight. Is this possible?

1oz = $1 ∴ 10oz = $10

Sell in units of weight as the quantity of the item.


Can plugin have two links in admin navigation?

The top links in the CP header are often called nav tabs.

Beyond the "default" nav tab for your plugin (pointing to the plugin's CP section), it's possible to declare additional tabs via the modifyCpNav hook (added in Craft 2.3.2640):

public function modifyCpNav(&$nav)
{
    $nav['mypluginhandle-newsletter'] = array('label' => 'Newsletter', 'url' => 'mypluginhandle/newsletter');
}

Of course, this will only create a tab with a link pointing to whatever you put in the url property. If you haven't already created the page for the newsletter, you'll need to do so by creating a route to a template or controller:

public function registerCpRoutes()
{
    return array(
        'mypluginhandle/newsletter' => 'myPluginHandle/newsletter',
    );
}

Read more about the registerCpRoutes hook in the official docs.

Both the modifyCpNav() and registerCpRoutes() methods should go in your plugin's main class.


Sounds like it's viewing the DB as being empty. The access credentials are correct (it's technically connecting to the database), but it's not seeing any tables in the database.

Does your site use a prefix (ie: craft_) before the database tables? Check to make sure that the prefix specified in config/db.php matches the actual table prefixes.
Double-check to make sure you're connecting to the right database.


I would suggest to read through the following articles:

https://nystudio107.com/blog/multi-environment-config-for-craft-cms

https://nystudio107.com/blog/database-asset-syncing-between-environments-in-craft-cms

About reinstalling craft on your droplet and uploading the local database:

the craft install i used in my local dev environment will be pushed onto the droplet, like this i can assure that it doesn't differ in any of the enviornments. About syncing the database read through the articles it will clear things up. In general all of the articles in nystudios blog are more than helpful. i hope it helped at least a bit.


Allow a dropdown custom field to be edit from a front end form

Just to make sure I am on the same page, you have a select field within the control panel that is populated with the prefix/title(s)?

If that's the case, within your registration form, you could do something like this. Not tested, but should be close...

{% set options = craft.fields.getFieldByHandle('yourFieldHandle').getFieldType.options %}

{% if options|length %}
    <label for="prefix">Prefix</label>
    <select id="prefix" name="fields[prefix]">
        {% for option in options %}
            <option value="{{ option.value }}">{{ option.label }}</option>
        {% endfor %}
    </select>
{% endif %}

EDIT

Good catch by @Benjammin'. You will need the options part to actually access the values. I've updated my answer, give it another try.


Problem loading css files in some templates

You will want to include the siteUrl variable before the file path to normalize all the resource URLs. That will also help when you move to production. For example:

{% includeCssFile siteUrl~'assets/html/css/slidestyle.css' %}

In your general config file, you can set different site URLs based on the server you are on.

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

    'localhost => array(
        'devMode' => true,
        'siteUrl' => 'http://localhost/craft/'
    ),
    'yourProductionDomain.com' => array(
        'devMode' => false,
        'siteUrl' => 'http://www.yourProductionDomain.com'
    ),
);


Identify immediate siblings block type in matrix

Fun question! :)

You can use getNext() and getPrev() Methods on the MatrixBlockModel documentation page.

{% for point in entry.keyPoints %}

    {# if this is the "typeToWrap" block type #}
    {% if point.type == 'typeToWrap' %}

        {# if there is a previous point to check #}
        {% if point.getPrev() %}

            {# if the previous point wasn't the "typeToWrap" type start a ul #}
            {% if point.getPrev().type != 'typeToWrap' %}

            {% endif %}

        {# if there isn't a previous point start a ul #}
        {% else %}

        {% endif %}

    {% endif %}

    {# output point #}

    {# if this is the "typeToWrap" block type #}
    {% if point.type == 'typeToWrap' %}

        {# if there is a next point to check #}
        {% if point.getNext() %}

            {# if the next point isn't the "typeToWrap" type end a ul #}
            {% if point.getNext().type != 'typeToWrap' %}

            {% endif %}

        {# if there isn't another point end a ul #}
        {% else %}

        {% endif %}

    {% endif %}

{% endfor %}


An exception has been thrown during the rendering of a template ("")

You're searching in the URI for a param with a key called search:

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

But the in the URI it's called token:

REQUEST_URI=/en/book/poll-availability?token=9923444c-13b4-41bb-b7ab-9e339277bacc&iframe=true&room-urns=

Therefore when it's not an AJAX request this passes:

{% if (not craft.request.isAjax and not token ) %}

And a 404 is thrown:

{% exit 404 %}


Apply imageTransform on twitter media feed

Craft's built-in transform functionality doesn't support transforming external URLs. You could use my Imager plugin to do this instead.

EDIT:

Based on your example, you'd use Imager something like this:

{% set response = craft.twitter.get('statuses/user_timeline', { tweet_mode:'extended', count: 20 }) %}
{% if response.success %}
    {% for tweet in response.data %}
        {% if tweet.extended_entities.media is defined %}
            {% for item in tweet.extended_entities.media if item.type == 'photo' %}
                {% set transformedImage = craft.imager.transformImage(item.media_url, { width: 200, height: 200 }) %}

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

So, the essential part is that you need to pick up the url to each item in the loop (item.media_url, if that's what the twitter plugin returns), and do the transform inside the for loop.


I guess it would be easier to use a for-loop instead of that nav-loop in your case. Although it's harder to get multi-level-dropdowns

{% set categories = craft.categories.group('compositions') %}

    {% for entry in categories %}
      {% if not entry.hasDescendants() %}

{{ entry.title }}

      {% else %}

          {{ entry.title }}

            {% for child in entry.getDescendants() %}
              {{ child.title }}
            {% endfor %}

      {% endif %}


Can I add fields to the User > Account screen?

User content fields can only be customized within the additional tabs, configured in the field layout interface. Users are a built-in custom Element Type, and have some non-configurable fields.

This is likely a measure taken by the Craft authors to isolate and protect important fields from being lost among other custom fields.

It is possible to create front-end form that rearranges these fields, if the UX of the admin is unworkable for your users!

Edit (1/24/2018): In Craft 2.6.3005, the authors have added support for multiple tabs in the User edit screen. This doesn't change our ability to customize the first page, but allows you to add more tabs to organize the remainder of your fields. ✌


How to use a global variable in a conditional statement if an entries relation field is empty?

The reason it wasn't rendering is because my original entry field is an Entries Field (see templating examples in the docs). The relationship fieldtypes (Entries, Assets, Users) require that you include the length filter in your conditional like so:

{% if entry.fieldHandle |length  %}
  {{ entry.fieldHandle}}
{% else %}
  {{ global.fieldHandle}}
{% endif %}

Thanks to Keith Mancuso @keithmancuso for the fix!


Your syntax is a bit off.

The withTransforms parameter is an Asset criteria, meaning it is only relevant when you're pulling Assets. Appending it to entry.relatedArticles (an Entries field, returning an ElementCriteriaModel) like you're currently attempting does nothing, but this does:

{% set assets = entry.someAssetsField.find({
    withTransforms: ['someTransform', 'someOtherTransform']
}) %}

This means your current code should probably be refactored to look something like this (simplified):

{% for article in entry.relatedArticles %}
    ...
    {% set bannerImage = article.bannerImage.find({
        withTransforms: ['cardImage']
    })[0] ?? null %}
    {% if bannerImage %}

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

Assuming there's not a ton of relatedArticles entries, and considering the fact that there's only one image per entry, the above might not make a huge impact on your performance. To take things a step further, you might consider eager loading the actual Asset field(s) as well as their transforms. There's a couple of ways to do this – you could use the same approach as above, adding the eager loading criteria to the Entries field relatedArticles:

{% set relatedArticles = entry.relatedArticles.find({
  with: [
      ['bannerImage', {
          withTransforms: ['cardImage']
      }]
  ]
}) %}
{% for article in relatedArticles %}
    ...
    {% set bannerImage = article.bannerImage[0] ?? null %}
    {% if bannerImage %}

    {% endif %}
{% endfor %}

...or you could use a more "traditional" eager loading approach, using craft.entries and the relatedTo parameter:

{% for article in craft.entries({
    relatedTo: {
      sourceElement: entry,
      field: 'relatedArticles'
    },
    with: [
        ['bannerImage', {
            withTransforms: ['cardImage']
        }]
    ]
}) %}
    ...
    {% set bannerImage = article.bannerImage[0] ?? null %}
    {% if bannerImage %}

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

With the above, assuming there's a fair amount of entries involved you'll probably see a decrease in the number of queries executed.

If you want to learn more about eager loading, I recommend taking a look at the official docs on the subject.