Challenge #11 – Where in the World

9 May 2023 Open Twig Difficult

You’ve been brought in as the expert” to devel­op the algorithm for a per­son­al­ised recom­mend­a­tion app. The app in ques­tion is a Sprig-powered Craft CMS site that sug­gests travel des­tin­a­tion recom­mend­a­tions. Users are presen­ted with pho­tos of places and, based on the pho­tos alone, select wheth­er they would like to vis­it them or not. With each choice, the algorithm presents a fresh set of recom­mend­a­tions to the user.

Check out the Demo App →

Where in the world

This Git­Hub repo con­tains the Craft CMS site that you can spin up with a single com­mand, either loc­ally or in the browser using a Git­Hub codespace (see the readme file in the repo).

Right now, the recommendations.twig tem­plate just returns 3 ran­dom des­tin­a­tions, exclud­ing any that have been dis­liked. Your algorithm should recom­mend up to 3 des­tin­a­tions to users based on their pre­vi­ous likes and dis­likes. All oth­er tem­plates and Sprig com­pon­ents have been set up for you, so the only” thing you need to do is pop­u­late the recommendations vari­able using your secret-sauce logic.

Liked and dis­liked des­tin­a­tion IDs are stored in cook­ies, so recom­mend­a­tions will be user-spe­cif­ic, and users need not be logged in. You can access them in the tem­plate using the likeIds and dislikeIds Twig variables. 

Des­tin­a­tions are tagged with up to 5 tags using an entries field (rather than a tags field, since Entri­fic­a­tion is now a thing), which will be the basis for weight­ing tags and scor­ing des­tin­a­tions for each indi­vidu­al user. 

Des­tin­a­tion tags should be assigned a weight based on wheth­er they were liked or dis­liked, and how many times. So for example, if 3 des­tin­a­tions were liked, all of which were tagged with Beach, and 3 des­tin­a­tions were dis­liked, 1 of which was tagged with Beach, then Beach would be giv­en a weight of +2 (3 - 1). If 1 des­tin­a­tion tagged with City was liked and 2 were dis­liked, then City would be giv­en a weight of -1 (1 - 2)

Tags

Finally, des­tin­a­tion tags are weighted based on their order in the entries field – the first tag gets the most weight and the last tag gets the least weight. The algorithm should take this into account both when weight­ing tags (based on an indi­vidu­al user’s likes/​dislikes). So if Beach is the first tag in one liked des­tin­a­tion, the second tag in anoth­er liked des­tin­a­tion, and the third tag in two dis­liked des­tin­a­tions, then it is giv­en a weight of 1x + 1y - 2z, where x is the weight of the first tag, y is the weight of the second tag and z is the weight of the third tag.

Once each tag has an assigned weight, the algorithm should give each des­tin­a­tion a score based on that destination’s weighted tags. Finally, the recom­men­ded des­tin­a­tions should be ordered by score des­cend­ing and should only con­tain des­tin­a­tions with pos­it­ive scores (great­er than 0).

For bonus points, make it so that scor­ing des­tin­a­tions (based on each destination’s tags) also takes the order of the tags in the entries field into account.

While this chal­lenge is tagged dif­fi­cult”, it’s still clearly easi­er than draw­ing sev­en red lines, all strictly per­pen­dic­u­lar, with red, green and trans­par­ent ink.

Rules

Your solu­tion should con­sist of the con­tents of only the _components/recommendations.twig template.

  • You may only edit the _components/recommendations.twig tem­plate. The con­tent struc­ture may not be changed.
  • You may only use ele­ment quer­ies (craft.entries, etc.) but you can use any of the avail­able para­met­ers on them.
  • No plu­gins or mod­ules may be used except for any that are pre-installed.
  • Optim­ise your code for read­ab­il­ity and main­tain­ab­il­ity (future you), and use eager-load­ing where appropriate.

Tips

  • Des­tin­a­tions can be tagged with at most 5 tags, so use that as a baseline for cal­cu­lat­ing des­tin­a­tion tag weights based on likes/​dislikes.
  • Recal­cu­lat­ing weights on each request is easi­er than stor­ing and keep­ing them in sync.
  • Using Col­lec­tions over Twig fil­ters will help to make your code clean­er and more read­able. Craft Clos­ure is installed and may be used.

Acknow­ledge­ments

Solution

Submissions will be closed on 31 May 2023.

Submit A Solution