Здравствуйте уважаемые читатели блога Site on! Прошло достаточно много времени с момента опубликования последней статьи, это связано с заказами, которые начали поступать после создания раздела "Услуги" на этом блоге. Так вот в одном из заказов мне нужно было сделать подсистему оптовой торговли на базе VM2 как здесь, только этот сайт написан на ASP.NET а не на PHP. Так вот для реализации точно такой же системы оптовых закупок было необходимо добавить дополнительные поля в "админку" VirtueMart 2, эти поля должны были отвечать за настройку VM.
Я считаю, что умение добавить дополнительные поля в конфигурацию интернет-магазина может пригодиться для множества проектов, поэтому сегодня я расскажу вам, как правильно и быстро это сделать.
Для начала нужно выбрать место, где должна размещаться новая настройка VM. Вся конфигурация Virtuemart2 размещена в одном месте и делится на несколько вкладок:
Все эти вкладки хранятся по адресу:
\administrator\components\com_virtuemart\views\config\tmpl\
В моём случае настройка отвечала за формирование цен, поэтому я должен открыть файл: default_pricing.php
Первое, что мы должны решить: в каком месте хотим поместить новые поля. Я решил, что здесь им самое место:
Теперь мы должны решить простой вопрос вёрстки. Если вы хотите поместить поля туда же, куда и я, то вы должны в файле default_pricing.php найти 110 строку:
<td valign="top">
И заменить её на:
<td rowspan="2" valign="top">
Далее, после 150 строки, между </tr> и </table> вставляем новую строку HTML таблицы - tr, с нужными нам ячейками и полями:
<tr> <td valign="top"> <fieldset> <legend>Настройка оптового порога</legend> <table class="admintable"> <tr> <td style="text-align:right;font-weight:bold;">Оптовый порог №1</td> <td><input type="text" class="inputbox" name="opt1" id="opt1" value="<?php echo VmConfig::get('opt1', 1) ?>" size="20" /></td> </tr> <tr> <td style="text-align:right;font-weight:bold;">Оптовый порог №2</td> <td><input type="text" class="inputbox" name="opt2" id="opt2" value="<?php echo VmConfig::get('opt2', 1) ?>" size="20" /></td> </tr> </table> </fieldset> </td> </tr>
В результате имеем:
У вас, до тех пор, пока вы не введёте новые данные, в текстовом поле может выскакивать Notice (замечание), ничего страшного, как только вы введёте нужное вам значение и сохраните, Notice больше не будет появляться.
Как это работает?
Конфигурация VM, с точки зрения программирования, сделана очень удобно: все семь вкладок (магазин, внешний вид, шаблоны, формирование цен, оформление заказа, настройки сортировки и SEO) находятся внутри одной единственной HTML формы, которая при нажатии на кнопку "сохранить" посылает всё данные обработчику.
Почему мы можем так запросто добавить любое поле, без добавления новых столбцов в БД? Всё дело в том, что PHP обработчик, который принимает данные пришедшие из формы, сериализует их (встроенная функция PHP – serialize()). Благодаря сериализации, все данные могут храниться в одной ячейке БД без потери их структуры!
Для тех, кто ещё не сталкивался с функцией serialize(), думаю, тяжело представить о чём идёт речь. Поэтому давайте рассмотрим пример, как же всё-таки хранится конфигурация VM:
shop_is_offline=s:1:"0";|offline_message=czo3MzoiT3VyIFNob3AgaXMgY3VycmVudGx5IGRvd24gZm9yIG1haW50ZW5hbmNlLiBQbGVhc2UgY2hlY2sgYmFjayBhZ2FpbiBzb29uLiI7|use_as_catalog=s:1:"0";|currency_converter_module=s:14:"convertECB.php";|order_mail_html=s:1:"1";|useSSL=s:1:"0";|dangeroustools=s:1:"0";|debug_enable=s:4:"none";|google_jquery=s:1:"0";|multix=s:4:"none";|usefancy=s:1:"1";|jchosen=s:1:"1";|pdf_button_enable=s:1:"1";|show_emailfriend=s:1:"1";|show_printicon=s:1:"0";|show_out_of_stock_products=s:1:"1";|coupons_enable=s:1:"0";|show_uncat_child_products=s:1:"0";|coupons_default_expire=s:3:"1,D";|weight_unit_default=s:2:"KG";|lwh_unit_default=s:1:"M";|showReviewFor=s:4:"none";|reviewMode=s:4:"none";|showRatingFor=s:4:"none";|ratingMode=s:4:"none";|reviews_autopublish=s:1:"1";|reviews_minimum_comment_length=s:3:"100";|reviews_maximum_comment_length=s:4:"2000";|vmtemplate=s:7:"default";|categorytemplate=s:7:"default";|showCategory=s:1:"1";|categorylayout=s:1:"0";|categories_per_row=s:1:"3";|productlayout=s:1:"0";|products_per_row=s:1:"3";|vmlayout=s:1:"0";|show_store_desc=s:1:"1";|show_categories=s:1:"1";|homepage_categories_per_row=s:1:"3";|homepage_products_per_row=s:1:"3";|show_featured=s:1:"1";|featured_products_rows=s:1:"1";|show_topTen=s:1:"1";|topTen_products_rows=s:1:"1";|show_recent=s:1:"1";|recent_products_rows=s:1:"1";|show_latest=s:1:"1";|latest_products_rows=s:1:"1";|assets_general_path=s:33:"components/com_virtuemart/assets/";|media_category_path=s:35:"images/stories/virtuemart/category/";|media_product_path=s:34:"images/stories/virtuemart/product/";|media_manufacturer_path=s:39:"images/stories/virtuemart/manufacturer/";|media_vendor_path=s:33:"images/stories/virtuemart/vendor/";|forSale_path_thumb=s:42:"images/stories/virtuemart/forSale/resized/";|img_resize_enable=s:1:"1";|img_width=s:2:"90";|img_height=s:2:"90";|no_image_set=s:11:"noimage.gif";|no_image_found=s:11:"warning.png";|browse_orderby_field=s:12:"product_name";|browse_orderby_fields=a:3:{i:0;s:12:"product_name";i:1;s:13:"category_name";i:2;s:7:"mf_name";}|browse_search_fields=a:5:{i:0;s:12:"product_name";i:1;s:14:"product_s_desc";i:2;s:13:"category_name";i:3;s:20:"category_description";i:4;s:7:"mf_name";}|show_prices=s:1:"1";|price_show_packaging_pricelabel=s:1:"0";|show_tax=s:1:"1";|basePrice=s:1:"0";|basePriceText=s:1:"0";|basePriceRounding=s:2:"-1";|variantModification=s:1:"0";|variantModificationText=s:1:"0";|variantModificationRounding=s:2:"-1";|basePriceVariant=s:1:"0";|basePriceVariantText=s:1:"0";|basePriceVariantRounding=s:2:"-1";|basePriceWithTax=s:1:"0";|basePriceWithTaxText=s:1:"0";|basePriceWithTaxRounding=s:2:"-1";|discountedPriceWithoutTax=s:1:"0";|discountedPriceWithoutTaxText=s:1:"0";|discountedPriceWithoutTaxRounding=s:2:"-1";|salesPriceWithDiscount=s:1:"0";|salesPriceWithDiscountText=s:1:"0";|salesPriceWithDiscountRounding=s:2:"-1";|salesPrice=s:1:"1";|salesPriceText=s:1:"0";|salesPriceRounding=s:2:"-1";|priceWithoutTax=s:1:"0";|priceWithoutTaxText=s:1:"0";|priceWithoutTaxRounding=s:2:"-1";|discountAmount=s:1:"0";|discountAmountText=s:1:"0";|discountAmountRounding=s:2:"-1";|taxAmount=s:1:"0";|taxAmountText=s:1:"0";|taxAmountRounding=s:2:"-1";|addtocart_popup=s:1:"1";|check_stock=s:1:"0";|automatic_payment=s:1:"1";|automatic_shipment=s:1:"1";|agree_to_tos_onorder=s:1:"0";|oncheckout_show_legal_info=s:1:"1";|oncheckout_show_register=s:1:"1";|oncheckout_show_steps=s:1:"0";|oncheckout_show_register_text=s:47:"COM_VIRTUEMART_ONCHECKOUT_DEFAULT_TEXT_REGISTER";|inv_os=a:1:{i:0;s:1:"C";}|email_os_s=a:5:{i:0;s:1:"U";i:1;s:1:"C";i:2;s:1:"X";i:3;s:1:"R";i:4;s:1:"S";}|email_os_v=a:4:{i:0;s:1:"U";i:1;s:1:"C";i:2;s:1:"X";i:3;s:1:"R";}|seo_disabled=s:1:"0";|seo_translate=s:1:"0";|seo_use_id=s:1:"0";|sctime=d:1379576424.0872099399566650390625;|vmlang=s:5:"ru_ru";|virtuemart_config_id=i:1;|enable_content_plugin=s:1:"0";|active_languages=a:1:{i:0;s:5:"ru-RU";}|enableEnglish=s:1:"1";|useVendorEmail=s:1:"1";|pdf_icon=s:1:"0";|recommend_unauth=s:1:"0";|ask_question=s:1:"0";|asks_minimum_comment_length=s:2:"50";|asks_maximum_comment_length=s:4:"2000";|product_navigation=s:1:"0";|display_stock=s:1:"0";|latest_products_days=s:1:"7";|latest_products_orderBy=s:10:"created_on";|lstockmail=s:1:"0";|stockhandle=s:4:"none";|rised_availability=s:0:"";|image=s:0:"";|show_manufacturers=s:1:"1";|manufacturer_per_row=s:1:"3";|mediaLimit=s:2:"20";|llimit_init_BE=s:2:"20";|pagseq=s:0:"";|llimit_init_FE=s:2:"20";|pagseq_1=s:0:"";|pagseq_2=s:0:"";|pagseq_3=s:0:"";|pagseq_4=s:0:"";|pagseq_5=s:0:"";|feed_cat_published=s:1:"0";|feed_cat_show_images=s:1:"0";|feed_cat_show_prices=s:1:"0";|feed_cat_show_description=s:1:"0";|feed_cat_description_type=s:14:"product_s_desc";|feed_cat_max_text_length=s:3:"500";|forSale_path=s:0:"";|feed_latest_published=s:1:"0";|feed_latest_nb=s:1:"5";|feed_topten_published=s:1:"0";|feed_topten_nb=s:1:"5";|feed_featured_published=s:1:"0";|feed_featured_nb=s:1:"5";|feed_home_show_images=s:1:"0";|feed_home_show_prices=s:1:"0";|feed_home_show_description=s:1:"0";|feed_home_description_type=s:14:"product_s_desc";|feed_home_max_text_length=s:3:"500";|css=s:1:"1";|jquery=s:1:"1";|jprice=s:1:"1";|jsite=s:1:"1";|askprice=s:1:"0";|rappenrundung=s:1:"0";|roundindig=s:1:"0";|cVarswT=s:1:"1";|unitPrice=s:1:"0";|unitPriceText=s:1:"0";|unitPriceRounding=s:1:"2";|popup_rel=s:1:"1";|oncheckout_opc=s:1:"0";|oncheckout_only_registered=s:1:"0";|oncheckout_show_images=s:1:"0";|vmlang_js=s:1:"0";|prd_brws_orderby_dir=s:3:"ASC";|browse_cat_orderby_field=s:13:"category_name";|cat_brws_orderby_dir=s:3:"ASC";|seo_sufix=s:7:"-detail";|task=s:5:"apply";|option=s:14:"com_virtuemart";|view=s:6:"config";|9585924ded6c9af5bdfe770ced6421da=s:1:"1";|cc2d302559e65683c7a323c83d1b5fb7=s:1:"1";|e5b2c07d7cf159d226562e3e13481e9d=s:1:"1";|cbd8355455aed29b53bcf36eeacbd1a1=s:1:"1";|opt1=s:4:"6000";|opt2=s:5:"15000";|51ea7a3d0491d43ce7582744dcd03eb8=s:1:"1";
Это не чистая функция serialize(), но она здесь присутствует. Суть проста, мы видим имя переменной, затем после символа равенства написан её тип (s – string, a – array, и тд.), далее количество символов и её значение. Следующая строчка из примера выше, является чистым примером работы функции сериализации:
a:5:{i:0;s:1:"U";i:1;s:1:"C";i:2;s:1:"X";i:3;s:1:"R";i:4;s:1:"S";}
С помощью функции unserialize() мы запросто превратим всё это обратно в привычный для нас массив.
Но вернёмся к добавленным нами полям:
<tr> <td style="text-align:right;font-weight:bold;">Оптовый порог №1</td> <td><input type="text" class="inputbox" name="opt1" id="opt1" value="<?php echo VmConfig::get('opt1', 1) ?>" size="20" /></td> </tr> <tr> <td style="text-align:right;font-weight:bold;">Оптовый порог №2</td> <td><input type="text" class="inputbox" name="opt2" id="opt2" value="<?php echo VmConfig::get('opt2', 1) ?>" size="20" /></td> </tr>
Мы добавили два полностью идентичных поля, поэтому рассмотрим подробнее на примере этой строки:
<td><input type="text" class="inputbox" name="opt1" id="opt1" value="<?php echo VmConfig::get('opt1', 1) ?>" size="20" /></td>
Где td – это просто обозначение ячейки HTML таблицы, далее идёт input типа text. Тип текст обозначает, что в это поле нужно будет что-то вписывать. Далее идёт класс inputbox, который служит для оформления, после него идёт самый важный атрибут под названием name, это имя, под которым наша настройка будет заноситься в БД. Далее идёт id, которое я по аналогии назвал одинаково с name, и в атрибут value мы записали вывод нашего значения.
Как пользоваться дополнительным полем?
Только что мы добавили новое поля в админ. панели Virtuemart2, которое никаким образом не нарушило структуры и целостности базы данных VM и VM в целом. Чтобы обратиться к вновь созданным полям, вы должны использовать следующий код:
VmConfig::get('opt1', 1)
Где opt1 – это значение атрибута name добавленного нами input’а.
Теперь Вы можете использовать этот код практически в любом месте вашего интернет-магазина: сравнивать с ним, выполнять математические операции, выводить значение в браузер и любые другие действия, доступные в PHP при работе с переменными.