Categorize & sub categorize from contents of one row and more execute even more queries in results
PDO has some rather handy fetching options.  FETCH_GROUP is good for grouping the first level (product categories), but some extra handling is necessary to group the second level (product name-sizes).  To perform this nested grouping, I'll show the implementation of a temporary variable to track whether or not the current iteration is processing a new group or the same group as the previous iteration.


It is important to point out that you should not be making multiple trips to the database.  Since this script can be sensibly executed with a single trip to the database, it should be.
Prepared statements should be used for stability/security.
&lt;li&gt; tags must live inside &lt;ul&gt; tags for proper html markup.


Tested Code:

$products = ['Tshirt', 'Trousers'];
$placeholders = str_repeat('?,', count($products) - 1) . '?';

$stmt = $conn-&gt;prepare("
     SELECT SUBSTRING_INDEX(product_type, '-', 1) AS product_group, product_type, text 
     FROM sales
     WHERE SUBSTRING_INDEX(product_type, '-', 1) IN ($placeholders)
     ORDER BY product_type
     ");
$stmt-&gt;execute($products);
$results = $stmt-&gt;fetchAll(PDO::FETCH_GROUP);
foreach ($results as $productGroup =&gt; $subarray) {
    echo "&lt;div&gt;{$productGroup}&lt;/div&gt;";
    $typeGroup = null;
    foreach ($subarray as $row) {
        if ($row['product_type'] != $typeGroup) {
            if ($typeGroup) {
                echo "&lt;/ul&gt;&lt;/ul&gt;";
            }
            echo "&lt;ul&gt;&lt;li&gt;{$row['product_type']}&lt;/li&gt;&lt;ul&gt;";
        }
        echo "&lt;li&gt;{$row['text']}&lt;/li&gt;";
        $typeGroup = $row['product_type'];
    }
    echo "&lt;/ul&gt;&lt;/ul&gt;";
}


Sample data / Rendered output:



...yeah, didn't try very hard on the images.