Thinking out loud about an Addon

If it doesn't quite fit in the other areas, put it here...
User avatar
burt
Core Team
Posts: 4550
Joined: Tue Oct 29, 2019 9:37 am
Phoenix Version: v1.1.0.8
Has thanked: 252 times
Been thanked: 412 times

Thinking out loud about an Addon

Post by burt »

I thought it might be nice to make a thread about my thought process for how I make an Addon. The general idea is to work out what's needed in advance and then make each piece needed bit by bit, tweaking as I go along for in-depth needs.

In this series of posts, I'm thinking about making a "Popular Search" Tag Cloud. This is something I have already made, but it would have been a good while back and certainly not for any recent iteration of Phoenix.
If anyone has any comments, questions or ideas do ask. I'll try my best to answer.
--

So, in general, what's needed;

1. A way to record every search made
2. A way (in admin) to see those searches
3. A way (in shop) to see those searches

Of course, we need to look more in-depth at each of these, so subscribe to this thread for the next instalment.


Join The Code Co-op to get access to your library in the Code Co-op Forum
User avatar
burt
Core Team
Posts: 4550
Joined: Tue Oct 29, 2019 9:37 am
Phoenix Version: v1.1.0.8
Has thanked: 252 times
Been thanked: 412 times

Re: Thinking out loud about an Addon

Post by burt »

1. A way to record every search made

Requirements

a/ A new DB table to be created to store the searches.
b/ A way to insert relevant data into the new DB table.

Seems straightforward.

--

A.
Now it's time to think about the structure of the new DB table;

Some things are obvious;

Search ID - just an auto-incremented number for each "record" in the DB
Search String - what someone searched for
Date of Search - might be useful I guess?
Status - 0 or 1 as shopowner might not want some searches to show shop side

What else could we add?
Language - it might be nice to record the language ID
As we know we're going to have to make a Cloud of searches, looks something like this;

https://en.wikipedia.org/wiki/File:Web_2.0_Map.svg

Where more popular words are in a BIGGER FONT than less popular words.
With this in mind, we know we have to somehow count searches. I can think of two ways to do this;

1. Add records to the DB and "count" as part of the SQL call
2. Have a counter in the DB and simply increase the counter if the search term has already been searched for

I like the idea of #2 as it would be more interesting to code. I now know I need to have a;

counter - which increments as people search for the same thing

Already a potential problem

If we have the counter this way, we need to determine that (for example) a search for (eg) "shiny" is the same as a search for (eg) "Shiny". Note the difference as one is capitalised, the other not. Basically we don't want both "shiny" and "Shiny" to be shown in the eventual Tag Cloud. I'll think about that.

B.
For recording the searches into the DB, I'm thinking a simple Hook will do the job. If there is no suitable hook listener I can easily add a Hook by overriding the advanced_search_result page. That is really simple, but obviously needs the DB table to be created in the structure that I decide on.

Put simply, it's the structure of the DB that is the most important right now - everything else comes from that.
User avatar
burt
Core Team
Posts: 4550
Joined: Tue Oct 29, 2019 9:37 am
Phoenix Version: v1.1.0.8
Has thanked: 252 times
Been thanked: 412 times

Re: Thinking out loud about an Addon

Post by burt »

A way to differentiate "shiny" and "Shiny" (or in fact, treat them as the same) is to use the PHP function called Metaphone. You can read more about Metaphone, it's pretty boring, here;

https://www.php.net/manual/en/function.metaphone.php

Put simply, it creates a "key" for similar sounding words. Thus;

shiny: XN
Shiny: XN
SHINY: XN

By comparing the "searched for" metaphone with a already existing Metaphone, we can increase the counter (or write a new DB record if there is no existing metaphone).

With that in mind, here's my first attempt at a usable DB structure;

This metaphone idea means that when someone searches for (eg) "shiny"...we must create the metaphone "XN" that is needed for comparison. Creating that "XN" is as simple as;

$sounds_like = metaphone($whatever_they_searched_for)

Where $whatever_they_searched_for is literally whatever they searched for, eg "shiny" or "red" or "red apples" or whatever. Now we simply check DB for $sounds_like and if found, increase counter by 1. If not found, write a new record to the DB.

Straightforward enough, I think.
User avatar
burt
Core Team
Posts: 4550
Joined: Tue Oct 29, 2019 9:37 am
Phoenix Version: v1.1.0.8
Has thanked: 252 times
Been thanked: 412 times

Re: Thinking out loud about an Addon

Post by burt »

Recording every Search

Decision made to use a Hook. It's the least invasive way to do this.
Unfortunately I can't find a suitable pre-placed listener, so I have to make a listener of my own.

It could not be simpler (assume here I'm using the "out of the box" override template);

a/ Over ride the standard page
copy: /templates/default/includes/pages/advanced_search_result.php
into: /templates/override/includes/pages/advanced_search_result.php

b/ In that new page add a hook

Code: Select all

$hooks->call('advanced_search_result', 'insertStringIntoDB');
c/ create a hook
new file: /includes/hooks/shop/advanced_search_result/search_strings.php

Code: Select all

class hook_shop_advanced_search_result_search_strings {
}
Next post, we will code some logic for the hook file, which will save searches to the DB (or increase the counter if the search already exists).
User avatar
burt
Core Team
Posts: 4550
Joined: Tue Oct 29, 2019 9:37 am
Phoenix Version: v1.1.0.8
Has thanked: 252 times
Been thanked: 412 times

Re: Thinking out loud about an Addon

Post by burt »

Hook Explainer;

When someone searches for (eg) "Shiny", the advanced_search_result page loads with a URL somewhat like this; www.your-site.com/advanced_search_resul ... ords=Shiny

We can therefore use the keywords bit of the URL, so long as we sanitize it appropriately;

Code: Select all

$string = Text::input($_GET['keywords']);
Making the Metaphone value;

Code: Select all

$metaphone = metaphone($string);
At this point, we have everything we need to insert to the Database;

Code: Select all

$sql_data = [{as above}];
and

Code: Select all

$GLOBALS['db']->perform('search_strings', $sql_data);
Another problem

By making the hook this simple, we have forgotten about the "counter" I previously posted about in this thread. The hook logic will need to be modified to look up to see if a matching record already exists and so just update that records counter, rather than write another entry into the database. Needs thinking about.
User avatar
burt
Core Team
Posts: 4550
Joined: Tue Oct 29, 2019 9:37 am
Phoenix Version: v1.1.0.8
Has thanked: 252 times
Been thanked: 412 times

Re: Thinking out loud about an Addon

Post by burt »

Solving the Problem

The idea is to check if the metaphone exists in the language of the users session;

Code: Select all

$exists_query = $GLOBALS['db']->query("SELECT 1 FROM search_strings WHERE metaphone = '" . $metaphone . "' AND language_id = " . (int)$_SESSION['languages_id']);
If it does exist, update the counter;

Code: Select all

if (mysqli_num_rows($exists_query)) {
  $GLOBALS['db']->query(sprintf(<<<'EOSQL'
UPDATE search_strings SET counter = counter+1, date = NOW() WHERE metaphone = '%s' AND language_id = %d
EOSQL
 , $metaphone, (int)$_SESSION['languages_id']));
}
otherwise, insert into the DB (which is the code shown in the previous post).

With this all done, checking phpMyAdmin shows this;
phpmyadm.jpg
Here you can see that "Shiny" has been searched for Two times (counter) with the latest search made at the "date". And that "Red Apples" has been searched for One time.

All seems to be working well.
You do not have the required permissions to view the files attached to this post.
User avatar
burt
Core Team
Posts: 4550
Joined: Tue Oct 29, 2019 9:37 am
Phoenix Version: v1.1.0.8
Has thanked: 252 times
Been thanked: 412 times

Re: Thinking out loud about an Addon

Post by burt »

burt wrote: Mon Dec 18, 2023 10:37 am 1. A way to record every search made
This part of the jigsaw puzzle seems to be complete.
User avatar
burt
Core Team
Posts: 4550
Joined: Tue Oct 29, 2019 9:37 am
Phoenix Version: v1.1.0.8
Has thanked: 252 times
Been thanked: 412 times

Re: Thinking out loud about an Addon

Post by burt »

Next up is to think about the Admin Side

Requirements
a/ see a list of searches
b/ ability to set search status on/off
c/ ability to delete a search
d/ ability to edit a search

I think that's about it. Although we do store the language_id in the database, it's done in a slightly different way to most "language" code. Most language code allows the ability to put in different language definitions for the same thing. To explain; in a shop running english and german, shopowner when adding a product has two inputs for the products_name. One for english, another for german.

In this search_strings system we don't need that complexity level of language.
If we did have it, the end result (shop side display) would display incorrectly.

--

We therefore need to find some existing admin side page that does points A to D above, but without the added complexity of language. A good example here is;

admin > special offers

This specials page;

a/ shows a list of special offers
b/ has the ability to set special status on/off
c/ has the ability to delete a special
d/ has the ability to edit a special

You can see that the specials page is broadly close to what I think we need for the searches. Perhaps we can use a copy of the specials.php page (with changed code as appropriate) for our new admin > searches page.
User avatar
burt
Core Team
Posts: 4550
Joined: Tue Oct 29, 2019 9:37 am
Phoenix Version: v1.1.0.8
Has thanked: 252 times
Been thanked: 412 times

Re: Thinking out loud about an Addon

Post by burt »

With the previous post in mind, I took a copy of the admin/specials.php page (and its language file) and changed both appropriately to display the searches instead of displaying the specials. The main part of the page has ended up like this;
admin-search.jpg
Another piece of the jigsaw puzzle is in place, which is;
a/ see a list of searches

These new style pages are relatively straightforward to work with. The next piece(s) is to make the following Requirements;
b/ ability to set search status on/off
c/ ability to delete a search
d/ ability to edit a search
The jigsaw puzzle is starting to make a coherent picture!
You do not have the required permissions to view the files attached to this post.
User avatar
burt
Core Team
Posts: 4550
Joined: Tue Oct 29, 2019 9:37 am
Phoenix Version: v1.1.0.8
Has thanked: 252 times
Been thanked: 412 times

Re: Thinking out loud about an Addon

Post by burt »

With some minor recoding of actions, I now have;
b/ ability to set search status on/off
search_status.jpg
c/ ability to delete a search
delete_search.jpg
d/ ability to edit a search
edit_search.jpg
I also thought why not allow the Shopowner to insert a Search?
That might be a good extra to have.
Here you can see that the shopowner can also insert "count".
Any search added by the shopowner is set to status = on.
new_search.jpg
You do not have the required permissions to view the files attached to this post.


Join The Code Co-op to get access to your library in the Code Co-op Forum
Post Reply