diff --git a/includes/rules_shipping_framework_woocommerce.php b/includes/rules_shipping_framework_woocommerce.php
index 726601e0b841957addde3a0525063e2778f404ae..cd676f921c067f8100a1f5d1d1b47e144e57af28 100644
--- a/includes/rules_shipping_framework_woocommerce.php
+++ b/includes/rules_shipping_framework_woocommerce.php
@@ -14,11 +14,12 @@ require_once( plugin_dir_path( __FILE__ ) . '/../library/rules_shipping_framewor
 class RulesShippingFrameworkWooCommerce extends RulesShippingFramework {
 	protected static $_method_ordering	= 'woocommerce_shipping_rules_ordering';
 	
-	function _construct() {
-		parent::_construct();
+	function __construct() {
+		parent::__construct();
 		load_plugin_textdomain('woocommerce-shipping-by-rules', false, basename( dirname( __FILE__ ) ) . '/languages' );
 		$this->registerScopings(array(
 			"categories"    => 'categories',
+			"subcategories" => 'subcategories',
 			"products"      => 'products',
 			"skus"          => 'products',
 		));
@@ -291,10 +292,36 @@ class RulesShippingFrameworkWooCommerce extends RulesShippingFramework {
 	*/
 	public function filterProducts($products, $filter_conditions) {
 		$result = array();
+		
+		// For the subcategories scoping we need all subcategories of the conditions:
+		$subcategories = array();
+		if (isset($filter_conditions['subcategories']) && !empty($filter_conditions['subcategories'])) {
+			foreach ($filter_conditions['subcategories'] as $catslug) {
+				// Get the term itself (we have only the slug!)
+				$cat = get_term_by('slug', $catslug, 'product_cat');
+				if (empty($cat))
+					continue;
+				$subcategories[] = $cat->slug;
+				// Get the list of all subcategories of the given categories
+				$args=array('child_of' => $cat->term_id, 'hierarchical' => 1);
+				foreach (get_terms( 'product_cat', $args) as $subcat) {
+					$subcategories[] = $subcat->slug;
+				}
+			}
+			$subcategories = array_unique($subcategories);
+		}
+		
+		// Now filter out all products that do not match the conditions
 		foreach ($products as $p) {
+			$prodcategories = array();
+			foreach (wc_get_product_terms( $p['data']->id, 'product_cat') as $cat) {
+				$prodcategories[] = $cat->slug;
+			}
 			if (!empty($filter_conditions['products']) && !in_array($p['data']->get_sku(), $filter_conditions['products']))
 				continue;
-			if (!empty($filter_conditions['categories']) && count(array_intersect($filter_conditions['categories'], $p['data']->get_categories())==0))
+			if (!empty($filter_conditions['categories']) && count(array_intersect($filter_conditions['categories'], $prodcategories))==0)
+				continue;
+			if (!empty($filter_conditions['subcategories']) && count(array_intersect($subcategories, $prodcategories))==0)
 				continue;
 			$result[] = $p;
 		}
diff --git a/includes/rules_shipping_framework_woocommerce_advanced.php b/includes/rules_shipping_framework_woocommerce_advanced.php
index a120ad77ed60bccfb209d4b461ea49d9e99a5156..d0f467708ddbb8735b4140e25c82a16a0857aa7b 100644
--- a/includes/rules_shipping_framework_woocommerce_advanced.php
+++ b/includes/rules_shipping_framework_woocommerce_advanced.php
@@ -21,8 +21,8 @@ class RulesShippingFrameworkWooCommerceAdvanced extends RulesShippingFrameworkWo
 		}
 		return $helper;
     }
-	function _construct() {
-		parent::_construct();
+	function __construct() {
+		parent::__construct();
 	}
 	function isAdvanced() {
 		return true;
diff --git a/library/rules_shipping_framework.php b/library/rules_shipping_framework.php
index aef007cabfe4be25354bbcd215f08bfa78354ef0..b34c48bb98a0d7c8a587a25a875b6c30f87b35fa 100644
--- a/library/rules_shipping_framework.php
+++ b/library/rules_shipping_framework.php
@@ -90,6 +90,14 @@ class RulesShippingFramework {
 		$this->available_scopings = $scopings;
 	}
 	
+	/**
+	 * Get the list of all scopings the framework implementation claims to have
+	 * implemented.
+	 */
+	public function getScopings() {
+		return $this->available_scopings;
+	}
+	
 	public function readableString($string) {
 		switch ($string) {
 			case "OTSHIPMENT_RULES_CUSTOMFUNCTIONS_ALREADY_DEFINED":
@@ -777,27 +785,30 @@ class ShippingRule {
 		}
 	}
 	
+	protected function normalizeScoping($scoping) {
+		$scopings = $this->framework->getScopings();
+// $this->framework->warning("<pre>normalizing Scoping $scoping. Registered scopings are: ".print_r($scopings,1)."</pre>");
+		if (isset($scopings[$scoping])) {
+			return $scopings[$scoping];
+		} else {
+			return false;
+		}
+	}
+	
 	/** Evaluate the given expression $expr only for the products that match the filter given by the scoping 
 	 * function and the corresponding conditions */
 	protected function evaluateScoping($expr, $scoping, $conditionvals, $vals, $products, $cartvals_callback) {
 		if (count($conditionvals)<1)
 			return $this->evaluateTerm($expr, $vals, $products, $cartvals_callback);
-
-		// TODO: Make this more general!
-		$filterkeys = array(
-			"categories"    => 'categories',
-			"products"      => 'products',
-			"skus"          => 'products',
-			"vendors"       => 'vendors',
-			"manufacturers" => 'manufacturers',
-		);
 		
-		$conditions = array();
-		if (isset($filterkeys[$scoping])) {
-			$conditions[$filterkeys[$scoping]] = $conditionvals;
-		} else {
-			$this->framworks->warning('OTSHIPMENT_RULES_SCOPING_UNKNOWN', $scoping, $this->rulestring);
+// $this->framework->warning("<pre>evaluating scoping $scoping of expression ".print_r($expr,1)." with conditions ".print_r($conditionvals,1)."</pre>");
+		// Normalize aliases (e.g. 'skus' and 'products' usually indicate the same scoping
+		$normalizedScoping = $this->normalizeScoping($scoping);
+		if (!$normalizedScoping) {
+			$this->framework->warning('OTSHIPMENT_RULES_SCOPING_UNKNOWN', $scoping, $this->rulestring);
 			return false;
+		} else {
+			$conditions = array($normalizedScoping => $conditionvals);
 		}
 
 		// Pass the conditions to the parent plugin class to filter the current list of products:
@@ -907,7 +918,7 @@ class ShippingRule {
 		// The scoping functions need to be handled differently, because they first need to adjust the cart variables to the filtered product list
 		// before evaluating its first argument. So even though parsing the rules handles scoping functions like any other function, their 
 		// evaluation is fundamentally different and is special-cased here:
-		$is_scoping = is_array($expr) && ($expr[0]=="FUNCTION") && (count($expr)>1) && (substr($expr[1], 0, 13)==="evaluate_for_"));
+		$is_scoping = is_array($expr) && ($expr[0]=="FUNCTION") && (count($expr)>1) && (substr($expr[1], 0, 13)==="evaluate_for_");
 
 		if (is_null($expr)) {
 			return $expr;
diff --git a/releases/opentools-woocommerce-advanced-shipping-by-rules_v1.1.zip b/releases/opentools-woocommerce-advanced-shipping-by-rules_v1.1.zip
index bb5caa12ccf4f9ab3edf07da27b2a87a3334aa82..9de621dcc2c182bdc1063f8b72394e3aabb57961 100644
Binary files a/releases/opentools-woocommerce-advanced-shipping-by-rules_v1.1.zip and b/releases/opentools-woocommerce-advanced-shipping-by-rules_v1.1.zip differ
diff --git a/releases/opentools-woocommerce-shipping-by-rules_v1.1.zip b/releases/opentools-woocommerce-shipping-by-rules_v1.1.zip
index 0b906f423d082006d5668bc9ebe8e0b375af70ec..e58e29a4b3c434bad9aeb8435407e4a137376086 100644
Binary files a/releases/opentools-woocommerce-shipping-by-rules_v1.1.zip and b/releases/opentools-woocommerce-shipping-by-rules_v1.1.zip differ