Skip to content

Commit

Permalink
Merge pull request #21962 from Yoast/show-alert-when-avif-file-is-use…
Browse files Browse the repository at this point in the history
…d-in-social-preview

Show alert when avif file is used in social preview
  • Loading branch information
igorschoester authored Jan 27, 2025
2 parents 765f7f7 + 3a1e591 commit ca4dc5f
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 10 deletions.
16 changes: 11 additions & 5 deletions packages/components/src/image-select/ImageSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import PropTypes from "prop-types";
import FieldGroup from "../field-group/FieldGroup";
import Alert from "../Alert";

/* eslint-disable complexity */
/**
* Renders ImageSelect component.
*
Expand All @@ -15,13 +16,16 @@ 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";
const showWarnings = props.warnings.length > 0 && ( imageSelected || props.usingFallback );
const imageClassNames = [ "yoast-image-select__preview" ];
if ( previewImageUrl === "" ) {
imageClassName = "yoast-image-select__preview yoast-image-select__preview--no-preview";
imageClassNames.push( "yoast-image-select__preview--no-preview" );
}
if ( showWarnings ) {
imageClassNames.push( "yoast-image-select__preview-has-warnings" );
}


const imageSelectButtonsProps = {
imageSelected: imageSelected,
onClick: props.onClick,
Expand Down Expand Up @@ -60,7 +64,7 @@ function ImageSelect( props ) {
>
{ props.hasPreview &&
<button
className={ imageClassName }
className={ imageClassNames.join( " " ) }
onClick={ props.onClick }
type="button"
disabled={ props.isDisabled }
Expand All @@ -86,6 +90,8 @@ function ImageSelect( props ) {
);
}

/* eslint-enable complexity */

export default ImageSelect;

ImageSelect.propTypes = {
Expand Down
18 changes: 15 additions & 3 deletions packages/js/src/components/social/FacebookWrapper.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useEffect, useState, useCallback, useMemo } from "@wordpress/element";
import { useEffect, useState, useCallback } from "@wordpress/element";
import { Slot } from "@wordpress/components";
import PropTypes from "prop-types";

import SocialForm from "../social/SocialForm";
import { useFallbackWarning } from "./useFallbackWarning";

/**
* This wrapper is connected to the facebook container. So the data is connected to both components.
Expand All @@ -15,6 +16,7 @@ import SocialForm from "../social/SocialForm";
const FacebookWrapper = ( props ) => {
const [ activeMetaTabId, setActiveMetaTabId ] = useState( "" );

const warnings = useFallbackWarning( props.imageFallbackUrl, props.imageUrl, props.imageWarnings );
// Set active meta tab id on window event.
const handleMetaTabChange = useCallback( ( event ) => {
setActiveMetaTabId( event.detail.metaTabId );
Expand All @@ -33,10 +35,11 @@ const FacebookWrapper = ( props ) => {
};
}, [] );

const allProps = useMemo( () => ( {
const allProps = {
...props,
activeMetaTabId,
} ), [ props, activeMetaTabId ] );
imageWarnings: warnings,
};

return (
props.isPremium
Expand All @@ -49,6 +52,15 @@ FacebookWrapper.propTypes = {
isPremium: PropTypes.bool.isRequired,
onLoad: PropTypes.func.isRequired,
location: PropTypes.string.isRequired,
imageFallbackUrl: PropTypes.string,
imageUrl: PropTypes.string,
imageWarnings: PropTypes.array,
};

FacebookWrapper.defaultProps = {
imageFallbackUrl: "",
imageUrl: "",
imageWarnings: [],
};

export default FacebookWrapper;
4 changes: 4 additions & 0 deletions packages/js/src/components/social/SocialForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ class SocialPreviewEditor extends Component {
description,
descriptionInputPlaceholder,
imageUrl,
imageFallbackUrl,
alt,
title,
titleInputPlaceholder,
Expand All @@ -139,6 +140,7 @@ class SocialPreviewEditor extends Component {
onRemoveImageClick={ onRemoveImageClick }
imageSelected={ !! imageUrl }
imageUrl={ imageUrl }
imageFallbackUrl={ imageFallbackUrl }
imageAltText={ alt }
onTitleChange={ onTitleChange }
onSelectImageClick={ onSelectImageClick }
Expand Down Expand Up @@ -167,6 +169,7 @@ SocialPreviewEditor.propTypes = {
description: PropTypes.string.isRequired,
onDescriptionChange: PropTypes.func.isRequired,
imageUrl: PropTypes.string.isRequired,
imageFallbackUrl: PropTypes.string,
onSelectImageClick: PropTypes.func.isRequired,
onRemoveImageClick: PropTypes.func.isRequired,
socialMediumName: PropTypes.string.isRequired,
Expand All @@ -183,6 +186,7 @@ SocialPreviewEditor.propTypes = {

SocialPreviewEditor.defaultProps = {
imageWarnings: [],
imageFallbackUrl: "",
recommendedReplacementVariables: [],
replacementVariables: [],
isPremium: false,
Expand Down
21 changes: 19 additions & 2 deletions packages/js/src/components/social/TwitterWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Slot } from "@wordpress/components";
import PropTypes from "prop-types";

import SocialForm from "../social/SocialForm";
import { useFallbackWarning } from "./useFallbackWarning";

/**
* This wrapper is connected to the twitter container. So the data is connected to both components.
Expand All @@ -13,20 +14,36 @@ import SocialForm from "../social/SocialForm";
* @returns {JSX.Element} The TwitterWrapper.
*/
const TwitterWrapper = ( props ) => {
const warnings = useFallbackWarning( props.imageFallbackUrl, props.imageUrl, props.imageWarnings );

useEffect( () => {
// Load on the next cycle because the editor inits asynchronously, and we need to load the data after the component is fully loaded.
setTimeout( props.onLoad );
}, [] );

const allProps = {
...props,
imageWarnings: warnings,
};

return props.isPremium
? <Slot name={ `YoastTwitterPremium${ props.location.charAt( 0 ).toUpperCase() + props.location.slice( 1 ) }` } fillProps={ props } />
: <SocialForm { ...props } />;
? <Slot name={ `YoastTwitterPremium${ props.location.charAt( 0 ).toUpperCase() + props.location.slice( 1 ) }` } fillProps={ allProps } />
: <SocialForm { ...allProps } />;
};

TwitterWrapper.propTypes = {
isPremium: PropTypes.bool.isRequired,
onLoad: PropTypes.func.isRequired,
location: PropTypes.string.isRequired,
imageFallbackUrl: PropTypes.string,
imageUrl: PropTypes.string,
imageWarnings: PropTypes.array,
};

TwitterWrapper.defaultProps = {
imageFallbackUrl: "",
imageUrl: "",
imageWarnings: [],
};

export default TwitterWrapper;
27 changes: 27 additions & 0 deletions packages/js/src/components/social/useFallbackWarning.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { useEffect, useState } from "@wordpress/element";
import { __, sprintf } from "@wordpress/i18n";

/**
* Checks if the fallback image is in AVIF format and sets a warning message.
*
* @param {string} imageFallbackUrl The fallback image URL.
* @param {string} imageUrl The image URL.
* @param {array} imageWarnings The image warnings.
*
* @returns {string[]} An array of warnings.
*/
export const useFallbackWarning = ( imageFallbackUrl, imageUrl, imageWarnings ) => {
const [ hasFallbackWarning, setHasFallbackWarning ] = useState( false );
const warningMessage = sprintf(
/* Translators: %s expands to the jpg format, %s expands to the png format, %s expands to the webp format, %s expands to the gif format. */
__(
"No image was found that we can automatically set as your social image. Please use %s, %s, %s or %s formats to ensure it displays correctly on social media.",
"wordpress-seo"
),
"JPG", "PNG", "WEBP", "GIF"
);
useEffect( () => {
setHasFallbackWarning( imageUrl === "" ? imageFallbackUrl.toLowerCase().endsWith( ".avif" ) : false );
}, [ imageFallbackUrl, imageUrl ] );
return hasFallbackWarning ? [ warningMessage ] : imageWarnings;
};
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ class SocialMetadataPreviewForm extends Component {
recommendedReplacementVariables,
imageWarnings,
imageUrl,
imageFallbackUrl,
imageAltText,
idSuffix,
} = this.props;
Expand All @@ -243,6 +244,7 @@ class SocialMetadataPreviewForm extends Component {
isActive={ activeField === "image" }
isHovered={ hoveredField === "image" }
imageUrl={ imageUrl }
usingFallback={ ! imageUrl && imageFallbackUrl !== "" }
imageAltText={ imageAltText }
hasPreview={ ! isPremium }
imageUrlInputId={ join( [ lowerCaseSocialMediumName, "url-input", idSuffix ] ) }
Expand Down Expand Up @@ -311,6 +313,7 @@ SocialMetadataPreviewForm.propTypes = {
recommendedReplacementVariables: PropTypes.arrayOf( PropTypes.string ),
imageWarnings: PropTypes.array,
imageUrl: PropTypes.string,
imageFallbackUrl: PropTypes.string,
imageAltText: PropTypes.string,
titleInputPlaceholder: PropTypes.string,
descriptionInputPlaceholder: PropTypes.string,
Expand All @@ -328,6 +331,7 @@ SocialMetadataPreviewForm.defaultProps = {
onSelect: () => {},
onReplacementVariableSearchChange: null,
imageUrl: "",
imageFallbackUrl: "",
imageAltText: "",
titleInputPlaceholder: "",
descriptionInputPlaceholder: "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ class SocialPreviewEditor extends Component {
onRemoveImageClick={ onRemoveImageClick }
imageSelected={ !! imageUrl }
imageUrl={ imageUrl }
imageFallbackUrl={ imageFallbackUrl }
onTitleChange={ onTitleChange }
onSelectImageClick={ onSelectImageClick }
description={ description }
Expand Down

0 comments on commit ca4dc5f

Please sign in to comment.