Allow uploading of asset with same name as existing asset I have an upload form working in my templates (on the frontend), however if I try to upload a file with the same name as an existing asset the file isn't uploaded.

I notice instead a prompt message comes back.

1) I'm not sure how to deal with this, I presume some AJAX call is required.

2) I would prefer it if I could send a value which tells Craft to keep both files without prompting.

What would be the best way of handling this?

The code I've tried is below, using jquery fileupload.

var url = '/actions/assets/uploadFile',
    uploadButton = $('<button/>')
        .addClass('btn btn-primary')
        .prop('disabled', true)
        .text('Processing...')
        .on('click', function () {
            var $this = $(this),
                data = $this.data();
            $this
                .off('click')
                .text('Abort')
                .on('click', function () {
                    $this.remove();
                    data.abort();
                });
            data.submit().always(function () {
                $this.remove();
            });
        });

$('#images-upload').fileupload({
    url: url,
    dataType: 'json',
    formData: [
        { name: 'folderId', value: 1 }
    ],
    autoUpload: true,
    acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
    maxFileSize: 7000000, // 7 MB
    // Enable image resizing, except for Android and Opera,
    // which actually support image resizing, but fail to
    // send Blob objects via XHR requests:
    disableImageResize: /Android(?!.*Chrome)|Opera/
        .test(window.navigator.userAgent),
    previewMaxWidth: 100,
    previewMaxHeight: 100,
    previewCrop: true,

})

And also

    window.csrfTokenName = "{{ craft.config.get('csrfTokenName') }}";
    window.csrfTokenValue = "{{ craft.request.getCsrfToken }}";

var url = '/actions/assets/expressUpload',
    uploadButton = $('<button/>')
        .addClass('btn btn-primary')
        .prop('disabled', true)
        .text('Processing...')
        .on('click', function () {
            var $this = $(this),
                data = $this.data();
            $this
                .off('click')
                .text('Abort')
                .on('click', function () {
                    $this.remove();
                    data.abort();
                });
            data.submit().always(function () {
                $this.remove();
            });
        });

$('#images-upload').fileupload({
    url: url,
    dataType: 'json',
    formData: [
        { name: 'elementId', value: $('input[name=entryId]').val() },
        { name: 'fieldId', value: 8 },
        { name: window.csrfTokenName, value: window.csrfTokenValue }
    ],
    autoUpload: true,
    acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
    maxFileSize: 7000000, // 7 MB
    // Enable image resizing, except for Android and Opera,
    // which actually support image resizing, but fail to
    // send Blob objects via XHR requests:
    disableImageResize: /Android(?!.*Chrome)|Opera/
        .test(window.navigator.userAgent),
    previewMaxWidth: 100,
    previewMaxHeight: 100,
    previewCrop: true,

})

I haven't tested this but from a brief look into how assets are uploaded you might be able to pass a userResponse value through post, it seems the options you can pass are:

keepBoth, replace, cancel

So I guess you would need to include the field in the form you are using to upload the asset like:

<input type="hidden" name="userResponse" value="keepBoth">

As I said I haven't tried this before and i'm assuming you're hitting the UploadFile action on the assets controller...


Inserting Relationship Into Entries Field - Plugin Not Saving Relation I was hoping someone could shed some light on this issue I'm having. I'm trying to update a relationship field through a plugin, without much success, the entry looks like this:

I saw a post on here regarding something similar here:  Relation row insertion in DB (plugin) so going from that my code at the moment looks like this:

// The id of the entry i want to attach to the relation
$storeId = $formData['storeId'];

// The entry as shown above
$source = craft()->elements->getElementById($entryId);

foreach($blocks as $blockId => $value)
{
 // The matrix block with the relation
 $matrixBlock = craft()->matrix->getBlockById($blockId);

 // Get the 'stores' field
 $fieldId = $matrixBlock->stores->relatedTo['field'];
 $field = craft()->fields->getFieldById($fieldId);

 // Save the relationship
 craft()->relations->saveRelations($field , $source, array($storeId));

}

$blocks is just an array like: array('1092' => 0) and $value will just be determining whether to set or unset the relation.

When I run the above through a controller, no errors appear but no relation actually takes place on the stores field. Are there any glaring mistakes i'm making? any help would be much appreciated!

Thank you.

Figured it out, trying to use the Entry as the source was wrong as the 'stores' relationship field actually belongs to the matrix field.

So by setting the matrix field as the source this is now working just fine!

craft()->relations->saveRelations($field , $matrixBlock, $relations);


Migrating categories from Entry to Asset Is it possible to migrate content like categories from an entry to an asset easily?
Each entry has an image asset and I'd like to move all the categories on the entry to the asset.
Would this require a SQL operation or is there any easier way?

I would probably do this in two steps:

Create a twig file formatted as a CSV that outputs the category and asset id's, i.e.

AssetId, Category

{% for entry in entries %}
{{ entry.asset.one().id }}, {% for category in categories %}{{ category.id }}{% if not loop.last %}-|-{% endif %}{% endfor %}

{% endfor %}

Use feed me to re-import the categories onto the assets using the CSV.


Erros when using Entry Variable in craft.app.feeds.getFeedItems I'm processing some feeds using craft.app.feeds.getFeedItems() and it works if I pass the limit as a hard coded number like this:

{% set items = craft.app.feeds.getFeedItems(entry.rssURL, '5') %}

    {% for item in items %}

{{ item.title }}

    {% endfor %}

However if I change '5' to a field handle I get errors. where entry.feedLimit is a number such as 3 or 5

{% set items = craft.app.feeds.getFeedItems(entry.rssURL, entry.feedLimit) %}

    {% for item in items %}

{{ item.title }}

    {% endfor %}

The errors I get is:

  TypeError Argument 2 passed to craft\feeds\Feeds::getFeedItems() must
  be of the type integer or null, object given, called in
  /path/to/vendor/twig/twig/lib/Twig/Extension/Core.php
  on line 1619

This code was previously working on Craft 2, but after the update it is now broken. I've temporarily hard coded the limit in, but that's not ideal.

Solution is simple, the field type is a select so I need to change

entry.feedLimit

to

entry.feedLimit.value

And then it works


How to add tags to an entry per site basis. And then only get the tags for that site in the frontend I have craft pro and have one tagGroup called Tags
Then I created a Tag field called newsTag like this:

When I add a tag for german, the tag is also created in the database for dutch and english, so when I get a list of used tags like this:
{% set tagsEntries = craft.entries
    .section('news')
    .limit(null)
    .all() %}

{% for atag in craft.tags.relatedTo(tagsEntries) %}

{{ atag.title }}

{% endfor %}

Now I get all tags used in all sites. when I use it like this:
{% set tags = craft.tags.relatedTo({
      sourceElement: tagsEntries,
      sourceLocale: craft.site
    }) %}

Then I still get all tags, because when I look at the database the tag for German is also created for Dutch and English:
In the content table:

When I remove the entry for site 1 and 3 (the dutch and english site) the it works, but will be added again on entry save...
Is it somehow possible to only save a tag for one site? That way I can get all the tags only used in that site and not all.
ps, this only happens with tags in entries that are used/enabled for 2 or more sites.
Thanks for the help,
Dimitri

currently disabling multi site for tag is not supported

unless you were to fork Craft and change the isLocalized() return
value from true to false

https://github.com/craftcms/cms/issues/3483#issuecomment-440782270
so tag itself is always created for all languages but you need another thing.
you need adding tag to entry per site basis so you have to check tag field -> advanced setting -> Manage relations on a per-site basis -it seems you enabled this already-.
now if there is two site and tag1 is added or selected for site1 entry but tag1 is not selected for that entry on site2, if you change source Locale to site2 id on your code, tag1 is not showing on results. - still tag1 is available on site1 and site2 but is not showing up on result because you enabled manage tag on per site basis and tag1 is not attached to site2 entry -


Convert textfield to be used in html class or id? Does anyone know if it is possible to apply a Twig filter or use escaping to convert a Craft textfield into a html class/id safe string?

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


Restrict viewing front end to specific group permissions How can I restrict content frontend to specific user groups?
There seems no sensible way to do this out of the box.
For example group permissions in CP are all about CP - there is no view option.

Never had a use case for this before today but have one now and finding Craft3 coming up short :(

Scenario is a support portal where different companies can provide user specific content. Idea is login with company id (done that ok via a plugin) but then once logged in they get redirected to content for that specific company.

So I have two probs now: redirect to company 'home page', and restrict access to content. I've considered splitting content into sites and pairing users with sites. I've considered section root parent and checking permissions for top of tree in twig. I'm thinking restricting per section is best and adding company homepage as entry field in user field or user group field and managing access via plugin + twig but its all feeling very heavy handed....

If you setup a User Group with the same handle as the Site you want them to have access to, this could be fairly easy.
Let's say you have a site called "Acme" setup in the Sites settings. You also created a corresponding User Group called "Acme." The handles for the Acme Site and Acme User Group are both "acme."
When you're on the Acme site's front-end, possibly example.com/acme depending on how you set up your site URLs, the {{ currentSite.handle }} tag will return acme.
To test if a user has access to content in your template you can use something like {% if currentUser.isInGroup(currentSite.handle) %}.
Adding this to any template will prevent unauthorized access if a user is not in a group:
{% if not currentUser.isInGroup(currentSite.handle) %}
  {% exit 403 %}
{% endif %}

You would also probably want to allow admins or users groups who can access the control panel:
allow admins:

{% if not currentUser.isInGroup(currentSite.handle) or not currentUser.admin %}
  {% exit 403 %}
{% endif %}

... or allow any user that can access the control panel:

{% if not currentUser.isInGroup(currentSite.handle) or not currentUser.can('accessCp') %}
  {% exit 403 %}
{% endif %}

Redirecting to the correct site after a login page is a little trickier because users can belong to more than one group.
But assuming that users only belong to one group you could redirect users to a sort of "routing" template that's only job is to send you to the right place.
{% set firstGroup = currentUser.getGroups()[0] ?? null %}

{% if firstGroup %}
  {% redirect firstGroup.handle %}
{% else %}
  ... default redirect or error
{% endif %}

Also, here's a list of permission you can use with the currentUser.can() method:
https://docs.craftcms.com/v3/users.html#permissions


Adding users outside of CP or front-end registration form Is there a simple / best practice way for creating new users programatically? My specific use case involves capturing user data for online sales using a 3rd-party form with Stripe integration. When a user checks out and makes the purchase (not on the Craft site), I'd like to capture the data and generate a user account automatically on the Craft site.

My current idea, which should work, is to trigger Zapier to write a custom record (containing the user fields) to the MySQL database directly. I've done it before in other contexts but am curious if there's a better way?

You could write a custom plugin that exposed a anonymous controller endpoint that accepted to the user info you want to save.

From there the controller endpoint could create a new UserModel, populate necessary fields/properties you want to save, then call craft()->users->saveUser() and let Craft do the database populating.


How to make an HTTP request from a plugin? I'd like to be able to make HTTP requests from within my plugin to hit an endpoint and get a response. How can I do this?

Craft uses an HTTP library called Guzzle, and it's built-in so you can import and use it from within your plugin. Here's an example:

// imports
use GuzzleHttp;

// GET request

$client = new GuzzleHttp\Client();
$response = $client->request('GET', 'https://example.com', [
  'query' => ['exampleParam' => 'example']
]);
$responseBody = json_decode($response->getBody(), true);

// POST request
$client = new GuzzleHttp\Client();
$response = $client->request('POST', 'https://example.com/api', [
  'form_params' => [
    'example' => 'example',
  ]
]);
$responseBody = json_decode($response->getBody(), true);

To figure out how to properly format your Guzzle request, refer to the Guzzle Docs.


Update Error: Could not validate update handle Recently, anytime an update to Craft core or a plugin is attempted on my site that requires a database migration I get an Internal Server Error: Could not validate update handle. Does anyone know what handle Craft is talking about here? Looking for help debugging this issue. My guess is that somewhere in the midst of updates and rollbacks the database got out of sync with the source code. Just need to track down where this faulty handle is.

Looks like the issue had to do with my production environment being load-balanced. To avoid errors like these on load balanced sites, remember to set the validationKey and appId config keys in your general.php file.


Can I use Craft CMS for a large custom web application? I know the easy answer is "yes", but let me elaborate:

Say I want to create a community for grocery shoppers. I let bloggers and other influencers design their own menus that define which ingredients end up in the users' shopping carts.

The users pick the menus that interest them, and based on factors like number of people in the family etc, the right quantity of ingredients are added to the cart. When the user is ready, she clicks purchase, and an order is sent to the nearest (or selected) grocery store.

I have developed sytems of similar complexity earlier in my career, but then by using my own CMS system- which of course let me do whatever I wanted.

My question is - would Craft CMS be suitable for this kind of task? Is it in fact more than a website CMS? Is it really scalable?

Craft isn't opinionated on how your site works; it just organizes and outputs your content however you want it to. You have 100% control over your HTML whether you want to use templates or dish out the data for some framework like React, Vue, etc (using the Element API plugin). So that should answer your question: yes it is more than just a website CMS because it simply manages your content, not the means you choose to collect and output that content like a website, app, etc.

However, Craft out of the box obviously isn't customized to all the extra functionality you described above, so you're going to need to write your own custom module in PHP to do these things. You can use Pluginfactory to start your scaffolding.

Off the top of my head, based on what you said, it sounds like you'll eventually need to buy Craft Commerce. Your users will create an account in Craft. The bloggers/influencers will need their own user group, and they will submit a form that will create an entry in a channel called "Menus". Your general users will be in their own user group and can choose among those Menus entries. You get an unlimited number of channels, categories, purchasables, etc, and they can all be related to each other within an entry, product, etc, so go nuts and keep everything modular for reuse. Your custom plugin/module will need to handle figuring out the number of ingredients and any other customization.

That's all just my interpretation of what you wrote, so obviously you'll want to look into this stuff yourself. But I don't think you have to go reading up extensively on a bunch of stuff before finally deciding to start. You can download Craft Commerce for free (you don't have to pay for a license until you push it up to your server), and you can always start exploring custom plugin/module development. Getting your hands dirty with the code is the way to answer your question, but if you're worried about investing your time in all this just to find out that Craft prohibits you from realizing your idea, I can assure you that's not the case, and you're not going to have to make it happen by having to hack around the system like some lame Wordpress site. Craft is made to be incredibly flexible for anything that needs content managed, and that includes your idea.


How can I get cookies that were set in javascript from a twig template? [NEW] This question was already asked a few years ago, and the way of doing it was through a plugin. I was wondering if there is a way of doing it just using Craft and Twig.

I set up a cookie using JavaScript, and I want to read it with Craft. Is this possible?

Assuming this is for Craft 3, you can do something like this from a template to loop through all available cookies for a site:

{% set cookies = craft.app.request.getCookies() %}

{% for cookie in cookies %}
    {{ cookie.name }}
{% endfor %}


RSS Aggregator for Craft? Curious if anything exists like this for Craft?

http://www.wpexplorer.com/create-rss-news-aggregation-portal-wordpress/

Just looking for something that can look at an RSS feed and post entries to a Craft powered site.

Perhaps the following plugin could help to import entries from RSS:

Craft CMS plugin to import entries from XML


Linking and showing archive by month With a bit of looking around i've got the following code on my News landing page:

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

  {% for year, entriesInYear in allEntries | group("postDate.year") %}

{{ year }}

        {% for month, entries in entriesInYear | group("postDate|date('F')") %}

{{ month }}&nbsp;({{ entries|length }})

        {% endfor %}

  {% endfor %}

Using
{{ month }}&nbsp;({{ entries|length }})
  I get the desired result (visually), see attached image.  If I use
{{ entry.getLink() }}
 I get the result shown on the right of the attached image.

In both instances I only get a link to the first segment (also shown in the attached image).

What I would like to do is have the Months link to a page that lists just the articles from that month (I don't need the year to link).

I assume I need to add a dynamic link into the href but how and what?

Many thanks in advance.

Martin

So P&T chipped in to help and of course solved my plight immediately :D

For anyone else who might encounter a similar scenario I'm posting the solution.

On the page containing the archive list:

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

    {% for year, entriesInYear in allEntries | group("postDate.year") %}

        {% set counter = ( counter | default(0) ) + 1 %}

            {{ year }}

                {% for month, entries in entriesInYear | group("postDate|date('F')") %}

{{ month }}&nbsp;({{ entries|length }})

                {% endfor %}

    {% endfor %}

Then on the actual archive page (I added this at the top of the page):

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

{% set firstDay = now | date_modify('first day of ' ~ month ~ ' ' ~ year ~ ' 00:00:00') %}
{% set lastDay = now | date_modify('last day of ' ~ month ~ ' ' ~ year ~ ' 23:59:59') %}

Then where you want the info to appear:

{% set archive  = craft.entries.section('sectionName').postDate('and', '>= ' ~ firstDay, '<= ' ~ lastDay) %}

    {% for entry in archive %}

{{ entry.title }}

            {{ entry.body }}

read more

{{ entry.postDate | date("d") }} {{ entry.postDate | date("M") }}

    {% endfor %}

Now here's the bit that caused the grief...  Instead of having 'month'-'year' as part of the route, P&T suggested using just '*'.

Or.. as P&T put it:

  Your dynamic route is set with the Month and Year token. If you look at the list of available tokens, you will see that Month and Year follow a specific format, which the URLs you set up in your menu do not follow. Therefore, those URLs do not follow the pattern you set in the Route and you get a 404 page.


Problems with Punctuation in Title using ElementCriteriaModel I've noticed something odd and I can't find anything in the documentation.

I'm writing a plugin and when I use ElementCriteriaModel to find an existing entry like so:

$criteria = craft()->elements->getCriteria(ElementType::Entry);
$criteria->section = 'entryHandle';
$criteria->title = 'The Title & Stuff';
$existingEntry = $criteria->first();

The entry is not found, and I believe it's because of the punctuation. The entry is clearly in the craft_content table (with the exact title including punctuation). Is there some sort of processing I need to do before setting the title criterion?

Thanks!

I've tested your code with a similar query in a local database and am getting the results you'd expect. So the code seems accurate. Aside from environmental variables that may be at play, the only part of the example code above that I see a potential issue with the line:

$criteria->section = 'entryHandle';

It's unclear what you may mean by entryHandle.  This value should be the sectionHandle. If entryHandle means slug, then the $criteria->section may need to get updated to be $criteria->slug = 'entryHandle';


Clearing temporary assets from craft/storage/runtime After some unsuccessful uploads I ended up with a lot of loose files in craft/storage/runtime/assets/tempuploads

They show up in the asset list when selecting assets for new entry. How do I remove them completely from the record?

Tried manually deleting them via FTP and running "Update Asset Indexes" but that didn't work. Also tried "Clear Caches" options.

In Craft 2 the only real solution is to delete all the entries from craft_assetfiles where the sourceId is set to null.

The reason why there's no clear cache tool for these is because that might allow for deletion of Assets that were just uploaded by someone else who might be about to use them.

This is really far from a practical solution and we know that, but it's not easily improved in Craft 2.

Craft 3 will slightly improve things by adding a "Temporary uploads" Asset volume which will hold all of the current user's leftover Assets, allowing you to deal with them as you would with regular Assets.


Configure Memcache per environment Is there any way to add memcache servers to use per environment? I mean, one server for dev, one for staging and one for production.

Your craft/config/memcache.php config file has the same multi-environment config support as any other of Craft's config files.

You can see all the default memcache config options Craft ships with in craft/config/etc/config/defaults/memcache.php.


Get all orders which contains a certain product type In want to print a list of orders:

{% set orders = craft.orders.completed(true).limit(null).all() %}

Now I want to make a list of orders with only the product.type XYZ.

I tried to fabricate something out of this question. But I'd like specific product types:

{% set orders = craft.orders.completed(true).hasPurchasables([type.XYZ]).limit(null).all() %}

This returns:

  Variable "type" does not exist.

How do I have to write this?

You're close. Products themselves aren't Purchasebles.

However, Variants of products are. And you can have more than one Variant of a Product.

So, we need to get all Variants of a particular Product type and then feed your query:

{# get products of a certain type #}
{% set productIds = craft.products.type('classes').ids() %}

{# get the variants from those product Ids #}
{% set theVariants = craft.variants.productId(productIds).all() %}

{# grab orders #}
{% set orders = craft.orders.completed(true).hasPurchasables(theVariants).limit(null).all() %}

You'll probably want to limit the orders returned at some point depending on how you're displaying or querying them.


Craft Commerce: Sage Pay - Redirect Required after payment? When I test with my payment gateway (Sage Pay) I get a server error stating Craft Commerce isn't providing a redirect after payment is received:

Server error 5006: Unable to redirect to Vendor's web site. The Vendor failed to provide a RedirectionURL.

This is what is shown in my error logs:

195.170.169.29 - - [20/Jul/2016:09:05:17 +0100] "POST /index.php/actions/commerce/payments/completePayment?commerceTransactionId=9&commerceTransactionHash=b965d6bb8ca17ffc475849ab878721d5 HTTP/1.1" 404 50171 "-" "SagePay-Notifier/1.0"

Does anyone know what might be causing the redirect issue?

Looks like your redirect does not contain the full url back to your site.

The error shows:

195.170.169.29 - - [20/Jul/2016:09:05:17 +0100] "POST /index.php/actions/commerce/payments/...

But I would expect to see a url starting with http://sitename.com/ since your gateway needs the full url to redirect you back to your site.

Make sure you have a siteUrl set up in your craft settings: https://craftcms.com/support/site-url


Entry Versions not showing up I just noticed that none of my recent changes in an entry don't show up in the entry-versions button in the CP.

Is it possible that these entry versions are triggered by the task runner? Because I lately disabled it 'runTasksAutomatically' => false, ?

I added a second locale to the entries and since then, the versions don't show up anymore?

Entry versions aren't managed by tasks.

My guess is you've got "Enable versioning for entries in this section?" unchecked for that section's settings in the control panel.


Deprecation Errors - How to Fix? We are in development of our new site in Craft 3 and we are getting some deprecation errors. This is keeping us from using Craft Commerce for our ordering page. Any suggestions on how to fix this?

Message Origin  Last Occurrence Stack Trace
The Purchasable::getPurchasableId() function has been deprecated. Use Purchasable::getId() instead. /srv/captioncall/templates/buy/index.twig:6 Yesterday   Stack Trace
craft.session.getFlash() has been deprecated. Use craft.app.session.getFlash() instead. /srv/captioncall/templates/buy/index.twig:33    Yesterday   Stack Trace
craft.session.getFlash() has been deprecated. Use craft.app.session.getFlash() instead. /srv/captioncall/templates/buy/index.twig:34    Yesterday   Stack Trace

I'm not sure I can tell you much more than the error messages are telling you, you need to update your twig code eg. in index.twig (line 6) where it says; getPurchasableId() change it to getId().

These errors are just warning you that a future version of Craft won't support them (I imagine it will be Craft 4, but could be sooner).

Changing e-commerce systems based on this error would not be advised as it's a very simple fix!


P&T Contact Form plugin: How can I copy "name" and "email address" in the body of the mail? I'm currently working with the Contact Form plugin from P&T. I don't need much more, but as usual the client wants to:

See the email address and name in the body of the mail (he won't understand the way it works now).

Is there a way to get this done?

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

It's actually quite simple:

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

Same thing for cc mail

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


Running module migrations I must be missing something or not understanding something.

I'm trying to build a module for an install, and I'd like to run the initial migration. So the module initial install migration for the DB lives in /modules/moduleName/migrations/Install.php.

Nothing I run from the CLI seems to work:

./craft migrate/up

Only sees what is in the root /migrations/ folder; seems counter-intuitive to have a migrations folder in my module if I have to manually move them.

./craft migrate/up --plugin=everyVariationOfAPossibleHandleItMightFind

Doesn't work ever, as the module is installed and works, but it isn't a plugin so I guess it doesn't see it somehow (looking in the wrong place in the file system I would bet).

./craft migrate/up migrationPath=@app/modules/moduleName

Craft CLI doesn't seem carry that Yii CLI param, so I can't specify a path.

What am I missing? How do others handle custom module migrations in Craft 3?

Per the Modules vs. Plugins docs, only plugins get their own migration track. Modules are considered part of the project (like templates and config files), so if there are any DB changes that need to be made for the module to run, those changes should be made via content migrations.

If the module is meant to be reused across multiple projects and does require DB migrations, then it will be better off as a plugin.


iCal feed import - Timezone query Has anyone got any experience working with iCal feeds - I have written a plugin utilising the CalFileParser library but the UK clock changes have thrown all the items out, so eg an all day event is now showing up as at 11pm the day before. For example:

BEGIN:VEVENT
DTEND:20170418T230000Z
DTSTAMP:20170412T114209Z
DTSTART:20170418T230000Z
SEQUENCE:0
SUMMARY:F4 Careers Day
UID:65d28288-9ba7-404c-85fe-b66682e2f605
END:VEVENT

Is importing as 23:00 on 18/04/2017. However importing the feed into Calendar (Mac) is reporting the event as expected at 00:00 on 19/04/2017.

If I update my site settings to BST (UTC+1) and parse the value into a DateTime object then it outputs to screen correctly, eg:

$tmp = DateTime::createFromString($item['dtstart']->date);

Outputs:

Craft\DateTime Object ( [date] => 2017-04-19 00:00:00.000000 [timezone_type] => 3 [timezone] => Europe/London )

However, on saving to my database record (to a column with AttributeType::DateTime) this date value is saved as 2017-04-18 23:00:00. This means that any attempt to retrieve and show this on my site outputs the wrong date/time.

Any thoughts on how to get my script to acknowledge the time difference and save this to the relevant record without having to tinker with the code every 6 months?

Cole

This sounds like that CalFileParser library you are using has some issues with timezones. There is a pull-request that supposedly fixes these, but I would rather exchange it for another library.

https://github.com/u01jmg3/ics-parser has the more modern codebase, seems to be actively maintained, more used, and can be installed using composer.


Show a list of pages but hide the current page from the list My setup

I'd like to show a navigation menu listing all my page entries.
In my layout file, I include a template for the navigation:

_layout.twig:

        {% include "_includes/navigation.twig" %}

        {% block content %}
        {% endblock %}

The current page is shown in the content block.

My question

Is there a way to globally access the currently viewed page, from inside the navigation.twig template. That way I could do:

{% set currentPageId = SOME_COOL_GLOBAL_FUNCTION %}
{% set pages = craft.entries.section('pages').id('not ' ~ currentPageId).all() %}

        {% for page in pages %}

{{ page.getLink() }}

        {% endfor %}

To me it looks like the entries in the section with the handle pages have their own URLs. This means that if you visit a URL that belongs to an entry in that section Craft will automatically make that entry available in the template as the entry variable. That being said your solution is in this case:

{% set currentPageId = entry.id %}
{% set pages = craft.entries.section('pages').id('not ' ~ currentPageId).all() %}

        {% for page in pages %}

{{ page.getLink() }}

        {% endfor %}

Or as an alternative:

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

        {% for page in pages if page.id != entry.id %}

{{ page.getLink() }}

        {% endfor %}

Here is a read about how Twig handles variable scope if you ask yourself why the entry variable is available in the included template:
https://nystudio107.com/blog/twig-processing-order-and-scope

Also, here is a link to Twig's docs on conditional for loops: https://twig.symfony.com/doc/2.x/tags/for.html#adding-a-condition


Is defined conditional passing, yet causes a "do not have a method or closure named" error Why is it that in the below, referencing stRow.caption causes an error despite being wrapped in an "if defined" check?

The error is:

  Craft\SuperTable_BlockModel and its behaviors do not have a method or
  closure named "caption".

I have to be doing something so catastrophically dumb that it's not sticking out yeah?

{% if stRow.caption is defined %}
    {% set caption = stRow.caption %} <<- This line causes the error
{% endif %}

Same with using a null coelescing operator or a ternary operand.

{{ stRow.caption ?? "" }} <<- This causes the error
-- or --
{{ stRow.caption is defined ? stRow.caption : "" }}  <<- This causes the error too!

All three of those should work.

Supertable: 1.0.4
Craft CMS: 2.6.2997

This is a weird twig behavior. You have to do if   stRow['caption'] is defined to make it work because of the object syntax of twig.

Sometimes the if defined statement becomes true when you don't use the array syntax


Search Plus Custom Mapping I've not managed to find any complete example of a custom mapping plugin for Search Plus—I'm wondering if anyone could steer me in the right direction?

In a nutshell what I'm wanting to do is to modify the standard Search Plus mapping to include the section handle. I think this is the function I need:

public function searchPlus_alterBasicItemMapping($mappedData, $orginalElement)
{
    $mappedData["sectionHandle"] = $section->handle;
    return $mappedData;
}

But I have no idea where to put it and how to get it to talk to the plugin...

A while since you asked, so in case you haven't figured it out yet, here goes:

To attach to a plugin hook, you need to create your own plugin. So in your plugins folder, add a new folder called SearchPlusItemMapping or whatever you want to call your plugin. In that folder you'll need to create a php file called SearchPlusItemMappingPlugin (change whatever comes before Plugin if you gave your plugin a different name. In this file, add the following lines:
    namespace Craft;

class SearchPlusMappingPlugin extends BasePlugin
{
    public function getName()
    {
        return Craft::t('Search Plus Item Mapping');
    }

    public function getVersion()
    {
        return '1.0';
    }

    public function getDeveloper()
    {
        return 'Your Name';
    }

    public function getDeveloperUrl()
    {
        return 'https://somesite.com';
    }

    public function searchPlus_alterBasicItemMapping(){}
}

And then at the bottom you add your function.


Getting fields of Matrix? How can I get the fields of a matrix field? I want to loop through the fields. I have the fields of the section, if the field.handle is of type matrix, I want to get the fields of the matrix.

Looping through a Matrix field is pretty easy, here is an example. Also read the docs on the Matrix field here - https://craftcms.com/docs/matrix-fields

{% for block in entry.myMatrix %}
    {% set handle = block.type.handle %} {# Grab the current block handle #}

    {{ handle }} {# Echo out the handle #}

    {% if handle == 'myMatrixBlock' %}
        {{ myMatrixBlock.heading }}  {# If you have a field called heading in myMatrixBlock #}
    {% endif %}

{% endfor %}

Updated

Take a look at these examples...

getting fields of a section (getFields())

How to loop through matrix block fields and pull out handle and content?


Native development log / API access? Problem:
I want to be able to log things to my Craft DB from an external app, via some sort of request.

So my first question is, is there any plans for any kind of built-in development log, or should use something like: https://github.com/themusicman/lumberjack/

Second, I'd have to set up some kind of shared key authentication so I could post to this log with an external request.

What tools does Craft/Yii already have for this process, and what would need to be custom development?

Craft has Craft::log() for that purpose. Brandon has an example of this function over here

To make this work from an external request, you can create plugin with a controller which saves incoming data (post or json) to the log.

To secure this with a key just send an additional variable and check if it's correct.
Take a look at Ben's Dump plugin, for an example of such a key-protected controller.


Error while sending QUERY packet I have a includeJS variable set that populates a javascript calendar from an entries loop, with a large amount of entries which needs to be cached.

Whenever I cache this section I get this error:

Error while sending QUERY packet. PID=11878

What's the problem here?

So turns out this is to do with the size of the packet being sent to the database cache.

My server had a limit of:
max_allowed_packet = 1M

Doubling this solved my problem.


Contact form on form submission redirects to index.twig I've run into issues with the contact form plugin - https://github.com/craftcms/contact-form/issues/156 - Any ideas

I inspected your form, and the redirect value is 45e4c422dc3ef7c10d24f04e10a42c07affd1f5456fb253747b332aed6481678thanks.

Perhaps try being more explicit with your redirect, something like: {{ redirectInput(siteUrl ~ 'thanks') }}


Querying the entry for an HTTP Referer craft.request.urlReferrer returns the full URL of the referrer, while craft.entries.uri accepts the URI only.

Do I need to split the URL just to get URI path, write a twig filter, a custom plugin?

Maybe I can’t see the forest for the trees, but it seems like there should be an easier way.

No obvious solution sticks out to me using only native Twig functions/filters.

It'd be pretty trivial to write a custom filter using parse_url(), though...


Update content inside cache tag Hello I am building a system in craft cms using the getharvest api. I have 'translated' the php api to support twig. The problem is the getharvest api is really slow (10+ seconds loading time)

I have solved this problem by using the {% cache %} tag
But now my problem is whenever content changes inside the {% cache %} you don't see the updated content but you see the same content as before.

Is there a way I can tell craft to update the cache whenever content changes inside the cache tag?

This is the code I use:

        {% cache globally using key craft.request.getParam('id') %}
            {% set range = craft.harvestapi.setRange %}
            {% set results = craft.harvestapi.getProjectEntries(id, range) %}

            Budget: {{ result.get("data").budget }}

            Uurprijs: {{ result.get("data").get("hourly-rate") }}

                    Werkzaamheden
                    Omschrijving
                    Uren

                {% for project in results.get("data") %}
                    {% set taskId = project.get("task-id") %}

                        {{ craft.harvestapi.getTask(taskId).get("data").get("name") }}
                        {{ project.notes }}
                        {{ project.hours }}

                {% endfor %}

        {% endcache %}

Thanks in advance!

Because your content is cached it "downloads" your website so it loads quick.
This can be fixed by disabling cache to users that are logged in or maybe even certain users. This way you "bypass" the cache so you see the changes as soon as your page is loaded.

unless #

Prevents the {% cache %} tag from activating if a certain condition is met.

{# Don't cache if someone is logged in #}
{% cache unless currentUser %}

You can find the cache options in the docs.

Source: https://craftcms.com/docs/templating/cache


List entries of documents in a section grouped by checkbox I'm trying to list entries in a section which are documents. Those documents are grouped by checkbox. I'd like to list the document title and the asset in the entry's url. I only want to list assets which have a specific checkbox ticket.

I was able to output and group the assets by checkbox, but I'm struggling to find that entries asset url. Any thoughts?

This is what I have so far:

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

{# get all checkbox options #}
{% set options = entries.first().documentType.options %}
{% set assets = entry.documents %}

 {% for entry in entries if entry.documentType.contains('Report') %}
    {% for asset in assets %}
       {{ entry.title }}
    {% endfor %}
 {% endfor %}

Unfortunately as expected the {{ asset.url }} returns the url of the entry and not of the asset documents which is attached to the entry.

Your assets variable is defined outside the entries loop so it is still referring to the page entry. If you move it inside the loop it should work as expected.

{% set entries = craft.entries.section('documentLibrary') %}
{% for entry in entries if entry.documentType.contains('Report') %}
    {% for asset in entry.documents %}
       {{ entry.title }}
    {% endfor %}
{% endfor %}

Rather than doing this manually however, you might also have a look at the group filter, which can group the entries array by document type.

{% set entries = craft.entries.section('documentLibrary').find() %}
{% set groupedEntries = entries|group('documentType') %}

{% for type, entriesByType in groupedEntries %}

{{ type }}

        {% for entry in entriesByType %}
            {% for asset in entry.documents %}
                {{ entry.title }}
            {% endfor %}
        {% endfor %}

{% endfor %}

Note: Also if each 'document' only contain one and only one 'asset' (i.e. pdf), then you can also get rid of the asset loop and just use {{ entry.document.first.url }}.


How to get an entry title and URI from a segment in order to create a breadcrumb navigation Is it possible to get an entry title and URI from a segment? e.g. If segment 1 has a value of 'about', I'd want to output an entry title of 'About Us', and a URI of 'mysite.com/about', and so on for other segments.

I'm trying to code up a breadcrumb menu, and my site has a mixture of Singles, Structures and Channels.

I have the following _includes/nav_breadcrumb.html template, but I'm hard-coding everything at the moment (and only have it one level deep) so it's not going to be sustainable to keep this up-to-date on anything but the smallest of static sites, hence why I'm wondering about being able to pull in entry details via the segments. Thanks for any help with this.

Home &raquo;

{% if craft.request.getSegment(1) == 'about' %}
  About

{% elseif craft.request.getSegment(1) == 'news' %}
  News

{% elseif craft.request.getSegment(1) == 'contact' %}
  Contact

{% endif %}

If your site is mixture of singles, structures and channels then there is no easy way to get the entry titles and or uris from the segments alone. You would have to add some logic based on your known site structure. And even then, you might need to make a lot of requests to retrieve the data. You would likely need to do a combination of static logic, looking up titles and uris based on section/handle, and looping through ancestors within a structure.

You could potentially use the segments themselves, if you where confident that the slugs always matched the titles (or were close enough), and that the uri's where all valid.

{% set segmentUri = "/" %}
{% for segment in craft.request.segments %}
    {% set segmentUri = segmentUri ~ "/" ~ segment %}
    <a href="segmentUri">{{ segment|replace('-',' ')|ucwords }}
{% endfor %}

There is also another technique that involves defining the breadcrumb using an entries field on the entry itself that you might consider — which is described in the documentation on How to create Breadcrumbs.


Comparing 2 versions of an entry and highlighting the changes I'm new to Craft and I'm wondering if Craft is able to display the differences within an entry in different versions.

Comparing 2 versions of the entry and highlighting the changes.

Something similar like most of the mergetools do.

I'm aware that the user can comment the last changes.

That's currently not a native feature in Craft, but you might want to consider voting for this similar feature request.

You could pull it off with a custom plugin in the meantime, too.  Since entry revisions are stored between saves, you'd need to pull that revision data from the database using the EntryRevisionsService, add the business logic for calculating the diffs and come up with a UI for displaying it.


How can I dynamically set checkboxes to be named variables? If I have a field of checkboxes, I'd like to be able to access them by the name of each checkbox as the variable name, and the 0 or 1 checked state as the value. Said variables need to be accessible beyond the for loop.

For example (doesn't work):

{% for checkbox in checkboxes %}
    {% set {{ checkbox }} = checkbox.selected %}
{% endfor %}

I've looked into things and seen answers mentioning _context, attribute(), and the like, but haven't been able to get anything to work.

In short, if I have a checkboxes field with a single checkbox whose name is my_checkbox, label is "My Checkbox", and is checked in an entry, I'd like to be able to use {{ my_checkbox }} to output "1" (i.e. it's checked).

So I had missed the entry.checkboxFieldHandle.contains('tequila') line in the docs, which allows me to access the checkbox values outside the for loop.


Extending Craft Commerce admin templates I would like to add an option to the gear menu seen below in Craft Commerce, is it possible to extend those templates ?

The idea is to create a plugin to export the selected orders to a CSV file

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

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


Imager resized image not shown (404) I'm just trying out the imager plugin. It looks promising!
I've set up the first usage example but I don't see any image on my site in the browser. The image is uploaded properly to the asset source but it seems that Imager is placing its transforms in a subfolder (in this case: '7' ->  http://craft-imager.dev/imager/images/7/nature-13_d4e4e04a52bfbdbeab5ba4d2cf1d1390.jpg)

The subfolder '7' doesn't exists on my machine..

I did some digging around, but I can't figure out what's wrong. The directory 'imager/images' exists and is writable by PHP.

Any idea?
Thanks in advance!

Solution:

I have this line inside my config.
define('BASEPATH', realpath(dirname(__FILE__) . '/../') . '/');

And inside the imager config file imager.php I have:
'.dev' => array('imagerSystemPath' => str_replace('craft/','images/', BASEPATH),

So, make sure the paths are all set according to your environment / directory structure.


Automatically assign a user group How can I assign a user group to a user when it's created through the front end?

EDIT: So a few more details. I see there are some great answers if you want to put all users in one group, but unfortunately that's not the case. I have different forms for different groups. Ideally I would like to have checkboxes on the front end you I can choose which group they are assigned to.

Under Settings > Users > Settings Tab there is an option to allow public registration and Default User Group with a drop down that lets you select a user group.

If you need more flexibility, you could also write a simple plugin with an init function defined in the primary plugin class that listens to the saveUser event, and assigns a user group based on some criteria that you define — perhaps test the value of a custom user field on users (that is a hidden field on the registration form).

*UPDATED to assign group based on checkbox field called 'groupPreference':

namespace Craft;
class BusinessLogicPlugin extends BasePlugin {
  public function getName() {
     return 'Business Logic';
  }
  public function getVersion() {
     return '0.1';
  }
  public function getDeveloper() {
     return craft()->getSiteName();
  }
  public function getDeveloperUrl() {
     return 'http://mysite.com';
  }
  public function init() {
     parent::init();

     craft()->on('users.saveUser', function(Event $event) {

        // only fire if new user
        if ($event->params['isNewUser']) {

           // retrieve the userModel from the event
           $user = $event->params['user'];
           // retrieve the groupPreference field content
           $groupPreference = $user->getContent()->groupPreference;
           // create an empty array to store group ids
           $groups = array();

           // test for values in groupPreference array
           if (in_array("group1", $groupPreference)) {
              $groups[] = 1;
           }
           if (in_array("group2", $groupPreference)) {
              $groups[] = 2;
           }
           if (in_array("group3", $groupPreference)) {
              $groups[] = 3;
           }
           // assign the user to the groups
           $_POST['groups'] = $groups;
        }
     });
  }
}

Haven't tested, but should be pretty close. Please comment if you see an error.

Keep in mind this event will fire, whenever this field is defined, even when saving a user through the CP. So you would have to delete the value before reassigning the user to a different group, or they will just get reassigned.


Dukt Twitter Plugin, problem with "search/tweets" or request to Twitter REST API we're using the Dukt Twitter plugin 0.9.25 and it works fine with calling the user's timeline:

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

If we request any other data like

    {% set tweets = craft.twitter.get('search/tweets', {q:'#craftcms',}) %}

we're receiving two tweets which are empty. Anyone else having these problems and found a solution?

Thanks, Lars

I've tested this works on my install:

{% set tweets = craft.twitter.get('search/tweets', {q:'#craftcms'}) %}

{% for tweet in tweets.statuses %}
    {{ tweet.text }}
{% endfor %}

Have you tried running a {{ dump(tweets) }} to see what you get?


Can Craft be used on same site as other eCommerce Solutions Is it possible to have a Craft installation on the same site as another ecommerce solution like OpenCart or OSCommerce?
Reason being those and some others are already linked with Sage and would like to keep the general content of the site updated using Craft.

You shouldn't have any issues running multiple applications on the same host but it would be smarter to decouple the different applications and build a bridge between them.

I've never worked with OSCommerce or OpenCart so I can't speak to the specifics of what's involved in doing that but if your high-level goal is to run Craft on the same server as the other application(s), that should be fine.


Set Twig variable with javascript/jquery for displaying entries based on clicked value I have a filter system on my website which uses categories. The categories have all got their own ID tagged to their HTML Element. Now I just need to get the clicked checkboxes to add their ID to the Twig variable which displays the entries in the for loop.

{% set categories = craft.categories.section('retrospect') %}

{% set relatedCategories = [] %}

{% for category in categories %}
  {% set relatedCategories = relatedCategories|merge([taggedIds]) %}
{% endfor %}

{% set related = craft.categories.section('retrospect').id(relatedCategories) %}

{% set relatedArticles = craft.entries.section('retrospect').relatedTo(related) %}

{% for entry in relatedArticles.order('caseNumber asc').after('2016-01').before('2016-12') %}
  {{ entry.title }}
{% endfor %}

The Twig code to fetch entries occurs on page load - Your JS code will run after the page loads and won't be able to update/fetch new entries. Instead, you should look at building a system that uses query strings to add the id's to the Twig variable on page load - then enhance this using AJAX.


How do I preserve user sessions across subdomains? I have defaultCookieDomain set to .site.com
I am logged into www.site.com
I expected to also be logged into sub.site.com (which is pointing to the same web root), but I'm not.

What am I missing?

Figured this out, the appId setting was the culprit: https://craftcms.com/docs/config-settings#appId

If using this setting, you probably don't want to set it to something dynamic (as I was, e.g. md5($url)).


How to have Craft 3 and 2 on same host? I have a Craft 2 installation that I'm upgrading to Craft 3.

I've got v3 running locally in its own virtual host, but now I need to temporarily put the dev v3 instance in the same hosting account as the live v2, with the v3 instance resolving at a dev subdomain:

account root
    craft              <-- v2 system
    craft              <-- v3 executable
    config … templates <-- other v3 dependencies
    public_html        <-- live web root
    dev                <-- dev web root

Given the naming conflict between the v2 system folder and the v3 executable, can I exclude the v3 executable and have v3 still run?

Or can I put all the v3 stuff in its own folder still above web root and then tell the dev index.php where to find it? It's not clear to me from the doc on customising directory structure that I can do that.

I know there is a doc on moving Craft files but that focuses on moving into web root (in my case, dev web root), which I don't want to do.

Both the craft/ folder name in Craft 2, and the craft executable in Craft 3, can be renamed.

Since the craft executable is user-facing (when SSH’d in), I’d recommend leaving that alone and rename your craft/ folder to something else, maybe craft2/. Then in public_html/index.php, update your $craftPath variable to point to the new location:

$craftPath = '../craft2';


User registration form with checkbox field Hi I have user registration form with multiple custom fields. They all work fine except for the field I have as a checkbox. It returns an error of 'my-field' is invalid. Any ideas anyone? code below (field in question is towards the bottom)...

<form method="post" accept-charset="UTF-8" class="login-form">
            {{ getCsrfInput() }}
            <input type="hidden" name="action" value="users/saveUser">
            <input type="hidden" name="redirect" value="{{ url('collection/') }}">

Register

To browse our collection please register your information below.

Already registered? Login.

            {{ entry.contentBeforeForm }}

            {% macro errorList(errors) %}
                {% if errors %}

                        {% for error in errors %}

{{ error }}

                        {% endfor %}

                {% endif %}
            {% endmacro %}

            {% from _self import errorList %}

First name

            <input id="firstName" type="text" name="firstName" {%- if account is defined %} value="{{ account.firstName }}"{% endif %} placeholder="First name">
            {{ account is defined and account ? errorList(account.getErrors('firstName')) }}

Last name

            <input id="lastName" type="text" name="lastName" {%- if account is defined %} value="{{ account.lastName }}"{% endif %} placeholder="Last name">
            {{ account is defined and account ? errorList(account.getErrors('lastName')) }}

Company

            <input id="company" type="text" name="fields[company]" {%- if account is defined %} value="{{ account.company }}"{% endif %} placeholder="Company">
            {{ account is defined and account ? errorList(account.getErrors('company')) }}

Phone

            <input id="phone" type="text" name="fields[phone]" {%- if account is defined %} value="{{ account.phone }}"{% endif %} placeholder="Phone">
            {{ account is defined and account ? errorList(account.getErrors('phone')) }}

Username

            <input id="username" type="text" name="username" {%- if account is defined %} value="{{ account.username }}"{% endif -%} placeholder="Username">

            {% if account is defined %}
                {{ errorList(account.getErrors('username')) }}
            {% endif %}

Email

            <input id="email" type="text" name="email" {%- if account is defined %} value="{{ account.email }}"{% endif %} placeholder="Email">

            {% if account is defined %}
                {{ errorList(account.getErrors('email')) }}
            {% endif %}

Password

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

            {% if account is defined %}
                {{ errorList(account.getErrors('password')) }}
            {% endif %}

            {# HERE IS THE FIELD CAUSING THE ERROR #}

            <input type="checkbox" id="termsAgreement" name="fields[termsAgreement]" {%- if account is defined %}value="1" checked{% endif %}>
             I agree to terms and conditions above

            {{ account is defined and account ? errorList(account.getErrors('termsAgreement')) }}

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

        </form>

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

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

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

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

name="fields[myCustomField][]"

Here's my code thats working:

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

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


Trouble with Custom Command in Custom Plugin. How do I do it? I found the documentation here very confusing: https://craftcms.com/docs/3.x/extend/commands.html#module-setup
I've scaffolded a simple test plugin from https://pluginfactory.io/ with "Console Commands" enabled and I've pulled my plugin into composer via 'path'. The plugin shows up fine in the Craft UI, and so I installed it.
However, I can't get the new command to display in the terminal when I do a 'php craft'. Am I supposed to see it?

You should see your commands when using the Craft CLI.
First thing to check would be that the module is registered in app.php, both in the modules and bootstrap arrays. Craft's documentation on that is here.
I find the best way to quickly validate that your module is registered, is by dumping something out from the module init() function. Craft::dd('Registered') does the trick. If you don't see anything on the frontend, your module isn't getting loaded into Craft.
Secondly, I would check that you are correctly setting the controllerNamespace, so that Craft knows where to look for controllers, depending on your request. Their documentation on that is here.
Finally, check that you have some valid functions setup in your controllers. Each function name should be prefixed with action. For example: actionRun() in a JobController.php file will be run with php craft mymodule/job/run.


Craft Commerce, variable product prices based on weight. Is this possible? I'm trying out the Craft Commerce plugin, and i'd like be able to let users order products with a custom price based on a choosen weight.

The price is now fixed to what you choose in the control panel, and there seems to be no easy way around that, but perhaps i'm wrong.

Is this possible? It's pretty crucial feature i need, so any help is appreciated :)

Cheers, Bob

1oz = $1 ∴ 10oz = $10

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


how to add a plugin? I want to add a 301 redirect plugin to a Craft CMS 2.6 website. I only have user permission as well.

Please give me steps on how to add my redirects to the back-end of the site?

You need access to the server your Craft site is installed on to install the plugin code in the craft/plugins folder.

In addition to that, you will need administrator access to the Craft Control Panel to access Settings->Plugins in order to install any plugins.

Most likely, you'll need to contact the administrator of your site or whomever developed/still maintains it to progress.


How to get entries between a time I'm using Craft 3 and I would like to do the following thing:

There is a start date and an end date filed in entry, is it possible to get entries that are between these two dates in PHP?

Thank you!

Entry::find()->startDate('>='. $someTime).endTime('<='.$someOtherTime).all();

Those variables can be timestamps, DateTimes or a correctly formated time string.

Here are some variants of these filters

Entry::find()
    ->variantOne('<=' .  Db::prepareDateForDb(new \DateTime())) <-- DateTime object
    ->variantTwo('<=' . time())  <-- as timestamp
    ->variantThree('<=' . (new \DateTime())->format('U')) <-- timestamp as well
    ->variant(['and', '<=' . time() , '>=' . time() - 3600]) <-- entries within the last hour
    ->validString(['or', '>=' . (new DateTime())->format('Y-m-d H:i:s'), '<= ' . time()])


Steps to publish a craft website from local to server is there any resource that list all the steps to publish a local finished website to the final server?

Thanks!

It probably depends most on your hosting but following these instructions are probably your best bet: http://buildwithcraft.com/docs/installing The only exception being instead of "installing" you'd move your files up and import your database.

If you are using github, it's as easy as "pulling" your code to your production server and importing the database into production database as well (local mysql, cloud db etc.)

You'll probably be best off looking at http://buildwithcraft.com/docs/multi-environment-configs so you can create settings for both your local environment and production.

Here's an example of a sample craft database file: https://gist.github.com/mccombs/5e17c84743a25dafddb9

Here's an example of a sample craft general config file:
https://gist.github.com/mccombs/b6a161cabc064d1f51b3

Hope this helps!


How to saveElement in EVENT_AFTER_SAVE_ELEMENT without infinite loop I am trying to update an entry's title in a Craft 3 module after an entry is saved. I cannot use EVENT_BEFORE_SAVE_ELEMENT because the title gets updated after this. If I use EVENT_AFTER_SAVE_ELEMENT to update the title and then do saveElement the event gets called again and I get into an infinite loop.

Event::on(Elements::class, Elements::EVENT_AFTER_SAVE_ELEMENT, function(Event $event) {
    if ($event->element instanceof \craft\elements\Entry) {
        if ($element->section->id == 1 && $element->typeId == 1) {
            $element = $event->element;
            $newTitle = "new title"; // logic goes here
            $element->title = $newTitle;
            Craft::$app->elements->saveElement($element); // causes loop
        }
    }
});

Is there a way to do this? Thanks.

I got this working by using the EVENT_BEFORE_SAVE_ELEMENT and adding the asset to the entry asset field 'pdfThumbnailImage' by using the setFieldValue.

 $entry->setFieldValue('pdfThumbnailImage', [$assetId]);

You dont need to save the element - leave this out

 Craft::$app->elements->saveElement($element); // causes loop


Email notifications solspace calendar I'm considering the Solspace Calendar plugin for a project.

Can the plugin send automatic e-mail notifications when an event has been submitted from the front-end?
Can the plugin save events submitted from the front-end as drafts?

Thanks.

To answer your questions:

Currently this isn't possible out of the box with Calendar. Perhaps there's some other plugin or custom module that can allow for this.
You cannot save them as Drafts, but they can be submitted as Disabled if you like. Just be sure to include the following hidden fields in your form:

<input type="hidden" name="enabled" value="0" />
<input type="hidden" name="enabledForSite" value="0" />


Frontend upload for images, mp3s and video? I would like to allow users of our site to be able to upload images, mp3's and video from the front-end. Can I do this with the entry form template easily enough?

I was thinking maybe I could use Wistia for the video upload with their widget.

Yes you can do that with an Entry Form in your template.

Have a look at the assets fields article in the docs, there is a small section about uploading files from front-end forms.


How to setup a multi-lingual site on IIS I've been trying to setup my site on IIS, which runs fine on Apache, without success.

My setup is this (with rewrites)
/ (loads craft for the admin panel)
/en (loads the english homepage)
/fr (loads the french homepage)

The root works without any issues so the web.config does its job.
The same web.config lives in the fr and en folder, but as soon as I try to get in there, I hit a 500.

If I remove the web.config from those 2 folders, I get the homepage of each language, but nothing for the entries.

Anywone knows how to get it to work ?

I'm also trying to get everything working with a single php file that checks for the lang in the p parameter and sets it, but Craft doesn't receive the good slug, even if I modify the p parameter to remove the language.

Thanks

Looks like it was only because I was missing the clear tag in my rules in the subfolders.  Everything works like a charm now.


When using getCriteria() along with buildElementsQuery() raw html gets displayed by the template I am trying to use getCriteria() along with buildElementsQuery () in my plugin in order to eventually modify the query.  At the moment, I am not making any modifications to the query.

But when the the fields are outputted in the template, I ended up getting raw html on the screen.  Not nicely formatted HTML.  For example, the paragraph tag shows as <p> and in the source of the page it is &lt;p&gt;.  The <p> should only be in the source.

How do I get the template to display the nice html and not the raw html?

In my plugin service

public function getMyLibrary()
{
    $criteria = craft()->elements->getCriteria(ElementType::Entry);
    $criteria->section = 'library';
    $criteria->limit = 10;

    return ($criteria->find());

}

In my template:

{% set my_library = craft.accd.my_library() %}

{% for entry in my_library %}

    {{ entry.title }}
    {{ entry.body}}

{% endfor %}

Everything works as expected and the rich text html from the body displays correctly.

But when I change it to use buildElementsQuery as I will modifying the query, the entry.title and entry.body get displayed in the template as raw html.

Here is the code with the buildElementsQuery added.  I had to also modify the field body to be field_body in the template.

In my plugin service

public function getMyLibrary()
{
    $criteria = craft()->elements->getCriteria(ElementType::Entry);
    $criteria->section = 'library';
    $criteria->limit = 10;

    $query = craft()->elements->buildElementsQuery($criteria);

    return ($query->queryAll());

}

In my template:

{% set my_library = craft.accd.my_library() %}

{% for entry in my_library %}

    {{ entry.title }}
    {{ entry.field_body}}

{% endfor %}

$query->queryAll() returns raw arrays of data from the database, this is why you're needing to prepend field_ to each attribute, to get the column name.

You need to populate some EntryModels before you can use them properly in the templates, with something along the lines of:

$query = craft()->elements->buildElementsQuery($criteria);

// modify the query here

$results = $query->queryAll();

return EntryModel::populateModels($results);


Why are all Craft files executable? I just downloaded the latest version of Craft (2.3.2617) and extracted the zip to check it out. Every file has execute permissions turned on for all users. Is there any reason for this?

Folders need to be executable for Apache/PHP to be able to open them and read their contents.

I'm guessing it's more of a a case of our build script being overly aggressive and setting the execute bit on files.

From what I can tell, though, setting the execute bit on a PHP script is effectively pointless.


How do I get different URL Format with parent/child structures & how do I display different templates? I need to create a features structure section for a website that will have parent features and child features.

Q1: How do I get different URL Format for parent & child pages?

I need the parent features here: website.com/features/parent-feature
And the Child features here website.com/parent-feature/child-feature

Q2: How do I display the Parent & Child in different templates? I want the parent features to look more dominant than the child features.

To get different URL Format for parent & child pages, you need to go to the CP structure settings and edit the Entry URI Format. This is how your URI should look like:

{% if level == 1 %}features/{slug}{% else %}{parent.slug}/{slug}{% endif %}

For your templating question, if you want a different template for parents and children, you need an if statement in your template file for that structure. So in your CP structure settings, you will have one template file:  features/feature_entry.twig and inside that file you will have:

{% if entry.children|length %}

   <!-- If it has a child, it's a parent page -->
   {% include 'features/_parent.twig' %}

{% else %}<!-- it's a child page -->

   {% include 'features/_child.twig' %}

{% endif %}

Just like that... You now have 2 different templates in 2 different .twig files.


Any examples of numeric pagination? I can find examples of prev/next style pagination but none of creating proper numeric-style pagination (eg. how Google do it).

Does anyone have an example I could use?

Sure, http://buildwithcraft.com/docs/templating/paginate

{% paginate craft.entries.section('blog').limit(10) as entries %}
    First Page
    {% if paginate.prevUrl %}Previous Page{% endif %}

    {% for page, url in paginate.getPrevUrls(5) %}
        {{ page }}
    {% endfor %}

    {{ paginate.currentPage }}

    {% for page, url in paginate.getNextUrls(5) %}
        {{ page }}
    {% endfor %}

    {% if paginate.nextUrl %}Next Page{% endif %}
    Last Page

This outputs something along the lines of: First Page, Previous Page, (nearby page numbers), Next Page, Last Page


Separate path for Element API plugin Is it possible to have a dev version path for the Element API plugin so we can keep live and dev API separated?

Craft config files usually allow to return environment-specific arrays. So you could just configure different endpoints like so:

return [
    '*' => [],
    '.com' => [
        'endpoints' => [
            'api/example<ext:(.json)?>' => function() {
                // example API config for live environment
            },
        ],
    ],
    '.dev' => [
        'endpoints' => [
            'api/example<ext:(.json)?>' => function() {
                // example API config for dev environment
            },
        ],
    ],
];


Entry UrI Format and ternary operators I tried setting up a URL format that takes the hierarchy of a structure into account, but deals with the magic __home__ slug transparently.

So I did this:

{parent.uri == '__home__' ? '' : parent.uri}/{slug}

Which works, but I wanted to tighten it up using the twig ternary ?:, like this:

{parent.uri != '__home__' ?: ''}/{slug}

But that doesn't work at all, seems to choke on the ?: part. Is that a bug, or just a short-coming of the URL format system (not being actual twig)?

I don't think the ternary operator does what you want it to do. According to this page, the first part of your URL format would return 1 (true) if the parent uri is not __home__, or an empty string if it is.

You could try:

{ parent.uri != '__home__' ? parent.uri }/{slug}


Can multi-environment configuration be used in 'index.php'? On my local dev sever, as well as the production server, the craft folder is one level above web root, so $craftPath in index.php is set like so:

$craftPath = '../craft';

On the staging server, the craft folder is two levels above web root, so $craftPath needs to be:

$craftPath = '../../craft';

Can this be accomplished in a single index.php file? Something similar to the multi-environment array in config/general.php and config/db.php perhaps?

Should be able to. Use a switch statement to check on the host and then server up the correct environment configuration like so:

public/index.php:

switch (strtolower($_SERVER['SERVER_NAME']))
{
    // Staging
    case 'stage.mydomain.com' :
        define('CRAFT_ENVIRONMENT', 'stage');
        $craftPath = '../../craft';
        break;

    // Local
    default :
        define('CRAFT_ENVIRONMENT', 'local');
        $craftPath = '../craft';
        break;
}


Converting existing content to a different locale I am in the process of building my first multilingual Craft site.

The site will have two languages:

English (default)
Spanish

When setting up the site, I chose U.S. English and Spanish - United States as the respective locales.

I am now thinking it might be better to keep the languages less specific to the United States and would like to switch the two to English and Spanish.

My question is if it is possible to do this without losing any content that has already been entered under both U.S. English and Spanish - United States.

Thanks!

Currently it's not possible to edit a locale from the CP, which means you have to edit it directly in your db.

Edit locale:

UPDATE craft_locales SET locale = 'en' WHERE locale = 'en_us';

Edit elements:

Each element (entries, assets, users, etc.) which can be translated has a locale-column:

UPDATE craft_categorygroups_i18n SET locale = 'en' WHERE locale = 'en_us';
UPDATE craft_content             SET locale = 'en' WHERE locale = 'en_us';
UPDATE craft_elements_i18n       SET locale = 'en' WHERE locale = 'en_us';
UPDATE craft_entryversions       SET locale = 'en' WHERE locale = 'en_us';
UPDATE craft_sections_i18n       SET locale = 'en' WHERE locale = 'en_us';

Edit permissions:

UPDATE craft_userpermissions SET name = 'editlocale:en' WHERE name = 'editlocale:en_us';

Check:

To be sure you've got them all do a sql search for en_us.


Throwing 500 error, but nothing logged in error logs or apache logs? I am trying to export query data to a CSV file, everything works fine when I limit the number of rows to 500 ($criteria->limit), but when I increase it to around 530 it gives a 500 Internal Server error. I changed PHP timeout time to 300 from 30 seconds and the issue is still there. I feel like it might be a memory issue or a PHP issue. Does anyone has this happened to them, if so how could you fix it?

It's likely environmental/configuration related and unfortunately some hosts do some things to make it really hard to debug stuff like this.

Off the top of my head, some common ones are if you've got something like Suhosin or mod_security installed, then they have their own configuration limits on top of the usual PHP/Apache limits that might be coming into play.

Or if you're running nginx/php-fpm as a proxy in front of Apache, you might be bumping into its configuration limits.

Or we've seen some hosts <cough>RACKSPACE</cough> that have hard-coded execution times of 30 seconds at the router/firewall level and there is absolutely nothing you can do to get around it, other than the obvious thing, which is to never use Rackspace.


Displaying An Entry's Image on Edit Page Currently, these Entries display just the title. Has anyone found a way to display entries as a thumbnail (from it's image field)? I'm starting to look at plugins, but haven't seen anything that would help yet.

This is not possible natively, and as far as I know there's currently no plugin to get a such display. You could develop you own plugin with a new custom field type.

However, if you double-click on this Entry you are able to view its fields within the small pop-up window. Maybe that could help if you need a quick preview of its image field.

You could also rethink the way you add your Work Entries: maybe this could be an Assets field instead of an Entries field. Like this, you would be able to display the thumbnail.


Is there any way to hook into saving a plugins settings? I'm attempting to create a plugin that is going to create some basic fields/sections as a post-installation setup. I don't really want to create a full-blown CP entry so is there any way of just doing stuff when the user clicks "save" in the settings template?

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

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


Site search that matches in more than one field I'm wondering how to conduct a site search that takes search words and matches them in more than one field. So for example if I have an entry with fields that contain the following words:

Description Field: foo

Body Field: bar baz

A search for 'foo', or 'bar', or 'bar baz' finds the entry, but a search for 'foo bar' does not.

I have rebuilt the search index.

foo bar implies foo AND bar by default.  What you're probably looking for is foo OR bar.

If you look at craft_searchindex, you can see that keywords for fields are indexed on a per field basis, which is why you'd need the OR to search across multiple fields.

You can omit OR if you already know the field names ahead of time, though. field1:foo field2:bar.

You can see more search syntax options here.


Making a base url without /public I'm creating a site that works now at www.mysite.com/public/

I would love to get to drop the /public off the url so it is:

www.mysite.com

Does anyone know how to do this?

Thank you!

This is not so much a Craft question as a web server question.

The directory structure of Craft is intended for the web server to have the public (or web in Craft 3) directory configured as the document root.

This is a configuration setting you’ll find in your Apache, Nginx or other web server documentation.


Calling Craft API from node.js I really love working with Craft, especially around how easy and user friendly it is. However, I do work with React/Vue and usually I setup a node server/app that will do some routing, render views and so on...

Would it be a good idea to have a setup like this:

Frontend: React / Vue
Backend: node app that has all my public routes setup, rendering views, server side render React/Vue etc
Backend no 2: Craft CMS with Element API setup

Example:

User requests /contact/person-1
The request will be matched in my node app as a valid route
Node app will make request to the API that has been setup for Craft, fetches the relevant info about Person 1, returns the result to node
Node app renders the view with the data that was fetched

Is this O.K. or completely nuts? Will it be ineffective or is it a good way to structure it like this when I'm in need for a nice CMS like Craft... ?

Please help me out on finding the best approach!

Sounds like you're using craft in 'headless' mode. I've heard about that for drupal, but not for craft. I don't see any reason why it wouldn't work. You get the craft UX for creating and modifying entities, but use node as a proxy and view generator.


Craft TaskService Overview/Cron Job I am trying to get my head around the TaskService that Craft comes with. I want to create a task that periodically (say every 15 minutes) uses the Twitter API. I am currently creating a task modeled on Pixel & Tonic's PowerNap which was very helpful, but I still don't understand how the tasks are triggered.

In the createTask method I didn't see any duration or anything like that and if the tasks are created within a controller that would have to be posted to, would this require a tandom cron job to trigger it from the server?

Any clarifications, insights, or references that might be helpful in better understanding the TaskService would be greatly appreciated as the Class Reference's docs aren't really that helpful.

Thanks!

Craft's tasks are meant for long-running PHP requests and don't have to execute immediately.  By default when you create a new task, it is queued in the database in the craft_tasks table and it takes a control panel request to trigger it to run, so with that method, there's no guaranteed way to have it run every 15 minutes.

However, if you set the runTasksAutomatically config setting to false, then you can setup an cron job that runs at any interval you wish.  You'd point it to a controller action on your plugin and manually trigger the task that way.


Output tags in the order they were added to an entry Is it possible to output tags for an entry page in the order they were added to related entry?

For example on a News page I would like to output any/all tags added to the News article on the specific article page in the order the tags were added to that article, I currently output the tags using the following:

        {% for tag in craft.tags.relatedTo(entry) %}
            <li>{{ tag }}</li>
        {% endfor %}

This works great as it only outputs the tags that have been added to that entry, but it shows the tags in the default title ascending order rather than reflecting the order on the entry.

I can switch the order by setting it to desc on the title .order('title desc') and I've also read through the docs on ordering but I'm still not sure how to achieve this.

Thanks,

I managed to solve this by defining the tags as a ElementCriteriaModel. Instead of using the code above I used the following:

{% set tags = entry.tagsFieldHandle %}

{% if tags | length %}
   {% for tag in tags %}
      <li>{{ tag }}</li>
   {% endfor %}
{% endif %}

Explained further in the Tag section in the docs. {% set tags = entry.tagsFieldHandle %} is a shortcut for:

{% set tags = craft.tags({
   relatedTo: { sourceElement: entry, field: "tagsFieldHandle" },
   order:     "sortOrder",
   limit:     null
}) %}

This meant I didn't need to define the entry relation as the model does that be default and it also sorted the tags as they were defined in the entry with the "sortOrder" (which is also default).


How to use category in auto generated title? I have an entry which has a category field. I want an auto-generated title for this entry that uses the assigned category title (first category title in case of multiple categories). I am not sure what to insert in the "Title Format" field.

In the Title Format field, try:

{categoryFieldHandle[0].title}


How do you add a core twig extension in plugins using addTwigExtension()? Is it possible to activate the following Twig extension from within a craft plugin:

http://twig.sensiolabs.org/doc/extensions/date.html

The Twig extension package is not included with your Craft install. So you need to download it and add it to your Craft plugin manually.


Search for the entry Id with the search form A customer of mine has printed references of the entry Ids of their product. Now they want to have a search form on their website where it's possible to search either by the name or by entry Ids.

How can you search for an entry id and other fields at the same time in a search form?

This currently isn't possible with Craft's native search solution.

Element IDs aren't indexed in the craft_searchindex table in the database.

As a workaround you could maybe use the Preparse plugin to copy the entry ID into a custom field called "entryId" so you could search via entryId:####.


Creating a matrix entry with a plugin I'm working on a plugin to save user profile data. I have a matrix field called addressMatrix, I've made address a matrix because users can save multiple addresses. Every address entry will have the following fields:

streetAddress
city
stateProvince
postalCode
country

NOTE: I did associate the field with users.

All I want to do is to be able to save a new address or update an existing address for each user. I have no idea where to begin.

I've looked at 1 or 2 Stack Exchange posts on the matter but it does not look like anyone else has raised this question. Sorry in advance... I have no code to post as I don't even have a solid starting point.

Thank you for any help you can provide.

UPDATE

Here's the code I have thus far:

// Load the user
$userModel = craft()->users->getUserById($profileDataModel->userId);

// Load the matrix field
$addressMatrix = craft()->fields->getFieldByHandle("addressMatrix");

$block = new MatrixBlockModel();
$block->fieldId    = $addressMatrix->id; // Matrix field's ID
$block->ownerId    = $userModel->id; // ID of entry the block should be added to
$block->typeId     = 7; // ID of block type

$block->getContent()->setAttributes(array(
    'streetAddress' => '1523 Kansas Ave'
));

$success = craft()->matrix->saveBlock($block);

The above does work, but what I'm current stumped on is how to get the type ID programmatically. I should be able to get a block ID by the block handle. Looking through the class reference I don't see it.

In case anyone is interested this is how I solved the problem:

First load the matrix field:

$addressMatrix = craft()->fields->getFieldByHandle("addressMatrix");

Then get all of the blocks of the matrix field:

$addressMatrixBlocks = craft()->matrix->getBlockTypesByFieldId($addressMatrix->id);

Next iterate over the blocks looking for a specific handle:

foreach($addressMatrixBlocks as $key => $data){

    if($data->handle === "address"){

    $addressBlock = $data;
    break;

    };

};

Now you have your block. To get the ID just do this:

echo $addressBlock->id;


Craft equivalent to EE snippets for use in templates? I am new to Craft from EE. I have a snippet of code which I will be reusing in several templates. I see Globals but that doesn't seem like like what I am looking for. What is the proper method of doing this within Craft? Thanks

Craft uses Twig, and Twig uses macros for reusing snippets of code within templates.

In your macro file (for instance, macro/userMacro.html), you can create a macro:

{% macro hairColor(user) %}
    {{ user.hairColor }}
{% endmacro %}

Then, in any other file (or in your main _layout template, for that matter), you can import and use this macro:

{% import "macro/userMacro" as userMacro %}

{% for user in craft.users %}
    {{ userMacro.hairColor }}
{% endfor %}

Place your import-tag at the top of your _layout file, and you will be able to use it in every template that extends it (or is included by it).


How to access Craft.EditableTable instance in CraftCM I am developing a custom plugin that has a variable setting that can take multiple options. I've decided to use forms.editableTable from Craft's _includes/forms. It does the job great, saving and retrieving the settings.

Now I am trying to add validation to the columns on the table: the validation model is set and I am correctly passing the errors to the "right" position (Meaning I get the row index and which column has the error).

I know Craft.EditableTable has the getRowHtml method that I can use to retrieve the row and apply error classes to the field(s).

I've watched the Javascript in the Control Panel video, but Craft.EditableTable doesn't set a data attribute with it's instance.

Is there any other ways to get it?

Thanks!

So, after fiddling with it for a while, this is what I came up with it:

When using forms.editableTable make sure you don't initialize Craft.EditableTable. You can do that by setting the initJs to false:

{{ forms.editableTable({
    id: 'myTableId',
    name: 'myTableName',
    cols: yourTableCols,
    ...
    initJs: false,
    ...
}) }}

That means that you will have to initialize the Craft.EditableTable yourself:

{% includejs %}
(function () {

  var t = new Craft.EditableTable(
    "{{ 'myTableId'   | namespaceInputId   | e('js') }}",
    "{{ 'myTableName' | namespaceInputName | e('js') }}",
    {{ yourTableCols|json_encode|raw }},
    {
      onAddRow: function( tr ) {
        // attach event listeners to row fields here
      }
    }
  );

} ());
{% endincludejs %}

From this point on, you can add your own listeners to the fields in the row.


How can I display related entries selected within a Matrix field? Consider an employee listing...

I have 2 sections: 1 for companies, 1 for personnel.  In the personnel section, there is a matrix field within which one field is a relational one to relate the staff member to his company.

On the front end, I'm attempting to display a listing of all staff associated with a particular company.

I can't seem to get the relational fields to work in the way that I want. I know I'm missing something basic here.

{% set employer = craft.entries.section('companies').slug(segment) %}
{% set personnel = craft.entries.section('people').relatedTo(employer) %}

{% for x in personnel %}
    {{ x.title }}
{% endfor %}

// Output: nothing

Is there something particular to Matrix fields that changes how I might do this?  I've tried using the targetElement parameter but still can't seem to get it to work.

Thanks for the help!

When you relate an element from a Matrix block, it's important to know that the relation is between the Matrix block and the related element; nor the entry (or whatever has the Matrix field) and the related element.

So, the correct way to select related elements through a Matrix field is:

{% set employer = craft.entries.section('companies').slug(segment) %}
{% set personnel = craft.entries.section('people').relatedTo({
    targetElement: employer,
    field: "matrixField.relationField"
}) %}

Update: Added a missing } on the last line.


ImageOptimize not using image url specified in my multi-environment setup and my volume config When I output my ImageOptimize field in the template, my images are not showing up. If you inspect the image url, it's missing a folder name I'm specifying as part of the url in my multi-environment setup and volume config.

If I manually change the image url in the browser tools to include the missing folder, the image shows up. Other images are rendered fine when using the standard asset field code so I'm not sure what could be wrong.

Things to note:

I am using Andrew's multi-environment setup.
I have two separate folders in my web root folder:

In the folder assets/, I'm serving my template assets like css, images, and fonts.
In the folder content/, I'm serving the files uploaded to the volumes I have setup in Craft - images, logos, documents etc.

My environment variables:

'BASE_URL' => $protocol . $httpHost . '/',

'BASE_PATH' => realpath(dirname(__FILE__)) . '/web/content/',

My aliases (set for all environments):

'aliases' => [
    '@basePath' => getenv('CRAFTENV_BASE_PATH'),
    '@baseUrl' => getenv('CRAFTENV_BASE_URL'),
],

My volume config:

'*' => [
    'images' => [
        'path' => '@basePath/images',
        'url' => '@baseUrl/content/images',
    ],
],

My ImageOptimize snippet:

The image path being used on the frontend (note the absence of the content/ folder):

You need to re-index your assets to show the correct URL after changes to your volume location when using imageOptimize. Just re-save the volume from within Craft CMS. Even if you have made amends to your volume config file you will need to re-save from within Craft CMS.

To quote Andrew, the plugin author...

  "So I want to say that this is normal (though maybe not desirable?)l.
  The URLs in the OptimizedImages fields get resolved at asset save
  time. So the full absolute URL to each image will resolve to whatever
  the alias is.

  Potentially this resolution could be postponed until runtime, but in
  the interim, if you re-index your assets on the environment."


Order entries based on date field in the Control Panel I have some entries and I want to order them in the Control Panel based on a date field of those entries. Is that possible ?

The CpSortableCustomColumns plugin lets you sort your element index tables on custom fields. Sounds like it does exactly what you want.


Display Relating Entry based on Page Routing I'm trying to create a submission page at the following URL structure

/campaigns/this-is-a-test-creation/submissions

As you can see /campaigns/ is the Channel and the /this-is-a-test-creation/ is the entry slug. I'm trying to currently set up my page using routing and fetch the related entry, but I'm having difficulties.

My route in the CP is set up as follows and works.

/campaigns/{slug}/submissions

My code to fetch the relating entry doesn't

{% set entry = craft.entries.section('campaigns').slug('craft.app.request.getSegment(3)').one() %}
{{ entry.title }}

This returns:

  Impossible to access an attribute ("title") on a null variable.

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

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


add text or image to Craft Commerce confirmation email through the CMS I have a customer that wants to modify the order confirmation email.  I set up a new Entry for order confirmation to include a content block that goes to the email/email_confirmation file.

When I check in the browser or preview it works perfectly. When I actually send the email it doesn’t appear.

1) It works in the browser with:

{% if entry.basicContentBlocks %}
// html code
{% endif %}

2) The Commerce plugin only seems to read from information in Commerce.  I tried to pull in the data:

{% set emailEntry = craft.entries.section('emailConfirmation') %}

3) I tried making a global variable that used the email confirmation entry:

{% set emailBlock = craft.globals.getSetByHandle('emailBlock') %}

It seems the email is loaded and sent before the entry information.

Is there a work around to allow customers to add information or pictures from the CMS?

Thank you for your help,

Even though the emailConfirmation was only one entry it was an array.

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

setting up the entry to the html was similar to what I thought, but I didn't include the ".first()" so I wasn't getting what I expected.


How to save widget settings How do you save Widget Settings?

I read this tutorial https://craftcms.com/docs/plugins/widgets several times but I could not find an answer. I'm new to Craft and this is my first plugin.

If I want to save plugin settings I create a Twig template like this

<form method="post" action="" accept-charset="UTF-8">
        <input type="hidden" name="action" value="sRGoogleAnalytics/settings/saveSettings">
        <input type="hidden" name="redirect" value="srgoogleanalytics/settings">
        <input class="btn submit" type="submit" value="{{ 'Submit'|t }}">
</form>

and know my function public function actionSaveSettings() in my SRGoogleAnalytics_SettingsController is going to be executed but I don't know how to do the same for widget settings since the widget itself already has a "submit" button and when I create a form in the template there will be two submits.

Could you please explain what I have to do exactly in order to get a callback into a specific function?

Thank you very much

You're over-thinking it a little bit. To save your widget settings, you don't need a controller class, you only need

a) a method called defineSettings() in your widget class, returning the settings you need, e.g.

protected function defineSettings()
{
  return array(
    'url'   => array(AttributeType::Url, 'required' => true, 'label' => 'URL'),
    'title' => array(AttributeType::Name, 'required' => true),
    'limit' => array(AttributeType::Number, 'min' => 0, 'default' => 5),
  );
}

You can take a look at the AttributeType class to see which attribute types Craft support.

b) a template to render your settings – you don't actually need to create the actual <form> element or add hidden action or redirect inputs in this template; Craft wraps the fields you render inside a form tag. Here's an example settings template corresponding to the settings from the defineSettings() example method above (this is the whole template):

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

{{ forms.textField({
  label: "URL"|t,
  id: 'url',
  name: 'url',
  value: settings.url,
  required: true,
  errors: settings.getErrors('url')
}) }}

{{ forms.textField({
  label: "Title"|t,
  id: 'title',
  name: 'title',
  value: settings.title,
  required: true,
  errors: settings.getErrors('title')
}) }}

{{ forms.textField({
  label: "Limit"|t,
  id: 'limit',
  name: 'limit',
  value: settings.limit,
  size: 2,
  errors: settings.getErrors('limit')
}) }}

Save the template to /yourplugin/templates/widgethandle_settings.html. Finally, you need

c) a method called getSettingsHtml(), also in your widget class, which simply renders the settings template you added above:

public function getSettingsHtml()
{
    return craft()->templates->render('yourplugin/widgettitle_settings', array(
        'settings' => $this->getSettings()
    ));
}

With these three things in place, you should be able to click the cogwheel that appears when you mouse over your widget in the Dashboard, which will display your settings form.

To be clear, this is actually exactly the same way plugin settings work, although for plugins themselves the defineSettings() and getSettingsHtml() method should exist in the primary plugin class. In short – you don't need a controller and you don't need the <form> tag, neither for plugin nor widget settings.