Warning: chmod(): Operation not permitted in /var/www/hopeinstoughton_www/wp-content/plugins/simple-universal-google-analytics/main.php on line 8 [0] in function chmod in /var/www/hopeinstoughton_www/wp-content/plugins/simple-universal-google-analytics/main.php on line 8 [1] in function include_once in /var/www/hopeinstoughton_www/wp-settings.php on line 560 [2] in function require_once in /var/www/hopeinstoughton_www/wp-config.php on line 85 [3] in function require_once in /var/www/hopeinstoughton_www/wp-load.php on line 50 [4] in function require_once in /var/www/hopeinstoughton_www/wp-blog-header.php on line 13 [5] in function require in /var/www/hopeinstoughton_www/index.php on line 17
| Server IP : 94.177.8.99 / Your IP : 216.73.217.165 Web Server : Apache/2.4.58 (Ubuntu) System : Linux aries 6.8.0-134-generic #134-Ubuntu SMP PREEMPT_DYNAMIC Fri Jun 26 18:43:11 UTC 2026 x86_64 User : www-data ( 33) PHP Version : 8.1.34 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/theyoungdesigners_com/modules/store/model/ |
Upload File : |
<?php
class TProduct {
private $DATA;
private $parent;
public function __construct($parent) {
$this->parent = $parent;
}
static
public function loadFromDataset($parent, database_record $record) {
$res = new static($parent);
$res->setData($record);
return $res;
}
static
public function toSlug($name) {
$name = strtolower($name);
$name = trim(preg_replace('/[^[:alnum:][:space:]]/u', ' ', $name));
return preg_replace('~\s+~', '-', $name);
}
public function setData($DATA) {
$this->DATA = $DATA;
}
public function empty() {
return !is_object($this->DATA) || $this->DATA->empty();
}
public function AsSellPrice() {
$price = sprintf('%0.2f', $this->DATA->sp_price);
$p = strpos($price, '.');
$node = [
'full' => $price,
'whole' => substr($price, 0, $p),
'frac' => substr($price, $p + 1),
];
if ($this->parent->PriceFormat() == 2 && $node['frac'] == '00') {
$node['frac'] = '';
}
return $node;
}
public function AsTitle() {
return $this->DATA->sp_product . ' ' . $this->DATA->sp_model;
}
public function AsCaption() {
return $this->DATA->sp_product ?? 'New Product';
}
public function getId() {
return $this->DATA->sp_id ?? 0;
}
public function uri() {
if ($this->DATA->sp_id) {
return '/' . static::toSlug($this->DATA->sp_product) . '/p/' . $this->DATA->sp_id;
} else {
return FALSE;
}
}
public function AsHandleBars($admin = FALSE, $real = FALSE) {
$data = [
'sp_id' => (int) $this->DATA->sp_id,
'sm_caption' => $this->DATA->sm_caption ?? '',
'sp_manu' => (int) $this->DATA->sp_manu ?? '',
'sp_product' => $this->DATA->sp_product ?? '',
'sp_model' => $this->DATA->sp_model ?? '',
'sp_sku' => $this->DATA->sp_sku ?? '',
'uri' => $this->uri(),
'price' => $this->AsSellPrice(),
'page_title' => $this->AsTitle(),
'sp_desc' => $this->DATA->sp_desc ?? '',
'sp_category' => (int) $this->DATA->sp_category ?? '',
'spv' => (int) $this->DATA->sp_variation ?? '',
'sp_weight' => $this->DATA->sp_weight,
];
if ($admin) {
$id = $this->getId();
if (!$id) { // set default values
// load store settings
$settings = $GLOBALS['loader']->LoadModuleSettings('store');
$this->DATA->sp_usestock = $settings['physical'] ? 1 : 0;
}
$data['sp_price'] = $this->DATA->sp_price;
$data['sp_usestock'] = (int) $this->DATA->sp_usestock;
$data['sp_stock'] = $this->DATA->sp_stock;
$data['sp_active'] = (int) $this->DATA->sp_active;
$data['sp_feature'] = (int) $this->DATA->sp_feature;
$data['sp_featuretext']=$this->DATA->sp_featuretext;
$data['sp_upc'] = $this->DATA->sp_upc;
$data['sp_lithium'] = $this->DATA->sp_lithium;
$data['sp_media'] = (int) $this->DATA->sp_media;
$data['_category'] = '/' . static::toSlug($this->DATA->sc_caption) . '/c/' . $this->DATA->sc_id;
}
if ( (int) $this->DATA->sp_usestock ) {
$available = $this->DATA->sp_stock - $this->DATA->sp_allocated;
if (!$real) {
if ($available < 0) $available = 0;
if ($available > 10) $available = 10;
}
$data['stock'] = $available;
} else {
$data['stock'] = 10;
}
// clean up desc
$data['sp_desc'] = str_replace(["\r\n", "\r"], "\n", $data['sp_desc']);
$data['sp_desc'] = str_replace(["\n\n\n\n", "\n\n\n", "\n\n"], "\n", $data['sp_desc']);
$data['sp_desc'] = str_replace("\n", '<br>', $data['sp_desc']);
return $data;
}
public function CloneProduct($param) {
$fields = [
'sp_manu' => (int) $this->DATA->sp_manu,
'sp_product' => $this->DATA->sp_product,
'sp_model' => $this->DATA->sp_model,
'sp_sku' => $this->DATA->sp_sku,
'sp_upc' => $this->DATA->sp_upc,
'sp_desc' => $this->DATA->sp_desc,
'sp_price' => $this->DATA->sp_price,
'sp_category' => (int) $this->DATA->sp_category,
'sp_variation' => (int) $this->DATA->sp_variation,
'sp_feature' => (int) $this->DATA->sp_feature,
'sp_active' => 0,
'sp_stock' => 0,
'sp_usestock' => $this->DATA->sp_usestock,
];
$data = $this->parent->TableName('store_product')
->AutoInc('sp_id')
->InsertOrUpdate([ 'sp_id' => NULL ], $fields);
$this->parent->DbErr();
$param['source'] = $this->record_id;
$param['target'] = $data->sp_id;
$param['vargroup'] = $fields['sp_variation'];
// create a new product based on the current product
hook_execute('product.clone', $param);
return $param['target'];
}
private function _updateValue(&$changed, $fieldname, $value) {
if ($this->DATA->$fieldname != $value) {
$changed[$fieldname] = $value;
$this->DATA->$fieldname = $value;
}
}
public function SaveDetails($post) {
// make sure id has not changed
$changed = [];
switch ($post['tab']) {
case 'general':
$this->_updateValue($changed, 'sp_active', intval($post['sp_active'] ?? '0', 10));
$this->_updateValue($changed, 'sp_desc', trim($post['sp_desc']));
$this->_updateValue($changed, 'sp_manu', trim($post['sp_manu']));
$this->_updateValue($changed, 'sp_product', trim($post['sp_product']));
$this->_updateValue($changed, 'sp_category', trim($post['sp_category']));
$this->_updateValue($changed, 'sp_model', trim($post['sp_model']));
$this->_updateValue($changed, 'sp_sku', trim($post['sp_sku']));
$this->_updateValue($changed, 'sp_price', $post['sp_price']);
break;
case 'stock':
$this->_updateValue($changed, 'sp_usestock', intval($post['sp_usestock'] ?? '0', 10));
$this->_updateValue($changed, 'sp_upc', trim($post['sp_upc']));
$this->_updateValue($changed, 'sp_stock', empty($post['sp_stock']) ? 0 : $post['sp_stock']);
$this->_updateValue($changed, 'sp_weight', $post['sp_weight']);
$this->_updateValue($changed, 'sp_lithium', $post['sp_lithium']);
$this->_updateValue($changed, 'sp_media', intval($post['sp_media'] ?? '0', 10));
// dimensions
break;
case 'feature':
$this->_updateValue($changed, 'sp_feature', intval($post['sp_feature'] ?? '0', 10));
$this->_updateValue($changed, 'sp_featuretext', trim($post['sp_featuretext']));
break;
}
if (count($changed)) {
$record_id = $this->DATA->sp_id ?? NULL ;
$data = $this->parent->TableName('store_product')
->AutoInc('sp_id')
->InsertOrUpdate([ 'sp_id' => $record_id ], $changed);
$this->parent->DbErr();
$this->DATA->sp_id = $data->sp_id;
return TRUE;
}
return FALSE;
}
}
class Product_model extends Database_Model {
private $sku;
private $record_id;
private $PRODUCT;
private $x_data;
private $priceformat = FALSE;
public function PriceFormat() {
if (func_num_args()) {
$this->priceformat = func_get_arg(0);
return $this;
}
if ($this->priceformat === FALSE) { // load from settings
$settings = $GLOBALS['loader']->LoadModuleSettings('store');
$this->priceformat = intval($settings['priceformat'] ?? '1');
}
return $this->priceformat;
}
public function SKU() {
if (func_num_args()) {
$this->sku = func_get_arg(0);
return $this;
}
return $this->sku;
}
public function RecordId() {
if (func_num_args()) {
$old_id = $this->record_id;
$this->record_id = func_get_arg(0);
if ($old_id != $this->record_id) {
$this->Load();
}
return $this;
}
return $this->record_id;
}
public function empty() {
if (is_object($this->PRODUCT)) {
return $this->PRODUCT->empty();
} else {
return TRUE;
}
}
static
public function toSlug($name) {
$name = strtolower($name);
$name = trim(preg_replace('/[^[:alnum:][:space:]]/u', ' ', $name));
return preg_replace('~\s+~', '-', $name);
}
public function AsCaption() {
return $this->PRODUCT->AsCaption();
}
protected function Load() {
$DATA = $this->Query("select p.*,m.*,sc_id,sc_caption from `store_product` as p\n".
"left join store_manu as m on sm_id=sp_manu\n".
"left join store_category on sc_id=sp_category\n"
)
->Where('sp_id=%d', $this->record_id)
->First();
$this->setData($DATA);
return $this;
}
public function LocateBySKU($sku) {
$DATA = $this->Query("select p.*,m.*,sc_id,sc_caption from `store_product` as p\n".
"left join store_manu as m on sm_id=sp_manu\n".
"left join store_category on sc_id=sp_category\n"
)
->Where('sp_sku=%s', $sku)
->First();
$this->setData($DATA);
return $this;
}
public function setData($DATA) {
$this->record_id = $DATA->sp_id ?? $this->record_id;
$this->DATA = $DATA;
$this->PRODUCT = TProduct::loadFromDataset($this, $DATA);
}
// $100 Apple Gift Card - App Store, Apple Music, iTunes, iPhone, iPad, AirPods, accessories, and more [Digital]
// 100-apple-gift-card-app-store-apple-music-itunes-iphone-ipad-airpods-accessories-and-more-digital/
public function uri() {
return $this->PRODUCT->uri();
}
public function AsHandleBars($admin = FALSE, $real = FALSE) {
return $this->PRODUCT->AsHandleBars($admin, $real);
}
public function listManufacturer() {
$rows = $this->Query("select * from `store_manu`\n")
->OrderBy('sm_caption')
->Get();
$output = [];
foreach($rows as $row) {
$output[] = [
'key' => $row->sm_id,
'value' => $row->sm_caption,
];
}
return $output;
}
public function SaveDetails($post) {
$status = $this->PRODUCT->SaveDetails($post);
if ($status) {
$this->record_id = (int) $this->PRODUCT->getId();
}
return $status;
}
public function CustomFields($rep) {
$rep->pagesize(25);
$col = $rep->AddColumn();
$col->name('sp_sku')
->caption('SKU')
->render([$this, '__displaySKU'])
->width(100);
$col = $rep->AddColumn();
$col->name('sp_product')
->caption('Product')
->render(function($value, $item) {
$safevalue = htmlspecialchars($value);
$active = (int) $item->sp_active;
if (!$active) $safevalue = "<i title=\"disabled product\">$safevalue</i>";
return [
'disp' => $safevalue,
'val' => $value,
];
});
$col = $rep->AddColumn();
$col->name('sp_feature')
->className('dt-center')
->caption('Featured')
->render(function($value, $item) {
if ($value) {
$safevalue = '✔';
} else {
$safevalue = ' ';
}
return [
'disp' => $safevalue,
'val' => $value,
];
})
->width(20);
$col = $rep->AddColumn();
$col->name('sp_usestock')
->className('dt-center')
->caption('Physical?')
->render(function($value, $item) {
if ($value) {
$safevalue = '✔';
} else {
$safevalue = ' ';
}
return [
'disp' => $safevalue,
'val' => $value,
];
})
->width(20);
$col = $rep->AddColumn();
$col->name('sp_price')
->className('right')
->caption('Price')
->render(function($value) {
return sprintf('%0.2f', $value);
})
->width(30);
$col = $rep->AddColumn();
$col->name('sp_stock')
->className('right')
->caption('Stock')
->render(function($value, $item) {
$physical = (int) $item->sp_usestock;
return $physical ? sprintf('%0.2f', $value) : 'n/a';
})
->width(25);
$col = $rep->AddColumn();
$col->name('sp_active')
->width(0);
}
public function ProductList($rep) {
$data = $rep->Query('select * from `store_product`')->Execute();
return ['data' => $data];
}
public function __displaySKU($value, $item) {
if ($value == '') $value = '(missing)';
return "<a href=\"/admin/product/{$item->sp_id}/edit#general\">$value</a>";
}
public function CloneProduct($param) {
return $this->PRODUCT->CloneProduct($param);
}
public function productOverlay(&$items) {
$where = [];
foreach($items as $item) {
$where[$item['product']] = NULL;
}
unset($item);
$rows = $this->Query("select * from `store_product` as p ".
"left join store_manu on sm_id=sp_manu ")
->WhereIn('sp_id', array_keys($where))
->Get();
$this->DbErr();
foreach($rows as $row) {
$product = TProduct::loadFromDataset($this, $row);
$where[$row->sp_id] = $product->AsHandleBars(TRUE);
}
foreach($items as &$item) {
$product_id = $item['product'];
if (is_array($where[$product_id])) {
$item = array_merge($item, $where[$product_id]);
}
}
$this->DATA = NULL;
$this->record_id = 0;
}
// returns full upc if valid, or check digit missing
// returns false if not upc or invalid check digit
static
public function checkUPC($value) {
$len = strlen($value);
if ($len < 11 || $len > 12) return FALSE;
if ($len == 12) {
$check = $value[$len - 1];
$len--;
} else {
$check = FALSE;
}
$evenDigitSum = $oddDigitSum = 0;
for($i = 0; $i < $len; $i++) {
if ($i & 1) {
$oddDigitSum += $value[$i];
} else {
$evenDigitSum += $value[$i];
}
}
$remainder = ($oddDigitSum * 3 + $evenDigitSum) % 10;
if ($remainder) return 10 - $remainder;
$value = substr($value, 0, 11);
if ($check !== FALSE && $remainder != $check) return FALSE;
return $value . $remainer;
}
public function AsDataTable_Manufacturer() {
$data = [];
$rows = $this->Query("select * from `store_manu` as m ")
->OrderBy('sm_caption')
->Get();
$this->DbErr();
foreach($rows as $row) {
$auth = hook_execute('nonce.create', FALSE, 'man', $row->sm_id, 300);
$safetext = htmlspecialchars($row->sm_caption);
$data[] = [
"<a href=\"/admin/store/manufacturer?auth={$auth}\">{$safetext}</a>",
];
}
return ['data' => $data];
}
// AssembleFieldlist($res);
public function editManufacturer($id) {
$res = [];
$row = $this->Query("select * from `store_manu` as m ")
->where('sm_id=%d', $id)
->Get()
->First();
$res['name'] = $row->sm_caption ?? '';
$res['auth'] = hook_execute('nonce.create', FALSE, 'man', $id, 600);
$fieldlist = [];
$fieldlist[] = ['type' => 'string', 'id' => 'name', 'name'=>'name', 'caption' => 'Name', 'required' => TRUE];
$res['fieldlist'] = $fieldlist;
return $res;
}
public function postManufacturer($param) {
$id = $param['id'] ? $param['id'] : NULL;
$name = $param['name'];
$row = $this->TableName('store_manu')
->AutoInc('sm_id')
->InsertOrUpdate([
'sm_id' => $id,
],[
'sm_caption' => $name,
]);
return (int) $row->sm_id;
}
public function generateSelect() {
$result = [];
$rows = $this->Query("select sp_id,sp_product from `store_product`")
->OrderBy('sp_product')
->Get();
foreach($rows as $row) {
$result[] = [
'key' => 'prod:' . $row->sp_id,
'value' => 'Product: ' . $row->sp_product,
];
}
return $result;
}
public function listActiveProducts() {
$rows = $this->Query("select * from `store_product`\n".
"left join store_manu as m on sm_id=sp_manu\n".
"left join store_category on sc_id=sp_category\n")
->Where('sp_active <> 0')
->OrderBy('sp_desc')
->Get();
$output = $this->_loadProducts($rows, FALSE, FALSE);
return $output;
}
public function getProductsInGroup($category_id, $include_images = TRUE) {
// get the product list
$this->Query("select * from `store_product`")
->Where('sp_active <> 0')
->OrderBy('sp_desc');
if (is_array($category_id)) {
$this->WhereIn('sp_category', $category_id);
} else {
$this->Where('sp_category=%d', $category_id);
}
$rows = $this->Get();
$this->DbErr();
$output = $this->_loadProducts($rows, $include_images);
// show only 1 variation
// (add ratings etc)
// return the list
return $output;
}
private function _loadProducts($rows, $include_images = TRUE, $include_availability = FALSE) {
$output = [ 'cart' => [] ];
foreach($rows as $row) {
$product = TProduct::loadFromDataset($this, $row);
$node = $product->AsHandleBars(FALSE, $include_availability);
if (($row->sm_caption ?? '') != '') $node['brand'] = $row->sm_caption;
$output['cart'][] = $node;
}
$output = [$output];
if ($include_images) { // merge in primary image
$output = hook_execute('order.list', $output, 0);
}
$output = $output[0]['cart'];
return $output;
}
// $features: 0 => all products
// 1 => featured only
public function getProductsByCategory($categories) {
$output = [];
$rows = [];
foreach($categories as $features => $category_ids) {
$this->Query('select p.*, '.
'if(sp_feature, if(sp_featuretext = "", sp_product, sp_featuretext), sp_product) as caption '.
'from `store_product` as p '.
'inner join `store_category` as c on p.sp_category=c.sc_id')
->Where('sp_active <> 0')
->WhereIn('sc_id', $category_ids);
if ($features) {
$this->Where('sp_feature=%d', 1);
}
$items = $this->Get();
foreach($items as $row) {
$row->sp_product = $row->caption;
$rows[] = $row;
}
}
$output = $this->_loadProducts($rows, TRUE);
return $output;
}
// https://developers.pinterest.com/docs/web-features/product-rich-pins/
public function OpenGraph($host, $company) {
$output = '';
// only if we are on a product page, we have different OG function for catalog and pages
if (!$this->empty()) {
$uri = $this->PRODUCT->Uri();
$price = $this->PRODUCT->AsSellPrice();
$safetitle = htmlspecialchars($this->PRODUCT->AsTitle());
$desc = $this->DATA->sp_desc ?? '';
$safedesc = htmlspecialchars(substr(trim(preg_replace('~\s+~', ' ', strip_tags($desc))), 0, 300)); // this should not contain any html tags. 512 is too long
$safeco = htmlspecialchars($company);
$output .= <<<BLOCK
<meta property="og:type" content="product" />
<meta property="og:title" content="$safetitle" />
<meta property="og:description" content="$safedesc" />
<meta property="og:url" content="$host$uri"/>
<meta property="og:site_name" content="$safeco"/>
<meta property="product:price:amount" content="{$price['full']}"/>
<meta property="product:price:currency" content="USD"/>
<meta property="og:availability" content="instock" />
BLOCK;
}
return $output;
}
// get the first product, otherwise return ''
public function getFirstProductPage() {
$row = $this->Query('select sp_id from `store_product`')
->where('sp_active<>0')
->OrderBy('sp_id')->First();
$this->DbErr();
if (!$row->empty()) {
return 'prod:' . $row->sp_id;
}
return '';
}
}