Jak korzystać z systemu nadpisywania w PrestaShop bez naruszania rdzenia

System nadpisywania w PrestaShop pozwala dostosować działanie rdzenia bez ingerencji w oryginalne pliki. Jednak nieostrożne jego użycie prowadzi do powstania niestabilnych sklepów, które przestają działać po aktualizacjach. Ten poradnik Knowbanda omawia, jak działają nadpisywania, kiedy ich używać i trzy kluczowe pułapki, które powinien znać każdy programista.

Czym jest system nadrzędny?

PrestaShop wykorzystuje dziedziczenie PHP, aby umożliwić Ci podmianę dowolnej klasy podstawowej bez ingerencji w oryginały. Każda klasa podstawowa ma nazwę z sufiksem Core, na przykład ProductCore. Jeśli utworzysz plik /override/classes/Product.php z klasą o nazwie Product, która rozszerza ProductCore, PrestaShop załaduje Twoją wersję. To samo dotyczy kontrolerów.

Nadpisuj tylko te metody, które chcesz zmienić, nigdy nie kopiuj całego pliku klasy. Dzięki temu nadpisanie będzie prostsze i znacznie zmniejszy się ryzyko kolizji z przyszłymi aktualizacjami.

Przykład: ujawnienie bieżącej nazwy kontrolera w szablonie nagłówka:

Gdzie umieścić pliki nadrzędne

Nadpisania mogą znajdować się w dwóch miejscach. Globalny katalog /override/ w katalogu głównym instalacji jest aktywny natychmiast po wyczyszczeniu pamięci podręcznej. Lepszym rozwiązaniem jest umieszczenie nadpisań w module.

Umieszczenie nadpisu w module (np. /modules/mymodule/override/classes/Product.php) powoduje, że PrestaShop kopiuje go do /override/ podczas instalacji i usuwa bezproblemowo podczas deinstalacji. Jest to zalecane podejście.

Szybki przykład nadpisania klasy. Załóżmy, że chcesz udostępnić nazwę bieżącego kontrolera w szablonie nagłówka:

// /override/classes/controllers/FrontController.php

klasa FrontController rozszerza FrontControllerCore {

    funkcja publiczna initHeader() {

        self::$smarty->assign('currentController', get_class($this));

        zwróć nadrzędny::initHeader();

    } }

Zawsze wywołuj metodę nadrzędną, chyba że masz ku temu celowy powód. Pominięcie jej spowoduje przerwanie działania podstawowej funkcjonalności.

Nadpisywanie klas modułów i kontrolerów

Od PrestaShop 1.6 można również nadpisywać klasy modułów. Dodaj „Override” do nazwy klasy (np. BlockUserInfoOverride rozszerzające BlockUserInfo) i umieść ją w katalogu /override/modules/. To samo dotyczy kontrolerów modułów. Po każdym nadpisaniu wyczyść pamięć podręczną, a konkretnie usuń plik /cache/class_index.php, w przeciwnym razie nie zostanie ono uwzględnione.

Kiedy NIE używać nadpisów

Nadpisania są wyłączne — może istnieć tylko jedno na klasę. Są one również zabronione w modułach marketplace i powinny być zarezerwowane dla prywatnych dostosowań sklepu. Zanim sięgniesz po nadpisania, rozważ jedną z poniższych alternatyw:

  • Haczyki: PrestaShop uruchamia zdarzenia hook przy każdym ładowaniu strony — możesz z nich korzystać z poziomu modułu, aby uruchamiać niestandardowy kod lub umieszczać treść na stronie bez konieczności korzystania z klasy podstawowej.
  • Nadpisania usługi Symfony: Części PrestaShop, które zostały zmigrowane do Symfony, zapewniają bardziej przejrzystą ścieżkę przez kontener usług. Dekorujesz lub zastępujesz usługę, zamiast deptać samą klasę.
  • Niestandardowy model obiektu: Potrzebujesz dodać pola do encji głównej? Zbuduj własny ObjectModel z własną tabelą, zamiast łatać istniejący.

Zachowywanie bezpieczeństwa nadpisów poprzez aktualizacje

Aktualizacje PrestaShop mogą po cichu zmieniać sygnatury metod, pozostawiając nadpisanie działające na podstawie nieaktualnych założeń. Traktuj każde nadpisanie jako coś, do czego należy wracać po każdej aktualizacji. Skomentuj zmiany i ich uzasadnienie, sprawdź dziennik zmian i staraj się, aby nadpisanie było jak najmniejsze. Wąskie, dobrze skomentowane nadpisanie, które poprawnie wywołuje metody nadrzędne, przetrwa aktualizacje. Pełna kopia klasy to błąd, który tylko czeka, aby się ujawnić.

Pamięć podręczna „Ghost”: dlaczego Twoja nadpisana pamięć wydaje się niewidoczna

Najczęstszy powód, dla którego programiści uważają, że ich nadpisanie jest uszkodzone: PrestaShop nie skanuje pliku /override/ przy każdym żądaniu. Kompiluje mapę klas do pliku /cache/class_index.php i dopóki ten plik nie zostanie usunięty i wygenerowany ponownie, nadpisanie jest niewidoczne, niezależnie od poprawności kodu. Wyczyszczenie pamięci podręcznej Smarty nie wystarczy. Usuń plik class_index.php ręcznie przez FTP/SSH, w zakładce Parametry zaawansowane > Wydajność w panelu administracyjnym lub za pomocą konsoli Symfony.

Rysunek 1: Przepływ informacji w systemie nadpisywania PrestaShop i rola pliku /cache/class_index.php.

 

The Symfony Wall: starsze nadpisy nie działają w przypadku nowoczesnych kontrolerów

Ten starszy system PHP działa tylko na starszej warstwie ObjectModel PrestaShop. Od PS 1.7 kluczowe obszary zaplecza, w tym nowa strona produktu i ekrany zamówień, zostały przepisane w Symfony. System nadpisywania kodu PHP nie ma wpływu na te kontrolery Symfony. Dla tych użyj Dekoracja serwisowa, opakowanie lub zastąpienie usługi za pomocą pliku services.yml modułu. Jeśli nadpisanie nie daje efektu nawet po wyczyszczeniu pliku class_index.php, kontroler prawdopodobnie został zmigrowany przez Symfony.

Rozwiązywanie konfliktów: gdy dwa moduły chcą tej samej klasy

Gdy dwa moduły nadpisują tę samą klasę, PrestaShop zgłasza błąd podczas drugiej instalacji i pozostawia nadpisanie nieaktywne. Rozwiązanie jest ręczne: otwórz oba pliki, scal wszystkie metody w jeden plik /override/, który rozszerza klasę Core, a następnie usuń plik class_index.php. Dodaj komentarze identyfikujące moduły, które wniosły każdą metodę. Właśnie dlatego nadpisania są zakazane w modułach na platformie sprzedażowej – konflikty stają się problemem dla sprzedawcy. Jeśli tworzysz dla innych, używaj hooków.

Rysunek 2: Jak powstają konflikty nadpisywania, gdy dwa moduły są przeznaczone dla tej samej klasy, oraz jak rozwiązać ręczne scalanie.

O Knowbandie

Knowband to zaufany dostawca wtyczek i rozszerzeń do handlu elektronicznego z wieloletnim doświadczeniem w pomaganiu sprzedawcom internetowym w budowaniu szybszych, inteligentniejszych i bogatszych w funkcje sklepów. Niezależnie od tego, czy prowadzisz swój sklep na PrestaShop, OpenCart, Shopify, WooCommerce, Magentolub dowolnej innej dużej platformie, Knowband oferuje szeroką gamę gotowych do użycia wtyczek i rozszerzeń, które pomogą Ci zwiększyć funkcjonalność, poprawić wydajność i zapewnić lepsze wrażenia zakupowe, bez konieczności budowania wszystkiego od podstaw.

Jak skopiować wózek na inny wózek, aby zmienić identyfikator id_cart?

Cele bloga

Po przeczytaniu tego bloga będziemy mogli skopiować wózek na inny koszyk, aby zmienić identyfikator koszyka.

Wymaganie

Musimy zmodyfikować poniższy plik, aby naprawić to samo. Będziemy wprowadzać zmiany w pliku Core dla tego samego.

Katalog główny \ classes \ PaymentModule.php

Procedura

Musimy zmodyfikować funkcję sprawdzania poprawności w pliku klasy PaymentModule. Ponieważ ta funkcja jest wywoływana tylko raz podczas wypełniania zamówienia. Dodaliśmy kod w ten sam sposób, aby uniknąć tworzenia wielu koszyków.

if (self :: DEBUG_MODE) {PrestaShopLogger :: addLog ('PaymentModule :: validateOrder - funkcja o nazwie', 1, null, 'Cart', (int) $ id_cart, true); } if (! isset ($ this-> context)) {$ this-> context = Context :: getContext (); } $ this-> context-> cart = new Koszyk ((int) $ id_cart);

Poniższy kod należy dodać w funkcji sprawdzania poprawności po powyższych liniach.

// rozpoczęte zmiany // Aby zapisać bezpieczny klucz z bieżącym identyfikatorem koszyka i ponownie przypisać go do nowego koszyka $ old_cart_secure_key = $ this-> context-> cart-> secure_key; // Aby zapisać identyfikator klienta o aktualnym identyfikatorze koszyka i ponownie przypisać go do nowego koszyka $ old_cart_customer_id = (int) $ this-> context-> cart-> id_customer; // Odmówienie klienta ze starego koszyka $ this-> context-> cart-> id_customer = 0; // Aby zaktualizować koszyk $ this-> context-> cart-> save (); // Aby pobrać aktualne produkty koszyka $ cart_products = $ this-> context-> cart-> getProducts (); // Tworzenie nowego obiektu koszyka $ this-> context-> cart = new Cart (); $ this-> context-> cart-> id_lang = $ this-> context-> language-> id; $ this-> context-> cart-> id_currency = $ this-> context-> currency-> id; // aby dodać nowy koszyk $ this-> context-> cart-> add (); // aby zaktualizować nowy foreach koszyka ($ cart_products jako $ product) {$ this-> context-> cart-> updateQty ((int) $ product ['quantity'], (int) $ product ['id_product'], (int) $ product ['id_product_attribute']); } if ($ this-> context-> cookie-> id_guest) {$ guest = new Guest ($ this-> context-> cookie-> id_guest); $ this-> context-> cart-> mobile_theme = $ guest-> mobile_theme; } // aby zmapować nowy koszyk z klientem $ this-> context-> cart-> id_customer = $ old_cart_customer_id; // aby zapisać nowy koszyk $ this-> context-> cart-> save (); if ($ this-> context-> cart-> id) {$ this-> context-> cookie-> id_cart = (int) $ this-> context-> cart-> id; $ this-> context-> cookie-> write (); } //, aby zaktualizować identyfikator $ id_cart do nowego koszyka $ id_cart = (int) $ this-> context-> cart-> id; $ this-> context-> cart-> secure_key = $ old_cart_secure_key; // zmienia się

Po wykonaniu powyższej procedury lista zakupów będzie wyglądać tak, np. Mając duplikat koszyka z tymi samymi danymi, co koszyk, z którym zostało złożone zamówienie.

Podsumowanie

Po wykonaniu powyższej procedury będziesz mógł skopiować wózek na inny wózek w celu zmiany id_cart.


Otrzymuj najnowsze produkty bez specjalnych cen (OpenCart 2.3)

Cele bloga

Po przeczytaniu tego bloga będziesz mógł pobierać produkty z bazy danych Opencart na podstawie parametru przekazywanego z adresu URL.

Wymaganie

Musimy wyświetlić najnowsze produkty na podstawie przekazanego parametru w adresie URL. Korzystając z tego parametru, musimy zdecydować, czy musimy wyświetlać specjalne produkty, czy nie.

Implementacja kodu

Aby to zaimplementować, musimy wprowadzić zmiany w naszym kontrolerze i modelu. W kontrolerze dodaliśmy warunek do przekazania parametru, aw modelu dokonamy zmian w zapytaniu zgodnie z przekazanym parametrem. Aby obsłużyć warunek, z którego korzystamy show_special parametr w kodzie. Poniżej znajduje się kod, który musimy dodać do kontrolera (katalog / kontroler / rozszerzenie / moduł / latest.php):

/ * Sprawdzanie klucza show_special w parametrze get * Ten klucz ($ show_special) zostanie użyty do warunkowego pobrania danych z bazy danych. * tzn. jeśli $ show_special = 1 wyświetli produkty, które specjalne * $ show_special = 0, a następnie wyświetla produkty, które nie mają specjalnego * innego * wyświetlają wszystkie produkty bez względu na specjalne * / if (isset ($ this-> request-> get [' show_special '])) {// przekazanie wartości zmiennej, jeśli ustawiono w URL $ show_special = $ this-> request-> get [' show_special ']; } else {// W przeciwnym razie pusty łańcuch zostanie przekazany $ show_special = ''; } // Tworzenie zmiennej do przekazania do modelu $ filter_data = array ('start' => ($ strona - 1) * limit $, 'limit' => limit $, show_special = = $ show_special); // Wywołanie funkcji modelu w celu pobrania danych z bazy danych zgodnie z danymi przekazanymi w tablicy filter_data. $ results = $ this-> model_catalog_product-> getProductLatest ($ filter_data);

W tym kodzie najpierw sprawdziliśmy, czy "show_specialParametr jest ustawiony w adresie URL lub nie. Jeśli tak, ustaw wartość parametru w zmiennej $ show_special a jeśli nie, ustaw zmienną jako pustą. Następnie stworzyliśmy tablicę ($ default_data) z wartościami, w imieniu których musimy pobrać produkty z bazy danych. Następnie nazwaliśmy funkcję modelu getProductLatest () aby pobrać najnowsze produkty zgodnie ze zmienną ($ filter_data) w funkcji. Oto funkcja, którą musimy dodać w modelu (katalog / model / katalog / produkt):

public function getProductLatest ($ data = array ()) {// Ustawianie parametrów $ join i $ condition w celu pobrania danych produktów specjalnych, jeśli ($ data ['show_special'] == '1') {$ join = "LEWE DOŁĄCZ" . DB_PREFIX. "product_special ps ON (ps.product_id = p.product_id)"; $ condition = "AND ps.customer_group_id = '". (int) $ this-> config-> get ('config_customer_group_id'). "'AND ((ps.date_start =' 0000-00-00 'LUB ps.date_start <NOW ()) AND (ps.date_end =' 0000-00-00 'LUB ps.date_end> NOW () LUB ps.date_end = '0001-01-01')) "; } // Ustawianie parametrów $ join i $ condition w celu pobrania danych produktów, które nie są specil elseif ($ data ['show_special]] ==' 0 ') {$ join = "LEFT JOIN". DB_PREFIX. "product_special ps ON (ps.product_id = p.product_id)"; $ condition = "AND ps.product_id IS NULL"; } else {// Ustawianie parametrów $ join i $ condition w celu pobrania danych wszystkich produktów bez względu na specjalne $ join = ''; $ condition = ''; } // Zapytanie do pobrania danych produktów z bazy danych. Dodano parametr $ join i $ condition w zapytaniu, aby pobrać dane odpowiednio $ sql = "SELECT DISTINCT p.product_id FROM". DB_PREFIX. "product p LEFT JOIN". DB_PREFIX. "product_description pd ON (p.product_id = pd.product_id) LEFT JOIN". DB_PREFIX. "product_to_store p2s ON (p.product_id = p2s.product_id) $ join WHERE p.status = '1' I p.date_available <= NOW () AND p2s.store_id = '". (int) $ this-> config-> get ('config_store_id'). "'$ condition GROUP BY p.product_id ORDER BY p.product_id DESC"; // Ustawianie limitu w zapytaniu, jeśli przekazano LIMIT z kontrolera. if (isset ($ data ['start']) || isset ($ data ['limit'])) {if ($ data ['start'] <0) {$ data ['start'] = 0; } if ($ data ['limit'] <1) {$ data ['limit'] = 20; } $ sql. = "LIMIT". (int) $ data ['start']. ",". (int) $ data ['limit']; } $ product_data = array (); // Wykonaj zapytanie $ query = $ this-> db-> query ($ sql); // Pętla do ustawienia pobranych danych w zmiennej do przekazania w kontrolerze. foreach ($ zapytanie-> wiersze jako wynik $) {$ product_data [$ result ['product_id']] = $ this-> getProduct ($ result ['product_id']); } // Zwróć dane produktów do kontrolera. return $ product_data; }

W modelu ustawiliśmy zmienne $ join i $ warunek na podstawie następujących trzech warunków:

  1. Jeśli show_special ma wartość 1: W tym przypadku wyświetliliśmy tylko produkty, które są wyjątkowe. Podobnie jak w opencart, dane specjalnych produktów są przechowywane w oc_product_special table, więc dodaliśmy join z tabeli oc_product do tabeli oc_product_secial, aby pobrać dane tylko z produktów specjalnych.
  2. Jeśli show_special ma wartość 0: W tym przypadku wyświetliliśmy produkty, które nie są ustawione jako specjalne. Aby znaleźć produkty, które nie są wyjątkowe, musimy pobrać produkty, które są w specjalnej tabeli, ale w tabeli oc_product_special. W tym celu dodaliśmy LEWE sprzężenie do tabeli oc_product z tabelą oc_product_secial i dodano warunek "ps.product_id IS NULL".
  3. Jeśli show_special jest inne niż 0 i 1: W takim przypadku musimy pobrać wszystkie produkty, niezależnie od tego, czy są specjalne, czy nie. W związku z tym pobraliśmy bezpośrednio dane z tabeli oc_product.

Po dodaniu wszystkich trzech możliwych warunków pisaliśmy zapytanie i wykonywaliśmy je. Następnie ustawiliśmy wszystkie pobrane dane $ product_data array i zwróć to samo do kontrolera.

Uwaga: tutaj, aby pobrać najnowsze produkty, które właśnie wykorzystaliśmy w zapytaniu "Zamów przez id_produktu DESC". Jeśli chcesz pobrać dane produktów, które zostały dodane w ciągu ostatnich kilku dni, możesz dodać jeszcze jeden warunek w klauzuli WHERE, np. Date_added> "any date".

Podsumowanie

Po wykonaniu powyższej procedury będziesz mógł pobrać najnowsze produkty specjalne na podstawie przekazanego parametru dla specjalnych produktów w adresie URL.


Jak obliczyć bezpłatną wysyłkę w oparciu o ostateczną cenę całkowitą w Prestashop?

Po przeczytaniu tego bloga będziemy mogli obliczyć bezpłatną wysyłkę na podstawie ostatecznej ceny całkowitej koszyka.

Problem Statement

Obecnie, gdy dodajemy produkty do „koszyka” i przechodzimy do sekcji kasy, aby skorzystać z rabatu i wysyłki, widzimy, że rabat obowiązuje po wysyłce. Powiedzmy,

  • Całkowita kwota koszyka wynosi 100 USD, co obejmuje bezpłatną wysyłkę, a także dodaje się pewną zniżkę w wysokości 5%
  • Następnie, gdy zniżka Całkowita kwota koszyka zostanie ustawiona poniżej 100 USD, ale nadal obowiązuje bezpłatna wysyłka, co nie powinno mieć miejsca. Bezpłatna wysyłka musi odnosić się do łącznej końcowej kwoty koszyka po rabacie.
  • Jest to domyślny proces Prestashop. Zapoznaj się z poniższym zrzutem ekranu, gdzie wysyłka musi być bezpłatna, jeśli suma zamówienia wynosi > 50, ale zastosowano bezpłatną wysyłkę, a suma zamówienia wynosi < 50 po rabacie –

Zalecane przeczytanie: Strategie bezpłatnej wysyłki: dlaczego warto oferować? Jak oferować? Kiedy oferować?

Dlaczego jest obecny problem?

Obecny problem występuje, ponieważ kwota wysyłki jest obliczana na podstawie Całkowitej kwoty zamówienia, która jest ustawiona w Koszyku przed zastosowaniem rabatu. Możesz sprawdzić poniższe wiersze kodu, gdzie suma zamówienia bez kwoty rabatu jest używana do obliczania kosztów wysyłki –

$shipping_cost += $carrier->getDeliveryPriceByPrice($the_total_price, $id_zone, (int)$this->id_currency);

Wymaganie

Musimy zmodyfikować�wymieniony poniżej�plik, aby to naprawić. Będziemy nadpisywać odpowiednie wiersze pliku class, aby uniknąć zmian w plikach Core.

Poniżej znajduje się lista plików klas, które zostaną nadpisane-

1. Katalog główny\klasy\Koszyk.PHP

Procedura rozwiązania problemu-

Wykonaj poniższe kroki –

1. Przepisz funkcję�GetPackageKosztWysyłki

2. Po linii podanej poniżej –

// Suma zamówienia w domyślnej walucie bez opłat $order_total = $this->getOrderTotal(true, Cart::BOTH_WITHOUT_SHIPPING, $product_list);

3. Dodaj następującą wypowiedź –

$listeDiscounts = $this->getCartRules(); $całkowite_rabaty = 0; if (is_array($listeDiscounts)) { if (isset($listeDiscounts[0]['value_real'])) $total_discounts = $listeDiscounts[0]['value_real']; } $price_to_apply_shipment = floatval($order_total) - floatval($total_discounts); Zalecana lektura: Najlepsze bezpłatne rozszerzenie menedżera wysyłki dla sklepu OpenCart

4. Zastąp wiersze wymienione poniżej –

Zastąp tę linię

$check_delivery_price_by_price = Carrier::checkDeliveryPriceByPrice($row['id_carrier'], $total_order, (int)$id_zone, (int)$this->id_currency);

Z

$check_delivery_price_by_price = Carrier::checkDeliveryPriceByPrice($row['id_carrier'], $price_to_apply_shipment, (int)$id_zone, (int)$this->id_currency);

————ORAZ—————–

Zastąp tę linię

$shipping_cost += $carrier->getDeliveryPriceByPrice($the_total_price, $id_zone, (int)$this->id_currency);

Z

$shipping_cost += $carrier->getDeliveryPriceByPrice($price_to_apply_shipment, $id_zone, (int)$this->id_currency);

5. Wyczyść pamięć podręczną i uruchom.

Zapoznaj się z poniższym zrzutem ekranu po zastosowaniu zmian w kodzie –

Po wykonaniu powyższej procedury będziesz mógł obliczyć koszty wysyłki na końcową łączną kwotę koszyka.

Wnioski

Jeśli chodzi o zakupy online, cała struktura cenowa odgrywa kluczową rolę dla klientów. Jednym z czynników, które mogą spowodować lub przerwać konwersje, jest dostępność bezpłatnej wysyłki. Jedną z metod określania opcji i kosztów wysyłki w witrynie eCommerce jest Darmowy dodatek do menedżera wysyłki od Knowband. Jednym z najważniejszych wymagań zwiększania średniej sprzedaży jest zapewnienie otwartości w transakcji.

Sklepy, które korzystały z tego modułu bezpłatnej wysyłki, zwiększyły ruch w witrynie, przychody i współczynniki konwersji. Za pomocą tej wtyczki do bezpłatnej wysyłki administratorzy sklepów mogą zdefiniować wytyczne i warunki dotyczące kosztów wysyłki. Co więcej, tę funkcję może dodać lub usunąć ze strony administrator sklepu.

Próg, powyżej którego oferowana jest bezpłatna wysyłka, może ustalić sprzedawcy online. W rezultacie zachęca nawet klientów do dokonywania większych zakupów w celu zakwalifikowania się do bezpłatnej wysyłki. Aby dowiedzieć się więcej o funkcjonalności modułu bezpłatnej wysyłki, skontaktuj się z nami pod adresem support@knowband.com