Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show alert when avif file is used in social preview #21962

Open
wants to merge 8 commits into
base: trunk
Choose a base branch
from

Conversation

pls78
Copy link
Member

@pls78 pls78 commented Jan 10, 2025

Context

  • AVIF file are currently not supported by Facebook and X: we want to warn users when their fallback image is in that format.

Summary

This PR can be summarized in the following changelog entry:

  • Issues a warning message when the image automatically selected for a post social preview is in the unsupported AVIF format.
  • [components/image-select 0.0.1] Makes possible to show warnings related to the fallback image file format.

Relevant technical choices:

  • I implemented this check in the warppers (FacebookWrapper and TwitterWrapper) because it wouldn't make sense to have it in the more general ImageSelect component
  • I opted to use the already-existing warning infrastructure which is currently used to display warnings about images that are manually selected by the user
    • I directly manipulate the props.imageWarnings array instead of using an action because:
    • currently there's no dedicated action to set warnings: warnings are set atomically with image selection in selectMedia prepareFacebookPreviewImage and prepareTwitterPreviewImage functions: refactoring this wouldn't make much sense also because the imageWarnings array is drilled down throughout the components' chain
    • Moreover, the warnings from the selected image and the fallback image are mutually exclusive, that's why I can empty the array each time the useFallbackWarning custom hook is called ( this is done to prevent duplicating the warning when the user accesses the Social media appearance modal)

Test instructions

Test instructions for the acceptance test before the PR gets merged

This PR can be acceptance tested by following these steps:

  • Upload an image in AVIF format
  • Edit a post and make sure you did not select any image for its social previews (both Facebook and X)
  • Use the AVIF image in the post, so that is being used as fallback for the social preview
  • Go to the Social tab in the Metabox and verify you see the following warning:
    Screenshot 2025-01-13 at 11 28 46
    • Check you see the same warning in the X appearance section, too
  • Click on Select image and select any image of a supported type
    • Check the warning is gone
  • Click on Remove image and check the warning is back
  • Click on Select image and select an image of AVIF type (you can select the same image you used in the post)
    • Check the warning is now as follows:
    Screenshot 2025-01-13 at 11 31 25
  • Restore the post to have no images for its social previews and an AVIF image in its body
  • Open the Social media appearance modal from the Yoast Sidebar
    • Check the warning is present there, too
  • Remove the AVIF image from the post body and use it as featured image instead
    • Perform the same checks as above
  • Perform the same tests in Elementor and Classic editor

Relevant test scenarios

  • Changes should be tested with the browser console open
  • Changes should be tested on different posts/pages/taxonomies/custom post types/custom taxonomies
  • Changes should be tested on different editors (Default Block/Gutenberg/Classic/Elementor/other)
  • Changes should be tested on different browsers
  • Changes should be tested on multisite

Test instructions for QA when the code is in the RC

  • QA should use the same steps as above.

QA can test this PR by following these steps:

Impact check

This PR affects the following parts of the plugin, which may require extra testing:

UI changes

  • This PR changes the UI in the plugin. I have added the 'UI change' label to this PR.

Other environments

  • This PR also affects Shopify. I have added a changelog entry starting with [shopify-seo], added test instructions for Shopify and attached the Shopify label to this PR.

Documentation

  • I have written documentation for this change. For example, comments in the Relevant technical choices, comments in the code, documentation on Confluence / shared Google Drive / Yoast developer portal, or other.

Quality assurance

  • I have tested this code to the best of my abilities.
  • During testing, I had activated all plugins that Yoast SEO provides integrations for.
  • I have added unit tests to verify the code works as intended.
  • If any part of the code is behind a feature flag, my test instructions also cover cases where the feature flag is switched off.
  • I have written this PR in accordance with my team's definition of done.
  • I have checked that the base branch is correctly set.

Innovation

  • No innovation project is applicable for this PR.
  • This PR falls under an innovation project. I have attached the innovation label.
  • I have added my hours to the WBSO document.

Fixes #4496

@pls78 pls78 added the changelog: enhancement Needs to be included in the 'Enhancements' category in the changelog label Jan 10, 2025
Copy link

@pls78 Please be aware that following packages have been abandoned and are not actively maintained anymore:

Package name Path
@yoast/babel-preset packages/babel-preset
@yoast/components packages/components
@yoast/e2e-tests packages/e2e-tests
@yoast/helpers packages/helpers
@yoast/jest-preset packages/jest-preset
@yoast/style-guide packages/style-guide

Please consider using the other packages instead.

@coveralls
Copy link

coveralls commented Jan 10, 2025

Pull Request Test Coverage Report for Build 67da9d8df481248df4b69940171cc88da52a3ae7

Details

  • 2 of 11 (18.18%) changed or added relevant lines in 4 files are covered.
  • 1 unchanged line in 1 file lost coverage.
  • Overall coverage decreased (-0.01%) to 54.608%

Changes Missing Coverage Covered Lines Changed/Added Lines %
packages/js/src/components/social/FacebookWrapper.js 0 1 0.0%
packages/js/src/components/social/TwitterWrapper.js 0 1 0.0%
packages/js/src/components/social/useFallbackWarning.js 0 7 0.0%
Files with Coverage Reduction New Missed Lines %
packages/js/src/components/social/TwitterWrapper.js 1 0.0%
Totals Coverage Status
Change from base Build abf031a7bd7917bce37c0e48b7e194c1fc89b41d: -0.01%
Covered Lines: 30086
Relevant Lines: 55464

💛 - Coveralls

Copy link

@pls78 Please be aware that following packages have been abandoned and are not actively maintained anymore:

Package name Path
@yoast/babel-preset packages/babel-preset
@yoast/components packages/components
@yoast/e2e-tests packages/e2e-tests
@yoast/helpers packages/helpers
@yoast/jest-preset packages/jest-preset
@yoast/style-guide packages/style-guide

Please consider using the other packages instead.

Copy link

@pls78 Please be aware that following packages have been abandoned and are not actively maintained anymore:

Package name Path
@yoast/babel-preset packages/babel-preset
@yoast/components packages/components
@yoast/e2e-tests packages/e2e-tests
@yoast/helpers packages/helpers
@yoast/jest-preset packages/jest-preset
@yoast/style-guide packages/style-guide

Please consider using the other packages instead.

@pls78 pls78 marked this pull request as ready for review January 13, 2025 12:01
Copy link
Member

@igorschoester igorschoester left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CR 🏗️

Regarding the size warning we have. Should that not also be checked for the fallback, while you are at it?

Regarding your tech choices:

I implemented this check in the warppers (FacebookWrapper and TwitterWrapper) because it wouldn't make sense to have it in the more general ImageSelect component

Why does that not make sense?

refactoring this wouldn't make much sense also because the imageWarnings array is drilled down throughout the components' chain

Why would that stop you? You just need to adapt the source, i.e. the selector. Right?
Just thinking a bit on alternative solutions:

  • You could make getFacebookWarnings and the like accept a second variable, the fallback URL. And then do this there. I'm not actually suggesting that is great, I'm just trying to get you to think a bit more inline with the current solutions.
  • Perhaps the warnings should always be calculated in a memoized selector. And taken out of the current set image with warning.
  • Perhaps it is worth just adding a set warning action.
  • Perhaps the prepareFacebookPreviewImage should encompass the fallback already so it can try to assess it too

@@ -72,7 +68,7 @@ function ImageSelect( props ) {
</button>
}
{
showWarnings && <div role="alert">
showWarnings && <div role="alert" className="yst-mt-4">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yoast/components uses styled-components. Please don't combine that with Tailwind, for which no configuration exists within this package.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding your changelog entry for this file

[components/image-select 0.0.1] Makes possible to show warnings related to the fallback image file format.

  1. It should state the package name, e.g. @yoast/components. You can find this in the closest package.json file
  2. Adding required props is a breaking API change for components. So that would mean a major release. Not a patch, e.g. 1.0.0 indicator.
  3. If you read it again. It does not really sound like proper English, does it? "Makes possible"

@@ -91,6 +87,7 @@ export default ImageSelect;
ImageSelect.propTypes = {
defaultImageUrl: PropTypes.string,
imageUrl: PropTypes.string,
imageFallbackUrl: PropTypes.string.isRequired,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this required? Even the default URL is not.

@@ -15,12 +15,8 @@ import Alert from "../Alert";
function ImageSelect( props ) {
const imageSelected = props.usingFallback === false && props.imageUrl !== "";
const previewImageUrl = props.imageUrl || props.defaultImageUrl || "";
const showWarnings = props.warnings.length > 0 && imageSelected;

let imageClassName = showWarnings ? "yoast-image-select__preview yoast-image-select__preview-has-warnings" : "yoast-image-select__preview";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If removing this class from ever existing. Why not mention it in the changelog, and why keep the style itself in the CSS file?

Funnily enough, this seems like the margin you went to solve with a Tailwind class later on?
So are you sure you can just remove this?

if ( previewImageUrl === "" ) {
imageClassName = "yoast-image-select__preview yoast-image-select__preview--no-preview";
}
const showWarnings = props.warnings.length > 0 && ( imageSelected || props.imageFallbackUrl !== "" );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this component need to keep track of this when in fact it does nothing with the imageFallbackUrl besides this?
Should you not change the usingFallback and/or imageUrl values instead?

Is this all to not even show the image? If so, that seems counter to what this always has done. And instead of untangling that (don't check imageSelected but let the callees determine that), more tangling is done with this extra prop.

export const useFallbackWarning = ( imageFallbackUrl, imageUrl, imageWarnings ) => {
useEffect( () => {
if ( imageUrl === "" ) {
imageWarnings.length = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems highly inappropriate to override an array calculated value. Do you mean to say you would want to imageWarnings = [] instead?
Even then, it is generally nicer to not mess with the input values, but instead copy and return your own variant instead. For more predictable code. It is easy to overlook your current and this is how bugs are born.

useEffect( () => {
if ( imageUrl === "" ) {
imageWarnings.length = 0;
if ( imageFallbackUrl.toLowerCase().endsWith( ".avif" ) ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why just test for .avif? Would it not be nicer to test against the allowed instead? E.g. the list below on line 24.

Also. How many URLs actually include the file extension? This seems a bit flimsy. But I suppose there is no way around that unless we want to go full on image processing.
And probably more the reason why it works like it currently does. Only when we know more, i.e. when setting the image, do we have a chance of more metadata.

imageWarnings.push( warningMessage );
}
}
}, [ imageFallbackUrl, imageUrl ] );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me, a useEffect hook where the rest of the code lives in containers format is very strange.

There is no need to keep watching it when we already control when it changes.

I think this highlights the fact that the selectors are not doing a proper job for you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
changelog: enhancement Needs to be included in the 'Enhancements' category in the changelog
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants