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

21908 double request to semrush api #21913

Merged
merged 10 commits into from
Dec 23, 2024
16 changes: 13 additions & 3 deletions packages/js/src/components/SEMrushRelatedKeyphrasesModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,21 @@ class SEMrushRelatedKeyphrasesModal extends Component {
* @returns {void}
*/
onModalOpen() {
if ( ! this.props.keyphrase.trim() ) {
this.props.onOpenWithNoKeyphrase();
const {
keyphrase,
onOpenWithNoKeyphrase,
onOpen,
location,
newRequest,
countryCode,
} = this.props;
if ( ! keyphrase.trim() ) {
onOpenWithNoKeyphrase();
return;
}

this.props.onOpen( this.props.location );
onOpen( location );
newRequest( countryCode, keyphrase );
}

/**
Expand Down Expand Up @@ -217,6 +226,7 @@ SEMrushRelatedKeyphrasesModal.propTypes = {
onAuthentication: PropTypes.func.isRequired,
countryCode: PropTypes.string,
learnMoreLink: PropTypes.string,
newRequest: PropTypes.func.isRequired,
};

SEMrushRelatedKeyphrasesModal.defaultProps = {
Expand Down
17 changes: 0 additions & 17 deletions packages/js/src/components/SEMrushRelatedKeyphrasesModalContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,18 +72,13 @@ export function getUserMessage( props ) {
export default function RelatedKeyphraseModalContent( props ) {
const {
response,
lastRequestKeyphrase,
keyphrase,
newRequest,
setCountry,
renderAction,
countryCode,
requestLimitReached,
setRequestFailed,
setNoResultsFound,
relatedKeyphrases,
setRequestSucceeded,
setRequestLimitReached,
isPending,
isRtl,
isPremium,
Expand All @@ -103,12 +98,6 @@ export default function RelatedKeyphraseModalContent( props ) {
setCountry={ setCountry }
newRequest={ newRequest }
keyphrase={ keyphrase }
setRequestFailed={ setRequestFailed }
setNoResultsFound={ setNoResultsFound }
setRequestSucceeded={ setRequestSucceeded }
setRequestLimitReached={ setRequestLimitReached }
response={ response }
lastRequestKeyphrase={ lastRequestKeyphrase }
userLocale={ userLocale.split( "_" )[ 0 ] }
/> }

Expand Down Expand Up @@ -137,12 +126,7 @@ RelatedKeyphraseModalContent.propTypes = {
countryCode: PropTypes.string.isRequired,
setCountry: PropTypes.func.isRequired,
newRequest: PropTypes.func.isRequired,
setRequestSucceeded: PropTypes.func.isRequired,
setRequestLimitReached: PropTypes.func.isRequired,
setRequestFailed: PropTypes.func.isRequired,
setNoResultsFound: PropTypes.func.isRequired,
response: PropTypes.object,
lastRequestKeyphrase: PropTypes.string,
isRtl: PropTypes.bool,
userLocale: PropTypes.string,
isPending: PropTypes.bool,
Expand All @@ -155,7 +139,6 @@ RelatedKeyphraseModalContent.defaultProps = {
renderAction: null,
requestLimitReached: false,
response: {},
lastRequestKeyphrase: "",
isRtl: false,
userLocale: "en_US",
isPending: false,
Expand Down
87 changes: 2 additions & 85 deletions packages/js/src/components/modals/SEMrushCountrySelector.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
/* External dependencies */
import PropTypes from "prop-types";
import { useEffect, useCallback, useState } from "@wordpress/element";
import apiFetch from "@wordpress/api-fetch";
import { addQueryArgs } from "@wordpress/url";
import { useCallback, useState } from "@wordpress/element";

/* Yoast dependencies */
import { CountrySelector } from "@yoast/related-keyphrase-suggestions";
Expand All @@ -14,12 +12,6 @@ import { CountrySelector } from "@yoast/related-keyphrase-suggestions";
* @param {Function} setCountry The function to set the country code.
* @param {Function} newRequest The function to fire a new request.
* @param {string} [keyphrase] The keyphrase.
* @param {Function} setRequestFailed The function to set the request as failed.
* @param {Function} setNoResultsFound The function to set the request as having no results.
* @param {Function} setRequestSucceeded The function to set the request as succeeded.
* @param {Function} setRequestLimitReached The function to set the request as having reached the limit.
* @param {Object} response The response object.
* @param {string} lastRequestKeyphrase The last requested keyphrase.
* @param {string} userLocale The user locale.
*
* @returns {JSX.Element} The SEMrush Country Selector component.
Expand All @@ -29,87 +21,20 @@ const SEMrushCountrySelector = ( {
setCountry,
newRequest,
keyphrase,
setRequestFailed,
setNoResultsFound,
setRequestSucceeded,
setRequestLimitReached,
response,
lastRequestKeyphrase,
userLocale,
} ) => {
const [ activeCountryCode, setActiveCountryCode ] = useState( countryCode );

/**
* Handles a failed response.
*
* @param {Object} res The response object.
*
* @returns {void}
*/
const handleFailedResponse = useCallback( ( res ) => {
if ( ! ( "error" in res ) ) {
return;
}

if ( res.error.includes( "TOTAL LIMIT EXCEEDED" ) ) {
setRequestLimitReached();

return;
}

setRequestFailed( res );
}, [ setRequestLimitReached, setRequestFailed ] );

/**
* Sends a new related keyphrases request to SEMrush and updates the semrush_country_code value in the database.
*
* @returns {void}
*/
const relatedKeyphrasesRequest = useCallback( async() => {
newRequest( countryCode, keyphrase );

apiFetch( {
path: "yoast/v1/semrush/country_code",
method: "POST",
// eslint-disable-next-line camelcase
data: { country_code: countryCode },
} );

const res = await apiFetch( {
path: addQueryArgs(
"/yoast/v1/semrush/related_keyphrases",
{
keyphrase,
// eslint-disable-next-line camelcase
country_code: countryCode,
}
),
} );

if ( res.status === 200 ) {
if ( res.results.rows.length === 0 ) {
// No results found.
setNoResultsFound();
return;
}

setRequestSucceeded( res );
setActiveCountryCode( countryCode );
return;
}

handleFailedResponse( res );
setActiveCountryCode( countryCode );
vraja-pro marked this conversation as resolved.
Show resolved Hide resolved
}, [ countryCode, keyphrase, newRequest ] );

// Listens to the change action and fires the SEMrush request.
// Fire a new request when the modal is first opened and when the keyphrase has been changed.
// Should only fire once at the start.
useEffect( ()=>{
if ( ! response || keyphrase !== lastRequestKeyphrase ) {
relatedKeyphrasesRequest();
}
}, [] );

return (
<CountrySelector
countryCode={ countryCode }
Expand All @@ -125,22 +50,14 @@ const SEMrushCountrySelector = ( {
SEMrushCountrySelector.propTypes = {
keyphrase: PropTypes.string,
countryCode: PropTypes.string,
response: PropTypes.object,
lastRequestKeyphrase: PropTypes.string,
setCountry: PropTypes.func.isRequired,
newRequest: PropTypes.func.isRequired,
setNoResultsFound: PropTypes.func.isRequired,
setRequestSucceeded: PropTypes.func.isRequired,
setRequestLimitReached: PropTypes.func.isRequired,
setRequestFailed: PropTypes.func.isRequired,
userLocale: PropTypes.string,
};

SEMrushCountrySelector.defaultProps = {
keyphrase: "",
countryCode: "us",
response: {},
lastRequestKeyphrase: "",
userLocale: null,
};

Expand Down
16 changes: 0 additions & 16 deletions packages/js/src/containers/SEMrushRelatedKeyphrases.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,6 @@ export default compose( [
const {
setSEMrushChangeCountry,
setSEMrushNewRequest,
setSEMrushRequestSucceeded,
setSEMrushRequestFailed,
setSEMrushSetRequestLimitReached,
setSEMrushNoResultsFound,
} = dispatch( "yoast-seo/editor" );
return {
setCountry: ( countryCode ) => {
Expand All @@ -50,18 +46,6 @@ export default compose( [
newRequest: ( countryCode, keyphrase ) => {
setSEMrushNewRequest( countryCode, keyphrase );
},
setRequestSucceeded: ( response ) => {
setSEMrushRequestSucceeded( response );
},
setRequestFailed: ( response ) => {
setSEMrushRequestFailed( response );
},
setRequestLimitReached: () => {
setSEMrushSetRequestLimitReached();
},
setNoResultsFound: () => {
setSEMrushNoResultsFound();
},
};
} ),
] )( RelatedKeyphrasesModalContent );
6 changes: 6 additions & 0 deletions packages/js/src/containers/SEMrushRelatedKeyphrasesModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export default compose( [
getSEMrushSelectedCountry,
getPreference,
selectLinkParams,
getFocusKeyphrase,
} = select( "yoast-seo/editor" );

return {
Expand All @@ -19,6 +20,7 @@ export default compose( [
countryCode: getSEMrushSelectedCountry(),
isRtl: getPreference( "isRtl", false ),
learnMoreLink: addQueryArgs( "https://yoa.st/3-v", selectLinkParams() ),
keyphrase: getFocusKeyphrase(),
};
} ),
withDispatch( ( dispatch ) => {
Expand All @@ -27,6 +29,7 @@ export default compose( [
setSEMrushOpenModal,
setSEMrushDismissModal,
setSEMrushLoginStatus,
setSEMrushNewRequest,
} = dispatch( "yoast-seo/editor" );

return {
Expand All @@ -42,6 +45,9 @@ export default compose( [
onAuthentication: ( status ) => {
setSEMrushLoginStatus( status );
},
newRequest: ( countryCode, keyphrase ) => {
setSEMrushNewRequest( countryCode, keyphrase );
},
};
} ),
] )( SEMrushRelatedKeyphrasesModal );
46 changes: 39 additions & 7 deletions packages/js/src/redux/actions/SEMrushRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,18 @@ export const SET_REQUEST_LIMIT_REACHED = "SET_LIMIT_REACHED";
export const NEW_REQUEST = "NEW_REQUEST";
export const NO_DATA_FOUND = "NO_DATA_FOUND";
export const SET_LOGIN_STATUS = "SET_LOGIN_STATUS";
export const SET_REQUEST_PENDING = "SET_REQUEST_PENDING";

/**
* An action creator for starting a new request.
* An action creator for when the request has succeeded.
*
* @param {Object} countryCode The country code of the database for the SEMrush request.
* @param {string} keyphrase The keyphrase for the SEMrush request.
* @param {Object} response The response of the request.
*
* @returns {Object} Action object.
*/
export function setSEMrushNewRequest( countryCode, keyphrase ) {
export function setSEMrushRequestPending() {
return {
type: NEW_REQUEST,
countryCode,
keyphrase,
type: SET_REQUEST_PENDING,
};
}

Expand Down Expand Up @@ -99,3 +97,37 @@ export function setSEMrushLoginStatus( loginStatus ) {
loginStatus,
};
}

/**
* An action creator for starting a new request.
*
* @param {Object} countryCode The country code of the database for the SEMrush request.
* @param {string} keyphrase The keyphrase for the SEMrush request.
*
* @returns {Object} Action object.
*/
export function* setSEMrushNewRequest( countryCode, keyphrase ) {
try {
yield setSEMrushRequestPending();

const response = yield{
type: NEW_REQUEST,
countryCode,
keyphrase,
};

if ( response.status === 200 ) {
if ( response.results.rows.length === 0 ) {
yield setSEMrushNoResultsFound();
} else {
yield setSEMrushRequestSucceeded( response );
}
} else if ( response.error && response.error.includes( "TOTAL LIMIT EXCEEDED" ) ) {
yield setSEMrushSetRequestLimitReached();
} else {
yield setSEMrushRequestFailed( response );
}
} catch ( error ) {
yield setSEMrushRequestFailed( error );
}
}
33 changes: 33 additions & 0 deletions packages/js/src/redux/controls/SEMrushRequest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import apiFetch from "@wordpress/api-fetch";
import { addQueryArgs } from "@wordpress/url";

/**
* Control for handling SEMrush related keyphrases request.
*
* @param {Object} action The action object.
vraja-pro marked this conversation as resolved.
Show resolved Hide resolved
*
* @returns {Promise} The API fetch promise.
vraja-pro marked this conversation as resolved.
Show resolved Hide resolved
*/
export const NEW_REQUEST = async( action ) => {
const { countryCode, keyphrase } = action;
vraja-pro marked this conversation as resolved.
Show resolved Hide resolved

await apiFetch( {
vraja-pro marked this conversation as resolved.
Show resolved Hide resolved
path: "yoast/v1/semrush/country_code",
method: "POST",
// eslint-disable-next-line camelcase
data: { country_code: countryCode },
} );

const response = await apiFetch( {
path: addQueryArgs(
"/yoast/v1/semrush/related_keyphrases",
{
keyphrase,
// eslint-disable-next-line camelcase
country_code: countryCode,
}
),
} );

return response;
vraja-pro marked this conversation as resolved.
Show resolved Hide resolved
};
1 change: 1 addition & 0 deletions packages/js/src/redux/controls/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ import { WISTIA_EMBED_PERMISSION_NAME, wistiaEmbedPermissionControls } from "../
export const wistiaEmbedPermission = wistiaEmbedPermissionControls[ WISTIA_EMBED_PERMISSION_NAME ];
export * from "./dismissedAlerts";
export * from "./snippetEditor";
export * from "./SEMrushRequest";
Loading
Loading