craftcms / cms

Build bespoke content experiences with Craft.
https://craftcms.com
Other
3.22k stars 627 forks source link

[3.7.59]: Editing Dropdown field labels or values with an existing default causes a blank option to display in the list. #12262

Closed KettyLezama closed 1 year ago

KettyLezama commented 1 year ago

What happened?

Description

Editing Dropdown field labels or values with an existing default causes a blank option to appear as the first option in the list in an entry that already exists.

This only happens on existing components; if I create a brand new component with this field, the blank value does not show. This doesn't cause problems when a field is optional, but as soon as the field is mandatory, authors are forced to select a value and resave. With so many entries already using this field, you can see how tedious this can be.

Is there a way to avoid this from happening?

Steps to Reproduce

  1. Let's say I had this as my original Dropdown field, with a default option set: Old Dropdown Field

This is how the author sees the field, and this is exactly what I want.

Old Dropdown
  1. But then I need to update the value of the dropdown options, as such: New Dropdown Field

This is what the author now sees on existing entry pages that are using this field:

New Dropdown

Expected Behavior

I would expect the dropdown options to display the same way they were originally -- without a blank option.

Actual Behavior

The first option displayed (and selected) is now blank (null).

Craft CMS version

3.7.59

PHP version

7.4.30

Operating system and version

macOS Monterey 12.6

Database type and version

MySQL 5.7

Image driver and version

No response

Installed plugins and versions

brianjhanson commented 1 year ago

Thanks for reaching out! This is currently working as expected, although I understand how it's not ideal.

When you update the values of the dropdown field, the values already in the database aren't affected. That means when you come back to the page, the value of the field getting rendered to the template will be the old text-align--center and not the new text-align-center value until you select a new value and save the field. The blank space occurs because the old value is no longer an available option for the select field.

To avoid having to migrate all the old values by hand, you can use the craft resave/entries command to set all the values. It gets a little long in your case, but something like this should do it:

./craft resave/entries --section mySection --type myEntryType --set dropdown --to "fn(\$element) => \$element->getFieldValue('textAlign')->value === 'text-align--center' ? 'text-align-center' : \$element->getFieldValue('textAlign')"

I definitely recommend taking a backup and testing that locally before running anything on production since I'm not able to test against your full data set, but if it's good, you can just repeat that same command with the other values.

You could do something similar with a content migration if you're more comfortable with taking that route.

I'm closing this for now, but still happy to answer any other questions if you have them.

KettyLezama commented 1 year ago

Hi Brian! Thanks for getting back to me!

Yikes, so we are definitely using this field in 275+ entries in our company's website under many, many different sections. I attempted to start with our main and empowerPages sections; but not ALL entries under those sections use this textAlign field. Therefore I end up with an error like this:

Screen Shot 2022-11-06 at 6 52 41 PM

`Resaving 49 entries ...

At least in part of the error, I see it's trying to resave the textAlign field in the Video Demo Library page, but this entry does not use this field. The entry is, however, a part of the main section so I assume that's why it's trying to be resaved.

So my follow-up questions are:

  1. Would we need to run this resave command per every section utilizing the textAlign field?
  2. Is there a way to run a resave/entries command and ignore all entries that do not use this field?

I'm curious if the faster solution for now (although a little painstaking) could be to delete this field entirely and recreate it in the component we're using. Thoughts?

brandonkelly commented 1 year ago

@KettyLezama Whoops, that’s a bug. Setting an invalid field handle should not have bailed the whole command like that. I’ve just fixed that for the next Craft 3 and 4 releases.

As you’re on Craft 3, you can pull that fix in a little early by changing your craftcms/cms requirement in composer.json to "v3.x-dev#fe70e3b9ca9454f396df7d5f14e686edba61c8e4 as 3.7.59", and running composer update.

KettyLezama commented 1 year ago

@brandonkelly Thank you for fixing that command! I'll give it a try for sure.

@brianjhanson @brandonkelly What do you both think about my first follow-up question, by the way? Our company has many, many sections. So am I right in saying that we would need to run this command per every section utilizing that field? Or is there a way to just run it for all sections now that it would just skip the entry if it doesn't have the field?

KettyLezama commented 1 year ago

@brandonkelly @brianjhanson Also, I am realizing that the command I need to use may be different? It may need to be resave/matrix-blocks? Check this screenshot out:

Screen Shot 2022-11-07 at 9 59 04 AM

My dropdown field is within a Matrix Block Type Text Span, that is within the components field of type Matrix. So would the command I use be something along the lines of:

./craft resave/matrix-blocks --field components --type textSpan --set dropdown --to "fn(\$element) => \$element->getFieldValue('textAlign')->value === 'text-align--center' ? 'text-align-center' : \$element->getFieldValue('textAlign')"

This command in particular doesn't work, but just showing you my train of thought.

Apologies for bugging about my specific question here -- if there is a better forum for this, please do let me know!

brandonkelly commented 1 year ago

@KettyLezama Correct, if it’s for a Matrix field you should use resave/matrix-blocks. What happens when you run that command?

KettyLezama commented 1 year ago

@brandonkelly This:

Screen Shot 2022-11-07 at 1 29 12 PM
brianjhanson commented 1 year ago

It looks like you might have forgotten to update the --set parameter from dropdown to your field handle. From the screenshot it looks like the command would be

./craft resave/matrix-blocks --field components --type textSpan --set textAlign --to "fn(\$element) => \$element->getFieldValue('textAlign')->value === 'text-align--center' ? 'text-align-center' : \$element->getFieldValue('textAlign')"
brandonkelly commented 1 year ago

Craft 3.7.60 and 4.3.2 are out with that fix where resave/* commands were completely bailing when an invalid field value was being set.

brandonkelly commented 1 year ago

Craft 4.5.0 is out with an improvement to Dropdown field behavior: now if a Dropdown field’s value is invalid, and the field contains an explicit Default option, the default option will be auto-selected, and the field will be marked as changed. (#13540)