Craft 3 multi site publish options If a user has permission to publish on multiple sites, he by default publishes to all of them. If he wants to exclude some sites, he needs to go in each one and turn off the post for that site. This is ok if you have several sites, but on +100 sites it is a very time consuming task.

It occured to me that we could use one user account for publishing on one site and another for publishing on multiple sites, but again, if you don't want to publish on all 100+ sites, you still have to invest a lot of time to disable the post for unwanted sites.

I found this field type plugin, but i am not sure if it can accomplish what I want.
https://github.com/eastslopestudio/craft3-sites-field

I think something like a list with checkboxes would be ideal for this (like the one in user permissions for Sites) with the current Site being automaticaly initially checked. Or a multi select field maybe.

Is something like that doable?
If not with core Craft then maybe with a plugin?

Thanks in advance for any advice!

It sounds like this is something that could be done using a module. You could use the sites field type to select the sites you want to enable the entry for, and then listen to the beforeSave event to enable the selected sites (and disable all others).

You would listen for, and act on, this event in your module's init method.

The beforeSave event gets called for every site the entry gets saved for, so it could be something like (untested):

Event::on(Entry::class, Entry::EVENT_BEFORE_SAVE, function (ModelEvent $event) {
    // Get the entry from the event
    $entry = $event->sender;

    if (
        $entry->type->id == 1 // <-- Section type ID for entry
        && !in_array(
            $entry->siteId,
            $entry->getFieldValue('visibleOnSites')
        )
    ) {
        $entry->enabledForSite = false;
    }
}

This assumes that entries are enabled for every site by default, and that propagation for this section is active.


Sprig - Filter entries by custom field checkbox values, separate values as well as all values I am having a question regarding Sprig.
I do want to filter my entries for values that are defined in a dropdown field (example below is simplified).
It does work to the point where I want to filter all entries for all values, on page load all single checkboxes should be checked as well as the all checkbox.
The problem is that Sprigs AJAX request sends a single request for each single filter e.g.:
dropdown_field[]: dropdown_value_1
dropdown_field[]: dropdown_value_2

but for the all filter, and e.g. one checkbox it will be:
dropdown_field[]: dropdown_value_1, dropdown_value_2 .....
dropdown_field[]: dropdown_value_2

Unchecking the all checkbox will not empty the array, what it should.
That will cause the single filters not to work if all is checked. How can I make sure that the query request will be one array for all values instead of multiple query requests?
All Filters should be activated on load, the all filter would be disabled then. If a single checkbox is checked all shouldn't be checked (array has to be empty except the single value).
{% set dropdown_field = ['dropdown_value_1', 'dropdown_value_2', 'dropdown_value_3', 'dropdown_value_4', 'dropdown_value_5'] %}

{% set entryQuery = craft.entries({
    dropdown_field: dropdown_field,
    section: 'section_1',
}) %}

        <input sprig type="checkbox" name="dropdown_field[]" id="dropdown_value_all" value="" {{ dropdown_field|length >= 5 ? 'checked disabled' : '' }}>

            Select All Values

    {% for value in dropdown_field %}

        <input sprig type="checkbox" name="dropdown_field[]" id="{{ value }}" value="{{ value }}" {{ value in dropdown_field ? 'checked' : '' }}>

            {{ value }}

    {% endfor %}

    {% for entry in entryQuery %}

{{ entry.title }}

    {% endfor %}

Thank you!

My suggestion would be to give the Select All Values checkbox a unique name. That way, you can easily detect whether it was selected or not. You should also break dropdown_field out into 2 variables to avoid confusion.
{% set select_all_values = select_all_values ?? false

{% set dropdown_field_options = ['dropdown_value_1', 'dropdown_value_2', 'dropdown_value_3', 'dropdown_value_4', 'dropdown_value_5'] %}
{% set params = {section: 'section_1'} %}

{% if not select_all_values %}
    {% set params = params|merge({dropdown_field: dropdown_field} %}
{% endif %}

{% set entryQuery = craft.entries(params) %}

        <input sprig type="checkbox" name="select_all_values" id="dropdown_value_all" value="1" {{ select_all_values ? 'checked disabled' : '' }}>

            Select All Values

    {% for value in dropdown_field_options %}

        <input sprig type="checkbox" name="dropdown_field[]" id="{{ value }}" value="{{ value }}" {{ value in dropdown_field ? 'checked' : '' }}>

            {{ value }}

    {% endfor %}


Getting Craft's storage folder to work on Heroku I'm using Heroku to host a Craft 3 site, and it's working fine, apart from the fact that Craft isn't able to write to the /storage folder (or anywhere else, for that matter). Consequently, the Database Backup utility doesn't work and nor is Craft able to write logs. I'm keen to fix both these issues.

Has anyone managed to solve this problem on Heroku? If so, how?

For anyone else trying this: the solution I eventually came up for was to follow these instructions for adding an argument to the Procfile to tell Heroku to tail Craft's log file into the "Logplex" stream.

There might well be situations where Brad's suggestion (using a plugin to write the logs to stderr) is preferable, but I wasn't sure what the implications would be for logs in development (where it's fine for them to be written to the file system). Adding an argument to the Procfile side-steps this issue, since it's only run by Heroku.

My Procfile now looks like this:

web: vendor/bin/heroku-php-nginx -C nginx_app.conf -l storage/logs/web.log web


Commerce PaymentGateway configuration So I made an account with MultiSafePay:

Added my website where i need to get payments from.
Filled in the API key and Locale
Enabled it for customers (me)
Changed the Gateway of MultiSafepay from XmlGateway to RestGateway.
(Because XMLGateway is deprecated)

How would I add it to the checkout process in Craft Commerce?

Now I only get to see the credit card fields if MultiSafePay is selected in the dropdown, but I enabled all the payment options at MultiSafePay.

Could somebody explain to me and others how to implement it correctly?

Craft Commerce 1.2.1238 added support for the REST based Multi-Safepay gateway.


Integration with MailChimp et al Is anyone aware of a solution for using Craft user data with something like MailChimp? This is a very simple use case of sending newsletters/announcements to registered Craft users. Would be even better if it could be by User Group, but I will settle for all users.

I understand that Sprout Email can connect to MailChimp mailing lists, but that does not address the issue of having to manually sync the Craft User data with a MailChimp list.

Thanks for any suggestions!

Most email service providers like MailChimp won't let you send to a list of addresses, even if they're user accounts on your site, without first adding them to a list inside the ESP's control panel.
If you're planning on sending out user emails through a tool like this, it's best to determine the sync strategy before you start signing up users.
That said you have a couple options for existing users:

Create a template to export your user information in CSV format, save it's output and import into MailChimp

Use the Campaign Plugin to send out messages


FeedMe error with iTunes RSS compatible feed I am trying to ingest an iTunes compatible RSS feed on the template with FeedMe... the enclosures have things like <itunes:description> in them. When I try and access these properties I get the following error:

Unexpected token "punctuation" of value ":" ("end of print statement" expected).

Anyone know how I can access these enclosures without creating a Twig error?

Example current Twig code:

{{ feed[0].itunes:image['@href'] }}

You can’t use dot syntax because of the colon, try this instead

{{ feed[0]['itunes:image']['@href'] }}


How can I check if a plugin is installed and enabled? As the title suggests, I was wondering how to check if a certain plugin exists (and has been installed).

And secondly, check that the plugin is actually enabled.

Thanks,

Mark

On top of checking within the admin area, there are some other ways you can do this, both in templates and in your plugins.

In a template

{# Second argument is if you want enabled only #}
{% set plugin = craft.plugins.getPlugin('pluginHandle', false) %}

{# Now you have access to these methods... #}
{{ plugin.isEnabled() }}
{{ plugin.isInstalled() }}

For a full list of methods, see PluginVariable in craft docs.

For more info on how to get plugins within your templates, see the PluginsVariable, note this is different from PluginVariable.

In your plugin

To check a plugin from within your own plugin:

// Again, second arg is if you just want enabled plugins
$plugin = craft()->plugins->getPlugin('pluginHandle', false);

// Then you can do things like:
$plugin->isInstalled
$plugin->isEnabled;

See the PluginService and also the BasePlugin for more info.

Hope that helps :)


Is it Possible to Assign Permissions Within a Content Structure I'd like to be able to assign permissions to content or sections of content within a structure. For example, if I have a structure modeled around an organization and there are several departments within that organization, maybe marketing and sales, I'd like to be able to create groups that can create/edit content within a specific department. Is it possible, using a plugin or by some other means, to restrict access to a specific area within a larger structure?

Currently there is no native way to do this, but you could:

...split the structure into multiple channels.
...write a plugin which checks: on what page a user is, and denies access if necessary
...ask P&T to add this as a feature.


Attempting to create a complicated grid layout with batch I'm trying to create the following layout using batch, but I can't quite get it right...

This is how far I've gotten:

{% for entry in items|batch(3) %}

     {% if loop.index is divisible by(5) or loop.index == 1 %}

        {% for batch in entry[0:3]   %}
          {% if loop.index == 1 %}

{{batch}}

          {% elseif loop.index == 2 %}

{{batch}}

          {% else %}

{{batch}}

          {% endif %}
        {% endfor %}

      {% elseif loop.index is divisible by(2) %}

        {% for batch in entry[0:2] %}
          {% if loop.index == 1 %}

{{batch}}

          {% else %}

{{batch}}

          {% endif %}
        {% endfor %}

      {% elseif loop.index is divisible by(3) %}

        {% for batch in entry[0:3] %}
          {% if loop.index == 1 %}

{{batch}}

          {% elseif loop.index == 2 %}

{{batch}}

          {% else %}

{{batch}}

          {% endif %}
        {% endfor %}

    {% endif %}

{% endfor %}

Json used:

{ "items": ["1" , "2", "3", "4", "5" , "6", "7", "8","9" , "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22" ] }

Any help will be much appreciated.

I think I got it. Here's what I did:

{% for entry in items|batch(10) %}

    {% for batch in entry[0:3] %}
        {% if loop.index == 1 %}

{{batch}}

        {% elseif loop.index == 2 %}

{{batch}}

        {% elseif loop.index == 3 %}

{{batch}}

        {% endif %}
    {% endfor %}

    {% for batch in entry[3:2] %}
      {% if loop.index == 1 %}

{{batch}}

      {% elseif loop.index == 2 %}

{{batch}}

      {% endif %}
    {% endfor %}

    {% for batch in entry[5:3] %}
      {% if loop.index == 1 %}

{{batch}}

      {% elseif loop.index == 2 %}

{{batch}}

      {% elseif loop.index == 3 %}

{{batch}}

      {% endif %}
    {% endfor %}

    {% for batch in entry[8:2] %}
      {% if loop.index == 1 %}

{{batch}}

      {% elseif loop.index == 2 %}

{{batch}}

      {% endif %}
    {% endfor %}

{% endfor %}


Getting redirected to login page on every other CP request when using Vagrant I'm developing on a Virtual Box on a Mac, and every time I log into the CP, I can log in successfully and click on one (maybe two) links before getting redirected to login again. I tested this on a staging server and it's working, but not in vagrant. However, I can get other things like Wordpress to allow me to login fine on the Vagrant box, so it seems to be some combination of Craft + Vagrant issue.

Any thoughts on where I might look to debug?

Note: I understand this is probably a vagrant issue, but curious if I can get any pointers of where to start looking inside of craft to find the potential problem/incompatibility.

I kind of doubt this is it, but Craft does have a couple of config settings that might be coming into play here.

You can tell if you're being affected by these by looking in your craft/storage/runtime/logs files and see if there are any messages being logged with a [warning] related to not being able to restore session.

If you are being affected by those, try setting both of them to false just to see if that helps.


Is there a way to detect if a action is triggered from a control panel form? We're building a content platform for a bank for a client of us. One required feature lets relationship managers add clients (members) to the platform which get assigned a specific group.

We listen to the users.onSaveUser event and when the specific group is chosen and the user gets added via the CP there should be sent out a specific email to that client. This is the code I have so far:

public function initRmAddsClient()
{
    craft()->on('users.onSaveUser', function(Event $event) {

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

        if ($event->params['isNewUser'])
        {
            //get new user group from form post
            $groups = craft()->request->getPost('groups');
            if ($groups)
            {
                if (count($groups) > 0)
                {
                    $userGroup = craft()->userGroups->getGroupById($groups[0]);

                    if ($userGroup->handle == 'premium' || $userGroup->handle == 'private')
                    {
                        craft()->email->sendEmailByKey($user, 'rm_adds_client', array(
                            'user' => $user,
                            'link' => TemplateHelper::getRaw(craft()->users->getPasswordResetUrl($user)),
                            'rm' => craft()->userSession->getUser(),
                        ));
                    }
                }

            }
        }
    });
}

I just want to add one extra check if the submission is done via the control panel since public registration is enabled as well.

Is there an easy check for that?
Thanks

If anyone comes here looking for this answer for Craft 3 the function you are looking for is Craft::$app->getRequest()->getIsCpRequest()


No craft_users table in Database Good Afternoon.

Im trying to recover admin login information for a website I have recently taken on, however there is no craft_users table within the database.  Any help to locate the user info would be greatly appreciated.

There are so many tables that phpMyAdmin paginates them. All the tables that came after craft_tags alphabetically are on the second page, making it look like there is no craft_users table. Pagination controls are at the top:

Reason I know? I just made the same mistake.


Filtering on related entries (with an array query param) I'm getting myself into a potential pickle here and wanting to know the best way to get apply filters on the current scenario:

I have a central business section which is getting populated via an API (just a little background info) and I have a second section drugs which has a Entries field that contains a link to business.

I've designed a table that pulls in all this info that looks a little something like this:

I've built out the table like this:

{# DEFAULTS #}
{% set queryParams = {
    section: 'business',
    order: 'title asc',
    limit: 30
} %}
{% for entry in craft.entries(queryParams) %}

{{entry.title}} {{entry.business_name}}

        {{entry.business_price}}
        {% if "+" in entry.business_change %}
            {{entry.business_change}} {{entry.business_percentChange}}
        {% else %}
            {{entry.business_change}} {{entry.business_percentChange}}
        {% endif %}

${{entry.business_market_cap}}

{{entry.business_number_of_shares|number}}

{{entry.business_shortRatio}}

{{entry.dateUpdated}}

                    Drug
                    Indication
                    Stage
                    News

            {% set relatedDrugs = craft.entries.section('drug').relatedTo(entry) %}
            {% for drug in relatedDrugs %}

                {{ drug.title }}
                {{ drug.drug_indication}}
                {{ drug.drug_stage.label}}
                {{ drug.drug_note}}

            {% endfor %}

{% endfor %}

Now – the pickle is the filtering side of things: I'm wanting to filter on the drug stage, AND to make matters even more exciting this is a multi-select filter which I've done like this:

<fieldset>
    <legend>Stage</legend>
    {% set stage = craft.fields.getFieldByHandle('drug_stage') %}
    {% for stage in stage.settings.options %}
        {% if loop.first %}<select name="stage[]" multiple>{% endif %}
          <option value="{{stage.value}}">{{stage.label}}</option>
        {% if loop.last %}</select>{% endif %}
    {% endfor %}
</fieldset>

I'm not really sure how to enable multiple params of the same name so I've called it stage[] which handily returns an array. The problem I'm having now is building that new param filter query... I got as far as this and stared blankly at the screen for 10 minutes (I'm no programmer...)

{% set stage = craft.request.getParam('stage') %}
{% if stage is not empty %}
    {# NO IDEA #}
{% endif %}

I really have no idea where to start. Any pointers or help would be fantastic!

This should take care of it:

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

{# check if stage is an array #}
{% if stage is iterable %}

    {% for stageItem in stage %}

        {# make sure stageItem has content #}
        {% if stageItem is not empty %}

            {{ stageItem }}
            {# would output the selected stage.value #}

        {% endif %}

    {% endfor %}

{% endif %}


Google Map setup for markers I'm getting started with the Google Maps plugin. I have experience with the EE version but not understanding some of the Craft version. I'm trying to output a set of markers from entries. Currently nothing outputs at all.

I imported all the addresses and then added a GoogleMap field to the entries. When I check the entries it all looks correct.

I have:

{% set options = {
    id: 'map',
    width: '950px',
    height: '500px',
} %}

{{ craft.googleMaps.map(options) }}
{% for entry in craft.entries.section('maps').limit(10) %}

    {{ craft.googleMaps.data('map', entry.mapData) }}

{% endfor %}

I also tried this for the markers:

{% for entry in craft.entries.section('maps').limit(100).find() %}
    <!-- {{ entry.title }} -->
    {% set marker = {
        address: '{{ entry.mapData }}',
        content: '{{ entry.title }}',
        clustering: true
    } %}
    {{ craft.googleMaps.marker('map', marker) }}

{% endfor %}

Your first example essentially looks correct — and I don't know if it makes a difference, but the syntax that I have used in the past looks something like this, where I output the map after setting the data.

{% set options = {
    id: 'map',
    width: '950px',
    height: '500px',
} %}

{% set map = craft.googleMaps.map(options) %}

{% for entry in craft.entries.section('maps').limit(10) %}
    {{ craft.googleMaps.data('map', entry.mapData) }}
{% endfor %}

<div class="map">
    {{ map }}
</div>


How to get the hash/anchor in the URL? I am using an entry's slug as the anchor for a page.

How do I grab the anchor from the request?
For example I want to get #article-one from /blog/#article-one

If it's not possible, is there a way to grab the full URI /blog/#article-one including the hash?

It depends on what you mean by "get" the hash anchor, but I'm assuming you're trying to get it in either PHP, Twig, or JavaScript.

It is physically impossible to get the #anchor part via PHP, since PHP never has access to that information. This SO thread describes the issue.

If you're trying to access the #anchor in Twig, you're probably out of luck there too. Twig is just a PHP parser, so you've essentially got the same problem.

All you can do is access it via JavaScript. In which case, there is nothing Craft-specific about it (see linked SO thread).


Use same handle for different fields on different entry types I've got two entry types: blog and job. Each has a category field but different category groups: blogCategories and jobCategories. I would like to write a Twig include to accept either a blog or a job and display its categories like:

{{ entry.title }}

{{ entry.category.all()|column('title')|join(', ') }}

Is there any way to do this? I tried creating two fields, both called categories but the field handle has to be unique. Is there such a thing as a field alias?

You need two different fields since you can only select one category group per category field. As you said, having two fields with the same name isn't possible. One way to work around this would be to add a behaviour that checks the entry type and returns the categories from the corresponding field (i.e. jobCategories for job entries and blogCategories for blog entries).
However, this is more complicated than it needs to be. You can just define a macro and pass it the appropriate field depending on the template:
{# macros/macros.twig #}
{% macro category_list(categoryQuery) %}

{{ categoryQuery.all()|column('title')|join(', ') }}

{% endmacro %}

{# blog/_entry.twig #}
{% from "macros/macros.twig" import category_list %}

{{ entry.title }}

{{ category_list(entry.blogCategories) }}

{# job/_entry.twig #}
{% from "macros/macros.twig" import category_list %}

{{ entry.title }}

{{ category_list(entry.jobCategories) }}

If you have a single entry template for both entry types, you can also check the different fields inside the macro:
{# macros/macros.twig #}
{% macro category_list(entry) %}
    {% switch entry.type.handle %}
        {% case "job" %}
            {% set categories = entry.jobCategories.all() %}
        {% case "blog" %}
            {% set categories = entry.blogCategories.all() %}
        {% default %}
            {% set categories = [] %}
    {% endswitch %}

{{ categories|column('title')|join(', ') }}

{% endmacro %}

{# entry/_entry.twig #}
{% from "macros/macros.twig" import category_list %}

{{ entry.title }}

{{ category_list(entry) }}


Complex Conditionals with ElementCriteriaModel / Element API Working with the Element API for the first time and I'm having a bit of a hard time finding any kind of documentation regarding writing more complex conditionals using the ElementCriteriaModel.

What I'm trying to accomplish, is selecting all entries (they are events with a start/end date as custom fields) from a given section, which overlap in any way with a passed-in query start/end date.

It is probably easier to simply supply the raw query that works, and perhaps someone could point me in the direction of documentation that could help me.

SELECT *
FROM craft_content
WHERE
! ( field_eventStartDate > @queryStartDate AND field_eventStartDate > @queryEndDate)
AND
! ( field_eventEndDate < @queryStartDate AND field_eventEndDate < @queryEndDate )

After doing a bit more digging, I think the only real option here is run a preliminary query to pull out the ids of the elements I want and then pass that into the ElementCriteriaModel. It's not ideal, but it'll do.


What's the right way to create a simple blog in Craft? Should I create a Single for the blog home page content (/blog) and then a Channel to hold the entries (/blog/{slug})?

The blog index page also needs to have non blog entries on, i.e. intro text describing what the blog is about.

A Channel called Blog as follows:

Entry URL Format: blog/{slug}
Entry Template: blog/_entry

In blog/_entry.html:

{% extends "_layout" %}
{% set title = "{{ entry.title }}" %}

{% block content %}

{{ entry.title }}

        {{ entry.body }}

Written by {{ entry.author }} on {{ entry.postDate|date('M d, Y') }}

{% endblock %}

You don't need to create a Single for the Blog index page.

You can just create a template file: blog/index.html with:

{% extends "_layout" %}
{% set title = "Blog" %}

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

{{ entry.title }}

            {{ entry.body }}

Written by {{ entry.author }} on {{ entry.postDate|date('M d, Y') }}

    {% endfor %}
{% endblock %}

EDIT:

If it is a requirement for end users to be able to publish and edit content, other than blog entries, appearing on Blog index page via the CP, then a Single is the way to go.

Create custom field(s).
Create Single called Blog Index, or Blog Homepage, or something other than Blog.
Add custom field(s) to Blog Single entry type.
Entry Template: blog/index

In blog/index.html:

{% extends "_layout" %}
{% set title = "Blog" %}

{% block content %}
    {{ entry.customField }}

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

{{ entry.title }}

            {{ entry.body }}

Written by {{ entry.author }} on {{ entry.postDate|date('M d, Y') }}

    {% endfor %}
{% endblock %}


Setting Date from URL I have a template, /calendar, which outputs a list of all entries from the events channel. If a user clicks a link for "July 2015", I want the same template to load showing only the events for July 2015. I can fetch the entries for a given month with something like this.

{% set setMonth = '2015-07' %}

{% set firstDay, lastDay
   =
   setMonth ~ '-01',
   setMonth ~ '-' ~ setMonth|date('t')
%}
{% set after, before
   =
   firstDay|date_modify('-1 day')|date('Y-m'),
   lastDay|date_modify('+1 day')|date('Y-m')
%}

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

I want to pass the date that will be assigned to setMonth in the URL using something like /calendar/2015-07, but I currently get a 404 error.

How can I pass the date in the URL without throwing a 404?

To make it even more complex, this template can also be filtered by category, so there would also be times the URL would look something like /calendar/catslug/2015-07. In this case, the template should display only the July events from the catslug category.

Assuming I can conquer the aforementioned 404 problem, will Craft still recognize /calendar/catslug/2015-07 as a category-triggering URL, or will the addition of the date segment break that functionality?

I suspect this isn't as difficult as I'm making it, so any assistance is appreciated.

Thanks in advance.

As mentioned in the comments, using a dynamic route is good method to create a date based uri (i.e. 'calendar/[year]-[month]'). See this answer for an example.

Adding 'category' into the route is a little more difficult, since there is no 'category' tag built into the dynamic route settings. However, you can use the wildcard * as part of the route for what would be the category (or anything else for that matter) — and then retrieve it using craft.request.segment method.

Dynamic route (which points to your 'calendar' template)

calendar/[*]/[year]-[month]

(note: using calendar/[slug]/[year]-[month] might also resolve to a category entry — don't know, but worth a try.)

Calendar template

{% set categorySlug = craft.request.segment(2) %}
{% set category = craft.category.slug(categorySlug).first %}
{% if year is defined and month is defined %}
    {% set startMonth = year ~ '-' ~ month ~ '-' ~ 1 %}
{% else %}
    {% set startMonth = now|date_modify("first day of this month") %}
{% endif %}
{% set nextMonth = startMonth|date_modify('+1 month')) %}
{% set previousMonth = startMonth|date_modify('-1 month')) %}

{% set entries = craft.entries.section('calendar').postDate('and', '>= ' ~ startMonth, '< ' ~ nextMonth).relatedTo(category) %}

{% for entry in entries %}
    {{ entry.title }}
    ...
{% endfor %}

    next month
    previous month

Advanced route method

If you want to be more specific in your route, then you can also set up an advanced route using named sub-patterns, which you can add to craft/config/routes.php, that will provide named variables to your template for 'category', 'year' and 'month'. Something like,

'calendar/(?P<category>\w+)/(?P<year>\d{4})/(?P<month>\d{2})' => 'calendar/_index',


How can I create list of a group’s fields for a select field’s options in my Field Settings? I’m trying to create a plugin that relies on the values of a Matrix field in the same entry. Knowing that a single entry type could have more than 1 Matrix field, I think I need a way to select which Matrix field to pull from in my field settings. Any thoughts?

Your plugin will need a few things.

A FieldType
FieldType Settings using defineSettings() and getSettingsHtml() method
A template that will render your settings which will be referenced in the craft()->templates->render function of the getSettingsHtml() method

On the settings template, I believe you will need two dropdowns.  The first, will just be a dropdown of available Sections.  Upon selecting the section, you would update the second Dropdown to have a list of the Matrix fields within that section, or a message saying that no Matrix fields we're available.  Or perhaps, you can just sort out which Sections have Matrix fields to start off with, and only display those Sections in the dropdown.

I'm not sure if there is a more efficient way to just grab Matrix fields, but here are some functions that may help you get to what you need:

Get all available Sections

$sections = craft()->sections->getAllSections()

Get a specific section by ID

$section = craft()->sections->getSectionById(1);

Get the FieldLayoutFieldModels attached to a Section (Note Fields are not related to the Section directly, they are related to a FieldLayout, which is related to an EntryType, which is related to your Section).  In the example below, I have assumed you are grabbing the first EntryType using getEntryTypes()[0] however in your code, you'll likely have to do a bit more logic to make sure you're getting what you want:

$fields = $section->getEntryTypes()[0]->getFieldLayout()->getFields();

Once you have the FieldLayoutFieldModels, you can access each FieldModel using the getField() method and check which type of field type it is:

foreach ($fields as $field)
{
  $field = $field->getField();

  if ($field->type == 'Matrix')
  {
    // Build an array of the options for your Matrix fields dropdown
  }
}

Once you build an array of your options, you can hand them off to your fields settings template in the getSettingsHtml() method and loop through and output them in your template file.  The doc pages referenced at the beginning of this post go over that in more detail.

return craft()->templates->render('yourplugin/_fields/settings', array(
    'settings' => $this->getSettings(),
    'matrixFieldOptions' => $matrixFieldOptions
));


doublesecretagency business logic module template: 404 on example form action I set up the business logic module template following these instructions:
https://doublesecretagency.github.io/craft-businesslogic/installation

The test works out well, so everything seems to be in order.

However, when I add the example action to a form and submit it, I get a 404:

Unable to resolve the request "business-logic/example/example-form-submit".

How do I find and fix the underlying issue?

EDIT: I tried setting up a module via https://pluginfactory.io/ and that works like a charm.

Did you remember to add the action as a hidden input (<input type="hidden" name="action" value="business-logic/example/example-form-submit">, rather than an action attribute on the form? And also use method="post" on the form.


Multi environment-lite Morning folks. First time doing multi-environment in Craft 3, and separate installations for staging and production is a bit overkill for this particular project. Instead I just want to show a few new bits in templates on the staging subdomain until sign-off.

Staging domain (https://staging.adddress.com) is pointed at the production 'public' directory. So in Craft 2, I'd just let the 'staging' key in my config.php set all the necessary environment variables. But in Craft 3 don't I need to load the correct .env first? Since it's all the same installation, is there a way to switch to .env.staging when on the staging subdomain? Is that the correct/best approach? Thanks.

Alright, so turns out all I need to do is comment out the following line in index.php:

define('CRAFT_ENVIRONMENT', getenv('ENVIRONMENT') ?: 'production');

Now I can use config.php keys, same way I did in Craft 2. For example:

'*' => [
    // My default/production variables
    'devMode' => false,
    etc...
],
// Local
'address.test' => [
    // Local variables
    'devMode' => true,
    etc...
]
// Staging
'staging.address.com' => [
    // Staging variables
    'devMode' => true,
    etc...
]

Thanks to Luke James for the assist on Slack.


Manual crop in Image Transforms I would like to manually crop the image transforms for an uploaded image.

I know there are crop plugins for Craft (image-resizer, AviaryImageEditor), but these plugins crop the original image and not the image transforms..

I'm looking for something very similar to the manual crop module in Drupal.

So you can upload one image, afterwards you manually crop the different image styles / image transforms..

Any suggestions?

I don't know a plugin like this for Craft. But this solution does a similar thing. Maybee it works for you: Let clients set crop position for images.
Otherwise you could also take a look on the focuspoint plugin: https://github.com/smcyr/Craft-FocusPoint


How to redirect from plugin? My plugin init function:

function init(){

    craft()->entries->onSaveEntry = function(Event $event) {

        //redirect to wanted url

    };

}

Is there a fancy way to redirect to my plugin url if, for example the entry channel is jobs.

Or I have to use header() function. Thank you in advance.

You can use the HttpRequestService:

craft()->request->redirect($myAwesomeUrl);


Channel URL Format leads to 404s for individual entries I've broken my news channel but I don't know how I did it, or consequently to fix it.

If one clicks on 'I just installed Craft' or 'Continue reading', it will take you to the URL I specified in the Section settings using the Craft control panel, but it results in a 404.

It didn't do this at first, then (I think this is when it broke) I changed the entry URL format from news/{postDate.year}/{postDate.month}/{slug} to just {postDate.year}/{postDate.month}/{slug}. After I got the 404s assumed I couldn't do that so I changed it back, but it's still broken.

I'm quite new to this kind of thing so I apologise if I'm wasting anyone's time. Any help would be much appreciated. Thanks.

It turned out that when I deleted news/ from the entry URL format, I also deleted it from the entry template path as well because I misunderstood what that field was for (and forgot to revert that change when everything broke).

Thanks to @Brad for drawing my attention to it.


Fire event first time future dated entry goes 'live' from 'pending' Is there a way I can run some code from a plugin when a future dated entry goes 'live' from 'pending'? I am trying to send an email update that a new entry has been posted. The related post below helped me with this, but it doesn't seem to cover future dated entries.

Here's what I have so far...

craft()->on('entries.onBeforeSaveEntry', function(Event $event) {
    $entry = $event->params['entry'];

    if ($entry->section->handle !== 'blog') {
        return;
    }
    if ($entry->status !== 'live') {
        return;
    }

    if (!$entry->getContent()->emailSent) {
        // send email
    }

    $entry->setContentFromPost(array('emailSent' => true));
});

Related to: Checking for first time an entry is "published" i.e. saved with a Live status

Thanks!

I've created a plugin called Published Event does exactly what Brad suggests in his answer. It fires off an event when a entry moves from pending to live.


Variable doesn't exist I get "Variable career does not exist". I'll just go straight to the code example...

{# Set ECM and get the entries stored in variable "entries" #}
{% set entries = craft.entries.getAllSections('and, not career').type('news').order('RAND()').limit(3) %}

{# Conditional statement - if more entries than 0, we output them. If false, we set other conditional statement/s. #}
{% if entries|length > 0 %}

    {# Loop through entries #}
    {% for entry in entries %}

            {# My Stuff #}

    {% endfor %}

    {# Set ECM and get the entries stored in variable "career" #}
    {% set career = craft.entries.section('career').type('news') %}

{% elseif career %}

    {# Loop through career #}
    {% for career in career %}

            {# My Stuff #}

    {% endfor %}

{% endif %}

Is it because of the first variable entries?

The problem is that you are setting career inside of the if statement. Defining it there won't make it available for your elseif statement.

I've trimmed down your code so you can see exactly what the problem is:

{% set entries = ... %}

{% if entries|length > 0 %}

    {% set career = ... %}

{% elseif career %}

    ...

{% endif %}

If you want career to be available to your elseif statement, you need to define it before your if statement.


Query Craft CMS Table Field for exact values Am I correct in saying you cannot search for specific text in a table field. e.g.

Table Fields Might hold the following data:

SKU1
SKU2
SKU3
SKU33

I then want to search for items that only return SKU3 not SKU33.

body::salty search will not work because i believe the field is stored as JSON.

Yeah because the data is stored as a JSON blob, I'm not sure this is going to be possible without retrieving all the data, parsing the JSON, then doing the exact match search via PHP, and then returning the results subset.


How to set a response 200 from a plugin? I’ve tried HeaderHelper::setHeader(array('code' => 200)) without success.

See here for various methods of setting the response code depending on what version of PHP and which PHP module you're running.


Import plugin error logs I'm using the import plugin from Bob Olde Hampsink and I've got a exported .csv file. There's nothing special in it but I can't seem to import. I know there's an error log somewhere, but I can't seem to find it. Does anyone know where it's situated? I've found it once but now I'm totally lost and can't seem to find an answer somewhere...

Thanks!

In Craft 2 the log files are usually stored in craft/storage/runtime/logs/ and named after the plugin handle.

If the Import plugin does nothing special, you should find its logs in craft/storage/runtime/logs/import.log


sessions being read inconsistently I've got a navigation bar that displays different links for logged in users using {% if currentUser %}. However, when clicking through links, sometimes it won't pick up that someone is logged in.

The same issue crops up occasionally with "denied permissions" error pages. Again, reloading the page will pick up the user session and display the template normally.

It's inconsistent which pages (and servers) it happens on. I'm not using any {% cache %} tags in the twig templates either.

Is there a cp setting or config/general.php option I'm missing?

Edit: Looks like the autogenerated appId based on filepath must have been the issue.

The site was on amazon AWS (without load balancing), so I set an appId in the config/general.php file to keep the session "sticky", even if the filepaths were "inconsistent" on a single server instance. The autogenerated appId based on filepath must have been interacting weird with Amazon's cloud setup.

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


Adding custom validation to core fields I've been looking at http://straightupcraft.com/articles/the-definitive-guide-to-validation-in-craft which seems to concentrate on custom models. However I am looking to validate data posted to a plugin that stores that data as core EntryModels.

So let's say you create a Section and assign some Fields in its field layout. You can set each Field to be required but I want to do more than that and check if it's an integer or if it's unique.

I am currently doing that in my service class:

private function validateReference()
{
    $reference = craft()->request->getPost('reference');

    $existingEntryCount = craft()->elements->getCriteria(ElementType::Entry)->total(array(
        'reference' => $reference
    ));

    return ($existingEntryCount === 0);
}

That all works but I am wondering if instead I should be setting the validation properties of each Field in this service and then just running a core validate method?

Your best bet is going to be to write your own field type for this. You can extend one of the built-in field types if you want.

You would put your custom validation logic in your field type’s validate() method.


Setting up redirects from routes.php I have a "/5minutes" url in routes.php and people keep typing in "fiveminutes". Is there a way to call a 301 redirect directly in routes.php or would I need to set up an action in my plugin (or alternatively mess with server settings)?

I'd try and avoid the routes.php route (pun intended).  There isn't any need to get Craft involved in a redirect when your web server (Apache?) can handle it much faster.

If you're using Apache, then adding something like this to your public .htaccess file should do the trick:

RewriteRule ^fiveminutes$ /5minutes [NC,R=301,L]

Update:

Missed the part where you said this was in a plugin.  In that case you'd want to setup something like this in your main plugin's class file:

public function registerCpRoutes()
{
    return array(
        'fiveminutes' => array('action' => 'myPluginController/fiveMinuteRedirect'),
   );
}

Then from your MyPluginController.php class have an actionFiveMinuteRedirect() method that simply did a permanent redirect:

`$this->redirect('5minutes', true, 301);`


Associating related entries to a new entry when using the API This may just be a 5PM Friday issue, but I'm scratching my head over here. I'm trying to associate a string of related entry id's represented by a variable with a new entry via the API. When I pass the variable, only the first one gets inserted into the DB. If I use the string they all get inserted. Here's the insert code:

 $article_countries = "1021,1047,1076,1123";

 $entry->getContent()->setAttributes(array(
   'article_countries' => array(
     $articleCountries
    )
 ));

Why is the string working where the variable isn't?

I dont think you can build arrays in PHP that way and you end up passing array(0 => '1021,1047,1076,1123') to the param.

Not shure if passing the string is supported:

'article_countries' => $article_countries

If not you could build the array like so:

'article_countries' => array_map('trim', explode(',', $article_countries))


How to do multi-day events in Solspace Calendar? If I'm adding events for course that is run Wed 8-5, Thurs 8-5, and Fri 8-12, how would I do that? It's not technically a recurring event, I don't think, but at the same time, it's not individual instances either. This event (or course) runs multiple times a year, to complicate things a bit more.

Has anyone done anything similar?

The only way to handle this would be to create 2 (or 3) separate events. The limitation here is the start and end times not being the same for all 3. If they were all the same, you could have done it as an individual event.

The first two are the same time, so those could be paired together, but the Friday one would have to be separate. :)


Hide users without profile pics I'm working on a site that has logins for members, but I'd like to have a page that shows all members with a name and picture.
To do this, we had to import an existing database that doesn't have a lot of profile pics. Now I want to hide all users that have no picture uploaded.

This is the code I'm trying, but with no luck...

{% if geslacht_param_string !=''  %}

{% set queryParams = {
    search: {
        query: geslacht_param_string,
        attribute: 'geslacht'
    },
    geboortedatum : dateRange,
    order :'lastName',
    photo : ':notempty:'
} %}

{% else %}
    {% set queryParams = {
        geboortedatum : dateRange,
        order :'lastName',
        photo : ":notempty:"
    } %}
{% endif %}

{% set leden = craft.users(queryParams) %}

I can't find the decent syntax for :notempty:, can anyone help me out here? Thanks a lot!

There's no photo attribute on the UserElementType, so you can't query by it like you're trying.

Completely untested, but you can probably work around that with something like this:

{% if geslacht_param_string !=''  %}

{% set queryParams = {
    search: {
        query: geslacht_param_string,
        attribute: 'geslacht'
    },
    geboortedatum : dateRange,
    order :'lastName',
} %}

{% else %}
    {% set queryParams = {
        geboortedatum : dateRange,
        order :'lastName',
    } %}
{% endif %}

{% set allUsers = craft.users(queryParams).find() %}

{% set usersWithPhotos = [] %}

{% for user in allUsers %}
    {% if user.photo %}
        {% set usersWithPhotos = usersWithPhotos|merge([user]) %}
    {% endif %}
{% endfor %}

There are {{ usersWithPhotos|length }} users with photos.


Programatically setting dropdown options in a matrix I'm building a Matrix field from within a module's migration.
I can get all fields setup correctly except the options of either a Dropdown or Checkboxes field.
$field = new \craft\fields\Matrix([
    'groupId' => 1,
    'name' => $fieldSettings['name'],
    'handle' => $fieldSettings['handle']
])

$blocks = [
    'new1' => [
        'name' => 'Heading',
        'handle' => 'heading',
        'fields' => [
            'new1' => [
                'type' => \craft\fields\Dropdown::class,
                'name' => 'Heading',
                'handle' => 'pageContentHeading',
                'options' => [
                     ['label' => 'H1', 'value' => 'h1', 'default' => 1],
                     ['label' => 'H2', 'value' => 'h2', 'default' => ''],
                     ['label' => 'H3', 'value' => 'h3', 'default' => '']
                 ]
             ]
         ]
     ]
]

$field->setBlockTypes($blocks);

try {
    Craft::$app->getFields()->saveField($field);
} catch (\Throwable $e) {
    echo $e->getMessage();
}

This creates the dropdown field, but doesn't set the options. Am I missing something obvious?

I figured it out! Field-specific options need to go inside 'typesettings'.
'typesettings' => [
    'options' => [
        ['label' => 'H1', 'value' => 'h1', 'default' => 1],
        ['label' => 'H2', 'value' => 'h2', 'default' => ''],
        ['label' => 'H3', 'value' => 'h3', 'default' => '']
    ]
]


Is it possible to execute a custom function on the entry crud methods? Is it possible to execute a custom function on the entry crud methods? Basically what I want to achieve is that a CP user with certain field value cannot read or save an entry that doesn't have the same field value. (in this case company) Are there any hooks/events available on that level? On group permission level I just want all permissions set to allow on that section.

Thanks in advance

You'd have to create a plugin but you could listen for the entries.saveEntry event that is noted here: http://buildwithcraft.com/docs/plugins/hooks-and-events

Then lookup the value, run validation and even return a custom error message if things were not saved correctly.

Hope this helps.


Force craft to do another job (queue) and pause the current one I'm currently working on a plug-in for Craft. I have to work with a lot of data and, some steps are slow. So that's why I added them to a job system. This job is doing a lot of stuff.
That job is blocking the other jobs that are also important. Is there a way to push a new job to the top of the list and start it directly in Craft 3?
I tried to priority tasks (https://craftcms.com/docs/3.x/extend/queue-jobs.html#specifying-priority) and, it didn't work.

The priority option is for setting the jobs in priority order before they start. A job that is already running will not be interrupted for a more important one.
I would suggest setting up another queue for the longer tasks. That way, your smaller tasks can continue to run separate to the more demanding ones.
There is some guidance on how to do this on an issue here.


Anonymous access to controller action fails I have this controller, and I've set $allowAnonymous to true, but I'm still getting redirect to CP login:

class SitemapController extends BaseController
{
    protected $allowAnonymous = true;

    public function actionXml()
    {
        ...
        $this->renderTemplate('sitemap/list.xml', array(
            'entries' => $entries,
            'sections' => $enabledSections
        ));
    }

}

Is there anything I'm missing?

I think your URL is wrong.

Try /index.php/actions/sitemap/sitemap/xml

Here is the section of the docs that explains URLs for plugin controllers: http://buildwithcraft.com/docs/plugins/controllers#how-controller-actions-fit-into-routing


Where should I put custom CSS files? I am a little puzzled by the way craft handles CSS files. Although I am used to working with SCSS and CSS assets and setting up a reasonable directory structure, I was expecting a little documentation or a best practice recommendation.

At first, I tried to create an asset folder with all CSS files. But then I realized that they could not be uploaded because they were not in the allowedFileExtensions config array.

The plugin documentation contains some info about handling plugin-specific frontend resources but it does not say anything about the general CSS files.

The most helpful information I found so far was this answer although it did not really help me with my question.

What is the recommended way to handle CSS assets? What are your best practices for asset management and setting up a frontend workflow in Craft?

Best regards

In general, Craft doesn't normally come into the equation when we're talking about general frontend assets.

Things like minification, preprocessing of SASS/LESS/Coffescript/WHATEVER, image compression (asset images, not content images) etc. should preferably be handled by a tool like Grunt or Gulp (my favorite).

Even when it comes to CSS/JS for your plugins, you might want to do the actual build process with Gulp.

I usually have all source files in the project root, under a folder named src. In there, you have subfolders named js, scss, img, fonts etc.

If you're unfamiliar with for example Gulp, I might recommend you Mark Goodyear's article Getting started with Gulp.

On the Craft side, you could take a look at John D. Wells' awesome Minimee and Inlin.


How to troubleshoot routes Very new to Craft CMS...

My first route, which i think is very simple, is not working, i'm getting a 404 error.  How can I troubleshoot routing?

My settings:

If the URI looks like this:

databases/

Load this template:

library-database-demo-section/index.html

Remove the / at the end of databases/ and it should work.

Technically, index.html is not required either, so you could just use library-database-demo-section.


Multiple URL's for news entry? For news entries I want both URL's www.example.com/news/678 (where 678 stands for the entry id) and www.example.com/news/some-slug to load the same entry.

www.example.com/news/some-slug works fine because 'Entry URL Format' is used for this so the news entry contains a readable slug for SEO.

Is there a way to generate www.example.com/news/678 (with entry id) for the same entry, to display the same news entry? Is it possible to handle this with Dynamic Routing? Or generate multiple URL Formats?

Setup a dynamic route that points to the same template that you have set up in the section settings for your "slug URLs". Use a pattern like so: news/<id>, which passes the 2rd URL segment as a variable named id to the template.

Add this snippet to the top of your template.

{% if not entry and id %}
    {% set entry = craft.entries.id(id).first() %}
{% endif %}

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

If Craft finds a route for your entry slug (routing case 3), that code does nothing at all, because the entry model is already set.

When no route was found that matches an entry slug, your dynamic route comes into play (routing case 4), which routes the request to the same template.
But now there is no entry variable set and we can go ahead and try to grab it manually using the id variable passed in.

Update:
as already mentioned in the comments, don’t forget to setup canonical meta tags to avoid duplicate content penalties.

<link rel="canonical" href="{{ entry.getUrl() }}">


Macro for entry loop causing 'null' variable template error I am new to the concept of Twig templates and I can’t get it right from the documentation … What I am trying to achieve is to have a reusable Blogroll snippet that outputs entries in different contexts: ALL entries on the homepage and then according to the entry’s category in other areas of the site.

I created a file blogroll.html in templates/macros containing my blogroll code which works fine if used directly in a template (simplified the HTML here):

{% macro blogroll(entry) %}

{{ entry.title }}

{% endmacro %}

In my index.html for the homepage I try inserting it with this code:

{% for entry in craft.entries.section('blog').limit(15).find() %}
{% for entry in entries %}
  {% import "macros/blogroll" as blogroll %}
  {{ blogroll.blogroll }}
{% endfor %}

In my category related templates I filter for the category first and try to insert it this way:

{% set entries = craft.entries.relatedTo(category) %}
{% for entry in entries %}
  {% import "macros/blogroll" as blogroll %}
{{ blogroll.blogroll }}
{% endfor %}

In both cases I get a Impossible to access an attribute ("url") on a null variable. error though.

Any hints where I am not getting the concept right or screw something up while passing the variable?

Your blogroll can be treated as a PHP function. In order to use functions you have to pass the required parameters. In your case your blogroll expects the parameter entry

{{ blogroll.blogroll(entry) }}
or
{{ blogroll.blogroll(category) }}

will work


pagination showing all entries I have the following code for my news page. The links show up but I'm seeing all the entries on every page. I'm not sure if this is related to my featured entry at the top.

{% extends "_layout" %}
{% set title = "News" %}
{% paginate craft.entries.section('news').limit(5) as pageInfo, pageEntries %}
{% block content %}

Company News

{% for featuredEntry in craft.entries.section('news').featured('1') %}

                {% for image in featuredEntry.featuredImage %}

                {% endfor %}

{{ featuredEntry.title }}

                {{ featuredEntry.body.getPage(1) }}
                Continue reading

{% endfor %}
{% for regularEntries in craft.entries.section('news').featured('not 1') %}

{{ regularEntries.title }}

            {{ regularEntries.body|hacksaw(words='25', allow='
') }}
            Continue reading

{% endfor %}

{% if pageInfo.prevUrl %}Previous Page{% endif %}
{% if pageInfo.nextUrl %}Next Page{% endif %}

{% endblock %}

When you use {% paginate %}, the second variable that's returned, pageEntries, is  the paginated entries. When you do craft.entries.section('news').featured('not 1') later in the template, you're doing a new query that's not paginated.

Assuming what you want is to return all featured entries at the top, then a paginated list of news below, try something like this:

{% extends "_layout" %}
{% set title = "News" %}

{% paginate craft.entries.section('news').featured('not 1').limit(5) as pageInfo, pageEntries %}

{% block content %}

Company News

        {% for featuredEntry in craft.entries.section('news').featured('1') %}

                    {% for image in featuredEntry.featuredImage %}

                    {% endfor %}

{{ featuredEntry.title }}

                    {{ featuredEntry.body.getPage(1) }}
                    Continue reading

        {% endfor %}

        {% for regularEntry in pageEntries %}

{{ regularEntry.title }}

                    {{ regularEntry.body|hacksaw(words='25', allow='
') }}
                    Continue reading

        {% endfor %}

        {% if pageInfo.prevUrl %}Previous Page{% endif %}
        {% if pageInfo.nextUrl %}Next Page{% endif %}

{% endblock %}

If additionally, you only want to show the featured entry on the first page, you could wrap the first for loop in:

{% if pageInfo.currentPage == 1 %}
    ...
{% endif %}

More details on pagination in the docs.


Globals versus Singles We are building a restaurant site that has a banner image and some introductory text on each page.  For pages that include content from a Channel, e.g. the wine list, we are using a Global to define the header image and the intro text, and then a "for loop" for the wine entries.

Are there any performance benefits to using a global versus a single?  Any other pros and cons related to those choices?

The performance aspect is difficult to answer. On every pageload, Craft pulls all your global sets, which can be a performance hit, especially if you have many huge, complex global sets with a lot of fields. Any Single used in place of a global could be pulled on a need-to-use basis, i.e. not on every page, although the extra call to the EntriesService would also come at a price. In any case, I wouldn't really worry too much about it one way or another.

As for other pros and cons – in my opinion, the pros would mainly be related to usability for your content editors.

Some people may find it easier to work with Singles because they live inside the Entries section of the CP, i.e. together with the bulk of the site's content. This is especially relevant if the global content in question is only displayed on certain pages, e.g. a tagline which is used in the homepage's header – in which case most content editors would look at the homepage single before anywhere else, I reckon.

The Expanded Singles plugin even lets you list your singles in the left sidebar, making it even easier for your editors to find them.

The most obvious con to using singles over globals would the fact that you would have to write Twig to pull the appropriate Single anytime you needed its data, whereas any global set will always be available everywhere – i.e. writing {{ settings.tagline }} is way simpler than {{ craft.entries.section('mySettingsSingle')|length ? craft.entries.section('mySettingsSingle').first.tagline }} or the like – unless, of course, you add the Single(s) to the global Twig context or implement a template variable, but that would require writing a custom plugin.

Also, there's no way to turn off URLs for singles – so any single you create in place of a global, you're going to have a "stray" URL in your system. Not a huge issue, but still.

Personally, I believe that opting for a Global Set is generally the Right Thing To Do if the content doesn't really have a place in any existing Single – rather than creating what is essentially "bucket" or container Singles to accommodate it. If your content editors find Globals hard to use/find, consider using the CP Nav plugin to rename the "Globals" tab in the CP to something a little less technical – e.g. "Settings" or "Misc. content". Using CP Nav, you can even add tabs for specific Global Sets, with your own titles – in your case I'd consider creating a set called "Listing settings", adding the fields for the header image and introductory text to that set, and finally creating a tab in CP Nav called "Listings" or the like (or even "Wine Listing" if you want to get really specific), pointing to that particular Global Set. Personally, I think Globals – if done right – is actually better for usability than Singles pretending to be something they're not.


createUrl adding p=actions Writing a plugin and creating some links. Trying to use:

$url = craft::$app->urlManager->createUrl(['', 'state' => 'KS']);

to create a URL. I am expecting:

  http://test.com/index.php?state=KS

but get:

  http://test.com/index.php?p=actions&state=KS

That results in the following error:

  HTTP 404 – Not Found – yii\web\NotFoundHttpException
  Template not found: actions

What is the p=actions that is being added to the url? I am a bit confused by this.

craft::$app->urlManager->createUrl will always return an action url because in the end this function does return UrlHelper::actionUrl($route, $params);

You want to create a basic site url so you need to do

UrlHelper::url('', ['state' => 'KR'] )


How to modify entry with a users field in the front-end? Is it possible to modify an field of an entry within the front-end? Something like this with an action URL:
add user to userfield of current entry

Sure... you'd just do it through whatever input tag you want using the name="fields[fieldHandle][]" syntax passing in the user's ID as the value.

There are examples of that here, under the "Relations" header:

https://straightupcraft.com/articles/craft-cms-field-guide-twig?view=input

You won't be able to do that should an anchor link GET request though... EntriesController::saveEntry() is explicitly checking for a POST request, so you'll want to do it though a proper form: https://craftcms.com/docs/templating/entry-form


Custom fonts with Printmaker I'm generating a PDF from a template using the Printmaker plugin.
My CSS is being picked up and rendered mostly correctly and
if the template is rendered to screen as HTML then the fonts work. However I can't get the fonts to work with the PDF generation.

Does anyone know what I need to do to get the font information embedded within the PDF?

Make sure your fonts are TTF.
If you're loading them by remote URL, make sure the isRemoteEnabled is set to true.
If you're changing weights, make sure to use the named weights in your CSS (normal, bold) rather than numeric weights.

(These are limitations of the underlying DOMPDF library, which is used in Printmaker 1.x. The next release of Printmaker, for Craft 3, uses a much nicer rendering engine, which will eliminate these limitations.)


Craft localisation caching error long time listener, first time caller.

I'm having some issues getting localisation setup on my homestead/vagrant craft 2 site. I'm running into issues, I believe, with the craft cache when I try to visit a localised url I have set up.

I've been following the guide here, but haven't been able to have any luck with it.

I am using the folder structure in my public folder as follows

    /public
      -index.php
      -.htaccess
      /es
        -index.php
        -.htaccess

My config/general.php file is like this,

    define('URI_SCHEME', (isset($_SERVER['HTTPS'] ) ) ? "https://" :
    "http://");
    define('SITE_URL',    URI_SCHEME.$_SERVER['SERVER_NAME']);
    define('BASEPATH',     realpath(dirname(__FILE__) . '/../'));

    return array(

    '*' => array(
      'appId' => 'app',
      'validationKey' => getenv('VALIDATION_KEY'),
      'devMode' => true,
      'backupDbOnUpdate' => false,
      'omitScriptNameInUrls' => true,

      'siteUrl' => array(
         'en' => 'http://example.test/',
         'es' => 'http://example.test/es/'
      ),
      'cacheMethod' => getenv('CACHE_METHOD'),

      'environmentVariables' => array(
        'basePath' => BASEPATH,
        'siteUrl'  => SITE_URL

      ),
     ),

    ),
    )

My public/es/index.php file is pointing to the correct craft folder and has a define(CRAFT_LOCALE, 'es'). I'm stuck as how to progress and any pointers or tips are very appreciated
Heres a screen shot of the actual error on example.test/es

My guess is this is the cause:

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

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


Entry Types Custom Slug The website I'm working on has different sections and each section different types of entries. I would like the types of entries to be shown in the URL. I have followed this tutorial to do so.

In a site example.com where we have:

A Section called: My Section
With Entry Types: Example Entry Type, Another Entry type.

Utilizing the model from the tutorial, we could structure the URL for My Section as follows:

/my-section/{type}/{slug}

Which would give us URLs like these:

example.com/my-section/exampleEntryType/new-entry-1
example.com/my-section/exampleEntryType/new-entry-2
example.com/my-section/anotherEntryType/new-entry-3
example.com/my-section/anotherEntryType/new-entry-4

Notice that the entry types are the only part of the URL camelCased. This is  because Entry Types can only be configured to have a Name, and a Handle; and handles can NOT have dashes. This interferes with keeping URLs consistent as the rest of the site uses dashes instead of spaces

The problem I am trying to solve is: how do we get the Entry Types to stay consistent with the rest of the site?

Does anyone have any suggestion on how to deal with this? Is this a problem that should be addressed in Craft? Should I be taking another approach for this?

I had considered using categories but the way the system is setup, entry types seem more appropriate.

You could just set your "Entry URL Format" to:

my-section/{type.name}/{slug}

Your entry type names couldn't be as clean when composing entries in the CP as you'd need to set them to something like "example-entry-type", but it would work.

Now for the really clean way:

Install the Low Regex for Craft plugin.

Set "Entry URL Format" to:

my-section/{type.handle|regex('/(^|[a-z])([A-Z])/e', 'strtolower(strlen("\\1") ? "\\1-\\2" : "\\2")',(type.handle))}/{slug}

This will convert the entry type handle from camelCase to all lowercase with dashes as word delimiters. Set the entry type handles to be like "exampleEntryType" and they will become "example-entry-type" when in a slug.


How to get query or param from URL and then use in Links? I'm trying to grab the query or param from an URL and then add it to an URL.

like products?price=15

How can I add the ?price=15 to a URL?

Like products/category?price=15?

Use craft.request.getQueryStringWithoutPath() like so:

products/category?{{craft.request.getQueryStringWithoutPath()}}

  Returns the query string, except for the p= param (which was probably added by your .htaccess redirect).

More complicated logic to avoid the ? when the query string is empty (one of several ways to do this):

{# queryString will include '?' if we have one, otherwise '' #}
{% set queryString = (craft.request.getQueryStringWithoutPath() ? '?'~craft.request.getQueryStringWithoutPath()) %}
products/category{{queryString}}


How to setup the Craft Commerce store both front and back end We've a requirement to setup Craft Commerce store as part of our testing, in this process we've gone through the documentation and found that we need to use HTML, CSS or JS code to complete the store setup.

Could anyone please help us how to setup the store?

You might need a web developer to install Craft and Craft Commerce 'locally' (on your computer), using a testing domain such at craftcommercedemo.dev

Using the '.dev' TLD will allow you to unlock Craft Pro and Craft Commerce so that you can see and test all of the CraftCMS + Commerce features.

Both Craft and Craft Commerce come with a set of template files, allowing you to interact with the site in the same way a regular visitor would (from the front end).

As a starting point, check out XAMPP (if you use a PC) or MAMP (if you use a Mac)

The above facilitates local Apache web server, plus MySQL database which will allow you to run Craft on your computer in the same way as you would on a real web server.

If you need a developer, check out this list of Craft Professionals...

Hope that helps


Getting the length of an audio asset? I'm trying to create a podcast feed with Craft, and I seem to have everything working... except I can't find out how to grab the length of an audio file dynamically. I can get the filesize in bytes, and if it's an image asset you can get width... but there doesn't seem to be a way to get the play-time for an audio file; which is needed for the <itunes:duration> tag.

Anyone know how to do this?

Craft doesn't come with a PHP library for audio, so there's no core solution for your problem.

But what you could do is to make a plugin, add such a library to it and provide duration and bitrate Twig filters to your templates.

EDIT:

You could try out my new "Asset Metadata" plugin. It makes use of the getID3 PHP library to extract all sort of metadata from your assets.

To make your life a bit easier, I added further beautified metadata properties like a sound file's playtime duration in ISO 8601 date interval format (i.e. PT1H21M48S), or a photo's exposure time as a ratio.


Output SuperTable fields from inside Matrix field Having looked at other answers I'm pretty sure I've got this correct but it's still not working for me.  I've stripped the code down to make it easier to read.

Error i'm getting is "Impossible to access an attribute ("packageName") on a string variable ("40")."  This error repeats for packageTitle, packageShortIntro etc if I delete the packageName line etc..

All other fields, 'block.body', 'block.subTitle' are coming through fine.

Also please note there is also a Table field within the SuperTable.

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

        {% case 'bodyText' %}
            {{ block.body }}

        {% case 'packages' %}
            <!-- Supertable -->
            {% for row in block.package %}
                {{ row.packageName }}
                {{ row.packageTitle }}
                {{ row.packageShortIntro }}

                {% for items in row.itemsAvailable %}
                    {{ items.item }}
                    {{ items.isAvailable }}
                {% endfor %}

                {{ row.packageCost }}
            {% endfor %}
            <!-- End Supertable -->

        {% case 'subTitle' %}
            {{ block.subTitle }}

    {% endswitch %}
{% endfor %}

Many thanks for looking and any advice you can offer.

Your Super Table field is probably configured as a static field.

Have a look at the documentation for how to access subfields in this case:  https://verbb.io/craft-plugins/super-table/docs/guides/templating-examples#static-super-table-field

So instead of the for-loop you’d have sth. like this: {{ block.package.packageName }}


How to order or filter entries by their author's custom field? Is it possible to order and/or filter all entries from a section whose author has a custom field value that is set to "X"?

Below is the starting code.

in Twig:

{% set elementQuery = craft.entries()
    .section('sectionHandle')
    .with(['author'])
%}

in PHP:

$elementQuery = Entry::find()
    ->section('sectionHandle')
    ->with(['author']);

This requires a bit of extra work on the ElementQuery, but it can be efficiently done in the same query.

We first perform an inner join on the author's content table using the authorId so that the custom field is available to us.

in Twig:

{% set elementQuery = craft.entries()
    .section('sectionHandle')
    .with(['author'])
    .innerJoin('{{%content}} author_content', '[[author_content.elementId]] = [[authorId]]')
    .andWhere({'author_content.field_customFieldHandle': 'X'})
%}

in PHP:

$elementQuery = Entry::find()
    ->section('sectionHandle')
    ->with(['author'])
    ->innerJoin('{{%content}} author_content', '[[author_content.elementId]] = [[authorId]]')
    ->andWhere(['author_content.field_customFieldHandle' => 'X']);

To order by a custom field we use orderBy.

in Twig:

{% set elementQuery = craft.entries()
    .section('sectionHandle')
    .with(['author'])
    .innerJoin('{{%content}} author_content', '[[author_content.elementId]] = [[authorId]]')
    .orderBy('author_content.field_customFieldHandle asc')
%}

in PHP:

$elementQuery = Entry::find()
    ->section('sectionHandle')
    ->with(['author'])
    ->innerJoin('{{%content}} author_content', '[[author_content.elementId]] = [[authorId]]')
    ->orderBy('author_content.field_customFieldHandle asc');

To filter by a custom field we add andWhere.

in Twig:

{% set elementQuery = craft.entries()
    .section('sectionHandle')
    .with(['author'])
    .innerJoin('{{%content}} author_content', '[[author_content.elementId]] = [[authorId]]')
    .andWhere({'author_content.field_customFieldHandle': 'X'})
%}

in PHP:

$elementQuery = Entry::find()
    ->section('sectionHandle')
    ->with(['author'])
    ->innerJoin('{{%content}} author_content', '[[author_content.elementId]] = [[authorId]]')
    ->andWhere(['author_content.field_customFieldHandle' => 'X']);


Exclude path in NGINX config (for FastCGI Caching) I've got a Craft 2 site on an NGINX server that uses FastCGI Caching (based on Static Page Caching with Craft CMS), but I've got a few pages that have some dynamic content that I'd like to exclude from the cache. I understand I can do this within the NGINX config, but my client has asked if they can somehow manage this within Craft.

I've tried doing this with headers and cookies, but haven't had any luck yet. What I think is happening is that these things are set after the request is made.

Is there a way to use a plugin that can get information on which path to exclude into my NGINX config on a per-path basis? If so, where would be a good place to start?

I've tried doing this with headers and cookies, but haven't had any luck yet. What I think is happening is that these things are set after the request is made.

You are correct. fastcgi_cache is basically a switch, is it on or off. Your backend has no say in that because nginx doesn't look to the backend at all to figure out whether it should serve the request via cache or fire up FPM. It looks via the things it does have access to at the time... location, query_string, user_agent, etc.

How often does your client need to update?

One of the things that makes nginx fast is config files are only read into memory once. Apache, by contrast, looks for .htaccess files inside every directory in the tree on every request being served.

To make changes to a config requires nginx to be reloaded (or restarted). Complicating things, port 80 is a privileged port which means to open it up/listen on it, you need to have root permissions. That's not something you would want to give to a user via a web interface.

However, there are some workarounds.

If you are able to name your slugs differently in advance (e.g. append or prefix "-form" or "-dyn" or something like that to the URL), you can use that to tell nginx not to load from cache.  You could even have Craft generate part of the URL for you based on the value of a "Does this have dynamic content?" lightswitch.
Generate part of the nginx config dynamically by using a cron job which runs a shell script every 15 mins or so to check if there are configuration changes. If there are changes, reload nginx. I'd recommend using a map, put that in a separate file, and then include it so you're not touching of the main config files.
Use the lua module. Lua is a scripting language that lets you run dynamic code on every request. I haven't used it so I don't know how performant it would be but it could work to set variables, etc.
Load content in via JavaScript. Depending on what you're trying to do, ignore the web server altogether and load content dynamically. If it's an interactive thing that's going to be tough for google to cache anyway, that could work well here.

Caching is super tricky. Varnish has a lot more options when it comes to dynamic content but it's potentially another dameon you need to setup and maintain. nginx is great because of its simplicity, however, that simplicity comes at a cost of flexibility.


Posting front-end form to plugin controller route results in 404 I'm working on a plugin and need a front-end (non CP) form that submits to one of the plugin controllers. Here's my setup:

- plugins
  - portal
    -- PortalPlugin.php
    - controller
      -- Portal_AccessController.php

Portal_AccessController.php

<?php
namespace Craft;

class Portal_AccessController extends BaseController {

    protected $allowAnonymous = true;

    public function actionLogin() {

        echo 'Here';

    }

}

I then created a front-end form by adding a new template directory in /craft/templates:

- pro-portal
  -- index.html

With index.html containing:

<form method="post" action="" accept-charset="UTF-8">
    <input type="hidden" name="action" value="portal/access/login">

        <input type="text" maxlength="4">
        <input type="text" maxlength="4">
        <input type="text" maxlength="4">
        <input type="text" maxlength="4">

    Test me
    <input class="btn submit" type="submit" value="Submit">
</form>

Hitting mydomain.com/pro-portal displays the form. On submit it returns to /pro-portal but with a 404 error.

I also tried creating an action link but that also results in a 404 at /index.php/actions/portal/access/login.

I've looked through answers on similar questions and tried all the solutions but no luck. Am I overlooking something? Missing something?

You're getting a 404 because your action method isn't telling Craft what do to after it has echo'd 'Here', so routing continues.

See #3 is that link:

The request doesn’t necessarily end after a controller has been called. The controller may allow it to keep going.

You can redirect, end the request, load up a template to display, etc.

Update:

The controller folder needs to be renamed to controllers.


How to disable loops from automatically wrapping non-marked up content? So I've got a completely clean install of Craft 3: RC 2. I've installed Redactor, and nothing else.

In the templates/index.twig file; this is all I have:

{% set test = ['one', 'two', 'three'] %}

{% for t in test %}
  {{ t }}
{% endfor %}

Output:

After some trial and error, I figured out that content without any html markup will be wrapped with 'pre' tags by default. Is there an option to stop this behaviour? Maybe a general config option I can disable?

Pretty sure that's just your browser's console trying to tidy things up when you inspect.

If you View Page Source, I'd guess it wouldn't be there.

I also just tested this with your example code on a fresh Craft 3 install on the latest Chrome and Firefox on Windows and the latest Safari on OSX and was not able to reproduce your picture.


Writing an Craft plugin for imgix? I have started using imgix on some non-Craft sites, and it’s bloody awesome. It’s a bit similar to Craft in the way you apply transforms to a master image, and those transforms are done on-demand and then cached for future use. Only with imgix the transforms are done in the cloud and stored on their global CDN. Now I was thinking if it might be possible to write a Craft plugin to use imgix instead of the internal image handling code.

Any tips/pointers on how to go about this would be most appreciated!

Certainly seems doable to me. And the complexity would depend on how comfortable you are with PHP.

But roughly you'd follow the same format as the Aviary Image Editor plugin for Craft where you have the user enter their imgix API key from their account and store that in the database. Then your plugin would be a wrapper for the imgix API calling their web service methods whenever you need to interact with them.


Change public URL for user photos We run all our images through a CDN to perform various manipulations. This works create for any image managed via assets, but I'm a bit stuck on any image that has a cpresources URL. In particular I'm running into this issue with profile photos which have a URL much like this:

http://www.mydomain.com/cpresources/userphotos/janedoe/100/JaneDoe.jpg

In the above, I just need to change the URL to something like http://cdn.mydomain.com/cpresources/userphotos/janedoe/100/JaneDoe.jpg

This image will then get downloaded from the www.mydomain.com host.

I did run into this issue with assets too tonight, where there was an issue with an image that didn't get moved into it's final destination, and ended up living in the temp folder, with a cpresources URL.

Is there any way to change this URL?

Never too late to answer your own question.

This is easily resolved now as Craft 3 stores user photos as assets, you just need to assign the CDN URL to the public URL field in Assets.

https://docs.craftcms.com/v3/changes-in-craft-3.html#user-photos


Craft 404 for admin dashboard OK, I have encountered the following issue:

Issue:
 Admin page gets a Craft 404 page error; home page loads fine though.

Home page: 192.168.10.95

Admin page: http://192.168.10.95/public/index.php/admin/dashboard

Clearly Craft is working, though I am not sure what is causing this to break for me. Any suggestions?  I can provide any information you may want to see, just let me know.

Thank you Craft friends!

Edit 03/14/2017 @08:24 PST

Here is the contents of my /etc/apache2/sites-availavble/000-default.conf file:

<VirtualHost *:80>

ServerAdmin webmaster@localhost
DocumentRoot /var/www/html/public

ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>

I have pointed my DocumentRoot to /var/www/html/public, though did I miss something in my configuration?

Thanks again Craft friends!

Apparently I am "to close to the painting" here and completely missed a simple answer. In my case, I was going to the wrong URL completely.

Bad: http://192.168.10.95/public/index.php/admin/dashboard

Good: http://192.168.10.95/admin

As you can see, USER error here. Thank you for the assistance everyone!


Plugin RegisterUrlRulesEvent - Regex URL-Routing gives 404 I'm updating a Craft 2 plugin to Craft 3 and I'm having difficulties getting the Regex URLs working correctly. The eocs I'm using: Craft3 Docs
I used pluginfactory.io to create the basic craft3 plugin scaffold.
 For context: the plugin name is expedweather.

This is the Route I'm trying to register:

$map_page = 'data/<range:\w+>/<peak:\w+>/<view:\w+>/<parameter:\w+>';
$event->rules[$map_page] = 'expedweather/forecastPanel';

In my DefaultController.php I've got this:

protected $allowAnonymous = ['index', 'forecast-panel'];

And I'm not sure what I'm doing wrong here but All I get is

  HTTP 404 – Not Found – yii\web\NotFoundHttpException Page not found. ↵
  Caused by: Invalid Route – yii\base\InvalidRouteException

I've made sure the plugin is enabled in the backstage.

Update I was able to solve half of my Problem:

Seems the Regex didn't like the "pure" slashes / in the URL between the parameters, once I escaped those, through backslashes like this: \/ it no longer gave me a yii\base\InvalidRouteException.

The new Problem I have now is that it can't find the action I'm referring to, see below:

// Path of File: ./src/Expedweather.php; in EVENT_REGISTER_SITE_URL_RULES

$map_page = 'data\/<range:\w+>\/<peak:\w+>\/<view:\w+>\/<parameter:\w+>';
$event->rules[$map_page] = 'expedweather/forecast-panel';

// Exert from ./src/controllers/DefaultController:
protected $allowAnonymous = ['index', 'forecast-panel'];
...
public function actionForecastPanel() {...}

An additional piece of info: I'm able to route to the DefaultController's index Function by removing /forecast-panel from the target action.


One large plugin vs multiple smaller plugins I'm finding that occasionally (especially on larger sites), there are little bits of functionality that I need that Craft doesn't offer out of the box. The functionality is usually simple and relatively specific, so I find myself quickly writing little plugins that do the job. Currently I've been creating separate plugins for each bit of functionality I need which can result in some sites having upwards of 5 or 6 small plugins, along with any other plugins that I might be using.

This led me to wonder, when it comes to keeping our Craft installs running as cleanly and efficiently as possible, which is better:

a. Having one large plugin that does multiple different, likely unrelated, things.

b. Having multiple smaller plugins, each doing their own thing.

From a development standpoint I find that having separate plugins makes life easier because everything is more organised, but is this having an impact on Crafts performance?

I don't believe there's any significant impact in having multiple small plugins vs. one big plugin. It's probably safe to say that there is a small amount of overhead in loading each plugin separately, but that effect is probably negligible.

Personally, I'd keep all of that functionality combined into a single plugin. You say they are for "different, likely unrelated, things", but I'm guessing that they all serve a larger purpose of handling the business logic. If you haven't already, you may want to check out the Business Logic template, which is designed as a starter plugin for exactly this type of scenario.


How to handle entry save in plugin when entryId is not set? Referring to my older question, I have the entryId working on an existing entry. However I've noticed a new entry doesn't have an entryId set (makes sense).

I have some custom information in text fields that needs to be saved after onSaveEntry is fired (which I have working). I have a custom model, record, controller and service setup. In my controller I retrieve these custom text fields including the entryId field from Craft. But because a new entry doesn't have an entryId set yet, my controller/service is not working as it should.

When the entry is saved and the page redirects to wherever, I also lose all the information in the text fields. So that's why I want to save my custom information directly after the entry is saved.

My question is, how do I handle this when I don't have the entry id. I don't want the user saving the entry first (to basically generate the entry id), then fill in the custom text fields and then save again (which works). But I think this is very devious.

This is my controller:

public function actionSaveRecord() {
   $this->requirePostRequest();

   if ($id = craft()->request->getPost('recordId')) {
          $model = craft()->plugin->getRecordById($id);
     } else {
        $model = craft()->plugin->newRecord($id);
   }

   $model->entryId = craft()->request->getPost('entryId');
   $model->customField = craft()->request->getPost('customField ');

   if ($model->validate()) {
       craft()->plugin->saveRecord($model);
   }
}

This is the service:

public function saveRecord(PluginModel &$model)
{
    if ($id = $model->getAttribute('id')) {
        $pluginRecord = PluginRecord::model()->findById($id);

        if (!$pluginRecord) {
            throw new Exception(Craft::t('Can\'t find record with ID "{id}"', array('id' => $id)));
        }
    } else {
        $pluginRecord = new PluginRecord();
    }

    if ($model->validate()) {
        $attributes = array(
            'entryId' => $model->entryId,
            'customField' => $model->customField,
        );

        foreach ($attributes as $k => $v) {
            $pluginRecord ->setAttribute($k, $v);
        }

        if ($pluginRecord ->save()) {
            // update id on model (for new records)
            $model->setAttribute('id', $pluginRecord->getAttribute('id'));
            return true;
        } else {
            $model->addErrors($pluginRecord->getErrors());
            return false;
        }
    }
}

The rest of the plugin can be found here for reference: https://github.com/iNalgiev/webtexttool1

Had to browse through your plugin repo for a bit to try and wrap my head around what's going on, but I think you have the problem nailed down in that the issue is this: https://github.com/iNalgiev/webtexttool1/blob/1.0.0/WebtexttoolPlugin.php#L57

Trying to grab the entry ID from the cp.entries.edit.right-pane template hook for a new entry is going to return null because IDs aren't assigned until after the element is saved.

Off the top of my head, you've got two not-so-thought-out options.

Refactor your plugin logic so that the code that eventually calls your controller/service's saveRecord methods happen after the entry has been saved in onSaveEntry and you've got a valid entry ID.
Come up with some AJAXy way to calling Craft's saveEntry method from the cp.entries.edit.right-pane template hook that returns the entry ID so the rest of your logic can assume that the entry already exists.


Click counter for links (craft v2) So I'm new to PHP and ok with Javascript. I have a page on my site with a long list of external links, would it be possible to add a counter to be displayed next to each link that shows how many times it has been clicked?

Yes, it would be possible. I don't think there's an easy (plugin) solution for this purpose, though. If your project has an active module, you could use that to save the click count and retrieve it from the DB.

Make sure your module works (in the default Craft project, it's as simple as uncommenting the module line in config/app.php)
Create a migration to create a table in which you store the click counts (per url, or by ID if each link has a unique ID)
Create a model to interact with your table
Create a controller method to handle the clicks (get DB row for URL, add 1, save it)
Create a template variable to get the click count for a URL

After that, all that's left is writing some JS to listen for link clicks and POST the URL to your controller method.

All in all, not very easy if you're new to PHP (be sure to read this before you start), but a nice first dive into Craft plugin/module development.


Is it possible to always show Assets folders as opened? When adding an image from an Assets field or uploading one to the Assets section (or anywhere there is an Assets field for that matter) if you have subfolders then it currently shows the main folder but closed so you have to click on the arrow to unfold the main folder structure.

Therefore looking for a way to have the folder structures already opened to save a click.

Thanks,

Mark

From what I know this isn't possible in Craft2 (it's a known issue). P&T has probably addressed this in Craft3 with the many updates to Assets in that release.


Register a user as part of a Commerce checkout? Is it possible to register a user for a Craft user account as part of a Craft Commerce checkout flow? Ideally something where you can ask if the user wants to create an account and save their details as part of the checkout flow. Is this doable? (I'm surprised this isn't somehow in Commerce, given how incredibly prevalent such a UX flow is.)

Luke's answer above is absolutely right and the simplest approach, but as I commented above, I wrote a plugin for this:

https://github.com/bossanova808/CommerceRegisterOnCheckout

..the reason being that I wanted to integrate registration during the checkout, not after as Luke has done above.  And the motivation for this is that site registration rates plummet (like, by 80%+ in my totally anecdotal data/experience) - if the registration comes AFTER checkout.  We get a MUCH higher rate of people joining (which has all sorts of business benefits for us) - if we integrate it right IN to the checkout flow.  I can't say why that is precisely, but it seems like most folks mentally check out (excuse the pun) the moment they hit 'Submit Order'....

So I wrote the above to allow a more integrated approach, which does much as what you describe - there's an ajax POST but it's during the payment part of the process (i.e. the actual checkout but), and the user is then registered & logged in (and can e.g. be taken then automatically to their orders summary page).  If there is any failure in registration (e.g. they've forgotten they registered before) - we handle that and present whatever we need to (including possibly a pre-filled registration form for them to have another go with).

(BTW I agree - this should definitely be supported by Commerce in core).


Recommended workflow when developing new websites A common workflow for me when building a web page is the following.

I'm getting a PSD-file (Photoshop) from a external advertising agency
Build the site in Webflow and then export to plain html/css/js
Build the site locally in Craft CMS using Textmate
Deploy to dev.customer.com using DeployBot and Github
Send username and password for Craft to advertising agency, they then start to fill the site with content

The problem with this workflow is when the agency in step 5 want changes (new fields, sections).  I don't want to add fields on both localhost and dev.customer.com. And I don't want to temporarily shut down dev.customer.com, export database on dev.customer.com to localhost and then import to dev.customer.com when done (there is often a tight schedule).

How would you do? Does Craft 3 solve this?  If not, maybe me and the agency should work on the same codebase and database. One way is to have a small server locally (which i don't have) turned on 24h and open port 80 from outside so the agency could work in Craft. Another way is to use SSHFS to mount file system over SSH on a remote Linux VPS (which i have plenty of), but i'm not sure how stable this is.

Essentially the question is "how can I manage changing database content across environments" which has been covered several times here before.  Some leisure reading:

What's the best practice for handling data migration and organization across development environments?

Git Workflow and Multi Environment - how to approach

What's the best practice for upgrading a versioned Craft site?

  Does Craft 3 solve this?

Craft 3.0 will not have a solution for this at launch, but we are planning on something post 3 launch that will help making managing Craft content across environments easier to manage.


GraphQL two image transforms for same field To get image transform in GraphQL we use this

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

But how do I get two different image transforms (for responsive image) for this asset field?

Untested, but should work:

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

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


How can I set a landing page for a structure with no slug? In Craft2, I have structures that each have a landing page/homepage for that structure.

If the structure's URI format is "liver/{slug}", how do I make the 'landing page' entry have a URI of only "liver/", with no slug?

This is important since I want users visiting the liver/about-us page to be able to remove 'about-us'...and land on the liver homepage (not get a 404).

I don't understand routing very well-- from what I have gleaned I cannot see how to make routing associate a given URI with a given entry-- I only understand how to associate it with a template.

This is similar to this question, except that I want these landing pages to have dashboard entries and use the same template as all the other pages...not be an index-type page.

Note: I have seen answers regarding adding a site homepage to a structure, but this is not a site homepage- these landing pages do not live at the site domain root...they live at the root of each structure's URI.

Thanks in advance for the help.

You can create change the uri pattern for your structured section to something like { parent.uri }/{ slug } and create an additional entry type landing-page. Your landing page will have the slug liver and all entries below that will have the URI liver/{slug}

You can load different templates based on the entry type and if the type is your landing page, you'll display all children

Another Approach is to use a template path directly and insert the template liver.twig in your templates folder


Radio buttons in matrix field not saving Craft CMS version 3.0.9 (updated from 3.0.1 to try and fix).

I have a layout field in a matrix box with the radio buttons field type with the options normal (default), full, left, right.

When saving the entry with the radio button as full, left or right it stays at the default normal.

This functionality was working in Craft CMS 2, doesn’t seem to work since the update to 3.

Any idea on how to fix this?

Steps to fix:

Change the radio button default to an alternative option.
Go to entry and remove the matrix block.
Save entry
Readd the matrix block.

You should be able to correctly save the block, a long process but I couldn’t figure out what was going on.


Bulk / Multiple License purchase Craft CMS Pricing FAQ

https://craftcms.com/pricing

The FAQ mentions discounts when cost is an issue, presumably non-profit sites.

But… is there a discount for bulk purchasing? Example. 10, 50, 100 licenses?

I can't see an 'official' tier for multiple purchase, is it best to ask?

The question is, is there a multiple license discount?

We currently don't have an official policy, but to-date we've handled bulk discount requests on a case-by-case basis.

As the FAQ suggests, contact support@craftcms.com :).


Ordering Looped Results by Field's Numerical Value I’m looping through some text fields on the form results page and need to order the numerical output from low to high.

How would I do this using twig?

{% for field in submission %}
  {% submission[field.handle].value %}
{% endfor %}

Note: I am using the Freeform Plugin. They have informed me that I would need to create a custom filter but before I do that wanted to see if there was a better way to do this.

It's an extra plugin but SuperSort would do the job - https://github.com/TopShelfCraft/SuperSort

Edit - couldn't make it work in one go, but this works:

{% set results = [] %}
{% for field in submission %}
  {% set results = results | merge([{'handle': field.handle, 'value': submission[field.handle].value}]) %}
{% endfor %}
{% set sortedResults = results | supersort('sortAs', '{value}', SORT_NUMERIC) %}

Not the most elegant, let me know if you find a better solution!