• Как заставить логирование Guzzle работать в Laravel?

    Denormalization
    @Denormalization
    Если нужно писать в общий лог файл лог Guzzle, то:
    use GuzzleHttp\HandlerStack;
    use GuzzleHttp\Middleware;
    use GuzzleHttp\MessageFormatter;
    use Monolog\Logger;
    
    $stack = HandlerStack::create();
    $stack->push(
        Middleware::log(
            \Illuminate\Support\Facades\Log::getMonolog(),
            new MessageFormatter('{req_body} - {res_body}')
        )
    );
    $client = new \GuzzleHttp\Client(
        [
            'base_uri' => 'some-url.com',
            'handler' => $stack,
        ]
    );


    Оно будет писать в общий лог файл.
    Если же нужно писать в кастомный лог файл, то:
    use Monolog\Handler\StreamHandler;
    // ....
    $logger = new Logger('GuzzleLogger');
    $logger->pushHandler(new StreamHandler(storage_path('logs/guzzle.log')));
    $stack->push(
        Middleware::log(
           $logger,
            new MessageFormatter('{req_body} - {res_body}')
        )
    );
    Ответ написан
    2 комментария
  • В каком плагине Woocommerce можно скрывать валюты (но не деактивировать) для фронта?

    wppanda5
    @wppanda5 Куратор тега WordPress
    WordPress Mедведь
    1) по крону ходите сюда https://api.privatbank.ua/p24api/pubinfo?exchange&... записываете курсы в базу/сохраняете файл локально и смотрите его, в общем не важно, главное смотреть курс
    2) заводите дополнительные поля _currency_price - тут храните стоимость в валюте и _currency_flag - тут храните код валюты
    3) на морде проверяете тип валюты, получаете стоимость из _currency_price умножаете на сохраненный курс и вешаете это дело на вывод цены на морде
    фильтры нормально описаны тут https://stackoverflow.com/questions/45806249/chang...
    Ответ написан
    1 комментарий
  • Как можно сделать бесплатную доставку при достижении определенной цены?

    @sand3001
    Всего по немногу
    Вот так например
    Ответ написан
    Комментировать
  • Как ускорить WordPress+WooCommerce?

    wppanda5
    @wppanda5 Куратор тега WordPress
    WordPress Mедведь
    Обходится следующим образом.
    Добавляется сводная таблица товаров в которой храните id товара и значения параметров по которым производится фильтрация, фильтр и поиск переписываете на поиск по ней.

    90 000 товаров 3 500 000 параметров по категории в которой 50к товаров WOFF product Filter отрабатывает 30-40 секунд, Фильтрация по таблице до полутора секунд
    Ответ написан
    1 комментарий
  • Как пропустить переход в карточку товара?

    @primandrej
    Зачем городить огород?
    1. Для того, чтобы товар добавить в корзину из любого места, нужно использовать ссылку https://my-domain/?add-to-cart=120 где 120 id добавляемого товара.
    2. Чтобы после этого пользователь перенаправлялся в корзину надо использовать ссылку https://my-domain/cart/?add-to-cart=120 где 120 id добавляемого товара.
    3. Можно отправить пользователя сразу на страницу оформления используя ссылку https://my-domain/checkout/?add-to-cart=120 где 120 id добавляемого товара.
    4. А ещё можно добавлять определённое количество товара в корзину сразу, дописав к ссылке &quantity=5 должно получиться так https://my-domain/cart/?add-to-cart=120&quantity=5
    Ответ написан
    Комментировать
  • Где лежат обработчики форм в Wordpress/Woocommerce?

    @antoshadrobyshev
    WordPress & Woocommerce developer
    Так это не работает. У WooCommerce есть Payment API, которое позволяет создавать свои шлюзы. Если кратко, то нужно расширить класс WC_Payment_Gateway и переопределить его методы.
    Вот референсы:
    - https://docs.woocommerce.com/document/payment-gate...
    - https://rudrastyh.com/woocommerce/payment-gateway-...
    Ответ написан
    2 комментария
  • Как реализовать ленту событий сайта для Wordpress?

    azerphoenix
    @azerphoenix
    Java Software Engineer
    1) создать кастомный тип записи для событий.
    2) повесить хук на публикацию новой записи и / или товара. При срабатывании создавать запись для события.
    3) вывести этот тип записей в шаблоне.
    4) Для возможности добавления события вручную вывести возможность публикации кастомной записи и з админки с заголовком и контентом.
    Готово
    Ответ написан
    5 комментариев
  • Как сделать векторный рисунок по координатам?

    BasiC2k
    @BasiC2k
    .NET developer (open to job offers)
    Лучший вариант в Вашем случае - рисовать по координатам в стороннем приложении и вставлять результат (картинку) на лист Excel. Подобное приложение для создания 3D диаграмм я делал на базе HelixToolkit. Попробуйте, библиотека очень мощная!

    Скриншот своего Add-In Excel прикладываю. Перед сохранением, мышкой можно крутить и масштабировать 3D картину - как угодно.
    5ef09f5665c5c118184709.png
    Ответ написан
    Комментировать
  • Wordpress создание роли с доступом к плагину?

    wppanda5
    @wppanda5 Куратор тега WordPress
    WordPress Mедведь
    Берете создаете юзера, добавляете ему кастомную роль и кастомную возможность. Затем для него закрываете все кроме того, что разрешено, проверяете по новой возможности. Разрешать/закрывать следующим образом

    Список плагинов получаете вот так
    global $wp_list_table;
    $plugins = $wp_list_table->items;
    #Ключами тут являются строки такого вида 'plugin-directory/plugin-file.php' проверять по ним


    Дaльше вешаетесь на след фильры.
    'site_transient_update_plugins' - скрыть обновление плагина
    'pre_current_active_plugins' - скрыть плагин из списка плагинов

    'admin_init' - сюда вешаете проверку на текущую страницу и запрет доступа к ней
    проверяете через current_screen и $_GET
    и если запрещено, то делаете так wp_die( 'Доступ запрещен' );

    Скрывать меню так

    global $menu;
    foreach ( $menu as $i => $item ) {
    	unset( $menu[ $i ] );
    }
    #В $item[2] строка вида page.php?param=param_val - проверять по нему


    Вешать на хук 'admin_menu'

    Это алгоритм как и что делать, если разбираетесь, то поможет, если нет, то извините(( писать сам функционал, но оно такое, нет желания час терять на это сейчас
    Ответ написан
    1 комментарий
  • Как сделать наценку за оплату по карте?

    wppanda5
    @wppanda5 Куратор тега WooСommerce
    WordPress Mедведь
    100 рублей - так
    add_filter( 'woocommerce_cart_calculate_fees', 'add_my_fee', 10, 1 );
     
    function add_my_fee() {
        $gateway = WC()->session->get( 'chosen_payment_method' );
         if ( $gateway == 'paypal' ) {
          WC()->cart->add_fee( 'Наценка за метод оплаты который нам не нравится', 100 );
       }
    }


    3% получите сумму заказа, получите с нее 3 процента и вместо 100 рублей подставьте полученную сумму
    Ответ написан
    Комментировать
  • Как разрешить в полях только латинские символы?

    IonDen
    @IonDen
    JavaScript developer. IonDen.com
    Во первых такую проблему нельзя решить вот так вот наскоком. Нужно выбрать стратегию:

    Стратегия А. Не пропускаем не латиницу (т.е. выдаем ошибку каждый раз когда встречаем иные символы)

    1. Пишем текстом что нельзя
    2. На инпуты навешиваем слушатели, которые предупреждают о не латинице
    3. При отправке выдаем ошибку если таки нашли латиницу
    4. Сервер тоже проверяет пришла ли только латиница и возвращает ошибку если нет.

    Стратегия Б. Тихо фильтруем лишние символы (никакие ошибки не показываются)

    1. Тихо стираем при вводе текста
    2. Удаляем не латинские части при отправке формы
    3. На сервере проверяем и тоже удаляем лишнее

    В обоих случаях вам нужно сделать 3 вещи:

    1. На стороне клиента проверять инпуты при вводе. Для этого вам поможет событие onInput
    2. При отправке формы тоже нужно проверить, для этого нужно найти все инпуты и снова вызвать проверочную функцию
    3. Ну и на сервере тоже добавить проверку, мало ли каким образом отправились данные.

    Функция на стороне клиента может выглядеть как то так:
    function deleteNonLatin (text) {
      return text.replace(/[^A-Za-z]/ig, '');
    }
    
    // чтобы выполнить эту функцию, вам нужно навесить событие на инпут(ы)
    const myInput = document.querySelector('.myInput');
    myInput.addEventListener('input', (e) => {
      const cleanValue = deleteNonLatin(e.target.value);
      e.target.value = cleanValue;
    });
    Ответ написан
    1 комментарий
  • Wordpress нужна консультация. Какой плагин выбрать, для определённых работ?

    youmixx
    @youmixx Автор вопроса
    PHP Developer
    Нашёл ответ.

    Сделал не большую функцию, которая возвращает количество уже совершенных покупок человеком на сайте. Работает без регистрации. Честно говоря, сам не совсем понимаю, когда он сохраняет сколько у кого заказов, главное что сохраняет.

    function check_count() {
            $id = get_current_user_id();
            $count = wc_get_customer_order_count($id);
            return $count;
        }


    $id = get_current_user_id(); - получить id человека.
    $count = wc_get_customer_order_count($id); - узнаем количество заказов.
    return $count; - возвращаем это количество.

    Потом, чтобы выдать саму скидку, я сделал так.

    add_action( 'woocommerce_cart_calculate_fees','woocommerce_custom_surcharge');
        function woocommerce_custom_surcharge() {
            global $woocommerce;
    
            if ( is_admin() && ! defined( 'DOING_AJAX' ) )
                return;
    
            if(check_count() == 0) 
            {
                $summ = $woocommerce->cart->subtotal;
                $summ = ceil($summ / 100 * 20);
                $woocommerce->cart->add_fee("Скидка за первый заказ: ", -$summ);
            }
        }


    $summ = $woocommerce->cart->subtotal; - узнаем общую сумму всего заказа (не считая цену доставки, если такова есть).
    $summ = ceil($summ / 100 * 20); - Цифра 20, это сколько выдать скидку в процентах. Если что, делайте свои вычисления. ceil() - чтобы округлить до целого.
    $woocommerce->cart->add_fee("Скидка за первый заказ: ", -$summ); Ну это добавляем уже саму скидку, выглядит хорошо.

    Пользуйтесь.
    Ответ написан
    Комментировать
  • Как запретить вход в аккаунт по роли?

    V_A_B
    @V_A_B
    ¯\_(ツ)_/¯
    add_filter('authenticate','filter_function_name_4601');
    function filter_function_name_4601($user){
    	if(isset($_POST['log'])){
    	$username=$_POST['log'];
    	if(isset($username)){$user=get_user_by('login',$username);$user_data=get_object_vars($user);}	
    	if(isset($user_data)){$userId=$user_data["ID"];$u_meta=get_userdata($userId);$u_roles=$u_meta->roles;}
    	}	
    	if(!empty($u_roles)&&(in_array('administrator',$u_roles,true)||in_array('editor',$u_roles,true))){//перебираем роли. которые хотим запретить
    	$Who=in_array('administrator',$u_roles,true)?__('Администраторам','VAB'):__('Редакторам','VAB');
    	wp_die($Who.' '.__('авторизация запрещена','VAB'));//пишем месседж для них
    	}else{
    	return $user;
    	}
    }

    Результат, смотря кто ломится
    5e9849612ddb8834465415.jpeg
    5e9849ed43f95972809011.jpeg

    через username
    add_filter('authenticate','filter_function_name_4601',10,3);
    function filter_function_name_4601($user,$username,$password){
    	if($username){
    	if(isset($username)){$user=get_user_by('login',$username);$user_data=get_object_vars($user);}	
    	if(isset($user_data)){$userId=$user_data["ID"];$u_meta=get_userdata($userId);$u_roles=$u_meta->roles;}
    	}	
    	if(!empty($u_roles)&&(in_array('administrator',$u_roles,true)||in_array('editor',$u_roles,true))){//перебираем роли. которые хотим запретить
    	$Who=in_array('administrator',$u_roles,true)?__('Администраторам','VAB'):__('Редакторам','VAB');
    	wp_die($Who.' '.__('авторизация запрещена','VAB'));//пишем месседж для них
    	}else{
    	return $user;
    	}
    }

    это, если разрабы завтра log поменяют на что-то другое...
    Ответ написан
    2 комментария
  • Как вывести общую сумму скидок в Woocommerce?

    @Mircek Автор вопроса
    UPD: проблему решила сама. Оставляю решение — вдруг у кого-то будет та же задача. В коде заменила

    . wc_price( $discount_total + $woocommerce->cart->discount_cart ) .

    на
    . wc_price( $woocommerce->cart->subtotal - $woocommerce->cart->total + $woocommerce->cart->shipping_total + $discount_total ) .
    .

    Что делает новая строка:
    $woocommerce->cart->subtotal - $woocommerce->cart->total — вычитаем из суммы всех товаров итоговую сумму заказа после применения всех скидок
    + $woocommerce->cart->shipping_total — добавляем стоимость доставки (если этого не сделать, то стоимость доставки вычтется из суммы сэкономленных денег)
    + $discount_total — добавляем сумму индивидуальных скидок на товары (если какой-то товар обычно стоит 1000 руб., но сейчас он на распродаже и стоит 800 руб., то эти 200 рублей тоже нужно учесть как сэкономленные).

    И добавляем условие выводить строку «Вы сэкономили: N руб.» только в том случае, если «сумма товаров + доставка» больше, чем «сумма заказа с учётом всех скидок + доставка» или если в заказе есть товар(ы) с индивидуальной скидкой.

    if ( $woocommerce->cart->subtotal + $woocommerce->cart->shipping_total > $woocommerce->cart->total + $woocommerce->cart->shipping_total || $discount_total > 0 )


    Весь готовый код выглядит так (вставлять в functions.php дочерней темы):

    function wc_discount_total_30() {
     
        global $woocommerce;
          
        $discount_total = 0;
          
        foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values) {
              
       $_product = $values['data'];
      
            if ( $_product->is_on_sale() ) {
            $regular_price = $_product->get_regular_price();
            $sale_price = $_product->get_sale_price();
            $discount = ($regular_price - $sale_price) * $values['quantity'];
            $discount_total += $discount;
            }
      
        }    
                
    if ( $woocommerce->cart->subtotal + $woocommerce->cart->shipping_total > $woocommerce->cart->total + $woocommerce->cart->shipping_total || $discount_total > 0 ) {
    	    
        echo '<tr class="cart-discount">
        <th>'. __( 'Вы сэкономили:', 'woocommerce' ) .'</th>
        <td data-title=" '. __( 'Saved', 'woocommerce' ) .' ">' 
        . wc_price( $woocommerce->cart->subtotal - $woocommerce->cart->total + $woocommerce->cart->shipping_total + $discount_total ) .'</td>
        </tr>';
    }    
     
    }
     
    // Hook our values to the Basket and Checkout pages
     
    add_action( 'woocommerce_cart_totals_after_order_total', 'wc_discount_total_30', 99);
    add_action( 'woocommerce_review_order_after_order_total', 'wc_discount_total_30', 99);


    Решение может быть не самое изысканное, но рабочее (проверено).
    Ответ написан
    Комментировать
  • Как в Woocommerce вывести вариации отдельными товарами с помощью php?

    @NickToot
    web developer
    Можно изменить стандартный запрос получения товаров WooCommerсe (добавьте код в functions.php или в отдельный файл который подключается в него):
    add_action( 'woocommerce_product_query', 'custom_woocommerce_product_query' );
    function custom_woocommerce_product_query ($q) {
      $q->set( 'post_type', array( 'product', 'product_variation' ) );
      return $q;
    }

    У вас выведутся все товары и все их вариации, я думаю это будет избыточно, тогда нужно изменить этот запрос под себя, условиями или как-нибудь еще если вы умеете. Я добавил галочку для вариаций отображать в каталоге или нет и получаю только отмеченные товары, простые товары при этом запросе пропадают, мне этого было достаточно:
    /**
     *  Добавление своего поля для вариаций
     */
    add_action( 'woocommerce_variation_options', 'add_custom_field_to_variations', 10, 3 );
    function add_custom_field_to_variations( $loop, $variation_data, $variation ) {
    $checked = get_post_meta( $variation->ID, 'catalog_visibility', true ) ) ? 'checked="checked"' : '';
    ?>
      <label>
        Показать в каталоге?
        <input type="checkbox" class="checkbox" name="catalog_visibility[<?= $loop ?>]" <?= $checked; ?>/>
      </label>
    <?php
    }
    
    /**
     *  Сохранение в админке своего поля для вариаций
     */
    add_action( 'woocommerce_save_product_variation', 'save_custom_field_variations', 10, 2 );
    function save_custom_field_variations( $variation_id, $i ) {
      $catalog_visibility = $_POST['catalog_visibility'][$i];
      if ( $catalog_visibility ) {
        update_post_meta( $variation_id, 'catalog_visibility', true );
      } else {
        delete_post_meta( $variation_id, 'catalog_visibility' );
      }
    }
    
    /**
     *  Добавление вариативных товаров в каталог
     */
    add_action( 'woocommerce_product_query', 'custom_woocommerce_product_query' );
    function custom_woocommerce_product_query ($q) {
      // Добавление вариаций в каталог
      $q->set( 'post_type', array( 'product', 'product_variation' ) );
      // Оставляем только вариации в каталоге
      $meta_query = (array) $q->get( 'meta_query' );
      $meta_query[] = array(
        'key'      => 'catalog_visibility',
        'value'    => '1',
      );
      $q->set( 'meta_query', $meta_query );
      return $q;
    }
    Ответ написан
  • Как удалить товар из корзины woocommerce автоматически?

    NikMaster777
    @NikMaster777 Автор вопроса
    1) Пустая корзина перед добавлением в корзину (если корзина не пуста) сбросит всю корзину:

    add_filter( 'woocommerce_add_to_cart_validation', 'one_cart_item_at_the_time', 10, 3 );
    function one_cart_item_at_the_time( $passed, $product_id, $quantity ) {
        if( ! WC()->cart->is_empty())
            WC()->cart->empty_cart();
        return $passed;
    }


    2) Этот код проверит только добавляемый товар, остальные товары если есть в корзине удалены не будут:

    add_filter('woocommerce_add_to_cart_validation', 'one_cart_item_at_the_time', 10, 3);
    
    function one_cart_item_at_the_time( $passed, $product_id, $quantity ) {
        if(! WC()->cart->is_empty()) {
            $cartId = WC()->cart->generate_cart_id($product_id);
            $cartItemKey = WC()->cart->find_product_in_cart($cartId);
            if ($cartItemKey) {
              return $passed;
            } else {
              $woocommerce->cart->add_to_cart( $product_id );
              return $passed;
            }
        }
    }
    Ответ написан
    Комментировать
  • Можно ли как то скрыть подстраницы в админке wordpress?

    deniscopro
    @deniscopro Куратор тега WordPress
    WordPress-разработчик, denisco.pro
    Попробуйте плагин Admin Collapse Subpages.
    Ответ написан
    Комментировать
  • Как деплоить правки?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Во-первых, запомнить раз и навсегда 2 простые истины:

    1. Продакшн база данных должна быть только на продакшне и больше нигде. Эти данные нельзя as-is использовать локально - в том числе по причинам юридическим и privacy (привет логины-пароли клиентов, их персональные данные и тд). Грубо говоря, за это можно и пострадать.
    2. Локальная / development база данных работает только с тестовыми / посевными данными.

    Между ними никакой синхронизации не должно быть, никогда. От слова совсем. И WordPress тут вообще ни при чем - эта проблема существует и в Laravel, Symfony, Ruby on Rails и тд. Просто там с нуля сразу учат решать ее правильно. Впрочем, продакшн-данные можно (и даже нужно) использовать как пример для генерации локальных данных. Например, в production БД можно посмотреть какие реальные first name и last name используются юзерами, чтобы улучшить валидацию и/или отображение.

    Как с этим жить?

    1. Для переноса изменений структуры базы данных используются миграции. В WordPress для этого есть dbDelta().
    2. Для переноса посевных данных используются посевы (seeds). Например, если нужно залить список терминов в глоссарий (custom taxonomy), заполнить список отделов компании и тд - все это сеется.
    3. Все остальное (настройки мышкой в админке, добавление контента и тд) делается руками. Локально вы вообще не должны даже думать о том, чтобы создавать какие-то страницы 1 в 1 с рассчетом на то, что потом будете их как-то "синхронизировать" на боевой сервер. Это в корне неправильный mindset, который и привел вас к этой проблеме. На локальной версии вы все тестируете с тестовыми данными. Даже если вы не используете lorem ipsum, а вставляете реальный текст предоставленный клиентом - это все равно тестовые данные.
    4. Чтобы сайт не ломался в процессе выкатывания изменений (когда код залили, а контент еще делается) код нужно писать с учетом этой логики (опять же - дело в mindset). Например, есть такое понятие как feature flags, есть function_exists(), есть isset(). Ваш код должен работать корректно всегда - например, если данные для какого-то блока не заполнены, то блок не выводится вообще.
    Ответ написан
    Комментировать
  • Как устранить и не допустить появления в дальнейшем вируса WordPress?

    Kozack
    @Kozack Куратор тега WordPress
    Thinking about a11y
    Я нахожу две наиболее вероятные причины взлома:
    1. Кривые руки пользователя (это и потенциально уязвимый код и пароли по типу "qwerty1234")
    2. Устаревшие компоненты, в которых нашли уязвимость.


    Следовательно основные меры безопасности:
    • Следить за обновлениями ядра.
    • Следить за обновлениями плагинов.
    • Перед установкой любого плагина смотреть когда он последний раз обновлялся, какие версии ядра поддерживает.
    • Следить за компонентами ОС.
    • Регулярно или автоматически обновлять весь софт до актуальных версий.
    • Не создавать пользователя с логином admin
    • Не создавать пользователей с легкоподбираемыми паролями.
    • Не публиковать и не пересылать пароли в открытых каналах или на скриншотах от таких сервисов как prnt.sc и тп.
    • Не копировать и вставлять на сайт код, если вы не понимаете как он работает.


    В качестве дополнительных мер можно:
    • Использовать какой-либо плагин для ограничения попыток входа
    • Установить двухфакторную аутентификацию.
    Ответ написан
    Комментировать