Я понял это сегодня. По сути, файл htaccess при создании обратной ссылки проходит через правила более одного раза.
Я добавил пропуск в исходную строку ключевого слова, но он будет просто проигнорирован:
#keyword
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]+)/(.*)/$ /$2?keyword=$1 [NC,QSA,PT,S=1]
#withoutactions
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php !-f
RewriteRule ^([^/]+)/(.*)$ /$2?keyword=$1 [NC,QSA,PT]
#actions
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php !-f
RewriteRule ^([^/]+)/(.*)$ /?action=$1 [NC,QSA,PT]
Когда htaccess запускается во второй раз, S больше не применяется, и затем он попадает в блок withoutactions. Чтобы обойти это, я просто проверил, существует ли уже ключевое слово в строке запроса и если да, чтобы пропустить правило:
#keyword
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]+)/(.*)/$ /$2?keyword=$1 [NC,QSA,PT,S=1]
#withoutactions
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php !-f
RewriteCond %{QUERY_STRING} !keyword
RewriteRule ^([^/]+)/(.*)$ /$2?keyword=$1 [NC,QSA,PT]
#actions
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php !-f
RewriteRule ^([^/]+)/(.*)$ /?action=$1 [NC,QSA,PT]
Надеюсь, это поможет кому-то, у которого возникла подобная проблема с обратными ссылками!