Задать вопрос
  • Как перейти от ACF PRO на Gutenberg?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    ACF Pro помогает создавать блоки для Gutenberg с помощью PHP, это удобно и значительно ускоряет работу. Но если надо полностью отказаться от ACF Pro и использовать только Gutenberg, то придется запилить свои блоки (привет React) или же найти готовые, подходящие под ваши задачи.

    Впрочем, по некоторым блокам стоит выдохнуть и немного подумать - возможно стоит изменить свое мышление. К примеру, на ACF мы повторяющийся контент автоматом считаем рипитером и создаем соответствующие поля. А на Gutenberg часто repeater как таковой и не нужен - достаточно самого блока. Ведь создать несколько одинаковых блоков подряд в Gutenberg не составляет труда, это как бы встроено из коробки.

    Простой пример - блок testimonials. На ACF мы создаем обычно рипитер, в нем нужные поля которые будут повторяться, скажем - text, name, photo (текст отзыва, имя клиента и его аватар). А на gutenberg достаточно иметь блок testimonial с этими же полями, и просто вставить его X раз подряд - вот вам и повторяющиеся данные.
    Ответ написан
    Комментировать
  • Как задать класс изображениям внутри записи на Wordpress?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Самый простой способ - на хуке the_content обычной заменой или регуляркой, но это если у картинок всегда одна структура (например, мы точно знаем что тег будет <img src="..." class="..." ...). Но вообще парсить html регулярками не самая светлая мысль - для этого есть DOMDocument:
    function add_class_to_images( $content )
    {
        $document = new DOMDocument();
        libxml_use_internal_errors(true); // чтобы не ругался на семантические HTML5 теги
        $document->loadHTML( $content );
        libxml_clear_errors();
    
        $images = $document->getElementsByTagName( 'img' );
    
        /** @var \DOMElement $image */
        foreach ( $images as $image ) {
            $image->setAttribute( 
                'class', 
                $image->getAttribute( 'class' ) . ' my-new-class'
            );
        }
    
        return $document->saveHTML();
    }
    add_filter( 'the_content', 'add_class_to_images' );
    Ответ написан
    9 комментариев
  • Как уменьшить запасы товаров в woocommerce при статусе "pending"?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Так, а давайте для начала определим, почему у вас заказы попадают в статусе pending?

    Потому что pending - это промежуточный, "технический" статус между созданием заказа и его оплатой с последующим переходом в статус processing (в случае успешной оплаты) или failed (в случае ошибки с оплатой или отказа).

    Методы оплаты с "отложенной оплатой" (банковский перевод, наличкой/наложенным при получении) могут использовать статус on-hold - если оплату нужно подтверждать (заказ не начнет выполняться пока не будет подтверждения платежа), или сразу processing, если подтверждение не требуется (наличкой при получении). И processing, и on-hold уменьшают сток, потому что это как раз статусы, с которыми вам и надо работать - они для этого и созданы. А pending - это немножко про другое.

    Подробнее: https://docs.woocommerce.com/document/managing-ord...
    Ответ написан
    Комментировать
  • Как кто пробился на фриланс-биржах?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Как по мне, то все достаточно просто:

    1. Идем сразу на Upwork, там есть деньги и адекватные заказчики. Местные биржи - болото.
    2. Листаем список проектов, тщательно отбираем только те, которые нам подходят. Не надо подаваться на все подряд в своей нише.
    3. Задача должна быть четко по нашему профилю, в этой задаче мы должны иметь возможность кратко дать понять, что знаем как ее решить - "уже решали, вот пример, на выходе получите вот эти результаты". Фильтр - наше все.
    4. Клиент должен быть в нашем ценовом диапазоне. Если у вас ставка $20/час, а у клиента написано что средняя ставка которую он платит - $5/час, то писать ему - трата времени и коннектов. Опять же, фильтр - наше все.
    5. Отвечаем на тщательно отобранные заявки. Они должны быть свежие, если прошло полдня и более с момента публикации заявки - особого смысла писать уже нету, если только задача не нишевая / специфичная.
    6. Ответ должен быть индивидуальным, никакой копипасты. Суть ответа должна быть заточена на эту конкретную задачу. Не надо писать всю автобиографию. Самый важный первый абзац, первые 1-2-3 предложения - именно их клиент видит в message preview и они могут быть триггером чтобы открыть вашу заявку. Текст лаконичный, короткие понятные предложения, абзацы. Суть - "задачу понимаю, уже сталкивался, решается вот так, есть вот такие нюансы о которых вы не подумали, мой estimate X часов. По этой ссылке пример решения подобной задачи, а вот по этой - подробнее обо мне и моем опыте/подходе если вам интересно".
    7. Отправляем. Конверсия при таком подходе достаточно высокая.

    Дополнительные мысли:

    - 30 заявок за 1.5 года это ни о чем. На первых порах 30 заявок в неделю может быть мало, пока не научитесь хорошо фильтровать, писать отличные cover letters и пока не получите Rising Talent / Top Rated + 100% JSS.
    - Первых клиентов получить сложнее всего, да. Дальше будет легче. В том числе сами будут писать и приглашать.
    - Даже при отсутствии заказов старайтесь обходить стороной подозрительных заказчиков и стремные проекты - идея хоть как-то заработать копейку несмотря на риски может сейчас казаться не такой уж плохой, но по итогу себе же дороже выйдет.
    Ответ написан
    Комментировать
  • Почему пишет, что путь не правильный?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Всегда используйте абсолютные пути. Всегда. И не будет таких вопросов.
    // require '../template/items-work.php';
    require get_template_directory() . '/template/items-work.php';
    Ответ написан
    Комментировать
  • Как очистить ключ от пробелов в meta_query?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Вам поможет array_map, чтобы применить определенное действие к каждому элементу массива, и preg_replace с простенькой регуляркой, который удалит все whitespace-символы.

    <?php
    // Входящие данные
    $values = [2500, '2 999'];
    
    // Очистка от пробелов
    $values = array_map(static function($value) {
        return preg_replace('/\s/', '', $value);
    }, $values);
    
    // Запрос
    $recent2 = new WP_Query(
        [
            'showposts' => 100, // Не используйте -1, используйте достаточно большое для ваших задач число
            'meta_query' => [
                [
                    'key' => 'cena', // Не называйте данные транслитом, используйтe price
                    'value' => $values,
                    'compare' => 'BETWEEN'
                ]
            ]
        ]
    );
    Ответ написан
  • Как правильно создать ajax-тему Wordpress?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    REST API + роутинг на фронтенде
    Ответ написан
  • Как синхронизировать данные двух таблиц wp_users и wp_2_users?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Готов поставить ящик пива, что ваша задача решается немного другим путем. Смотрите мой ответ в другом вашем вопросе: Как сделать регистрацию на wordpress в две таблицы?
    Ответ написан
    Комментировать
  • Как сделать регистрацию на wordpress в две таблицы?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Я бы вам советовал подойти к задаче с другой стороны. На самом деле пользователи должны создаваться в одной таблице, точнее в одной паре таблиц (wp_users и wp_usermeta), и храниться в единственном экземпляре. А на втором сайте вы просто указываете, что надо использовать эту пару таблиц от первого сайта. Для этого в wp-config.php есть 2 конфигурационные константы:
    define( 'CUSTOM_USER_TABLE', $table_prefix.'my_users' );
    define( 'CUSTOM_USER_META_TABLE', $table_prefix.'my_usermeta' );

    Подробнее тут.
    Ответ написан
  • Как решить проблему с 404 ошибкой при изменении количества товаров на страницу WooCommerce?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Если там при выборе количества записей на страницу просто добавляется параметр ?prod-count=5 к текущему URL и браузер отправляется по этому новому URL, то проще всего повесить обработчик этого get-запроса где-нибудь на template_redirect. Смотрите, есть ли GET-параметр prod-count, если да - смотрите на какой вы странице, сколько всего результатов у WC_Product_Query, сколько выводить просит prod-count. Считаете, и если получается что страница Х у вас не будет существовать - редиректите на нужную.
    Ответ написан
    7 комментариев
  • Не работает ajax сервер WAMP?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Ошибки нужно читать, они содержат детальное описание проблемы. Разобьем вот эту ошибку на кусочки:
    Notice: Undefined index: text in D:\Wamp\www\tost\index.php on line 12


    1. Notice: - ошибка уровня notice, по сути даже не ошибка, а уведомление.
    2. Undefined index: text - индекса "text" не существует, это говорит о том, что вы пытаетесь обратиться к индексе "text" какого-то массива, но такого индекса (элемента массива) не существует.
    3. D:\Wamp\www\tost\index.php on line 12 - а вот это конкретное место в вашем коде где эта ошибка возникла. Это строка 12, она содержит вот такой код: echo 'Данные приняты - '.$_POST['text'];

    Что с этим кодом не так? Вы пытаетесь вывести элемент массива $_POST под индексом "text", но еще до того, как вы отправили данные этим самым методом POST. Чтобы этого избежать, необходимо выполнить проверку:

    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>Document</title>
        <script src="jquery-3.3.1min.js"></script>
        <script src="js.js"></script>
    </head>
    <body>
    <h1>Нажать</h1>
     
    <?php
    if (isset($_POST['text'])) {
        echo 'Данные приняты - ' . htmlspecialchars($_POST['text']);
    } ?>
     
    </body>
    </html>


    В этом случае мы сначала проверяем, чтобы данные были действительно отправлены, и только тогда их выводим. Кроме того, мы используем https://www.php.net/manual/en/function.htmlspecial... чтобы обезопасить себя.
    Ответ написан
    Комментировать
  • Почему не создаются посты без перезагрузки?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Вы не поняли как работает ajax. Данные вы отправили, пост создался. Но чтобы на странице/страницах, которые УЖЕ загружены в браузере увидеть обновления, нужно либо вручную их обновить, либо из полученного по аякс ответа сгенерировать нужный html и вставить его в эти страницы (сможете только в ту из которой инициировали загрузку). Если же вы хотите в других вкладках чтобы открытые страницы сами обновлялись когда на бекенде новые данные появились, то вам нужны другие технологии. Читайте про веб-сокеты.
    Ответ написан
    1 комментарий
  • Загрузка изображения перед его загрузкой. Как это делают?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Для начала решите, что вам на самом деле нужно - предварительный просмотр изображения (чтобы выглядело как будто картинка загружена, пользователь видел ее в контенте который пишет) или реальная загрузка изображения на сервер. В зависимости от ответа будет разная техника.

    Осознанно учтите и взвесьте основные минусы загрузки на сервер. Самая главная - картинки на сервере будут накапливаться и вам придется разрабатывать систему определения "нужных" и "ненужных" а также механизм автоматического удаления ненужных. Потому что мусора будет много. Кто-то писал черновик и не опубликовал / закрыл окно и забил, а картинка (или даже несколько) уже загружена. Кто-то загрузил одну картинку, посмотрел, не понравилось, выбрал и загрузил другую. И так 10 раз подряд пока не подобрал картинку которая нравится. А у вас 9 ненужных картинок на сервере загружено. Через некоторое время у вас папка с загрузками вырастает до гигабайтов / тысяч файлов, вы смотрите на это и реально не понимаете что из этого используется, а что нет.

    Исходя из этого, в большинстве случае все, что вам нужно это предварительный просмотр на клиенте с помощью javascript. Это можно сделать ванильным js или использовать адекватную библиотеку типа https://github.com/blueimp/JavaScript-Load-Image которая уже решает кучу мелких задач, о которых вы еще даже не догадываетесь (например автоматический поворот по метаданным, ресайз превью в целях оптимизации производительности, crossorigin и тд).

    Если же все-таки вы решите грузить из сразу на сервер, то начните с минимального ТЗ. Используете ли вы какую-то CMS или фреймворк. Куда и как будете загружать файлы. Как будете хранить историю загруженных и очищать ненужные. И так далее. Сам процесс загрузки тривиален - у вас должен быть URL который методом PUT или POST принимает данные (изображение + любую полезную инфу, например ID/UUID черновика записи к которому картинка загружена), обрабатывает их и возвращает URL изображения. Аяксом туда шлете картинку, получаете ответ с адресом картинки на сервере, вставляете его в DOM.
    Ответ написан
    1 комментарий
  • Как выявить нагрузку на CPU в index.php Wordpress?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Дело в том, что index.php это входная точка, там всего пару строк кода. Это не один изолированный скрипт со всеми фичами, который вы можете как-то отдебажить. Он поднимает все ядро WP, там тысячи других файлов. Для отладки используется профилирование кода - Xdebug, XHProf, Tideways, Blackfire. На shared хостинге разумеется этого всего не будет.
    Ответ написан
    Комментировать
  • Зачем писать url: admin-ajax.php?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Ваш js отправляет данные на файл-обработчик, который является входной точкой. Воспринимайте его как API endpoint. Потому что отправить запрос на файл functions.php вы не сможете, это include. А вот /wp-admin/admin-ajax.php - это не include, там поднимается слегка облегченная версия всего WordPress которая рассчитана исключительно на то, чтобы принять ваши отправленные данные, определить какой action вы хотите использовать и через этот action передать полученные данные на обработчик, который висит на этом экшне. И вот уже в functions.php вы на этот экшн в формате wp_ajax_{$action} и wp_ajax_nopriv_{$action} подключаете свой обработчик, который примет отправленные данные, сделает с ними все что нужно и вернет ответ, который в свою очередь /wp-admin/admin-ajax.php вернет обратно вашему js.

    По ссылке Пычев Анатолий более подробно с примерами. А вообще откройте в редакторе сам файл /wp-admin/admin-ajax.php и часть вопросов сама отпадет.
    Ответ написан
  • Как скрыть таксономии при добавлении поста?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Вам погомут conditional rules.

    Создайте одно поле с выбором таксономий (городов). Это может быть поле типа select, radio, checkbox - зависит от того нужно ли вам выбирать один или несколько городов. В значения этого поля добавьте все ваши города/таксономии. Можно это сделать вручную, а можно программно заполнить из существующих таксономий.

    Дальше под каждую таксономию (город) создайте свое поле типа Taxonomy, в котором и будут выбираться термины. Включите в этом поле галочки Create Terms, Save Terms и Load Terms, а также включите Conditional Logic - именно в этом вся магия. Теперь в conditional настройте условие. Вот так это выглядит:

    5e9820dca3b3f788190769.jpeg

    А вот так это выглядит на странице редактирования записи - по умолчанию город не выбран:

    5e9820f420767468763297.jpeg

    А если выбрали город - показало поле для выбора категории в этом городе:

    5e9821140e5ab394583256.jpeg

    Вот вам экспорт этой тестовой группы полей, имопртните себе в ACF и поковыряйте:

    [
        {
            "key": "group_5e981df6cbdcc",
            "title": "Taxonomies",
            "fields": [
                {
                    "key": "field_5e981e4bb1454",
                    "label": "City",
                    "name": "taxonomy",
                    "type": "checkbox",
                    "choices": {
                        "spb": "SPB",
                        "msk": "Moscow",
                        "omsk": "Omsk"
                    },
                    "layout": "vertical",
                    "return_format": "value",
                },
                {
                    "key": "field_5e981e18b1453",
                    "label": "MSK",
                    "name": "term",
                    "type": "taxonomy",
                    "conditional_logic": [
                        [
                            {
                                "field": "field_5e981e4bb1454",
                                "operator": "==",
                                "value": "msk"
                            }
                        ]
                    ],
                    "taxonomy": "post_tag",
                    "field_type": "checkbox",
                    "add_term": 1,
                    "save_terms": 1,
                    "load_terms": 1,
                    "return_format": "id",
                    "multiple": 0,
                    "allow_null": 0
                }
            ],
            "location": [
                [
                    {
                        "param": "post_type",
                        "operator": "==",
                        "value": "post"
                    }
                ]
            ],
            "menu_order": 0,
            "position": "side",
            "style": "default",
            "label_placement": "top",
            "instruction_placement": "label",
            "active": true,
        }
    ]
    Ответ написан
    2 комментария
  • MustHave плагины для wordpress?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Давайте для начала определим вашу роль и ваши цели.

    Если ваша роль - разработчик, то must-have плагинами будут те, которые облегчат вашу работу - Advanced Custom Fields (желательно Pro), Query Monitor, Laps и тд, или же малой кровью решать типовые задачи - Classic Editor, Disable Comments, Safe SVG, Enable Media Replace и подобные. Под "малой кровью" имеется в виду что они имеют минимальный overhead, не делают ничего лишнего и вы сами лучше все равно не напишете. Все остальное пишем сами, форкаем у других разработчиков, тюним под свои задачи и тд - со временем накапливаем собственный инструментарий.

    Если ваша роль - имплементатор (собираете сайтики на WP, но в PHP не умеете), то набор плагинов будет другим. Тут уж коллеги-имплементаторы подскажут какие плагины важны, какие нужны.

    Если ваша роль - владелец сайта, который все сам хочет делать - это ближе к имплементаторам.

    Если ваша роль - контент пилить, а все остальное вторично - просто выбирайте плагины под нужную функциональность и старайтесь всегда в голове держать простое умозаключение - чем плагин навороченнее (больше фич, больше настроек, больше страниц в админке и тд), тем он как правило медленнее. Чем бoльше таких плагинов - тем медленнее сайт. Поэтому стараемся ставить только то, что абсолютно необходимо и из доступных вариантов на фичу выбираем тот, который наиболее легковесный. В идеале - тестируем несколько штук и выбираем один.

    Теперь по целям. Чего вы хотите? Чтобы можно было быстро собрать сайт для тестирования бизнес идеи с минимальными расходами? Это одна кухня. Чтобы был легкий и быстрый контент-сайт, который выдерживает серьезный трафик? Это другая кухня. Интернет-магазин? Вообще другое. А в какой нише этот интернет-магазин? Физические товары или цифровые? А рынок местный или международный? Это все будет вас приводить к разному набору плагинов. Думаю, смысл уже понятен.
    Ответ написан
    2 комментария
  • Добрый день, как писать на новом фреймворке корректно?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Лучше 3 года копипастить адекватный код, написанный опытными и светлыми головами, чем городить свои костыли и не только не развиваться, а тупо скатываться в бездну говнокода.
    Ответ написан
  • WordPress, как скрыть информацию из профиля пользователя от поисковиков?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Для начала уточните - это публичные профили, или приватные (для их просмотра надо авторизоваться). Если приватные - забудьте и спите спокойно, роботы не будут регистрироваться, авторизовываться и индексировать закрытые части сайта. А если профили публичные - тогда, имхо, публичные данные и должны быть доступны для индексации.
    Ответ написан
  • Почему SASS в PhpStorm не компилируется по стайл гайду?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Т.е. хочется настроить перенос скобок, отступы.

    Зачем? o_O

    В скомпилированный CSS заглядывать не надо, он вообще должен быть минифицирован (мы этого обычно не делаем на этапе разработки исключительно для того чтобы быстрее пересобирались стили). Это тупо "машинный код".
    Ответ написан