Reverse related entry with Solspace Calendar I'm using Solspace Calendar,
When I create an event with it I use a related entry field called 'project'
to choose an entry from a section called projects
I can display the project title etc in the Calendar template,
however I want to display the projects event date when on the project page (reverse related)
I can't fathom how to construct a reverse related entry – being 'events' is neither an entry, user, asset etc as per this question: Related Entries
I would like to understand if its even possible as for example - the plugin not being a section, this clearly won't work:
{% set relatedDates = craft.entries.section('events').relatedTo(entry) %}

how would one grab the calendar event to begin with?
Thanks

after reading and re-reading the docs got this working:
{% set relatedDates = craft.calendar.events.relatedTo(entry).all() %}

{% for relatedEventEntry in relatedDates %}
 {{ relatedEventEntry.title }} - {{ relatedEventEntry.startDate.format("l, F j, Y \\a\\t g:ia") }}
      ({{ relatedEventEntry.duration.humanReadable }})
      in {{ relatedEventEntry.calendar.name }} calendar.
      {% if relatedEventEntry.repeating %}
        Repeats {{ relatedEventEntry.readableRepeatRule }}
      {% endif %}
{% endfor %}

this is called from the projects/_entry template


Is there a quick way to check a server for Craft's minimum requirements? Is there a quick way (or some sort of wizard) that can be run on a server in order to establish whether it fulfils Craft's minimum requirements without uploading all of the Craft files? Finding out PHP and MySQL versions is easy enough but sometimes it's hard to get the finer details from clients.

There is no way of programmatically checking whether a server fulfils the minimum requirements in Craft without uploading all of the Craft files, however I have created a script that performs all of Craft's web server related checks. It does not connect to a database so cannot check the MySQL version or that the InnoDB storage engine is installed and enabled, but this should be relatively easy to find out by asking your web hosting company.

The script is available for download here:

https://github.com/putyourlightson/craft-requirements


Do field values get serialized before validation? I am learning to write my first plugin for Craft CMS 3.x

I have a field that gets displayed as a string, but is stored in the database as binary. When I validate it, I write:

public function getElementValidationRules(): array
{
    return [
        /* Other rules, */
        ['unique']
    ];
}

What I wonder is, will it get compared in its string form to the binary? Or will serializeValue() get called?

First of all: this validator requires an active record as target in order to know what table it should check to search for uniqueness. Since Craft has not such a thing you would need to create a record for the content table in order to make it work.

Furthermore you'll need to check the context of the field, if it's inside a matrix or inside a super table field or whatever so you need to set the target Attribute dynamically based on the table.

Finally it won't serialize your value automatically and search for the string, instead it will just fail because of these lines

foreach ($rawConditions as $key => $value) {
    if (is_array($value)) {
        $this->addError($model, $attribute, Yii::t('yii', '{attribute} is invalid.'));
         return;
    }
    $conditions[] = [$key => $value];
}

Your value is an array so it will add an error no matter what

However: you can rebuild the functionality by actually validating the model by yourself with this validator instead of defining a validator and letting Craft handling it.

You can see an example in the matrix field it inserts just a function that is being called in the class instead of a validator. Then you can create a dynamic model  and validate that one. You can read more about  ad hock validations

$email = 'test@example.com';
$validator = new yii\validators\EmailValidator();
if ($validator->validate($email, $error)) {
    echo 'Email is valid.';
} else {
    echo $error;
}


Set custom sort order for index pages in the CP? Good chance this is more of a feature request than a question you can help out. But as I am new to Craft plugin development and might oversee something I ask it anyways:

Now that it is possible to customize the index pages in the CP using the plugin hooks modifyEntryTableAttributes and getEntryTableAttributeHtml, what do I have to do to make my custom columns appear in the sort order dropdown / make the entries sortable by my new columns?

You weren’t overlooking anything, we were :)

We just released Craft 2.3.2616 with four new hooks:

modifyEntrySortableAttributes
modifyCategorySortableAttributes
modifyAssetSortableAttributes
modifyUserSortableAttributes

That should do the trick for you.


Influence Twig parse order? I'm working on a plugin where I set a variable from my template. The plugin also provides a Twig filter
that makes use of that variable.

{% do craft.myPlugin.setVar('example') %}

{# Filter appends 'example' to the entry title #}
{{ entry.title|myFilter }}

One thing I'd like to do is to make it possible to set the variable anywhere in my template,
but still provide it to the Twig filter everywhere it is used (within that template).

{{ entry.title|myFilter }}
{% do craft.myPlugin.setVar('example') %}
{{ entry.body|myFilter }}

Yes, this probably is a very very stupid question and this cannot be done.
But maybe there's a chance I'm overlooking something and you can influence the parse order or do some magic to make this possible? Any answers welcome :)

Short answer: Cannot be done :)

Twig doesn't really have a "parse order", it compiles to plain old PHP. Upon compilation, this would make your Twig snippet basically this:

$myVariable = 'someInitialValue';
echo $entry->title . $myVariable;
$myVariable = 'example';
echo $entry->title . $myVariable;

Obviously, setting $myVariable to "example" the second time won't affect the output of the first echo statement.

An obvious way of accomplishing basically the same thing, would be to wrap the whole template in a {% set %} call – then your options would be many, you could for instance use placeholders and the replace filter:

{% set myContent %}
   {{ entry.title | myFilter }} {# myFilter appends placeholder "%myPlaceholder%" to the input #}
{% endset %}
{# Echo the template, replacing the placeholders with whatever #}
{{ myContent | replace( { "%myPlaceholder%", craft.myPlugin.getVar } ) }}

I get that this is not what you really want though.

If you really want to get your hands dirty you can see if you can find a way to manipulate the Twig internals.

You can access the Twig instance in your plugin via the TemplatesService:

$twig = craft()->templates->twig;

I guess that one way to achieve what you want is to write your own Lexer – fairly ambitious stuff for doing something easily done by extends, embeds or by output buffering/set and replace as per my example above.

Other concepts to look at (which may or may not be useful to your quest!) are Template hooks, global Twig variables, template embedding or Twig's StringLoader extension.

Finally, I'm quite curious about the actual use case here. If you'd care to elaborate, I'd love to know why you need/want to do this.


Custom static assets I would like to let my static assets (JS, CSS and images file) close to my templates files.

public/
templates/
    css/
    images/
    scripts/
    template.html

Until now, I didn't find a clean way to access these files.
{% includeCssFile %} and {% includeJsFile %} works, but I get strange "compiling" issues with my javascript "templates" saying unclosed comment.

Anyway, does a clean solution, other than copying these files to public, exists ? A variable like siteUrl pointing to the right folder ?

The problem with putting them in your templates folder is now PHP/Craft is going to try and serve them.  Meaning that you've got the overhead of PHP and Craft when trying to request every single asset instead of if they were in the public folder where Apache can instantly serve them (orders of magnitude faster).


Updating plugins from the admin doesn't work Suddenly getting this strange error every time I try to update Craft or any plugins through the admin;

Status: Internal Server Error

Response:
PHP Fatal Error &#039;yii\base\ErrorException&#039; with message &#039;Allowed memory size of 134217728 bytes exhausted (tried to allocate 4096 bytes)&#039;

in /Users/a/Sites/askrembla/vendor/composer/composer/src/Composer/DependencyResolver/Solver.php:220

Stack trace:
#0 [internal function]: yii\base\ErrorHandler-&gt;handleFatalError()
#1 {main}

Memory and all that is fine as far as I can tell, so not sure why this error is thrown. Will continue investigating on my end.

Memory is definitely not fine, the error message is very explicit:

  Allowed memory size of 134217728 bytes exhausted

You need to raise your PHP memory limits. Craft requires a minimum of 256MB to run properly.

  https://docs.craftcms.com/v3/requirements.html


Plugin uninstall only removes one table When uninstalling my plugin, only one table is removed. Two others are left behind.  Any suggestions what I'm doing wrong?  Could it be naming with and without the underscore?

The good:

<?php
namespace Craft;

class Calendar37Record extends BaseRecord
{
    public function getTableName() {
        return 'calendar37';
    }
    protected function defineAttributes() {
        return array(
            'event_id'   => AttributeType::Number,
            'dateYmd'    => AttributeType::String,
            'timestr'    => AttributeType::String,
            'alt_text'   => AttributeType::String,
            'css_class'  => AttributeType::String,
            'userJson'   => AttributeType::String,
        );
    }
    public function defineIndexes() {
        return array(
            array('columns' => array('event_id', 'dateYmd'), 'key' => true),
        );
    }
}

and the bad:

<?php
namespace Craft;

class Calendar37_SubsetsRecord extends BaseRecord
{
    public function getTableName() {
        return 'calendar37_Subsets';
    }
    protected function defineAttributes() {
        return array(
            'handle'              => AttributeType::String,
            'title'               => AttributeType::String,
            'categoriesToInclude' => AttributeType::String,
            'categoriesToExclude' => AttributeType::String,
            );
    }
    public function defineIndexes() {
        return array(
            array('columns' => array('handle'), 'unique' => true),
        );
    }
}

Bad #2:

<?php
namespace Craft;

class Calendar37_ViewsRecord extends BaseRecord
{
    public function getTableName() {
        return 'calendar37_Views';
    }
    protected function defineAttributes() {
        return array(
            'subsetId'     => AttributeType::String,
            'startDateYmd' => AttributeType::String,
            'endDateYmd'   => AttributeType::String,
            'htmlBefore'   => array(AttributeType::String, 'column' => ColumnType::Text, 'required' => false),
            'htmlAfter'    => array(AttributeType::String, 'column' => ColumnType::Text, 'required' => false),
        );
    }
    public function defineIndexes() {
        return array(
            array('columns' => array('subsetId', 'startDateYmd' ), 'key' => true),
        );
    }
}

Thanks for that tip, Lindsey, but here's what happened: I changed calendar37 to calendar37_Occurrences and then all three tables wouldn't uninstall.  It turns out that the issue is having a capital letter after the underscore.  So it seems like an "undocumented feature" that you can make plugin tables persist after uninstall by including a capital letter after the underscore.

return 'calendar37_Subsets';
return 'calendar37_Views';

needed to become:

return 'calendar37_subsets';
return 'calendar37_views';


Edit custom field value inside "commerce_orders.onBeforeSaveOrder" event I would like to edit custom Lightswitch field value to true inside of event on order save

          $order = $event->params["order"];
          $order->setContentFromPost(array(
              'ediCheck' => true,
          ));

          $order->getContent()->setAttributes(array(
              'ediCheck' => true,
          ));

Tried following but the value still stays the same.

Also If there is an documentation file on following that I maybe missed would also be helpful.

That looks right, but I think you may need to set the value of that field to '1' - looking in the craft_content table, it seems switches are stored as 0 and 1.

      $order = $event->params["order"];
      $order->setContentFromPost(array(
          'ediCheck' => 1,
      ));

If that still doesn't work, try throwing in a craft()->commerce_orders->saveOrder($order); at the end of your function.  It shouldn't be needed though as it should fall through to the saveOrder it's going to do anyway....


Need .last() functionality for categories – .last() will be deprecated going forward I have a matrix block that calls a category channel. The categories are nested three levels "deep" at times. I want to select first, second or third level links as needed.

When I use .last(), I can get the full url path to return. When I use .nth(n), I have to specify a value, which automatically limits the link path to that level of "deepness".

What can I do to get the .last() functionality, without using .last()?

Note: .last() will be deprecated going forward in Craft 3 and beyond.

If you are not going to update your current project to Craft 3 (which will break nearly all your templates and all plugins anyway) you don't need to bother about that message. This is only for Craft 3 and not for Craft 2.

Otherwise looking in the docs might be a good idea. You can do

{% set query = craft.entries().section('news') %}
{% set total = query.count() %}
{% set last = query.nth(total - 1) %}

or

{% set oldest = craft.entries()
    .section('news')
    .inReverse()
    .one()
%}


Can the Craft CMS admin be blocked from accessing the Internet? In our production environment, we have set up a three-tier architecture. Craft CMS is deployed on a server sitting in the private zone. We want to have it serving client browser's request through a proxy server which sits in the DMZ. We want to make sure the app server does not have internet access for security.

However, it seems to us that craft CMS admin page is trying to access the internet. We would like to know why it is doing that and whether this can be disabled.

Instead of blocking the CMS's access to the internet, you should consider firewalling access to the CMS from the outside world. Basically, block all incoming IP addresses but your own. I can understand your need for security, but the CMS's core functionality relies on being able to communicate with the outside world to keep the system updated.

If you block access as you're wanting to do, I think you will find that it's going to be much more difficult to manage the system. Things that come to mind:

You'll need to be able to keep the system updated with source control (eg. Git) which requires internet access.
If you get into a situation where an update fails in the CMS, you may need to  run Composer via command line on the server. This will require the internet to update packages.
One of the best ways to manage assets (images) in CraftCMS is to use a CDN like Amazon S3. You'll get much better site performance with a CDN. If your server cannot communicate with the internet, you'll lose this ability.

I'm sure there are many more ways that you'd essentially be hobbling the system. I'm not directly answering your question here (which I would prefer to do), but instead I'm trying to dissuade you from creating a system that is unmanageable.

UPDATE

As I began thinking about this more, I came up with a few more things to consider:

Keep your CraftCMS site files on a server that has access to the internet, and connect it to a database on a server which has no internet access. I did this for a previous client using Rackspace's Rackconnect which is essentially a back-door network that is only accessible to other Rackspace servers. I'm not sure how you host, but I'm sure this can be done with other service providers. At the end of the day, what you really want to protect is the contents of the DB.
Set up a VPN and require that users authenticate to the VPN before being able to connect to crucial protocols like SSH. I had this scenario set up for a previous client as well. Essentially, you must establish a VPN connection first, then you can SSH into the server.

Caveat, I'm not a server security person. I've set up a bunch of servers, and learned along the way what makes good security from people smarter than me. Your IT people may have even better suggestions than what I've provided.


Get all entries for a structure section including disabled I am building a plugin and in that plugin I am trying to grab all entries including disabled ones.  My structure is a single entry as the parent and then it will have multiple levels of children.  Currently I am grabbing the main parent with this code.

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

Then I am doing nested for loops to work my way down such as the following.

{% for event in events.children() %}
   {% for day in event.children %}
      {% for session in day.children() %}
      {% endfor %}
   {% endfor %}
{% endfor %}

This works just fine but the issue is it will not return the disabled entries.  I have noticed the status(null) when you are doing a find but I have not figured out a way to do it with the for loops.  I intend to keep the relationship structure in the ui so I am not looking to just get a random ordered list of all entries.

Any help would be appreciated and I am open if there is a more efficient solution.

{% set events = craft.entries.section('events').first() %}
{% for event in events.children().status(null).find() %}
   {% for day in event.children().status(null).find() %}
      {% for session in day.children().status(null).find() %}
      {% endfor %}
   {% endfor %}
{% endfor %}

event.children() does not return an array of elements but an object of type ElementCriteriaModel the same as craft.entries thus you can append whatever you want until you execute it with find() or first()


Trying to show selected categories in a multi select form input I have a users form, which they can select their occupations. They can choose multiple values from a multi-select input.

Occupations are categories that are related to users profile.

Here in this code, i can get the values and submit witout any problem,but i cannot show as selected when user returns to form. They should see thier previous selections.

{% set categories = craft.categories.group('occupation').all() %}
<input type="hidden" name="fields[occupation][]" value="">
<select multiple name="fields[occupation][]" class="selectpicker" >

{% for category in categories %}
  {% set selected = currentUser.occupation.all()  %}
  <option value="{{ category.id }}" {% if category.id == selected  %} selected{% endif %} > {{ category.title }} </option>
{% endfor %}

How can i access to selected arrays id value?

When you do currentUser.occupation.all() your selected variable is an objet so your conditional {% if category.id == selected %} will never pass as you are checking if category.id equals an object.

For this to work, first get the ids of the currentUser occupations:

{% set selected = currentUser.occupation.ids() %}

Which would return an array of ids (key/value pairs) then you compare doing:

{% if category.id in selected|values %}

So in full:

    <select multiple name="fields[occupation][]" class="selectpicker" >
        {% for category in categories %}
        {% set selected = currentUser.occupation.ids() %}
          <option value="{{ category.id }}" {% if category.id in selected|values %} selected{% endif %} > {{ category.title }} </option>
        {% endfor %}
    </select>


Template error: Method "siteUrl" for object "Craft\ConfigVariable" does not exist Method "siteUrl" for object "Craft\ConfigVariable" does not exist

{% for locale in otherLocales %}

    {# Is this an entry page? #}
       {% if entry is defined %}

         {# Find the current entry in the other locale #}
        {% set localeEntry = craft.entries.id(entry.id).locale(locale).first %}

        {# Make sure that it's actually localized to this locale #}
       {% if localeEntry.locale == locale %}

           {# Output a link to it #}
            <link rel="alternate" hreflang="{{ locale }}" href="{{ craft.config.siteUrl[locale] ~ (localeEntry.uri != '__home__' ? localeEntry.uri) }}">
         {% endif %}

    {% else %}

        {# Just output the same path with the locale's base URL #}
        <link rel="alternate" hreflang="{{ locale }}" href="{{ craft.config.siteUrl[locale] ~ craft.request.getPath() }}">
    {% endif %}
{% endfor %}

Did you configure siteUrl in general.php?

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


How can you choose which group to output first when using the group filter? I am using the group filter to group like entries together. I need to be able to control which group is output first. How can I do this?

Rather than changing the order of the actual array returned by the group filter, you can just assemble a new array that has the keys in the order you want:

{# Get the grouped entries #}
{% groups = entries|group('foo') %}

{# Create an array of the group keys in the desired order #}
{% set keys = ['foo']|merge(groups|keys|without('foo')) %}

{# Now loop through the keys, rather than the groups directly #}
{% for key in keys %}

    {# Get the group with this key #}
    {% set group = groups[key] ?? [] %}

    {# Loop through the entries #}
    {% for entry in group %}
        ...
    {% endfor %}

{% endfor %}

(Note that the ?? operator requires Craft 2.6.)


Craft 3 Multi-site with no "default" site I have setup a Craft 3 multi-site with the following configuration:

But what I really want is:

Additionally, I want to have a 'default' http://localhost:8888 so I can always redirect to /en or /es based on the browser language, but I don't want to add it as a site in the CMS through the admin panel, because I end up with a third unwanted version for each entry.

Which is the way to go?

This can be done in 3 main steps.

1. Get the site subdirectories working

First just get the /en/ and /es/ subdirectory working:

Create en/ and es/ subfolders in your webroot
Each subfolder should have its own index.php file and .htaccess file (if using Apache).
Assuming you used the craftcms/craft project as a starting point, update the define('CRAFT_BASE_PATH'... line in each of the index.php files to:

define('CRAFT_BASE_PATH', dirname(__DIR__, 2));

Update your English site’s Base URL to include the /en/.

At this point, if you point your browser directly to /en/, the English site should work as expected.

2. Create a redirect script in the webroot’s index.php

Create an index.php file in your webroot (alongside the en/ and es/ subfolders). This script will be responsible for redirecting the request to the correct subfolder, based on the requested URI and language.

<?php

// Bootstrap Craft -------------------------------------------------------------

// Set path constants
define('CRAFT_BASE_PATH', dirname(__DIR__));
define('CRAFT_VENDOR_PATH', CRAFT_BASE_PATH.'/vendor');

// Load Composer's autoloader
require_once CRAFT_VENDOR_PATH.'/autoload.php';

// Load dotenv?
if (file_exists(CRAFT_BASE_PATH.'/.env')) {
    (new Dotenv\Dotenv(CRAFT_BASE_PATH))->load();
}

// Load Craft (but don't run)
define('CRAFT_ENVIRONMENT', getenv('ENVIRONMENT') ?: 'production');
/** @var \craft\web\Application $app */
$app = require CRAFT_VENDOR_PATH.'/craftcms/cms/bootstrap/web.php';

// Custom Logic ----------------------------------------------------------------

// find a site language that matches the browser's requested language
$siteLanguages = $app->i18n->getSiteLocaleIds();
$language = $app->request->getPreferredLanguage($siteLanguages);

// find the first site that uses that language
foreach ($app->sites->getAllSites() as $site) {
    if ($site->language === $language) {
        // found it
        break;
    }
}

// figure out where to redirect this request now
$url = (function() use ($app, $site) {
    $uri = $app->request->getPathInfo();

    // see if we have an exact URI/language match
    if ($element = $app->elements->getElementByUri($uri, $site->id, true)) {
        return $element->getUrl();
    }

    // see if we have an exact URI match in any other site
    foreach ($app->sites->getAllSites() as $otherSite) {
        if ($otherSite !== $site) {
            if ($otherSiteElement = $app->elements->getElementByUri($uri, $otherSite->id, true)) {
                // found one! now see if the element is also available in the requested site
                if ($element = $otherSiteElement::find()->id($otherSiteElement->id)->siteId($site->id)->one()) {
                    return $element->getUrl();
                }
                // otherwise we'll just ignore the browser language
                return $otherSiteElement->getUrl();
            }
        }
    }

    // no element matches. we'll just redirect to the same URI in the requested site.
    return \craft\helpers\UrlHelper::siteUrl($uri, null, null, $site->id);
})();

// redirect to the URL
$app->response->redirect($url)->send();

With that in place, you should be able to start testing the redirects by pointing your browser to /index.php?p=some/uri.

3. Redirect nonlocalized requests to the webroot’s index.php

Finally, we want to get all requests that don’t start with en/ or es/ to be routed to an index.php file in your web root. If you’re using Apache, you can do that with mod_rewrite:

# Send requests missing en/ or es/ to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/(en|es) [NC]
RewriteRule (.+) index.php?p=$1 [QSA,L]

Now everything should work!


How would I pass an entry URL to an iframe in a template? I'm trying to showcase some responsive code and would like to create entries just with that code example. I would like them to appear in a template that has some js to resize an iframe and show responsiveness of the entry.

Any thoughts on how I can accomplish this?

Load the entries into a div then create several buttons to change the width of the div, or use JS to resize the div. Thus showing your users what happens to the responsiveness of the design at different widths. It doesn't need to be a iframe. Or just send them to a template with a UI element showing them to resize the browser.


Live Preview fails to load Live preview is not working.  The following error appears in Inspect Element (Safari).  It then times out and generates a whole bunch of can't load errors. but this appears to the root of those subsequent errors.

  XMLHttpRequest cannot load http://www.mydomain.com/index.php?p=posts/2016/thisost. Origin http://mydomain.com is not allowed by Access-Control-Allow-Origin.

I saw a related question that referred to the .htaccess file.  But I can't seem to find the.htaccess file.

So, I guess this is an A and then B question.  The first (A) being the focus and B only of import if its related to the solution for A.

I hope that makes sense.  Thanks

A browser will give that error by default when you try make an AJAX call from domain A to domain B.

In your particular case, it looks like you're loading the control panel from mydomain.com, but the live preview request (which comes from how you defined your Site URL under Settings->General) has www.mydomain.com in it.

Note the www.  A browser will treat that as an entirely separate domain.

If that's how you want it, great.  You need to modify your public .htaccess file (the one that sits next to Craft's public index.php file to allow the other domain via Access-Control-Allow-Origin.

Likely it's just a mistake though and you should correct the Site URL setting or access the control panel from the other domain.

It's also worth forcing one or the other (www redirect to non, or non redirect to www) via .htaccess for consistency and because search engines will treat them as one site.


Commerce - Edit Products via Plugin I need to setup a way to quick-edit products while viewing them in a list, similar to woocommerce bulk edit feature:

I can't find any documentation on actual editing of the products, as opposed to editing the product in a cart (such as quantity.)

For example, I can grab products in my plugin template file using:

{% set products = craft.commerce.products.order('title ASC').limit(10) %}

But that doesn't give me access to things like how much inventory is left, so that I can output that and offer a field to edit it.

Did I miss the docs to do this? Not sure if Commerce is setup with services available for other plugins to edit products.

This is a fairly complex question and this is only really a sketch of an answer.

You'll want to get to know the available models and services in Commerce pretty well to achieve this in all.

You'll most likely do much more work in the plugin side of things than the template side of things - that is, you'll pull together the models/data you want in the plugin, and then pass those things through to the template, rather than just retrieve the data in the template I'd say (as per your example there).

You'd take the various selection paramaters (categories, stock level, whatever) and post these to a controller in your plugin. Then in your plugin, you'd get the variant models you want via PHP, and then post this data through to a template that would render it into a form, and probably just return this whole form via json as some html that you then display with some front end ajax

         $this->requirePostRequest();
         $param1 = craft()->request->getPost('whatever'));

        //This is a service in your plugin that gathers and returns variant models
        $data = craft()->yourplugin->searchStock($param1,...);

       $html = $this->renderTemplate('yourplugin/stockEditForm', array(
            'products' => $data,
        ), true);

        $this->returnJson(["success"=>true, "html"=>$html]);

... in your stockEditForm you then just loop through the products as normal

       {% for product in products %} ...etc

... then some ajax to actually render that on the plugin page

        $.ajax({
        type: 'POST',
        url: '/actions/yourplugin/bulkStockEdit',
        data: form_data,
        success: function(response) {
            $spinner.hide();
            $results.html(response.html);
            $results.show();
        },
        statusCode: {
            500: function(jqXHR, textStatus, errorThrown) {
              $spinner.hide();
              $results.html(jqXHR.responseText);
              $results.show();
            }
        },
    });

That will get you a form with the data populated into it.  From there, each save button in your constructed will need to be hooked up to some ajax to call appropriate Commerce controllers to actually save the changed variants...

I think that, as a basic structure, would get you going with this.  Bulk stock editing certainly would be handy at times!


In Craft 3 plugins, should CRUD operations go in Controllers or Services? The documentation states:

  Many service methods perform some sort of operation for a given model, such as a CRUD operation.

(Link)

But browsing through existing plugins, I see the CRUD logic is most often done in controllers.

What's the best practice here?

Putting aside the term "CRUD" for a moment, it essentially breaks down like this...

If something wants to ping your site, it is (almost) inevitably going to be pinging a Controller.
If you want to do something in the database (create, update, delete), you should probably be doing that in a Service.

Which raises the question, "how/where to bridge that gap?"

The answer is, "it depends."

You could keep most of your logic in the Controller, and just move the DB interactions to the Service. Or you could immediately ping a Service method as soon as your Controller is hit. Either way is fine, and it depends heavily on what the site requires, and what you (as the developer) are more comfortable with.

As you noted, sometimes people bend the rules and put DB interactions directly into the Controller method. While that's frowned upon, there may not be any negative repercussions. So don't worry too much about how other people are handling it... just do what makes sense to you.


Adding alt tag to an image All of my assets have fields for alt text and I understand how to access that info from an asset field, but can not figure out how to do it when an image has been inserted using Redactor.

Any help will be much appreciated!

For alt tag content you can just click the image in the richtext field, hit the 'edit' button and add a title.

As far as I know there is no way to integrate an alt text field (or any other fields) from assets without writing a custom redactor plugin. I posted a similar question here and the only solution was to use a matrix field instead. But I too would love to hear about any other options.


Migration of Craft CMS from one host to another I'm a newbie in Craft CMS. I need to make changes in an existing craft website which is with one hosting platform.
The site was previously managed by another developer. I need to migrate to a new hosting platform and i would like to know what all credentials i would need to obtain to perform this task and how i can migrate it?

You need a copy of the database which you can either export via Craft's Control Panel or via phpMyAdmin or a similar database management tool.
You need these folders:

craft/templates
craft/translations (if it's multi-language)
craft/plugins
craft/config
public

They might be called differently, I am writing this as if the previous developer followed the installation instructions.

Upload a fresh copy of Craft to the new server.

Import the database.

Replace the stock folders with the ones you got from the other install.

Make sure db-credentials are correct in craft/config/db.php. Make sure all paths are correct in craft/config/general.php.

Make sure the folders that need to be writeable are writeable.

Generally speaking your site should be running now.


Education test website Q&A - how? I've had a potential job come through that I want to run on Craft, but I'm a bit sketchy about one particularly bit. The site is going to include educational modules and tests for each. Test results will be stored in their profile which can be reviewed the admins. I know how to create a new entry for each test submission, but the thing I'm not sure about is this:

How can I store whether a question was answered correctly or not?
Is there a way to display a score based on the test result?

As always, I'm not a plugin developer... if this can be done with template logic that would be perfect.

The catch is, it sounds like you need to add an entry and modify user data all in a single shot. That's not really possible out-of-the-box... different forms will submit to different places.

Edit an Entry
Edit a User Profile

One possible solution is to create an intermediary page:

First page is your test form,
Upon submission, creates a new entry. (Edit an Entry)
Then redirects to a second page,
Second page displays the results, and offers to "Save the results",
Upon submission, saves results to user profile. (Edit a User Profile)

It's pretty rough, to be honest. If you know any PHP at all, I'd highly recommend using this project to teach yourself a little plugin development. If you build some customized Controllers and Services to handle this data, you'll end up with a far more robust solution.

Sounds like a fun project... Let us know what architecture you decide to go with!


PHP Fatal error: Uncaught Error: Class 'Craft\DbConnection' not found I'm getting a 500 error when trying to visit my page. Was able to track it down to this error in the logs, but can't seem to get it fixed. Updated the craft/app folder with the latest Craft version, but still no luck.

From my phperrors.log

[14-Mar-2017 17:56:34 UTC] PHP Fatal error:  Uncaught Error: Class 'Craft\DbConnection' not found in /var/www/site/craft/app/etc/behaviors/AppBehavior.php:849

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


Access Matrix field that is assigned to a user Using Craft 3.

I created the following field:

myMatrix which has Field Type = matrix
and is part of the group myGroup

This is composed of one block:

myMatrixBlock
with 2 fields:

myMatrixField1

myMatrixField2

I have assigned the myMatrix field to Users using the control panel (user settings >> fields).

How do I

Access the data in myMatrix from my twig template?  I'd like to get all the data in this matrix for the current user and loop through it and display data for each myMatrixField1 & Field2.  I can't figure out how to retrieve myMatrix field.
How do I create a new record in the myMatrix field? I'd like to create a new entry in the myMatrix field and store data for the current user in each of the fields.

I've been searching at this for several hours now ... I feel this must be VERY easy but I can't seem to figure it out.  Also, if you have a link to documentation on functions/variables that are available for each object at the template level I'd be grateful.  I can't seem to find that in the docs either.

Thank you!

You need to use 'currentUser' to access the field. So;

{% for block in currentUser.myMatrix %}
  {{ block.myMatrixField1 }}
  {{ block.myMatrixField2 }}
{% endfor %}

As for creating a new record in the matrix (I'm guessing you mean from the front end) then you need to create a form that submits the current matrix data alongside your new block data. This isn't super straight forward, but basically you need to create a user profile form that submits the current matrix data alongside the new data.


Craft 3 FeedMe - Help accessing deeper XML nodes I'm importing data from an XML file.
I'm having trouble accessing some of the deeper nodes in the xml file.

Example of my xml here (chapter being the repeating item):

<chapter>
<title> Title – Version 5.0.11.110 </title>
<subtitle> Release Notes </subtitle>
<info>...</info>
<sect1>
<title> Improvement </title>
<sect2>
<title> AP - Accounts Payable </title>
<itemizedlist>
<listitem xml:id="A50-3451-1">
<para>
Allow edit for Shipment Comment on Both Shipments after Post Invoice if Edit Shipment After Posting is enabled.
</para>
</listitem>
<listitem xml:id="A50-3487-2">
<para>
Make AP Generate Payment form and report all fields from AP Transaction.
</para>
</listitem>
</itemizedlist>
</sect2>
<sect2>
<title> CB - Cash Book </title>
<itemizedlist>
<listitem xml:id="A50-3314-3">
<para>
Added StatementID, StatementLineNo and PeriodReconciled as available fields for the transactions band on the CB Unreconciled Transactions layout, making it easy to see if a transaction which is unreconciled as at the period reported on is on a statement, and reconciled subsequently.
</para>
</listitem>
</itemizedlist>
</sect2>
</sect1>
<sect1>
<title> Bug Fix </title>
<sect2>
<title> ALL - All Modules </title>
<itemizedlist>
<listitem xml:id="A50-3400-1">
<para>
Fix possible A record already exists with that Layout (..) code - Error message.
</para>
</listitem>
</itemizedlist>
</sect2>
</sect1>
</chapter>

And my template code so far:

{% set params0 = {
    url: 'https://sitename/downloads/ReleaseNotes.xml',
    type: 'xml',
    element: 'chapter',
    cache: 60,
} %}

{% set params1 = {
    url: 'https://sitename/downloads/ReleaseNotes.xml',
    type: 'xml',
    element: 'sect1',
    cache: 60,
} %}

{% set params2 = {
    url: 'https://sitename/downloads/ReleaseNotes.xml',
    type: 'xml',
    element: 'sect2',
    cache: 60,
} %}

{% set feed0 = craft.feedme.feed(params0) %}
{% set feed1 = craft.feedme.feed(params1) %}
{% set feed2 = craft.feedme.feed(params2) %}

{% for node in feed0 %}

{{ node.title }}

    {% for node in feed1 %}

{{ node.title }}

        {% for node in feed2 %}

{{ node.title }}

{{ node.itemizedlist.listitem.para }}

        {% endfor %}

    {% endfor %}

{% endfor %}

I've ended up using multiple feeds as I couldn't get to the "para" node at all. This maybe wrong.
I thought that
{{ node.itemizedlist.listitem.para }}
 would do the trick.
Can someone offer some help please.

I think your problem is that <listitem xml:id="A50-3487-2"> has an attribute, so you would need to use <p>{{ node.itemizedlist.listitem['@'].para }}</p> to get the node value.

See the bottom of the docs here:
https://docs.craftcms.com/feed-me/v4/feature-tour/using-in-your-templates.html


CMS login redirects to back to login I have an existing CMS website that seemingly has been working fine for several months.  Just recently we have lost the ability to access the admin portion of the site (the rest of the site works well).  To our knowledge, nothing has changed to make the site behave differently.

We have since set up our own dev box with identical code and it seems to behave the same way.  Works one day, next day we can't log in.  No errors in browser or log files.  Browser cache and cookies cleared.  Different browsers all work the same way.  You log in, it blinks a second, then redirects to login.  If wrong password entered, we get the wrong password error.  Even the database seems to show our login was good.

We have multiple environments on the original site, only the production environment has this issue.  Our second environment only has the production environment so i don't think they are conflicting.

Only thing i can think of is nginx cache but we don't cache the admin directories.  I don't see anything different in .htaccess that would do this.

Any ideas?

Sorry for answering my own question.

Upon a suggestion from P&T, we found that our Nginx configuration was removing the cookies when it cached the page. When we left the cookies in, we were able to log in.

We still don't know what changed to make the site suddenly not work, but at least the control panel is usable.


How to output a field as raw HTML? I have a field in a matrix block that is used for video embed codes. I want to output the contents of that field directly as HTML. However, it always seems to get entity-encoded (ie. the < and > get converted to &lt; and &gt;), so the html just appears as text.

I know about Twig's |raw filter, so I tried outputting the field's content through it (eg. using {{ element.blockContent|raw }}), but it seems to make no difference. Can anyone tell me what I'm doing wrong?

(Just in case it's relevant, this is a sub-template that is being included in a for loop that goes through the matrix blocks and outputs them)

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.


How can I localize cpEditUrl? I use the following code to link to the CP from the front end:

{% if entry.isEditable() %}
  Edit entry
{% endif %}

What do I have to add to link to the correct locale as it always jumps to the global locale instead of the current one?

The following code should work for you:

 {% if entry.isEditable() %}
    Edit entry
 {% endif %}


Wildcard subdomain for posts I want to assign a wildcard domain to every entry from a specific type. For instance:

client.example.com

Where client is the slug of an entry. Is that possible? If yes, how?

Thanks!

It’s definitely possible. Here’s the gist:

Forget the whole subdomain idea, and start by getting everything working using a URI format like /client/<slug>.
Make all subdomain traffic get routed to the same server/virtual host.
Make Craft think that subdomain requests actually had a URI in the format of /client/<slug>, so it will route the request the way it did in step 1.

How you go about the second step depends on whether you’re on Nginx or Apache.

For Nginx, add default_server to the server config’s listen directive:

server {
    listen 80 default_server;
    // ...
}

For Apache, create a _default_ virtual host definition:

<VirtualHost _default_:*>
    // ...
</VirtualHost>

Exact details depend on your hosting environment so you may need to do some of your own googling here. You’ll likely need to restart the webserver before changes take effect, too.

Once you have all subdomain traffic routing to the same place, add something like this to your index.php file:

<?php

$domainParts = explode('.', $_SERVER['HTTP_HOST']);

if (count($domainParts) === 3)
{
    $slug = $domainParts[0];

    // Fake Craft into thinking the URI was actually /clients/<SLUG>/uri/...

    // Nginx:
    $_REQUEST['REQUEST_URI'] = "/clients/$slug".($_REQUEST['REQUEST_URI'] ?? '');

    // Apache:
    $_GET['p'] = "clients/$slug/".($_GET['p'] ?? '');
}

// ...

With that in place, your client.domain.tld requests should start serving those client entry pages!


Specific template for a structure I wondered if it is possible to use one specific template for just one structure.

So let me make this clear. I have a structure called "Onze Diensten" (Our Services) and inside are child structures that are the actual services that the website offers. These child structures use a template that I assigned to them through structure so that works perfectly.
But what I want now is that the actual "Onze Diensten" gets it's own individual template which would show all the services on one page.

How do I do that?
Thank you for taking the time reading my question.

What I hoped would be the solution is using routes. By adding a route that when you visit onze-diensten/ it would load up the template onze-diensten/onze-diensten/ (Which is the path to the template I want to use).

But it seems to completely ignore the route at all.

I can't answer it clearly, but I did a workaround for something similar.

I've loaded the same template for my structure but gave my structure 2 entry-types(overviewPage, detailPage).

Both entry types loaded the same template but got handled differently. So my template for the structure looked something like this:

{% if entry.type == 'overviewPage' %}
  {% include 'snippets/content_overviewPage.html' %}
{% elseif entry.type == 'detailPage' %}
  {% include 'snippets/content_detailPage.html' %}
{% endif %}

I hope to see on this thread how other people handle this.


How can I order a sections entries by their children entry postDate? Is it possible to order a section of entries by their child entries post date?

{% for article in craft.entries({
    section: 'articles',
    type: 'videoArticle',
    limit: 6
}).getChildren().order('postDate asc') %}
    {{ article.title }}
{% endfor %}

Each article has 1 child under it. I want to filter the articles by the latest postDate of the children.

This should do what you want.

{% set videos = craft.entries({
    section: 'articles',
    type: 'video',
    level: 2,
}) %}

{% set articleIds = [] %}
{% for video in videos %}
    {% set article = video.getParent() %}
    {% set articleIds = articleIds|merge([article.id]) %}
{% endfor %}

{% set articles = craft.entries({
    id: articleIds,
    fixedOrder: true,
    limit: 6
}) %}

You go through all the videos and collect the IDs of the parent article entries. Once you have the IDs, make sure to set fixedOrder in the final criteria model and the entries are retuned in the same order as the IDs in the id param.

Note that the getParent function queries the database for each video in your section. You might want to consider caching that piece of code.

And you can also test if replacing the code in the for loop with the following performs better.

{% set articleId = video.getAncestors(1).ids()[0] %}
{% set articleIds = articleIds|merge([articleId]) %}


Resolving the $entry variable for custom routes somewhere but a Twig template I have several custom routes defined on the routes.php and, as usual, I am resolving the value of the template's entry in the Twig template when it is not defined (which is when it doesn't match a Craft Route) but I'd like to do it somewhere else before it reaches the template because I want to remove the logic in Twig.

Can I add a method to be executed before last Craft's renderTemplate($template, $variables) in which I would resolve and add $entry to $variables when it's not defined? What's the way to go?

Thank you :)

Alright, if you didn't already create a custom plugin I suggest you to visit Pluginfactory.io to create the boilerplate. Let's assume your plugin handle is awesome-plugin, just for testing purposes.

You create a controller with the name RouteController that contains the function actionMyAwesomeRoute

In summary:

handle: awesome-plugin
controller: RouteController
function: actionMyAwesomeRoute

All routes in Craft are defined via plugin-handle/controller-name/function-name without the "required" parts - and in snake-case

That means your route will be awesome-plugin/route/my-awesome-route (remove "Controller" and "action")

That being said: you can register your routes in your Plugins main init function

Defining the routes

public function init(){

    Event::on(
        UrlManager::class,
        UrlManager::EVENT_REGISTER_SITE_URL_RULES,
        function(RegisterUrlRulesEvent $event) {
            // easy route for demonstration
            $event->rules[] = [
                'pattern' => '/some-nice-url',
                'route'   => 'awesome-plugin/route/my-awesome-route'
            ];
            // when you visit www.example.com/some-nice-url your function will be executed

            // more complex example if you are not interested
            // skip that and don't think about it
            $event->rules[] = [
                'pattern' => 'my-fancy-route/<action:>/<id:\d+>/<siteHandle:\w+>',
                'route' => 'awesome-plugin/route/<action>',
                'defaults' => [
                    'id' => null,
                    'siteHandle' => null,
                    'action' => 'index'
                ]
            ];
            // you can visit this route via www.example.com/my-fancy-route
            // this way, your actionIndex will be called
            // when you do www.example.com/my-fancy-route/foo
            // Craft tries to call the actionFoo in your Controller
            // www.example.com/my-fancy-route/bar -> actionBar

            // when you do www.example.com/my-fancy-route/edit/5
            // your actionEdit will be called and Craft passes 5 as a parameter

            // www.example.com/my-fancy-route/save-entry/9/siteOne
            // will call actionSaveEntry(9, 'siteOne');

        }
    }
}

Your Controller

public function actionMyAwesomeRoute(){
    $variables = // define whatever you want

    return $this->renderTemplate('path/to/template', $variables);
}

More complex examples, skip that if you don't need it

// www.example.com/my-fancy-route/show-entry/9/siteOne
public function actionShowEntry($id = null, $siteHandle = null){
    // $id will be 9, $siteHandle 'siteOne' since those parameters
    // are passed via URL, otherwise they are both null
    $entry = Craft::$app->getElements()->getElementById($id, $siteHandle);

    return $this->renderTemplate('path/to/template',  ['entry' => $entry]);
}

Just a little bit more complex stuff

You could actually use the default route and inject it with another parameter as well. So When you have an existing route to an entry like news/2018/feb/awesome-news/ you can as well visit this entry with news/2018/feb/awesome-news/fooBar

$event->rules[] = [
    'pattern' => '/<route:\S+>/<something:\S+>',
    'route'   => 'awesome-plugin/route/catch-all'
];

And in your Controller

public function actionCatchAll($route, $something){
    $entry = Craft::$app->getElements()->getElementByUri($route);
    if ($entry instanceof Entry) {
        $section = $event->getSection();
        $siteSettings = $section->getSiteSettings();
        foreach ($siteSettings as $site) {
            if ((int) $site->siteId === (int) $entry->siteId) {
                $templatePath = $site->template; // the template path for the entry
                return $this->renderTemplate(
                    $templatePath,
                        [
                            'entry'     => $entry,
                            'whatever'  => $something
                        ]
                    );
            }
        }
    }

    return Craft::$app->runAction(Craft::$app->getRequest()->getFullPath());
}


Restricting Payment Gatways by User Group using Commerce Pro? Is it possible to restrict payment gateways on a per user group basis?
e.g. Say you want a user group to assign users into from a certain country that cannot use PayPal, so you can offer them a different gateway instead?
Thanks

This is really more of a Craft general thing than Commerce per se, if you're content to simply 'restrict' them by only showing them the appropriate options depends on their group.
If so, then it's as simple as some twig code to test the user group and show/not show things accordingly.
{% if currentUser.isInGroup('groupHandle') %}
   ... show something
{% else %}
   ... show something else
{% endif %}

(Of course that requires a logged in user and the bigger questions here is whether user groups is the right way to handle this scenario...)
If you want to take things further, you could listen to various Commerce events in a custom module and take action there if they should/shouldn't be allowed to do what they arte doing.  You might look at:
https://craftcms.com/docs/commerce/3.x/events.html#beforeprocesspaymentevent
https://craftcms.com/docs/commerce/3.x/events.html#beforecompleteorder
...or others - they are listed here:
https://craftcms.com/docs/commerce/3.x/events.html
In reality, as usual, probably some combination of front end logic and back end verification would be the way to go.
Hopefully that is enough to get you started!


Craft 3 via composer with Mamp Pro Is it possible to get an idiots guide to this:

Error on Craft 3 install

I'm just not following the context of the answer/commands, a detailed step by step would be invaluable for fear of trying something, not really understanding what's going on and possibly doing it wrong and affecting dependent tech, just a thought, thanks.

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


Partial match in URL getSegment() Is there a way to partially match text in a URL segment? I would like to conditionally show code if the text "vascular" is in Segment 3.

If my URL is: https://website.com/segment1/segment2/10009-vascular-access

This is what I've tried so far...

{% if craft.request.getSegment(3) == 'vascular' %}

{% if craft.request.getSegment(3).contains("vascular") %}

You should be able to utilize twig's built-in containment operator.

Your code would look like this:

{% if 'vascular' in craft.request.getSegment(3) %}
    ...
{% endif %}

Here is official documentation on the containment operator: http://twig.sensiolabs.org/doc/templates.html#containment-operator.


Matrix gallery with Imager plugin I have a portfolio page for a client that has a simple two column grid of images. However, I'd like to set it up so that it creates responsive images via the excellent Imager plugin.

I have the following code below so far. However, it's only outputting the first image from the Matrix. So I need it to output all the images the client drops in.

So need a little bit of help to tweak the code to output all images please?

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

    {% case "images" %}
    {% set image = block.portfolioImage.first() %}
    {% set transformedImages = craft.imager.transformImage(image,
      [
          { width: 1200, ratio: 4/3 },
          { width: 992, ratio: 4/3 },
          { width: 768, ratio: 4/3, jpegQuality: 60 },
      ],
      {
          format: 'jpg',
          allowUpscale: false,
          mode: 'crop',
          jpegQuality: 80,

          interlace: true
      }
    ) %}
    {% if image | length %}
    <img class="img-responsive"
         src="{{ transformedImages[1].url }}"
         sizes="50vw"
         srcset="{{ craft.imager.srcset(transformedImages) }}"
         alt="{{ image.title }}">
    {% endif %}

    {% endswitch %}
{% endfor %}

Assuming it's the field portfolioImage that can have multiple assets, try this:

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

    {% case "images" %}

    {% for image in block.portfolioImage %}
        {% set transformedImages = craft.imager.transformImage(image,
            [
                { width: 1200, ratio: 4/3 },
                { width: 992, ratio: 4/3 },
                { width: 768, ratio: 4/3, jpegQuality: 60 },
            ],
            {
                format: 'jpg',
                allowUpscale: false,
                mode: 'crop',
                jpegQuality: 80,
                interlace: true
            }
        ) %}
        <img class="img-responsive"
             src="{{ transformedImages[1].url }}"
             sizes="50vw"
             srcset="{{ craft.imager.srcset(transformedImages) }}"
             alt="{{ image.title }}">
    {% endfor %}

    {% endswitch %}
{% endfor %}


Output values from all entries in a specific section EXCEPT those with a specific category id Currently, this is NEARLY doing what I want except instead of the output being entries that do NOT have the id, it's output is ONLY the entries with the id.  I'm not sure why, since I've included the 'not' keyword within the parameter.

{% set entries =
craft.entries.section('driverPositions').limit(null).relatedTo('not' , 7192) %}

{% for entry in entries.order('state, city').limit(null) %}

<option value="{{entry.url}}">{{ entry.state }} - {{ entry.city }}</option>

{% endfor %}

thanks in advance!

You can get the entry IDs that have are related to the category and then exclude them from the all the entries.

{% set entryIdsWithCategory =
craft.entries.section('driverPositions').relatedTo('7192').limit(null).ids() %}

{% set entryIdsWithoutCategory = craft.entries.section('driverPositions').limit(null).ids()|without(entryIdsWithCategory) %}

{% set entries = craft.entries.section('businesses').limit(null).id(entryIdsWithoutCategory).order('state, city') %}

{% for entry in entries %}
    <option value="{{entry.url}}">{{ entry.state }} - {{ entry.city }}</option>
{% endfor %}


Setting the page title for a category page I am trying to get the page title of the categories page. Currently it shows as: category-name, but I would like to have it set to Category Name to match the category.title.
My categories/index.html looks like this:

{% set title = category %}

{% block content %}

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

    {% for entry in entries %}

        -- Code Here --

    {% endfor %}

{% endblock %}

Thanks in advance.

We would need to know how you render your title. Otherwise it would just be

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <meta charset="utf-8" />
    <title>{% if title is defined %}{{ title }} {% endif %}{{ siteName }}</title>
</head>

and in your category template

{% set title = 'Category ' ~ category.title %}


URL validation without http:// or https:// in the URL Is is possible to use Craft's URL validation without http:// or https:// in the URL?
Or use some sort of function / filter to conditionally add it to the URL if it is missing?

I'm posting a form using sprout forms. The form contains a field that is set to validate as url.
If you post this field without adding http:// or https:// it doesn't validate.
Is it possible to somehow to set the defaultScheme of an url field to http without changing the core Craft UrlValidator or Yii's CUrlValidator?

To conditionally add http:// to strings that don't begin with http:// or https://, use the Twig matches operator in a comparison.

To keep the syntax compact, I use a ternary operator within the set tag.

{# Set an example URL without `http://` #}
{% set url = 'example.com' %}

{# "Correct" the URL notation #}
{% set url = url matches '/^(https?:\\/\\/)/' ? url : 'http://' ~ url %}

{# Test output #}
{{ url }}

.

This is no full URL check in my regular expression, but you could simply work that in too. Pay attention to the escaping character \ that (currently) needs to be escaped itself, so you end up with \\ (it's wrong in the Twig docs).


Can I atttach uploaded file in A&M Forms to notification email I have form created with A&M Forms plugin where the user can upload a file.
I would like to attach the file to the notification email itself.

Is this possible? How?

There is a switch in notification tab for doing that -
Add attachments with notifications / Whether to add possible attachments to the email.

Feeling stupid now :)


How to check if a field exists on a section When you remove a field from Craft, the data itself doesn’t disappear. So removing i.e. an intro field from a section, if that intro field is still used in the template, that content will be output still on an entry.

Presumably this is intentional more than a bug so that Craft doesn’t have to go and re-save all of the entries in that section, which would probably cause the webserver to catch on fire (therefore I’m not going to write a plugin to hook into the save entry hook to clear it).

Is there a way to check in twig if a field is on a given section? The “if x defined and x|length” check passes because this data exists against the entry, even if the fields isn’t on the section.

I’m using a template for multiple sections that share a similar set of fields for a preview, and don’t want to replicate 99% identical templates.

I think you're running in to a caching issues here or you're not testing with devMode turned on perhaps.

I've just tested here and if I remove a field and reload an entry in devMode I immediately get an exception e.g.:

Craft\Commerce_ProductModel and its behaviors do not have a method or closure named "unimformityMeasurement".

Actually, even with devMode off I get a 500 server error with the same information, so I am thinking that you're very likely hitting a cached result that is preventing you from  seeing these errors.

(In my experience you are correct the data is still in the database though).


Check if a field a included in a Matrix block Situation: I have a matrix with about 10 block types, 3 of which have a certain field. I want to check if the current block has that field.

The field in question is a dropdown with values in all 3 options.

I've tried:

{{ attribute(block, 'backgroundColor') is defined ? 'true' : 'false' }}

=>  returns true for all blocks

{% if block.backgroundColor|length %}

=> errors out with Craft\MatrixBlockModel and its behaviors do not have a method or closure named "backgroundColor".

{% if block.backgroundColor is defined %}

=> same error as above

Anyone know how to do this?

In certain cases Twig is unable to recognize the correct object oriented syntax with magic properties so {% if object.property is defined %} will still produce an error.

You can use {% if block['backgroundColor'] is defined %} it seems strange and would usually considered as wrong syntax (PHP wise) but it works in Twig


How do I pass a URL segment to a search parameter? I'm trying to set up an archive page by passing dates in the URL to the entries search parameter to show events from a specific month.  The eventstart is a custom date field.  If I enter numbers i.e. 2017-11 in the search parameter it works but the URL segments don't seem to parse.

Thanks in advance.

{% set year = craft.request.segment(3) %}
{% set month = craft.request.segment(4) %}

{% set entries = craft.entries.section('calendar').search('eventstart:"year-month)"') %}

{% for entry in entries %}

{{ entry.title }}

{% endfor %}

You'd need to use Twig's string concatenation in order to do this with the ~ operator.

{% set entries = craft.entries.section('calendar').search('eventstart:' ~ year ~ '-' ~ month) %}


An unknown error has occurred in asset reindex I am getting the error: An unknown error occurred for each file in a folder when I try Update Asset Indexes.  The folder is a local folder that is outside of webroot.  The files just contain json data. I have looked through Craft log files and apache log files and cannot find anything. Any ideas?

I have tried the following from other questions with the same error message and none of these made an difference.

Deleted entire craft/storage/runtime/ folder

An unknown error occurred - no log entry

Made sure no record in table assetindex has null for dateModified column

"An unknown error occurred" in assets screen

Reset folder ownership

permissions userphotos "an unknown error occurred"

Try to call the json file in the browser. There are chance of showing unknown error when the path of the json file is missing in Asset Index.


Do temporary files stored in craft/storage/runtime/temp get automatically deleted? This is somewhat related to the question at Where should a plugin create temporary files

I have a plugin that needs to store temporary files. Do I need to worry about cleaning up the craft/storage/runtime/temp after I'm done with them, or do they get deleted automatically on some kind of recurring basis?

The only two times Craft clears that folder is 1) at the end of an automatic or manual update and 2) when you have the "Temp files" checkbox checked under the "Clear Caches Tool" under Settings->Tools.


Config variable does not exist I'm trying to set up caching and have it disabled for my local environment using {% cache unless craft.config.devMode %}. This works fine on non-local environments, but on my local environment I'm getting the error Method "devMode" for object "Craft\ConfigVariable" does not exist. Even though it does, this is my config file:

return array(
    '*' => array(
        'addTrailingSlashesToUrls' => true,
        'omitScriptNameInUrls' => true,
        'enableCsrfProtection' => true,
        'cpTrigger' => 'example-admin',
        'siteUrl' => (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on") ? "https://" : "http://" . $_SERVER['HTTP_HOST'],
        'environmentVariables' => array(
            'basePath' => $_SERVER['DOCUMENT_ROOT'] . '/data/uploads/',
            'baseURL' => (isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on") ? "https://" : "http://" . $_SERVER['HTTP_HOST'] . '/data/uploads/',
        )
    ),
    '.local' => array(
        'devMode' => true
    )
);

If I {{ dump(craft.config.devMode) }} I get bool(true) so it is being set, it's just when being used in the cache conditional.

Looks like it was an issue with character encoding. I copied the {% cache unless craft.config.devMode %} from What are the best practices for using the {% cache %} tag?.

When I manually retyped out the conditional it worked properly.


How secure is Craft and why is it secure? What measures have been put in place in regards to securing Craft at the core level.
What measures have been put in place in regards to Craft's Plugins which make use of (connect to if you will) Craft's core?
If possible (without an opinion piece being written), is there anyway to make a comparison between other popular CMS and Craft in regards to security?
How does one know third party libraries which are used in Craft are secure?
Craft is built on Yii PHP Framework and Twig. How secure are these?
Has Craft ever had any security incidents to date?
In the case there is a security incident how does the team at Craft notify people such incident occurred?
How safe is auto-updating within Craft?

Updated Answer for Craft 3

I've updated and consolidated the technical parts of this for Craft 3 and placed them in a security FAQ for easier referencing: https://craftcms.com/guides/security-faq

Original Answer for Craft 2)

Let me get this out of the way, first... there is no perfect software.  Bugs exist and some of those will be security related.

Having said that, we're pretty paranoid people (thanks NSA!) so we think about security a lot and take it seriously.

  What measures have been put in place in regards to securing Craft at the core level.

Off the top of my head here's some of what we currently do:

Perhaps the biggest thing Craft has going for it, in the event a security related bug is that we can get the fix deployed quickly to our users with Craft's one-click auto-updating.  In addition to that, we can mark a release as "critical", which gets special attention in the control panel UI making it obvious there is an update that needs to occur. Thankfully, we've yet to use that feature.
Craft/Yii uses PDO for all database queries, so all dynamic values are parameterized helping prevent SQL injection attacks. Don't think SQL injection attacks are still a problem? They are... even with the more popular apps.
Craft validate sensitive cookie data to ensure no cookie tampering has taken place between requests.
Craft has CSRF token validation support to help prevent CSRF attacks.
Twig auto-encodes all HTML by default, helping avoid XSS attack vectors.
Rich Text Fields have an HTML purification option that is enabled by default, which strips any malicious strings from the input. This is powered by the venerable HTML Purifier.
Craft ensures that sensitive data (server paths, stack traces, etc.) doesn't get exposed to an end-user in the case where an error occurs and Dev Mode is disabled.
Craft uses email verification for creating new accounts. You can configure how long the token in that email is valid.
Craft makes the control panel trigger configurable for better security by making it harder for people guess the entry point to your control panel.
Craft exposes the blowFishHashCost config setting which helps control how long a breached password hash will survive a brute-force attack.
If a user has an invalid login attempt X times within a Y window duration, you can force them to wait for Z minutes before they try again or permanently lock their account until an admin unlocks it. All configurable.
The user session duration is configurable.
The default file and folder permissions are configurable.
Craft jumps through some pretty significant hoops to ensure in-app purchasing is secure even on installs without SSL enabled.
Craft helps prevent session/cookie hijacking, by doing things like storing the browser's user agent string in the identity cookie and validating that it matches on subsequent session requests.
Craft will deny all requests to start a session that don't present a user agent string or IP address to prevent direct socket connections from trying to connect.
Craft uses elevated sessions that forces people to re-enter/validate their existing password for critical actions (changing passwords, emails, permissions, etc.). By default these elevated sessions are valid for 5 minutes, but that is configurable.
No one, not even admins, can directly change another user's password.
Craft's codebase has been frequently audited by third party security firms and with tools like OWASP's Zed Attack Proxy Project.
Craft has permission enforcement at the controller level for all actions that make changes to the site.
Craft requires PHP 5.3. Some applications are still supporting back to PHP 5.2.4, which is over 14 years old (approximately 980 internet years).  Craft 3 will require 5.6.
Craft requires mcrypt with blowfish for password hashing, arguably the currently most secure and reliable method of password encryption.
There is a help article explaining how to force SSL for all CP requests. (http://craftcms.com/help/force-ssl)
Craft inserts caution tape across the top of all control panel pages when running in Dev Mode, reminding you not to use it on production.
Craft can be configured to store PHP session files in a Craft folder (craft/storage/runtime/sessions) so they don't get mingled with other app's session files on shared host.
Craft provides granular permissions on user accounts and user groups via a intuitive/simple permission system.
Craft provides a preventUserEnumeration config setting for people that want to prevent user enumeration attempts on their forgot password pages.
Craft provides a validateUnsafeRequestParams config setting that will ensure certain request parameters, such as redirect, are not tampered with on a POST request preventing a Denial of Service (DoS) attack vector. This config setting will be removed in the upcoming Craft 3 and the behavior will be enabled by default in Craft itself.
Craft's session cookies get set to HTTP only.
By default Craft will set the secure flag on all cookies if the request is over https. You can set the useSecureCookies config setting to true to force the secure flag no matter what.
Because Craft requires OpenSSL, we have a cryptographically strong way of generating randomness for things like email verification and password reset tokens.
Craft keep logs of any error and/or suspicious activity to help track issues down.
Any uploaded files have their file names cleaned as well as any code embedded in the image stripped.
Craft's default folder structure encourages people to keep Craft's application files above the web root and the requirements page at yourdomain.com/cpTrigger/utils/serverinfo does a test and warns you if sensitive Craft folders appear to be in the public web root.
We provide an RSS feed for updates you can subscribe to that includes all bug fixes.
Craft sets the X-Frame-Options: SAMEORIGIN header on all control panel requests to prevent the CP from being loaded in an iframe to help prevent clickjacking.
Craft sets the X-Content-Type-Options: nosniff header on all control panel requests to help prevent some older IE/Ajax XSS attack vectors.
Craft uses timing safe methods for sensitive comparisons like checking password the equality of password hashes helping prevent timing attacks.
There is a “Securing Craft” support article to help guide people through securing their Craft installation.

And keep in mind that there are still plenty of additional security related things on "The List" that we plan on implementing.

  What measures have been put in place in regards to Craft's Plugins which make use of (connect to if you will) Craft's core?

Permissions are enforced at the user/user group level, so if a user is using a plugin as an admin, then they'll be able to use any of Craft's services that require an admin.

  If possible (without an opinion piece being written), is there anyway to make a comparison between other popular CMS and Craft in regards to security?

Someone smarter than me will have to do that.

  How does one know third party libraries which are used in Craft are secure? Craft is built on Yii PHP Framework and Twig. How secure are these?

Lumping these two together because as far as Craft is concerned, Yii and Twig are both third party libraries as well.

Remember... there is no bug-free software.

I'm much more comfortable with using 3rd party libraries for things like a templating language, an RSS feed reader, an email library, an HTTP client and even (especially) a framework instead of attempting to roll our own for various reasons.

It's not our core competency.  The people working on these libraries have gained very specific, very valuable domain knowledge about the problems their libraries are trying to solve. We can't (and shouldn't) try to be the experts in all of those areas and we should be focusing on what we do best. For example... if I had to write this code, I'd drink myself to death.
The libraries we use have been around a long time, are very popular and have been tried and tested across countless installs, configurations and use-cases.  On an order of magnitude greater than the Craft install base is. The more installs and eyeballs on the code, the more it's been exposed and audited.
Worst case scenario. A devastating security bug and exploit is revealed before the library has had a chance to release an update (which is kind of a jerk move). If we think the library authors are taking too long for a fix, we can fork the library, fix it with a patch of our own and merge in the official patch when it's been released.

  Has Craft ever had any security incidents to date?

Nothing that's been exploited that we're aware of. Nearly everything that we've found or that people have reported to us has been pretty minor.  i.e. XSS vulnerabilities that could occur in the control panel under very specific conditions.

  In the case there is a security incident how does the team at Craft notify people such incident occurred?

Depends entirely on the severity of the incident.

All fixed bugs get mentioned in the change log and we tweet about every release: http://craftcms.com/changelog

If it is severe, then we have the ability to mark an update as "critical", bringing special attention to it as well as filing an official CVE, blog post, etc.


Image in entry only showing when using entry.image instead of entry.assetFieldHandle I discovered that I can replace:

{% for asset in entry.assetFieldHandle %}
    {{ asset.url }} -- {{ asset.width }} -- {{ asset.height }}
{% endfor %}

From assetFieldHandle to the name of the handle ... then it works.
But why not with entry.assetFieldHandle?

{% for asset in entry.image %}
    {{ asset.url }} -- {{ asset.width }} -- {{ asset.height }}
{% endfor %}

I assume you got Entry.assetFieldHandle from the docs? That's a way of telling you that you should call the asset field you're looking for by its handle.

You'd have to use the actual asset field handle of the asset field you're addressing, because an entry could have multiple asset fields (so there is NO attribute assetFieldHandle within the entry).

Let's say that your entry has two asset fields: images (multiple images) and logo (1 image).
In this case, this would be the way to display those assets:

{# get multiple assets from field with handle 'images' #}
{% for image in entry.images %}
    {{ image.link }}
{% endfor %}

{# if you know an asset field only contains 1 asset (because its input is limited to 1)
   you can use 'first()' to get it without any for loop #}
{{ entry.logo.first().link }}


How to set url of delete button of editableTableField? As title says, I have a URL which I need to call when someone clicks on delete button. I already have a primary key which I need to set and append in delete URL. How'd I do that?

Update

Rows are being generated as:

{% if posts is defined %}
    {% for post in posts %}
        {% set rows = rows|merge([
        [
            post['scheduledTime'],
            post['URL']
        ]
        ])
    %}
        {% set index = index+1 %}
    {% endfor %}
{% endif %}

Because the table saves the inputs as JSON they are not individually deleted from the backend.

The way the table works is, when you click a delete button javascript removes those inputs for each cell from the form. When the user saves the form it saves the updated cells as JSON, if there are any.

However if you are saving each row individually then I would listen for the click of the delete button. When clicked, grab your id, then call your plugin action method for delete by using this:

Craft.postActionRequest('pluginname/controller/deleteMethod', {params:value}, function(data){
   "do stuff if needed…";
});


Dynamic relatedTo queries I've got an advanced search form which culminates in:

craft.entries.section('whatsOn').relatedTo(
    'and',
    { element: artCategories },
    { element: locationCategories },
    { element: bbfcCategories }
).search(searchTerm).order('score').limit(8)

This works, but only if the item being searched for has populated artCategories, locationCategories, and bbfcCategories.

Any of those are optional; i.e., the bbfcCategories line may not be needed at all... and likewise the searchTerm - is there a way to do this dynamically?

You can build the array for your criteria model's relatedTo parameter step for step before adding it:

{# Initial criteria model #}
{% set exhibitions = craft.entries.section('exhibitions').limit(null) %}

{# Compose relatedTo parameter #}
{% set relatedToParam = ['and'] %}

{% if query.art is defined %}
    {% set catIds = craft.categories.group('artCategories').id(query.art).ids() %}
    {% set relatedToParam = relatedToParam|merge([{ targetElement: catIds }]) %}
{% endif %}

{% if query.location is defined %}
    {% set catIds = craft.categories.group('locationCategories').id(query.location).ids() %}
    {% set relatedToParam = relatedToParam|merge([{ targetElement: catIds }]) %}
{% endif %}

{# Add additional criteria. Avoid passing an array with 'and' only #}
{% if relatedToParam|length > 1 %}
    {% set exhibitions = exhibitions.relatedTo(relatedToParam) %}
{% endif %}


Change name of "New Entry" button is it possible to change the name of the "New Entry" button?

In my case the user can add a new program part. And so the button should call "New program" or something like that.

You can do this without hacking core files using Craft's static translation support.


Query table in a different database I'm writing another plugin for my craft app, this time I'm attempting to reuse a MySQL table that's used by other applications as well. I've a class extending the BaseRecord, and getTableName() will return differentdb.tablename. Does Craft handle this, or do I have to make a copy of that table in the craft database? (MySQL permissions for the craft user already give it read access to that database)

Have you tried it? I'm pretty sure that's not going to work as Active Record is tied to the db connection in craft/config/db.php hanging off of craft()->db.

You should be able to pull it off with a plugin that instantiates its own DbConnection, though and uses Query Builder instead of Active Record.  Completely untested, but something like this:

$otherDbConnection =  Craft::createComponent(array(
    'emulatePrepare'    => true,
    'charset'           => 'utf8',
    'tablePrefix'       => 'craft_',
    'class'             => 'Craft\DbConnection',
    'autoConnect'       => true,
));

$otherDbConnection->connectionString = 'mysql:host=localhost;dbname=otherdb;port=3306';
$otherDbConnection->username = $userName;
$otherDbConnection->password = $password;

From there you can do $otherDbConnection->createCommand() and grab all of the data you want from the other database.  It's up to you how you'd merge that in with data from your existing database.

If you wanted to get fancy and access the database in other files/places in code, you could do:

craft()->setComponent('otherDb', $otherDbConnection);

And access the other database via: craft()->otherDb->createCommand().


ElementCriteriaModel UTF-8 Encoding I have been working with data received from Guzzle and it is producing a Unicode String that looks similar to this Bachelor\u2019s Degree (after some parsing). When I save other content within craft through craft()->entries->saveEntry( $entry ) The unicode items are converted to their appropriate characters. However, when I use this in the ElementCriteriaModel searches, it does not work because it is using the literal Bachelor\u2019s Degree. It does work when I hard code Bachelor's Degree so the lookup code is functional. Also, I tried all of the StringHelper static functions and have done tons of iterations of mb_convert_encoding( 'Bachelor\u2019s Degree', 'HTML-ENTITIES', 'utf-8' ), htmlspecialchars, and htmlentities, but it has not produced a good result. Here is the code I am using for the query just in case:

$criteria = craft()->elements->getCriteria( ElementType::Category );
$criteria->title = $job[ 'eduReq' ];
$eduReq = $criteria->first();

Do you all know how to convert this string correctly so that the ElementCriteriaModel uses Bachelor's Degree?

Could this maybe be a unicode issue? Maybe the api plugin is producing \u2019 instead of the unicode to produce a normal '


How can I get the requested entry from a plugin? If I’m accessing an entry’s URL (the 4th check in Routing), how can I get the entry that the URL matched from a plugin?

You can get the request’s matched element via:

$element = craft()->urlManager->getMatchedElement();

There are two things to remember though:

There may not be a matched element
The matched element might not be an entry. (It could also be a category, and if you have any plugins installed that add their own element types that can have their own URLs, it could be one of those.)

To defend against those possibilities, just use the following conditional:

if ($element && $element->getElementType() == ElementType::Entry)
{
    // There was a matched element, and it's an entry!
    // ...
}


Custom routes using kebab {type} in URL segment I have a section that has multiple entry types. I would like to use kebab-style url segments in the URL format. I can get the articles to serve kebab URIs using this for the section's Entry URL Format:

our-firm/{type.name|kebab}/{slug}

However, this will not call the template when making the page call — needs to be:

our-firm/{type}/{slug}

So, how do you set things up to have the best of both worlds: kebab'd url segments and working templates?

You could have a try with dynamic routing, where you map a URL (or a url pattern) to a specific template.

Dynamic routes take priority over template paths.

If I misunderstood you, can you give an example as to what the URL is for a specific entry compared to what you need it to be?


Removing headers from blog post "excerpts" (using Hacksaw) I'm using hacksaw to display the first part of my article on a blog listing page.

{{ entry.body|hacksaw(chars='300',allow='<p>', append='...') }}

The issue I have is when an article starts with a heading in it's body it looks like the attached. I'd ideally like to remove any headings from the excerpts.

As you can see the headings 'Reducing the size...' and 'Scaling' come through as plain text and the rest continues with my allowed

The only way I can think to do this is to allow their headings (h2 and h3) and then hide them in CSS, but I'm hoping there's a better way.

You could use the Twig replace filter with a regular expression, this'll remove the tag and it's content.

{{ entry.body | replace('/<h([1-6])>.*?<\\/h([1-6])>/', '') | raw | hacksaw(chars='300',allow='<p>', append='...') }}

The only limitation is regular expressions aren't fantastic with nested html tags, so your mileage my vary!

You might need to play around with the Regex a bit if you want to just limit it to a few headings, this will strip all h1, h2, h3, h4, h5, h6. You also might not need the | raw filter, it seemed to escape everything after the replace when I quickly tested it.


Can I POST to a template? In the documentation "search form" example you can run a GET request to a specific template and if you use a Plugin you can run a POST request to a specific controller action.

But is it possible to run a POST request directly to a template?

Sure, works just the same. Just change method="GET" to method="POST".

You can acquire the POST values by using craft()->request->getPost('yourPostName') in your plugin controller or by using {{ craft.request.getPost('yourPostName') }} in a template.


Slow saving when devMode false, but not while true All of a sudden, saving entries became really slow (up to a minute). Regardless of entry type.

I came across this question: Saving entries in admin panel

Problem is when I turn on devMode saving goes without a problem and only takes a second, so I am unable to debug it.

Does anyone know why saving all of a sudden is very slow, and/or why saving is fast only with devMode true?

I cleared all caches and updated file index, and now everything runs smooth. No idea why, but it fixed the problem.


Login form redirect not working My login form  is not redirect like I want it to.

<form method="post" accept-charset="UTF-8">
{{ csrfInput() }}
<input type="hidden" name="action" value="users/login">
<input type="hidden" name="redirect" value="profile">

Username or email

<input id="loginName" type="text" name="loginName"
    value="{{ craft.app.user.rememberedUsername }}">

Password

<input id="password" type="password" name="password">

    <input type="checkbox" name="rememberMe" value="1">
    Remember me

<input type="submit" value="Login">

Anybody know why?

All redirect parameters needs to be hashed in Craft 3. If not, they're completely ignored.

Try using:

<input type="hidden" name="redirect" value="{{ '/profile' | hash }}">

Or

{{ redirectInput('profile') }}


Is it possible to tell if a user was registered through the front end or CP? I would like to be able to perform actions on those users that register through the front end and skip ones who are created in the CP... is there are way of checking or a parameter accessible in the onBeforeSaveUser or onSaveUser events?

I assume there must be something hidden in there as users registered on the front end can be assigned to a certain user group which isn't applied to a CP registration.

You already answered your own question, but I thought I would post an example. In the plugin's class definition file create an init method with the following:

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

    craft()->on('users.saveUser', function(Event $event)
    {
        $user = $event->params['user'];
        $isNewUser = $event->params['isNewUser'];

        if ($isNewUser && !$currentUser) {

            // do your thing, whatever it is

        }
    });
}

This should only target 'new user registrations' by users who are 'not already logged in' (i.e. public registrations through the front-end). By the time the Users Service has raised the event, it should have already passed all the other checks, regarding whether to allowPublicRegistration, etc.


Unable to set slug to value used previously I have an entry whose slug I would like to set to 'archive', but when I save it, it is 'archive-1'. There is no existing entry with slug of 'archive' (craft.entries.slug('archive') returns null). There have been previous entries with that slug.

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


Encrypt ID on front-end and decrypt on back-end I have a front-end form that posts through the ID of a particular element/entry to a back-end controller. Is there any way to encrypt/hash that ID on the front-end, so the plain ID number is not visible, and then decrypt that ID in the back-end controller?

<input type="hidden" name="foo" value="{{ 'bar'|hash }}">

and then in your controller:

if (($foo = craft()->request->getPost('foo')) !== null)
{
    $foo = craft()->security->validateData($foo);
}

at which point $foo will either be null (not present), false (present but tampered with), or a string (present and valid)


Show parent and it's children as a nav Newbie here with hopefully a simple question...

I have a structure as per the image below where I want to only show the parent item and it's children on their pages.

I want to exclude the other entries but they should show on their own pages.

You can access children through the entry's descendants property.

{# display event-information #}

{{ entry.title }}
    {# display subsections #}

            {% for subsection in entry.descendants %}

{{ subsection.title }}

            {% endfor %}

You can also use the nav tag, as described in the documentation.

    {% nav entry in entries %}

            {{ entry.title }}
            {% ifchildren %}

                    {% children %}

            {% endifchildren %}

    {% endnav %}

More generally speaking, you can use any of the following properties of the EntryModel to traverse the structure: parent, children, descendants, ancestors, siblings, nextSibling, prevSibling, and level.


Unable to activate trial licence I would like to test out Craft Pro to see if it would be a good fit for my next project.

I have one issue. I have followed the instructions to install Craft CMS @ http://site1.craft.dev - but am unable to see the upgrade/test link in the footer?

Here is a screen shot of the domain I have it installed at:-

Here is a screen shot of the footer:-

How would I activate the trial licence (I am probably missing something obvious, so forgive me if this is the case) :)?

I know it sounds silly, but try refreshing or clicking another tab (like entries). What you should see is in the attached screenshot.

Click that box and click "Try" and you should be all set.


Craft plugin controller for batch update users break with empty page I made a plugin to update my 3000 users. It is kind of a toolbox to manage and update some users fields.

I am calling the controller directly through its url action.
It is working basically but it stops after 20 seconds when updating too many users, and display a white page in browser, no results.

I can see in my plugin log it updated some few lines before stopping.
I checked php and craft logs and cannot see any error information.

public function actionUsersFix() {

    // Delete all the entry caches
    craft()->templateCache->deleteCachesByElementType('User');

    // Now find the entry IDs
    $criteria = craft()->elements->getCriteria('User', array('group' => 'migMembers', 'limit' => null, 'status' => null, 'localeEnabled' => null));
    $criteria->group = 'migMembers';
    $criteria->limit = null;
    $criteria->status = null;
    $criteria->localeEnabled = null;
    $criteria->accent = '2';

    $userIds = $criteria->ids();
    //$totalEntries = count($userIds);

    //
    foreach ($userIds as $userId)
    {
        $user = craft()->users->getUserById($userId);

        $oldAccent = $user->accent;
        $newAccent = '3';

        $user->getContent()->accent = $newAccent;
        $success = craft()->users->saveUser($user);
        MigPlugin::log('User '.$user->email.' - accent = '. $oldAccent .' - modified = '.$newAccent, LogLevel::Warning);
    }

}

It was a php.ini config problem, I put some parameters values up and the update succeeded in less than 2 minutes and completed my users batch update.

So you just need to update the values below and reload your web server (ie: Apache).

max_execution_time 120 (instead of initial value 30)
memory_limit 512M (instead of initial value 128M)


Question About Eager Loading Syntax I am trying to add eager loading to a query. The original query was as follows (‘sticky’ is a custom lightswitch field for marking sticky entries):

{% set news = craft.entries.section('news').order('sticky desc, postDate desc').limit(9) %}

Is the following ok syntax for adding eager loading?

{% set news = craft.entries.section('news').order('sticky desc, postDate desc').limit(9).find({
    with: [
        ['newsHighlightImage', {
            withTransforms: ['newsMedium', 'newsSmall']
        }]
    ]
}) %}

I ask because although the above seems to work, in the examples in the documentation, the find/with bits come right after the section parameter. But if I do it that way, I get an error about not being able to apply the “order” method. I reckon that’s because find() turns the result into an array so “order” is not longer available. But I couldn’t figure out the correct carry syntax to make it work that way. Is there a better way to do this?

Thanks!

Willhaus

How about stacking all the element query params into a single object?

{% set entries = craft.entries({
    section: 'news',
    order: 'sticky desc, postDate desc',
    limit: 9,
    with: [
        ['newsHighlightImage', {
            withTransforms: ['newsMedium', 'newsSmall']
        }]
    ]
}) %}

Also, I don't believe you need to use the find() function here. The examples in the documentation only use find() when eager-loading just the image transforms related to a single asset field.

{% set assets = entry.assetsField.find({
    withTransforms: [
        'heroImage',
        { width: 100, height: 100 }
    ]
}) %}


Using Aliases inside Admin Panel for fields I was wondering if it was possible to use an alias inside a field in the Admin panel. For example, I have a global section called "Navigation" which contains a matrix called "Links". This matrix allows the client to create links for their navigation bar. Inside each matrix block, is a field called "Link Url" where the client can put in a link.

Right now the client is hardcoding urls for the production site, so my links don't work on my dev environment. I would like to rectify this, with some type of elegant solution.

Any ideas?

A good approach would be to use the UrlHelper class it has a function UrlHelper::url() that is available in Twig and will return the correct URL for a certain path. So you could ask your client to not insert the entire URL, only the path -> instead of example.com/entries -> entries or you can include a custom Twig function/behavior that strips the domain before you use the {{ url('entries') }} function.
Anyway: to be honest I would create a different approach in the first place. Creating static URLs in a text field is usually not a good thing. I'm always a fan of the

protect clients against themselves

philosophy so you may want to consider to create a custom field type with autosuggestion or something. SEO wise it could be a bad idea if you clients are able to insert whatever they want and you output too many dead links. Maybe a Relation field could be something for you?