Before answering the question itself, an important detail that can cause a lot of confusion in your tests: do not forget to set the base path!
This can be done in .htaccess, but the simplest way is to do the same html:
<!-- inclua isso no "head" do html -->
<base href="http://a_url_do_seu_site.com/" />
So, especially when working with many folders and subfolders, files with sections and subsections, do not miss the absolute beginning of navigation for reference of all links.
In your case , if "categories" is always the basis, you could do this:
<!-- inclua isso no "head" do html -->
<base href="http://www.meusite.com/categoria/" />
And all the return of friendly urls would start with "product / page", ignoring the categories, which would be your "home", so to speak.
Returning to your problem, this kind of situation is what we call "multiple entries" when there is more than one .php file to call, instead of just one index.php. In this case, .htaccess can be configured in two ways.
First Choice
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?p=$1
Here it does not change anything compared to the single-entry case, but the existing files are also called by the "friendly" query string. To do this, simply agree that the first parameter (in your case) is a folder, and the second is the name of the file. For example:
www.meusite.com/categoria/produtos/2
extracting the query srtring:
$qs = explode("/", ltrim($_GET['p'], "/"));
$caminho = $qs[0];
$arquivo = $qs[1].".php";
$parametro = $qs[2];
// e assim sucessivamente...
The most important thing about this method is that you need to work out a way to standardize the addresses and file and folder structure of your project. It's easier (and beneficial in many ways) to plan the project well, than to get match-burning with .htaccess.
Second Option (not recommended, but exists)
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ $1\.php
What changes, is that you can now pass full paths, and the last parameter (without slash) will be the name of the php file. I do not even need to say that there are no advantages to this approach in your case, mainly because it makes it difficult to pass query strings.
Finally, I see something that could be changed in your paging code, which looks like this:
if(empty($_GET['page'])){
$page=1;
}
if($page >= '1'){
$page = $page;
} else {
$page= '1';
}
When would it be more interesting to do this:
$page = 1; // por padrão, page é sempre 1
$dir = "produtos"; // outro padrão, por exemplo
if (!empty($_GET['page'])) { // todo o resto só faz sentido se houver dados
$dados = explode("/", ltrim($_GET['pages'], "/"));
$dir = $dados[0];
$page = empty($dados[1]) ? 1 : $dados[1]; // só por garantia...
}