Skip to content

Comments

[6.1] [webservices] use logic and when filter multiple tag values#46325

Open
alikon wants to merge 15 commits intojoomla:6.1-devfrom
alikon:webservices-logic-and-for-tags
Open

[6.1] [webservices] use logic and when filter multiple tag values#46325
alikon wants to merge 15 commits intojoomla:6.1-devfrom
alikon:webservices-logic-and-for-tags

Conversation

@alikon
Copy link
Contributor

@alikon alikon commented Oct 19, 2025

Pull Request for Issue #46241 .

Summary of Changes

This change adds support for a tag_mode filter to the Articles list in com_content so callers can choose whether tag filtering should use OR (any) or AND (all) semantics. It also exposes the new filter via the API controller.

What this does

  1. Adds a new model state key filter.tag_mode (default: "any") to ArticlesModel.
  2. Implements "all" tag mode: when tag_mode=all and multiple tag IDs are provided, an article must have all of the specified tags to be included (AND semantics).
  3. Preserves the existing behavior as the default: tag_mode=any (OR semantics).
  4. Exposes the tag_mode parameter in the API controller (ArticlesController::displayList) and cleans input with the request filter.

Testing Instructions

GET api/index.php/v1/content/articles?filter[tag][]=2&filter[tag][]=3&filter[tag_mode]=all

Manual tests performed for:

  • Single tag with default behavior (any)
  • Multiple tags with tag_mode=any (OR)
  • Multiple tags with tag_mode=all (AND)
  • Missing/invalid tag_mode falling back to default

Actual result BEFORE applying this Pull Request

only logic OR

Expected result AFTER applying this Pull Request

Adds logic AND

Link to documentations

Please select:

  • Documentation link for docs.joomla.org:

  • No documentation changes for docs.joomla.org needed

  • Pull Request link for manual.joomla.org:

  • No documentation changes for manual.joomla.org needed

@alikon alikon marked this pull request as ready for review October 19, 2025 08:50
@ceford
Copy link
Contributor

ceford commented Nov 5, 2025

I tried to test this PR but got a 500 error response. I am an API novice so it could be something to do with my set up. This is my stack trace:

{"errors":[{"code":500,"title":"Internal server error","detail":"RuntimeException: Unable to load renderer class module in /Users/ceford/Sites/joomla-cms6/libraries/src/Document/Factory.php:101\nStack trace:\n
#0 /Users/ceford/Sites/joomla-cms6/libraries/src/Document/Document.php(1128): Joomla\CMS\Document\Factory->createRenderer(Object(Joomla\CMS\Document\JsonapiDocument), 'module')\n
#1 /Users/ceford/Sites/joomla-cms6/plugins/content/loadmodule/src/Extension/LoadModule.php(223): Joomla\CMS\Document\Document->loadRenderer('module')\n
#2 /Users/ceford/Sites/joomla-cms6/plugins/content/loadmodule/src/Extension/LoadModule.php(154): Joomla\Plugin\Content\LoadModule\Extension\LoadModule->loadModule('tags_similar', 'Similar Tags Mo...', 'html5')\n
#3 /Users/ceford/Sites/joomla-cms6/libraries/vendor/joomla/event/src/Dispatcher.php(454): Joomla\Plugin\Content\LoadModule\Extension\LoadModule->onContentPrepare(Object(Joomla\CMS\Event\Content\ContentPrepareEvent))\n
#4 /Users/ceford/Sites/joomla-cms6/libraries/src/Application/EventAware.php(111): Joomla\Event\Dispatcher->dispatch('onContentPrepar...', Object(Joomla\CMS\Event\Content\ContentPrepareEvent))\n
#5 /Users/ceford/Sites/joomla-cms6/api/components/com_content/src/View/Articles/JsonapiView.php(200): Joomla\CMS\Application\WebApplication->triggerEvent('onContentPrepar...', Array)\n
#6 /Users/ceford/Sites/joomla-cms6/libraries/src/MVC/View/JsonApiView.php(127): Joomla\Component\Content\Api\View\Articles\JsonapiView->prepareItem(Object(stdClass))\n
#7 /Users/ceford/Sites/joomla-cms6/api/components/com_content/src/View/Articles/JsonapiView.php(153): Joomla\CMS\MVC\View\JsonApiView->displayList()\n
#8 /Users/ceford/Sites/joomla-cms6/libraries/src/MVC/Controller/ApiController.php(269): Joomla\Component\Content\Api\View\Articles\JsonapiView->displayList()\n
#9 /Users/ceford/Sites/joomla-cms6/api/components/com_content/src/Controller/ArticlesController.php(107): Joomla\CMS\MVC\Controller\ApiController->displayList()\n
#10 /Users/ceford/Sites/joomla-cms6/libraries/src/MVC/Controller/BaseController.php(730): Joomla\Component\Content\Api\Controller\ArticlesController->displayList()\n
#11 /Users/ceford/Sites/joomla-cms6/libraries/src/Dispatcher/ApiDispatcher.php(61): Joomla\CMS\MVC\Controller\BaseController->execute('displaylist')\n
#12 /Users/ceford/Sites/joomla-cms6/libraries/src/Component/ComponentHelper.php(361): Joomla\CMS\Dispatcher\ApiDispatcher->dispatch()\n
#13 /Users/ceford/Sites/joomla-cms6/libraries/src/Application/ApiApplication.php(433): Joomla\CMS\Component\ComponentHelper::renderComponent('com_content')\n
#14 /Users/ceford/Sites/joomla-cms6/libraries/src/Application/ApiApplication.php(116): Joomla\CMS\Application\ApiApplication->dispatch()\n
#15 /Users/ceford/Sites/joomla-cms6/libraries/src/Application/CMSApplication.php(320): Joomla\CMS\Application\ApiApplication->doExecute()\n
#16 /Users/ceford/Sites/joomla-cms6/api/includes/app.php(50): Joomla\CMS\Application\CMSApplication->execute()\n
#17 /Users/ceford/Sites/joomla-cms6/api/index.php(31): require_once('/Users/ceford/S...')\n
#18 {main}"}]}


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/46325.

@alikon
Copy link
Contributor Author

alikon commented Nov 16, 2025

do you have some {loadmoduleid xxx} or similar in one of your articles ?

@HLeithner HLeithner changed the title [6.1][webservices] use logic and when filter multiple tag values [6.1] [webservices] use logic and when filter multiple tag values Nov 24, 2025
@Razzo1987
Copy link
Contributor

Razzo1987 commented Jan 10, 2026

I have tested this item ✅ successfully on 3642879

Request: https://joomla.sviluppo.online/api/index.php/v1/content/articles?filter%5Btag%5D%5B%5D=2&filter%5Btag%5D%5B%5D=3&filter%5Btag%5D%5B%5D=5&page%5Blimit%5D=20&page%5Boffset%5D=0

or

https://joomla.sviluppo.online/api/index.php/v1/content/articles?filter%5Btag%5D%5B%5D=2&filter%5Btag%5D%5B%5D=5&filter%5Btag%5D%5B%5D=3&filter%5Btag_mode%5D=any&page%5Blimit%5D=20&page%5Boffset%5D=0

2 expected items

Response:

{
  "links": {
    "self": "https://joomla.sviluppo.online/api/index.php/v1/content/articles?filter%5Btag%5D%5B%5D=2&filter%5Btag%5D%5B%5D=3&filter%5Btag%5D%5B%5D=5&page%5Blimit%5D=20&page%5Boffset%5D=0"
  },
  "data": [
    {
      "type": "articles",
      "id": "11",
      "attributes": {
        "id": 11,
        "asset_id": 142,
        "title": "Tipografia",
        "alias": "tipografia",
        "state": 1,
        "access": 1,
        "created": "2026-01-10 10:22:13",
        "created_by": 393,
        "created_by_alias": "Joomla",
        "modified": "2026-01-10 11:29:01",
        "featured": 0,
        "language": "*",
        "hits": 0,
        "publish_up": "2026-01-10 10:22:13",
        "publish_down": null,
        "note": "",
        "images": {
          "image_intro": "",
          "image_intro_alt": "",
          "float_intro": "",
          "image_intro_caption": "",
          "image_fulltext": "",
          "image_fulltext_alt": "",
          "float_fulltext": "",
          "image_fulltext_caption": ""
        },
        "metakey": "",
        "metadesc": "",
        "metadata": {
          "robots": "",
          "author": "",
          "rights": ""
        },
        "version": 2,
        "featured_up": null,
        "featured_down": null,
        "typeAlias": "com_content.article",
        "text": "<h1>Schema colore</h1>\r\n<p class=\"_QQ_\"><span class=\"btn btn-secondary\">secondario</span> <span class=\"btn btn-primary\">primario</span> <span class=\"btn btn-info\">info</span> <span class=\"btn btn-success\">successo</span> <span class=\"btn btn-warning\">avviso</span> <span class=\"btn btn-danger\">pericolo</span></p>\r\n<p><span class=\"text text-secondary\">testo-secondario</span> <span class=\"text text-primary\">testo-primario</span> <span class=\"text text-info\">testo-info</span> <span class=\"text text-success\">testo-successo</span> <span class=\"text text-warning\">testo-avviso</span> <span class=\"text text-danger\">testo-pericolo</span></p>\r\n<h1>Tipografia (h1)</h1>\r\n<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex. (p)</p>\r\n<h2>Lorem Ipsum Dolor Sit Amet (h2)</h2>\r\n<p><strong>Lorem ipsum dolor sit amet, consectetuer adipiscing elit </strong> (strong), sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex. (p)</p>\r\n<h3>Lorem Ipsum Dolor Sit Amet (h3)</h3>\r\n<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex. (p)</p>\r\n<h4>Lorem Ipsum Dolor Sit Amet (h4)</h4>\r\n<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex. (p)</p>\r\n<h5>Lorem Ipsum Dolor Sit Amet (h5)</h5>\r\n<p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex. (p)</p>\r\n<p><a href=\"index.php\"> Lorem ipsum dolor (a)</a></p>\r\n<h1>Lists</h1>\r\n<p>(ol)(li)</p>\r\n<ol>\r\n<li>Lorem ipsum dolor sit amet consectetur</li>\r\n<li>Lorem ipsum dolor sit amet consectetur</li>\r\n</ol>\r\n<p>(ul)(li)</p>\r\n<ul>\r\n<li>Lorem ipsum dolor sit amet consectetur</li>\r\n<li>Lorem ipsum dolor sit amet consectetur</li>\r\n</ul>\r\n<h1>Visualizza</h1>\r\n<p class=\"display-1\">Lorem (display-1)</p>\r\n<p class=\"display-2\">Lorem (display-2)</p>\r\n<p class=\"display-3\">Lorem ipsum (display-3)</p>\r\n<p class=\"display-4\">Lorem ipsum (display-4)</p>\r\n<p class=\"lead\">Lorem ipsum arma virumque cano (lead)</p> ",
        "informazioni-sullautore": "",
        "tags": {
          "2": "Milioni",
          "3": "In tutto il mondo"
        }
      },
      "relationships": {
        "category": {
          "data": {
            "type": "categories",
            "id": "11"
          }
        },
        "created_by": {
          "data": {
            "type": "users",
            "id": "393"
          }
        },
        "tags": {
          "data": [
            {
              "type": "tags",
              "id": "3"
            },
            {
              "type": "tags",
              "id": "2"
            }
          ]
        }
      }
    },
    {
      "type": "articles",
      "id": "10",
      "attributes": {
        "id": 10,
        "asset_id": 141,
        "title": "Flussi di lavoro",
        "alias": "flussi-di-lavoro",
        "state": 1,
        "access": 1,
        "created": "2026-01-10 10:22:13",
        "created_by": 393,
        "created_by_alias": "Joomla",
        "modified": "2026-01-10 11:29:18",
        "featured": 0,
        "language": "*",
        "hits": 0,
        "publish_up": "2026-01-10 10:22:13",
        "publish_down": null,
        "note": "",
        "images": {
          "image_intro": "",
          "image_intro_alt": "",
          "float_intro": "",
          "image_intro_caption": "",
          "image_fulltext": "https://joomla.sviluppo.online/images/sampledata/cassiopeia/nasa4-400.jpg#joomlaImage://local-images/sampledata/cassiopeia/nasa4-400.jpg?width=400&height=400",
          "image_fulltext_alt": "",
          "image_fulltext_alt_empty": "1",
          "float_fulltext": "float-end",
          "image_fulltext_caption": "www.nasa.gov/multimedia/imagegallery"
        },
        "metakey": "",
        "metadesc": "",
        "metadata": {
          "robots": "",
          "author": "",
          "rights": ""
        },
        "version": 2,
        "featured_up": null,
        "featured_down": null,
        "typeAlias": "com_content.article",
        "text": "<p>I workflows gestiscono le fasi che i tuoi articoli devono attraversare fino alla loro pubblicazione.</p>\r\n<p>Il componente per gestire i workflows non è abilitato di default.</p>\r\n<p>Per vedere il flusso di lavoro che abbiamo fornito con i dati di esempio, devi prima abilitare questa funzionalità.</p>\r\n<ol>\r\n<li>Accedete all'area di amministrazione</li>\r\n<li>Da 'Contenuto' &gt; 'Articoli' &gt; 'Opzioni' &gt; scheda 'Integrazione' impostate 'Abilita workflows' su 'Si'</li>\r\n<li>Salva i cambiamenti</li>\r\n</ol>\r\n<p>Ora quando accedete nuovamente a 'Contenuto' vedrete la sezione 'workflows'.</p>\r\n<p>Quando modificate un articolo vedrete anche le nuove transizioni per gli articoli relativi ai workflows.</p> ",
        "informazioni-sullautore": "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.",
        "tags": {
          "5": "Joomla 6"
        }
      },
      "relationships": {
        "category": {
          "data": {
            "type": "categories",
            "id": "9"
          }
        },
        "created_by": {
          "data": {
            "type": "users",
            "id": "393"
          }
        },
        "tags": {
          "data": [
            {
              "type": "tags",
              "id": "5"
            }
          ]
        }
      }
    }
  ],
  "meta": {
    "total-pages": 1
  }
}

Request: https://joomla.sviluppo.online/api/index.php/v1/content/articles?filter%5Btag%5D%5B%5D=2&filter%5Btag%5D%5B%5D=3&filter%5Btag%5D%5B%5D=5&filter%5Btag_mode%5D=all&page%5Blimit%5D=20&page%5Boffset%5D=0

0 expected items

Response:

{
  "links": {
    "self": "https://joomla.sviluppo.online/api/index.php/v1/content/articles?filter%5Btag%5D%5B%5D=2&filter%5Btag%5D%5B%5D=3&filter%5Btag%5D%5B%5D=5&filter%5Btag_mode%5D=all&page%5Blimit%5D=20&page%5Boffset%5D=0"
  },
  "data": [],
  "meta": {
    "total-pages": 0
  }
}

This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/46325.

@tecpromotion tecpromotion added the PBF Pizza, Bugs and Fun label Jan 23, 2026
@exlemor
Copy link

exlemor commented Jan 30, 2026

I have tested this item ✅ successfully on 3642879

I have tested this during PBF 2026 with Olivier watching... @alikon - I was able to match BEFORE and AFTER successfully but I have 1 doubt.

With the PR applied, with:
https://www.domain.com/_j61a4/api/index.php/v1/content/articles?filter[tag][]=2&filter[tag][]=3&filter[tag_mode]=all

I got:

{
"links": {
"self": "https://www.domain.com/_j61a4/api/index.php/v1/content/articles?filter[tag][]=2&filter[tag][]=3&filter[tag_mode]=all"
},
"data": [],
"meta": {
"total-pages": 0
}
}

as expected based on my tags distribution on articles.

but with https://www.domain.com/_j61a4/api/index.php/v1/content/articles?filter[tag][]=2&filter[tag][]=3&filter[tag_mode]=any

SHOULD I get articles, 16, 6, 5, 4, 3, and 1 to show up EVEN THOUGH I have UNPUBLISHED the Tags in the backend?

IF I am NOT supposed to have them listed, then the PR fails, if I am supposed to have them listed, then it passes.


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/46325.

@TerryHarker
Copy link

I have tested this item ✅ successfully on 3642879


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/46325.

@alikon
Copy link
Contributor Author

alikon commented Jan 31, 2026

RTC


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/46325.

@alikon alikon removed the PBF Pizza, Bugs and Fun label Jan 31, 2026
@joomla-cms-bot joomla-cms-bot added the RTC This Pull Request is Ready To Commit label Jan 31, 2026
@jikubiswal
Copy link

I have tested this item ✅ successfully on 3642879

I have verified that the patch for Applied Commit SHA: 3642879
is functioning correctly.
I confirmed that ArticlesModel.php now correctly handles the tag_mode filter, switching to AND logic when tag_mode=all. I also confirmed that ArticlesController.php exposes this filter to the API.


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/46325.

@KishoriBKarale
Copy link

I have tested this item ✅ successfully on 3642879


This comment was created with the J!Tracker Application at issues.joomla.org/tracker/joomla-cms/46325.

@richard67
Copy link
Member

@alikon Your PR changes filtering in the articles list in the backend model, but your testing instructions only test the new functionality of the API, they do not covert to test that filtering in the articles list in backend works as well as before, including the filtering for articles which do not have any tags assigned (tags filer "None"). So in my opinion your testing instructions are incomplete.

@Razzo1987 @exlemor @TerryHarker @jikubiswal @KishoriBKarale Has anyone of you tested that filtering in the articles list in backend is not broken so it works as well as before, also when filtering for articles which do not have any tags assigned (tags filer "None")?

Copy link
Member

@richard67 richard67 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please apply my change suggestions to revert unrelated and unnecessary and partly wrong code style changes.

@richard67 richard67 added the Updates Requested Indicates that this pull request needs an update from the author and should not be tested. label Feb 14, 2026
alikon and others added 5 commits February 14, 2026 16:30
Co-authored-by: Richard Fath <richard67@users.noreply.github.com>
Co-authored-by: Richard Fath <richard67@users.noreply.github.com>
Co-authored-by: Richard Fath <richard67@users.noreply.github.com>
Co-authored-by: Richard Fath <richard67@users.noreply.github.com>
Co-authored-by: Richard Fath <richard67@users.noreply.github.com>
@richard67
Copy link
Member

richard67 commented Feb 14, 2026

I have no idea why integration and unit tests are failing for Windows at the PHP installation, but it is not related to this PR.

@richard67
Copy link
Member

richard67 commented Feb 14, 2026

@alikon Please check the one remaining code style suggestion I made above: #46325 (comment) . Thanks in advance.

P.S.: Human tests and so RTC would still be valid as all changes after that were only code style changes.

@richard67 richard67 removed the Updates Requested Indicates that this pull request needs an update from the author and should not be tested. label Feb 15, 2026
->select('DISTINCT ' . $db->quoteName('content_item_id'))
->from($db->quoteName('#__contentitem_tag_map'))
->where([
$db->quoteName('tag_id') . ' = ' . $db->quote($tagId),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why don't you use prepared parameters here? You only need to bind the parameter to the $query object with bindArray() and use the result or by normal bind()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature PR-6.1-dev RTC This Pull Request is Ready To Commit Webservices

Projects

None yet

Development

Successfully merging this pull request may close these issues.