With Matt’s help, I’ve developed a new system to add custom option/attribute values to the product class.
This system eliminates the need to override the entire product_loader class just to add custom values within the load_attributes method, located here:
includes/system/versioned/1.0.7.other/1.0.7.12/product_loader.php
Instead, it uses a system hook that overrides the load_attributes method. It performs a liberalized option/attribute query to retrieve all existing table columns, and includes a hook call that allows you to extend the attributes array with additional custom option/attribute values.
Here is the system hook file:
includes/hooks/shop/system/_09_loadAttributesRaiwa.php
Code: Select all
<?php
/*
* $Id: _09_loadAttributesRaiwa.php
* $Loc: /includes/hooks/shop/system/
*
* Name: OptionsImages
* Version: 3.2
* Release Date: 2025-04-14
* Author: Rainer Schmied
* phoenixcartaddonsaddons.com / raiwa@phoenixcartaddons.com
*
* License: Released under the GNU General Public License
*
* Comments: Author: [Rainer Schmied @raiwa]
* Author URI: [www.phoenixcartaddons.com]
*
* CE Phoenix, E-Commerce made Easy
* https://phoenixcart.org
*
* Copyright (c) 2021 Phoenix Cart
*
*
*/
class hook_shop_system__09_loadAttributesRaiwa {
protected static $saved_attribute_loader = null;
public function listen_productCapabilities($parameters) {
self::$saved_attribute_loader = $parameters['capabilities']['attributes'];
$parameters['capabilities']['attributes'] = __CLASS__ . '::add_image_to_attributes';
}
public static function add_image_to_attributes($product) {
$attributes = call_user_func(self::$saved_attribute_loader, $product);
$attributes_query_raw = sprintf(<<<'EOSQL'
SELECT po.*, pov.*, pa.*,
pad.products_attributes_filename, pad.products_attributes_maxdays, pad.products_attributes_maxcount
FROM products_options po
INNER JOIN products_attributes pa ON po.products_options_id = pa.options_id
LEFT JOIN products_options_values pov ON pa.options_values_id = pov.products_options_values_id AND po.language_id = pov.language_id
LEFT JOIN products_attributes_download pad ON pa.products_attributes_id = pad.products_attributes_id
WHERE po.language_id = %d AND pa.products_id = %d
EOSQL
, (int)($language_id ?? $_SESSION['languages_id']), (int)$product->get('id'));
if (defined('AM_DEFAULT_TEMPLATE_ORDER')) {
$attributes_query_raw .= <<<'EOSQL'
ORDER BY pa.sort_order, po.sort_order, po.products_options_name, pov.sort_order, pov.products_options_values_name
EOSQL
;
} else {
$attributes_query_raw .= <<<'EOSQL'
ORDER BY po.sort_order, po.products_options_name, pov.sort_order, pov.products_options_values_name
EOSQL
;
}
$attributes_query = $GLOBALS['db']->query($attributes_query_raw);
$attributes = [];
while ($attribute = $attributes_query->fetch_assoc()) {
if (!isset($attributes[$attribute['options_id']])) {
$attributes[$attribute['options_id']] = [
'name' => $attribute['products_options_name'],
'values' => [],
];
}
$attributes[$attribute['options_id']]['values'][$attribute['options_values_id']] = [
'name' => $attribute['products_options_values_name'],
'prefix' => $attribute['price_prefix'],
'price' => $attribute['options_values_price'],
'filename' => $attribute['products_attributes_filename'],
'maxdays' => $attribute['products_attributes_maxdays'],
'maxcount' => $attribute['products_attributes_maxcount'],
];
}
$parameters = [
'attributes' => &$attributes,
'attributes_query' => $attributes_query,
];
$GLOBALS['all_hooks']->cat('load_attributes', $parameters);
$product->set('has_attributes', (count($attributes) > 0) ? '1' : '0');
$product->set('attributes', $attributes);
return $attributes;
}
}
Code: Select all
<?php
/*
* $Id: optImages.php
* $Loc: /includes/hooks/shop/siteWide/
*
* Name: OptionsImages
* Version: 3.2
* Release Date: 2025-04-14
* Author: Rainer Schmied
* phoenixcartaddonsaddons.com / raiwa@phoenixcartaddons.com
*
* License: Released under the GNU General Public License
*
* Comments: Author: [Rainer Schmied @raiwa]
* Author URI: [www.phoenixcartaddons.com]
*
* CE Phoenix, E-Commerce made Easy
* https://phoenixcart.org
*
* Copyright (c) 2021 Phoenix Cart
*
*
*/
class hook_shop_siteWide_optImages {
public function listen_load_attributes($parameters) {
$attributes = &$parameters['attributes'];
$attributes_query = $parameters['attributes_query'];
$attribute = $attributes_query->data_seek(0);
while ($attribute = $attributes_query->fetch_assoc()) {
if ( isset($attribute['option_image']) || isset($attribute['products_options_values_image']) ) {
$attributes[$attribute['options_id']]['values'][$attribute['options_values_id']]['image'] = $attribute['option_image'] ?: $attribute['products_options_values_image'] ?: '';
}
}
}
}
Only the load_attributes method is overridden, instead of the entire product_loader class.
Multiple addons can add custom option/attribute values independently, without the need to manually merge or combine the product_loader class.
I’ve already refactored the following addons to use this new system:
Ajax Attributes Manager 4.0+
Attributes Weight 2.1+
Option Images 3.2+
Option Types 2.1+
QtPro 8.0+
Wholesale Lite 5.1+
Wholesale Pro 5.1+
For developers who want to use this system:
Include the hook file with your addon:
includes/hooks/shop/system/_09_loadAttributesRaiwa.php
(Include the Note: This file may already exist if any of the above addons are installed.)
Copy the second hook as a template:
includes/hooks/shop/siteWide/optImages.php
Rename and modify it according to your addon’s requirements.
Here both hooks packed:
Enjoy!
Rainer