megauser Posted December 8, 2023 Report Share Posted December 8, 2023 Есть связанные товары в товаре, А кто делал для обычной страницы товары? На форуме что то не нашел ничего похожего. Quote Link to post Share on other sites
phukortsin Posted December 9, 2023 Report Share Posted December 9, 2023 Все это можно делать по аналогии. Но код не совсем простой и довольно объемный, требуется аккуратность... Quote Link to post Share on other sites
Kami Posted December 9, 2023 Report Share Posted December 9, 2023 15 часов назад, megauser сказал: Есть связанные товары в товаре, А кто делал для обычной страницы товары? На форуме что то не нашел ничего похожего. Чтоб не разжевывать скинул полные файлы, ищи в коде комменты /*related_page_products*/ /*/related_page_products*/ Запрос в базу CREATE TABLE `s_related_page_products` ( `page_id` int(11) NOT NULL, `related_id` int(11) NOT NULL, `position` int(11) NOT NULL, PRIMARY KEY (`page_id`,`related_id`), KEY `position` (`position`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; api/Pages.php <?php /** * Simpla CMS * * @copyright 2011 Denis Pikusov * @link http://simplacms.ru * @author Denis Pikusov * */ require_once('Simpla.php'); class Pages extends Simpla { /* * * Функция возвращает страницу по ее id или url (в зависимости от типа) * @param $id id или url страницы * */ public function get_page($id) { if(gettype($id) == 'string') $where = $this->db->placehold(' WHERE url=? ', $id); else $where = $this->db->placehold(' WHERE id=? ', intval($id)); $query = "SELECT id, url, header, name, meta_title, meta_description, meta_keywords, body, menu_id, position, visible FROM __pages $where LIMIT 1"; $this->db->query($query); return $this->db->result(); } /* * * Функция возвращает массив страниц, удовлетворяющих фильтру * @param $filter * */ public function get_pages($filter = array()) { $menu_filter = ''; $visible_filter = ''; $pages = array(); if(isset($filter['menu_id'])) $menu_filter = $this->db->placehold('AND menu_id in (?@)', (array)$filter['menu_id']); if(isset($filter['visible'])) $visible_filter = $this->db->placehold('AND visible = ?', intval($filter['visible'])); $query = "SELECT id, url, header, name, meta_title, meta_description, meta_keywords, body, menu_id, position, visible FROM __pages WHERE 1 $menu_filter $visible_filter ORDER BY position"; $this->db->query($query); foreach($this->db->results() as $page) $pages[$page->id] = $page; return $pages; } /* * * Создание страницы * */ public function add_page($page) { $query = $this->db->placehold('INSERT INTO __pages SET ?%', $page); if(!$this->db->query($query)) return false; $id = $this->db->insert_id(); $this->db->query("UPDATE __pages SET position=id WHERE id=?", $id); return $id; } /* * * Обновить страницу * */ public function update_page($id, $page) { $query = $this->db->placehold('UPDATE __pages SET ?% WHERE id in (?@)', $page, (array)$id); if(!$this->db->query($query)) return false; return $id; } /* * * Удалить страницу * */ public function delete_page($id) { if(!empty($id)) { /*related_page_products*/ $this->db->query('DELETE FROM __related_page_products WHERE page_id=?', intval($id)); /*/related_page_products*/ $query = $this->db->placehold("DELETE FROM __pages WHERE id=? LIMIT 1", intval($id)); if($this->db->query($query)) return true; } return false; } /*related_page_products*/ function get_related_products($page_id = array()) { if(empty($page_id)) return array(); $page_id_filter = $this->db->placehold('AND page_id in(?@)', (array)$page_id); $query = $this->db->placehold("SELECT page_id, related_id, position FROM __related_page_products WHERE 1 $page_id_filter ORDER BY position "); $this->db->query($query); return $this->db->results(); } // Функция возвращает связанные товары public function add_related_product($page_id, $related_id, $position=0) { $query = $this->db->placehold("INSERT IGNORE INTO __related_page_products SET page_id=?, related_id=?, position=?", $page_id, $related_id, $position); $this->db->query($query); return $related_id; } // Удаление связанного товара public function delete_related_product($page_id, $related_id) { $query = $this->db->placehold("DELETE FROM __related_page_products WHERE page_id=? AND related_id=? LIMIT 1", intval($page_id), intval($related_id)); $this->db->query($query); } /*/related_page_products*/ /* * * Функция возвращает массив меню * */ public function get_menus() { $menus = array(); $query = "SELECT * FROM __menu ORDER BY position"; $this->db->query($query); foreach($this->db->results() as $menu) $menus[$menu->id] = $menu; return $menus; } /* * * Функция возвращает меню по id * @param $id * */ public function get_menu($menu_id) { $query = $this->db->placehold("SELECT * FROM __menu WHERE id=? LIMIT 1", intval($menu_id)); $this->db->query($query); return $this->db->result(); } } simpla/PageAdmin.php <?PHP require_once('api/Simpla.php'); class PageAdmin extends Simpla { public function fetch() { $page = new stdClass; /*related_page_products*/ $related_products = array(); /*/related_page_products*/ if($this->request->method('POST')) { $page->id = $this->request->post('id', 'integer'); $page->name = $this->request->post('name'); $page->header = $this->request->post('header'); $page->url = trim($this->request->post('url')); $page->meta_title = $this->request->post('meta_title'); $page->meta_keywords = $this->request->post('meta_keywords'); $page->meta_description = $this->request->post('meta_description'); $page->body = $this->request->post('body'); $page->menu_id = $this->request->post('menu_id', 'integer'); $page->visible = $this->request->post('visible', 'boolean'); ## Не допустить одинаковые URL разделов. if(($p = $this->pages->get_page($page->url)) && $p->id!=$page->id) { $this->design->assign('message_error', 'url_exists'); } else { if(empty($page->id)) { $page->id = $this->pages->add_page($page); $page = $this->pages->get_page($page->id); $this->design->assign('message_success', 'added'); } else { $this->pages->update_page($page->id, $page); $page = $this->pages->get_page($page->id); $this->design->assign('message_success', 'updated'); } /*related_page_products*/ if(is_array($this->request->post('related_products'))) { foreach($this->request->post('related_products') as $p) { $rp[$p] = new stdClass; $rp[$p]->page_id = $page->id; $rp[$p]->related_id = $p; } $related_products = $rp; } $query = $this->db->placehold('DELETE FROM __related_page_products WHERE page_id=?', $page->id); $this->db->query($query); if(is_array($related_products)) { $pos = 0; foreach($related_products as $i=>$related_product) $this->pages->add_related_product($page->id, $related_product->related_id, $pos++); } /*/related_page_products*/ } } else { $id = $this->request->get('id', 'integer'); /*related_page_products*/ $related_products = (!$id ? array() : $this->pages->get_related_products(array('page_id'=>$id))); /*/related_page_products*/ if(!empty($id)) $page = $this->pages->get_page(intval($id)); else { $page->menu_id = $this->request->get('menu_id'); $page->visible = 1; } } /*related_page_products*/ if(!empty($related_products)) { foreach($related_products as &$r_p) $r_products[$r_p->related_id] = &$r_p; $temp_products = $this->products->get_products(array('id'=>array_keys($r_products))); foreach($temp_products as $temp_product) $r_products[$temp_product->id] = $temp_product; $related_products_images = $this->products->get_images(array('product_id'=>array_keys($r_products))); foreach($related_products_images as $image) { $r_products[$image->product_id]->images[] = $image; } } $this->design->assign('related_products', $related_products); /*/related_page_products*/ $this->design->assign('page', $page); $menus = $this->pages->get_menus(); $this->design->assign('menus', $menus); // Текущее меню if(isset($page->menu_id)) $menu_id = $page->menu_id; if(empty($menu_id) || !$menu = $this->pages->get_menu($menu_id)) { $menu = reset($menus); } $this->design->assign('menu', $menu); return $this->design->fetch('page.tpl'); } } simpla/design/html/page.tpl {capture name=tabs} {if in_array('pages', $manager->permissions)} {foreach $menus as $m} <li {if $m->id == $menu->id}class="active"{/if}><a href='index.php?module=PagesAdmin&menu_id={$m->id}'>{$m->name}</a></li> {/foreach} {/if} {/capture} {if $page->id} {$meta_title = $page->name scope=parent} {else} {$meta_title = 'Новая страница' scope=parent} {/if} {* Подключаем Tiny MCE *} {include file='tinymce_init.tpl'} {* On document load *} {literal} <script src="design/js/jquery/jquery.js"></script> <script src="design/js/jquery/jquery-ui.min.js"></script> {*related_page_products*} <script src="design/js/autocomplete/jquery.autocomplete-min.js"></script> {*related_page_products*} <script> $(function() { /*related_page_products*/ // Удаление связанного товара $(".related_products a.delete").live('click', function() { $(this).closest("div.row").fadeOut(200, function() { $(this).remove(); }); return false; }); // Добавление связанного товара var new_related_product = $('#new_related_product').clone(true); $('#new_related_product').remove().removeAttr('id'); $("input#related_products").autocomplete({ serviceUrl:'ajax/search_products.php', minChars:0, noCache: false, onSelect: function(suggestion){ $("input#related_products").val('').focus().blur(); new_item = new_related_product.clone().appendTo('.related_products'); new_item.removeAttr('id'); new_item.find('a.related_product_name').html(suggestion.data.name); new_item.find('a.related_product_name').attr('href', 'index.php?module=ProductAdmin&id='+suggestion.data.id); new_item.find('input[name*="related_products"]').val(suggestion.data.id); if(suggestion.data.image) new_item.find('img.product_icon').attr("src", suggestion.data.image); else new_item.find('img.product_icon').remove(); new_item.show(); }, formatResult: function(suggestions, currentValue){ var reEscape = new RegExp('(\\' + ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\'].join('|\\') + ')', 'g'); var pattern = '(' + currentValue.replace(reEscape, '\\$1') + ')'; return (suggestions.data.image?"<img align=absmiddle src='"+suggestions.data.image+"'> ":'') + suggestions.value.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>'); } }); // Сортировка связанных товаров $(".sortable").sortable({ items: "div.row", tolerance:"pointer", scrollSensitivity:40, opacity:0.7, handle: '.move_zone' }); /*/related_page_products*/ // Автозаполнение мета-тегов menu_item_name_touched = true; meta_title_touched = true; meta_keywords_touched = true; meta_description_touched = true; url_touched = true; if($('input[name="menu_item_name"]').val() == generate_menu_item_name() || $('input[name="name"]').val() == '') menu_item_name_touched = false; if($('input[name="meta_title"]').val() == generate_meta_title() || $('input[name="meta_title"]').val() == '') meta_title_touched = false; if($('input[name="meta_keywords"]').val() == generate_meta_keywords() || $('input[name="meta_keywords"]').val() == '') meta_keywords_touched = false; if($('textarea[name="meta_description"]').val() == generate_meta_description() || $('textarea[name="meta_description"]').val() == '') meta_description_touched = false; if($('input[name="url"]').val() == generate_url()) url_touched = false; $('input[name="name"]').change(function() { menu_item_name_touched = true; }); $('input[name="meta_title"]').change(function() { meta_title_touched = true; }); $('input[name="meta_keywords"]').change(function() { meta_keywords_touched = true; }); $('textarea[name="meta_description"]').change(function() { meta_description_touched = true; }); $('input[name="url"]').change(function() { url_touched = true; }); $('input[name="header"]').keyup(function() { set_meta(); }); }); function set_meta() { if(!menu_item_name_touched) $('input[name="name"]').val(generate_menu_item_name()); if(!meta_title_touched) $('input[name="meta_title"]').val(generate_meta_title()); if(!meta_keywords_touched) $('input[name="meta_keywords"]').val(generate_meta_keywords()); if(!meta_description_touched) { descr = $('textarea[name="meta_description"]'); descr.val(generate_meta_description()); descr.scrollTop(descr.outerHeight()); } if(!url_touched) $('input[name="url"]').val(generate_url()); } function generate_menu_item_name() { name = $('input[name="header"]').val(); return name; } function generate_meta_title() { name = $('input[name="header"]').val(); return name; } function generate_meta_keywords() { name = $('input[name="header"]').val(); return name; } function generate_meta_description() { if(typeof(tinyMCE.get("body")) =='object') { description = tinyMCE.get("body").getContent().replace(/(<([^>]+)>)/ig," ").replace(/(\ )/ig," ").replace(/^\s+|\s+$/g, '').substr(0, 512); return description; } else return $('textarea[name=body]').val().replace(/(<([^>]+)>)/ig," ").replace(/(\ )/ig," ").replace(/^\s+|\s+$/g, '').substr(0, 512); } function generate_url() { url = $('input[name="header"]').val(); url = url.replace(/[\s]+/gi, '-'); url = translit(url); url = url.replace(/[^0-9a-z_\-]+/gi, '').toLowerCase(); return url; } function translit(str) { var ru=("А-а-Б-б-В-в-Ґ-ґ-Г-г-Д-д-Е-е-Ё-ё-Є-є-Ж-ж-З-з-И-и-І-і-Ї-ї-Й-й-К-к-Л-л-М-м-Н-н-О-о-П-п-Р-р-С-с-Т-т-У-у-Ф-ф-Х-х-Ц-ц-Ч-ч-Ш-ш-Щ-щ-Ъ-ъ-Ы-ы-Ь-ь-Э-э-Ю-ю-Я-я").split("-") var en=("A-a-B-b-V-v-G-g-G-g-D-d-E-e-E-e-E-e-ZH-zh-Z-z-I-i-I-i-I-i-J-j-K-k-L-l-M-m-N-n-O-o-P-p-R-r-S-s-T-t-U-u-F-f-H-h-TS-ts-CH-ch-SH-sh-SCH-sch-'-'-Y-y-'-'-E-e-YU-yu-YA-ya").split("-") var res = ''; for(var i=0, l=str.length; i<l; i++) { var s = str.charAt(i), n = ru.indexOf(s); if(n >= 0) { res += en[n]; } else { res += s; } } return res; } </script> <!--related_page_products--> <style> .autocomplete-suggestions{ background-color: #ffffff; width: 100px; overflow: hidden; border: 1px solid #e0e0e0; padding: 5px; } .autocomplete-suggestions .autocomplete-suggestion{cursor: default;} .autocomplete-suggestions .selected { background:#F0F0F0; } .autocomplete-suggestions div { padding:2px 5px; white-space:nowrap; } .autocomplete-suggestions strong { font-weight:normal; color:#3399FF; } </style> <!--/related_page_products--> {/literal} {if $message_success} <!-- Системное сообщение --> <div class="message message_success"> <span class="text">{if $message_success == 'added'}Страница добавлена{elseif $message_success == 'updated'}Страница обновлена{/if}</span> <a class="link" target="_blank" href="../{$page->url}">Открыть страницу на сайте</a> {if $smarty.get.return} <a class="button" href="{$smarty.get.return}">Вернуться</a> {/if} <span class="share"> <a href="#" onClick='window.open("http://vkontakte.ru/share.php?url={$config->root_url|urlencode}/{$page->url|urlencode}&title={$page->name|urlencode}&description={$page->body|urlencode}&noparse=false","displayWindow","width=700,height=400,left=250,top=170,status=no,toolbar=no,menubar=no");return false;'> <img src="{$config->root_url}/simpla/design/images/vk_icon.png" /></a> <a href="#" onClick='window.open("http://www.facebook.com/sharer.php?u={$config->root_url|urlencode}/{$page->url|urlencode}","displayWindow","width=700,height=400,left=250,top=170,status=no,toolbar=no,menubar=no");return false;'> <img src="{$config->root_url}/simpla/design/images/facebook_icon.png" /></a> <a href="#" onClick='window.open("http://twitter.com/share?text={$page->name|urlencode}&url={$config->root_url|urlencode}/{$page->url|urlencode}&hashtags={$page->meta_keywords|replace:' ':''|urlencode}","displayWindow","width=700,height=400,left=250,top=170,status=no,toolbar=no,menubar=no");return false;'> <img src="{$config->root_url}/simpla/design/images/twitter_icon.png" /></a> </span> </div> <!-- Системное сообщение (The End)--> {/if} {if $message_error} <!-- Системное сообщение --> <div class="message message_error"> <span class="text">{if $message_error == 'url_exists'}Страница с таким адресом уже существует{/if}</span> <a class="button" href="">Вернуться</a> </div> <!-- Системное сообщение (The End)--> {/if} <!-- Основная форма --> <form method=post id=product enctype="multipart/form-data"> <input type=hidden name="session_id" value="{$smarty.session.id}"> <div id="name"> <input class="name" name=header type="text" value="{$page->header|escape}"/> <input name=id type="hidden" value="{$page->id|escape}"/> <div class="checkbox"> <input name=visible value='1' type="checkbox" id="active_checkbox" {if $page->visible}checked{/if}/> <label for="active_checkbox">Активна</label> </div> </div> <!-- Параметры страницы --> <div class="block"> <ul> <li><label class=property>Название пункта в меню</label><input name="name" class="simpla_inp" type="text" value="{$page->name|escape}" /></li> <li><label class=property>Меню</label> <select name="menu_id"> {foreach $menus as $m} <option value='{$m->id}' {if $page->menu_id == $m->id}selected{/if}>{$m->name|escape}</option> {/foreach} </select> </li> </ul> </div> <!-- Параметры страницы (The End)--> <!-- Левая колонка свойств товара --> <div id="column_left"> <!-- Параметры страницы --> <div class="block layer"> <h2>Параметры страницы</h2> <ul> <li><label class=property>Адрес</label><div class="page_url">/</div><input name="url" class="page_url" type="text" value="{$page->url|escape}" /></li> <li><label class=property>Заголовок</label><input name="meta_title" class="simpla_inp" type="text" value="{$page->meta_title|escape}" /></li> <li><label class=property>Ключевые слова</label><input name="meta_keywords" class="simpla_inp" type="text" value="{$page->meta_keywords|escape}" /></li> <li><label class=property>Описание</label><textarea name="meta_description" class="simpla_inp"/>{$page->meta_description|escape}</textarea></li> </ul> </div> <!-- Параметры страницы (The End)--> </div> <!-- Левая колонка свойств товара (The End)--> <!-- Правая колонка свойств товара --> <div id="column_right"> {*related_page_products*} <div class="block layer"> <h2>Связанные товары</h2> <div id=list class="sortable related_products"> {foreach from=$related_products item=related_product} <div class="row"> <div class="move cell"> <div class="move_zone"></div> </div> <div class="image cell"> <input type=hidden name=related_products[] value='{$related_product->id}'> <a href="{url id=$related_product->id}"> <img class=product_icon src='{$related_product->images[0]->filename|resize:35:35}'> </a> </div> <div class="name cell"> <a href="{url id=$related_product->id}">{$related_product->name}</a> </div> <div class="icons cell"> <a href='#' class="delete"></a> </div> <div class="clear"></div> </div> {/foreach} <div id="new_related_product" class="row" style='display:none;'> <div class="move cell"> <div class="move_zone"></div> </div> <div class="image cell"> <input type=hidden name=related_products[] value=''> <img class=product_icon src=''> </div> <div class="name cell"> <a class="related_product_name" href=""></a> </div> <div class="icons cell"> <a href='#' class="delete"></a> </div> <div class="clear"></div> </div> </div> <input type=text name=related id='related_products' class="input_autocomplete" placeholder='Выберите товар чтобы добавить его'> </div> <input class="button_green button_save" type="submit" name="" value="Сохранить" /> {*/related_page_products*} </div> <!-- Правая колонка свойств товара (The End)--> <!-- Описагние товара --> <div class="block layer"> <h2>Текст страницы</h2> <textarea name="body" class="editor_large">{$page->body|escape}</textarea> </div> <!-- Описание товара (The End)--> <input class="button_green button_save" type="submit" name="" value="Сохранить" /> </form> <!-- Основная форма (The End) --> view/PageView.php <?PHP /** * Simpla CMS * * @copyright 2011 Denis Pikusov * @link http://simplacms.ru * @author Denis Pikusov * * Этот класс использует шаблон page.tpl * */ require_once('View.php'); class PageView extends View { function fetch() { $url = $this->request->get('page_url', 'string'); $page = $this->pages->get_page($url); // Отображать скрытые страницы только админу if(empty($page) || (!$page->visible && empty($_SESSION['admin']))) return false; $this->design->assign('page', $page); $this->design->assign('meta_title', $page->meta_title); $this->design->assign('meta_keywords', $page->meta_keywords); $this->design->assign('meta_description', $page->meta_description); /*related_page_products*/ // Связанные товары $related_ids = array(); $related_products = array(); foreach($this->pages->get_related_products($page->id) as $p) { $related_ids[] = $p->related_id; $related_products[$p->related_id] = null; } if(!empty($related_ids)) { foreach($this->products->get_products(array('id'=>$related_ids, 'visible'=>1)) as $p) $related_products[$p->id] = $p; $related_products_images = $this->products->get_images(array('product_id'=>array_keys($related_products))); foreach($related_products_images as $related_product_image) if(isset($related_products[$related_product_image->product_id])) $related_products[$related_product_image->product_id]->images[] = $related_product_image; $related_products_variants = $this->variants->get_variants(array('product_id'=>array_keys($related_products), 'in_stock'=>1)); foreach($related_products_variants as $related_product_variant) { if(isset($related_products[$related_product_variant->product_id])) { $related_products[$related_product_variant->product_id]->variants[] = $related_product_variant; } } foreach($related_products as $id=>$r) { if(is_object($r)) { $r->image = &$r->images[0]; $r->variant = &$r->variants[0]; } else { unset($related_products[$id]); } } $this->design->assign('related_products', $related_products); } /*/related_page_products*/ return $this->design->fetch('page.tpl'); } } В шаблоне сайта {if $related_products} {foreach $related_products as $related_product} Тут товары {/foreach} {/if} Ну и в api/Products.php в функции delete_product добавить удаление товара из связанных при его удалении /*related_page_products*/ $this->db->query("DELETE FROM __related_page_products where related_id=?", $id); /*/related_page_products*/ Quote Link to post Share on other sites
Kami Posted December 9, 2023 Report Share Posted December 9, 2023 5 часов назад, phukortsin сказал: Все это можно делать по аналогии. Но код не совсем простой и довольно объемный, требуется аккуратность... Ну не прям объемный, но да, внимательно надо отнестись к запросам при копировании связанных. Quote Link to post Share on other sites
phukortsin Posted December 12, 2023 Report Share Posted December 12, 2023 В 09.12.2023 в 15:05, Kami сказал: Ну не прям объемный Именно объемный. В Вашем же посте вижу с ходу тому два подтверждения. Первое: В 09.12.2023 в 14:59, Kami сказал: Чтоб не разжевывать скинул полные файлы Пользователю куда удобнее иметь инструкцию в виде "в файле таком-то вставить код такой-то в место такое-то". То, что Вы в таком виде не написали, говорит о том, что это требует трудозатрат, и куда больше чем пара минут. Второе: В 09.12.2023 в 14:59, Kami сказал: ищи в коде комменты /*related_page_products*/ /*/related_page_products*/ Потому как если выискать только такие комменты и сделать только по ним изменения, то с гарантией работать не будет. Потому как есть еще несколько иные комменты, и даже ДВУХ типов. Добавочно вспоминаем и тезис об аккуратности... Quote Link to post Share on other sites
Kami Posted December 14, 2023 Report Share Posted December 14, 2023 В 12.12.2023 в 08:32, phukortsin сказал: Именно объемный. В Вашем же посте вижу с ходу тому два подтверждения. Первое: Пользователю куда удобнее иметь инструкцию в виде "в файле таком-то вставить код такой-то в место такое-то". То, что Вы в таком виде не написали, говорит о том, что это требует трудозатрат, и куда больше чем пара минут. Второе: Потому как если выискать только такие комменты и сделать только по ним изменения, то с гарантией работать не будет. Потому как есть еще несколько иные комменты, и даже ДВУХ типов. Добавочно вспоминаем и тезис об аккуратности... Так как решение я дал бесплатно, то тут либо голову включать человеку, либо тут найти специалиста кто это всё перенесет исправно. В целом дал более чем полное решение) Quote Link to post Share on other sites
phukortsin Posted December 14, 2023 Report Share Posted December 14, 2023 Вам большая благодарность. Выложили довольно сложное решение бесплатно. Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.