• Как реализовать такое?

    @wadowad
    Можно реализовать через padding. Например, padding-top: 30% - это верхний внутренний отступ 30% от ширины родителя. Обратное поведение можно задать через calc:

    padding-top: calc(100px - 10%);

    Тогда при уменьшении ширины родителя, верхний отступ будет увеличиваться.
    Ответ написан
    1 комментарий
  • Как сделать связь между select option?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const selects = [...document.querySelectorAll('select')];
    
    selects.forEach(n => n.addEventListener('change', onChange));
    
    function onChange() {
      const values = selects.map(n => n.value);
    
      selects.forEach((select, i) => {
        [...select.options].forEach(option => {
          option.hidden = values.includes(option.value) && values[i] !== option.value;
        });
      });
    }
    Ответ написан
    1 комментарий
  • Как сверстать такой треугольник с градиентом у border?

    RAX7
    @RAX7
    Первый вариант svg mask.
    плюсы: не требует js
    минусы: нельзя применить backdrop-filter


    Второй вариант svg clip-path.
    плюсы: можно применить backdrop-filter
    минусы: требует js и желательно ResizeObserver
    Ответ написан
    Комментировать
  • Как в WooCommerce добавить кнопку "Купить в 1 клик" рядом с кнопкой "Добавить в корзину"?

    1. Добавьте кнопку и в атрибуте (можно data-id) передайте id товара
    global $product;
    $id = $product->id;


    2. Повесьте обработчик на клик кнопки
    jQuery('.one-click-button').click(function(e) {
     	e.preventDefault();
     	jQuery(this).addClass('adding-cart');
     	var product_id = jQuery(this).data('id');
    
     	var ajax_url = "/wp-admin/admin-ajax.php"
    
     	jQuery.ajax ({
     		url: ajax_url,  
     		type:'POST',
     		data:'action=oneclick&product_id=' + product_id + '&quantity=1',
    
     		success:function(results) {
    		// Показываем окно успешного добавления
    		$('.form_popup').hide();
    		$('#modal').css('display','inline-block');
    		$('.good_cart').css('display','inline-block');
    		document.location.href = 'http://domain.ru/oformlenie-zakaza/'; //Переход на оформление заказа
    	}
    });
     });


    3. Обработчик в functions.php
    function oneclick() {
    			$product_id = $_POST['product_id'];
    			$variation_id = $_POST['variation_id'];
    			$quantity = $_POST['quantity'];
    
    			if ($variation_id) {
    				WC()->cart->add_to_cart( $product_id, $quantity, $variation_id );
    			} else {
    				WC()->cart->add_to_cart( $product_id, $quantity);
    			}
    
    			$items = WC()->cart->get_cart();
    			global $woocommerce;
    			$item_count = $woocommerce->cart->cart_contents_count; ?>
    
    			<?php die();
    		}
    
    add_action('wp_ajax_oneclick', 'oneclick');
    add_action('wp_ajax_nopriv_oneclick', 'oneclick');
    Ответ написан
    7 комментариев
  • Как грамотно верстать несколько страниц веб-сайта?

    delphinpro
    @delphinpro
    frontend developer
    Берёте и верстаете как обычно.
    Любые из озвученных инструментов актуальны. Выбирайте по душе.

    Лично я предпочитаю верстку делать, используя mix. Потому что его практически не нужно конфигурировать. Сразу начинаешь работать. Плюс, есть куча готовых расширений https://laravel-mix.com/extensions

    Примерный конфиг
    const mix = require('laravel-mix');
    require('laravel-mix-twig');
    
    mix.setPublicPath('dist');
    mix.browserSync({
        server      : {
          baseDir  : 'dist',
          directory: true,
        },
        files       : ['./dist'],
      });
    }
    
    mix.sass('src/scss/main.scss', 'css');
    
    mix.js('src/js/main.js', 'js')
      .sourceMaps(true)
      .extract();
    
    mix.alias({
      '@': path.join(__dirname, 'src'),
    });
    
    mix.twig({
      root    : './src/templates',
      entries : [
        '*.twig',
      ],
      output  : './',
    });

    package.json
    {
      "private": true,
      "scripts": {
        "dev": "mix",
        "watch": "mix watch",
        "watch-poll": "mix watch -- --watch-options-poll=1000",
        "hot": "mix watch --hot",
        "prod": "mix --production"
      },
      "devDependencies": {
        "laravel-mix": "^6.0.43",
        "laravel-mix-twig": "^2.0.1"
      }
    }
    Ответ написан
    Комментировать
  • Как передать содержимое в переменную PHP?

    @easycode
    не боюсь задавать глупые вопросы ))
    ну типа:
    <div id="list"></div>
    
    <script type="text/javascript">
      jQuery(document).ready(function($) {
        jQuery.post('index.php', 'list': jQuery('#list').html(), function(data, textStatus, xhr) {
          /*optional stuff to do after success */
        });
      });
    </script>


    на стороне сервера:
    <?php
    #index.php
    echo $_POST['list']; // содержимое div-а с id = list
    Ответ написан
    Комментировать
  • Какие lazy load-плагины для изображений лучше?

    @SergeiB
    После появления Intersection Observer API надобность в плагинах отпала. Всё решается парой десятков строчек кода.
    Пример.

    const options = {
      root: null,
      rootMargin: '0px',
      threshold: 0.05
    };
    
    const lazyload = function(entries, observer) {
      entries.forEach(function(entry) {
        const target = entry.target;
        const dataset = target.dataset;
    
        if (entry.isIntersecting) {
          try {
            if ('src' in dataset) {
              target.src = dataset.src;
            }
    
            if ('bg' in dataset) {
              target.style.backgroundImage = `url(${dataset.bg})`;
            }
    
            target.classList.add('lazyloaded');
            observer.unobserve(target);
          } catch (error) {
            console.error(error);
          }
        }
      });
    };
    
    const observer = new IntersectionObserver(lazyload, options);
    
    document.querySelectorAll('.js-lazyload').forEach(elem => observer.observe(elem));

    <!-- Изображение без плейсхолдера -->
    <img class="js-lazyload" data-src="path/to/image/elephant.jpg" alt="The pink elephant">
    
    <!-- Изображение с плейсхолдером -->
    <img class="js-lazyload" data-src="path/to/image/elephant.jpg" src="path/to/placeholder.jpg" alt="The pink elephant">
    
    <!-- Ситуация, когда изображение надо задать как фон -->
    <div class="js-lazyload" data-bg="path/to/image/elephant.jpg"></div>

    Ответ написан
    3 комментария
  • Как минимизировать риски атак и взлома сайта?

    pro100taa
    @pro100taa
    Реализуйте из пункта "Что делать чтобы обезопасить сайт" что получится.

    https://ru.wordpress.org/support/article/faq-hacked/
    Ответ написан
    Комментировать
  • Как создать на wp кастомную роль с просмотром post_type?

    V_A_B
    @V_A_B
    ¯\_(ツ)_/¯
    интересный вопрос.....Спасибо!
    Пройдя по ссылке Анатолия и поковырявшись вот такой вариант у меня вышел)):
    создаем новую роль
    add_role('newvabuser',
    		__('Новый пользователь','VAB'),
    		array(
    		'read'=>true,
    		'edit_posts'=>false,
    		'delete_posts'=>false,
    		'publish_posts'=>false,
    		'upload_files'=>true,
    	 )
    	);

    насколько я понял данный код можно удалить после того как роль с массивом попадет в базу....
    если что не так, используйте
    remove_role('newvabuser');
    далее создаем новый пост тип
    add_action('init','create_custom_post_types');
    function create_custom_post_types(){
    	register_post_type('vabs',
    		array(
    			'labels'=>array(
    					'name'=>__('Новый тип записи','VAB'),
    					'singular_name'=>__('Новый тип записи','VAB'),
    					'menu_name'=>__('Новый тип записи','VAB'),
    					'add_new'=>__('Добавить новую','VAB'),
    					'add_new_item'=>__('Добавить новую','VAB'),
    					'edit_item'=>__('Редактировать','VAB'),
    					'new_item'=>__('Новая','VAB'),
    					'all_items'=>__('Все записи','VAB'),
    					'view_item'=>__('Просмотр','VAB'),
    					'search_items'=>__('Искать','VAB'),
    					'not_found'=>__('Записи не найдены','VAB'),
    					'not_found_in_trash'=>__('В корзине записи не найдены','VAB'),
    					'parent_item_colon'=>''
    			),
    			'public'=>true,
    			'has_archive'=>true,
    			'rewrite'=>array('slug'=>'vab'),
    			'capability_type'=>'vab',
    			'capabilities'=>array(
    				'publish_posts'=>'publish_vabs',
    				'edit_posts'=>'edit_vabs',
    				'edit_others_posts'=>'edit_others_vabs',
    				'delete_posts'=>'delete_vabs',
    				'delete_others_posts'=>'delete_others_vabs',
    				'read_private_posts'=>'read_private_vabs',
    				'edit_post'=>'edit_vabs',
    				'delete_post'=>'delete_vabs',
    				'read_post'=>'read_vabs',
    				'assign_terms' =>'edit_taxo',
    				'manage_terms'=>'manage_vab_terms',
    				'edit_terms'=>'manage_vab_terms',
    				'delete_terms'=>'delete_vab_terms',
    				'assign_terms'=>'edit_vab-type'
    			),
    			'supports'=>array('title','editor','thumbnail')
    		)
    	);
    }

    важно обратить внимание на массив с параметрами capabilities. его мы дальше передадим нашей роли:
    add_action('admin_init','add_vabs_caps');
    function add_vabs_caps(){
    	$admins=get_role('newvabuser');
    	$admins->add_cap('edit_vabs');
    	$admins->add_cap('publish_vabs');
    	$admins->add_cap('read_vabs');
    	$admins->add_cap('read_private_vabs');
    	$admins->add_cap('delete_vabs');
    	$admins->add_cap('edit_taxo');
    	$admins->remove_cap('edit_others_vabs');
    	$admins->remove_cap('delete_others_vabs');
    	$admins->add_cap('manage_vab_terms');
    	$admins->add_cap('delete_vab_terms');
    	$admins->add_cap('edit_vab-type');
    	$admins->add_cap('manage_categories');
    	$admins->add_cap('edit_categories');
    	$admins->add_cap('delete_categories');
    	$admins->add_cap('assign_categoriess');
    }

    В итогах данную запись смогут редактировать только админ и пользователь с данной ролью больше никто:
    5d5c421fb2511245944305.jpeg
    5d5c422ca4152143576315.jpeg
    Вам нужно все это только под себя переделать
    Ответ написан
    1 комментарий
  • Как добавить поле поиска записи или таксономии в админке Wordpress или Woocommerce?

    DrZhmurge
    @DrZhmurge Автор вопроса
    переопределяем функцию которую дата указана в "data-action", на любую кастомную.
    У меня: data-action="search_posts".
    Далее создаем функцию search_posts:

    add_action('wp_ajax_search_posts', 'search_posts');
    function search_posts()
    {
    	$s = $_GET['term']; //получает данные введенного текста для поиска
    	$args = array(
    		'post_type' => 'collection',  //ваш тип поста
    		's' => $s, //поисковый запрос
    	);
    	$data = [];
    	$loop = new WP_Query($args);
    	if ($loop->have_posts()) {
    		while ($loop->have_posts()) {
    			$loop->the_post();
    			$post_id = get_the_id(); //получаем id записи
    			$post_name = get_the_title(); //получаем title записи
    			$data[$post_id] = $post_name; // добавляем в массив data
    		}
    	}
    	echo json_encode($data); //кодируем в json и выводим
    	wp_die(); //иначе 0 в конце всегда лишний в выводе
    }


    Далее меняем вывод нужных нам данных уже в самом поле select. Приведу в пример полный код select, чтобы не запутаться:
    <select id="product_field_type" name="product_field_type[]" class="wc-product-search" multiple="multiple" style="width: 50%;" data-placeholder="<?php esc_attr_e('Поиск по названию коллекции', 'woocommerce'); ?>" data-action="search_posts">
    					<?php
    					$product_ids            = [];
    					$product_field_type_ids = get_post_meta(get_the_ID(), '_product_field_type_ids', true);  //сменил $post->ID на get_the_ID()
    					
    					if (!empty($product_field_type_ids)) {
    						$product_ids = array_map('absint', $product_field_type_ids);
    					}
    
    					if ($product_ids) {
    						foreach ($product_ids as $product_id) {
    							//$product = new WP_Query($product_id);  больше не нужен
    							
    							echo sprintf(
    								'<option value="%s" %s>%s</option>',
    								esc_attr($product_id),
    								selected(true, true, false),
    								esc_html(get_the_title($product_id)) //получаем нужный нам title по id записи
    							);
    						}
    					}
    					?>
    				</select>
    Ответ написан
    Комментировать
  • Принцип, по которому можно такое реализовать?

    artzolin
    @artzolin Куратор тега WordPress
    php, WordPress разработка сайтов artzolin.ru
    Комментировать
  • Как добавить несколько файлов в поле acf(galery) при отправке формы с сайта?

    wppanda5
    @wppanda5 Куратор тега WordPress
    WordPress Mедведь
    Вы на каждой итерации обновляете id картинки

    Надо как-то так
    $files = $_FILES[ "photo" ];
    	$_ids  = $_errors = [];
    	foreach ( $files[ 'name' ] as $key => $value ) {
    		if ( $files[ 'name' ][ $key ] ) {
    			$file   = array (
    				'name'     => $files[ 'name' ][ $key ],
    				'type'     => $files[ 'type' ][ $key ],
    				'tmp_name' => $files[ 'tmp_name' ][ $key ],
    				'error'    => $files[ 'error' ][ $key ],
    				'size'     => $files[ 'size' ][ $key ]
    			);
    			$_FILES = array ( "rev_foto" => $file );
    
    			$attachment_id2 = media_handle_upload( "rev_foto", 0 );
    
    
    			if ( is_wp_error( $attachment_id2 ) ) {
    				$_errors[] = $attachment_id2->get_error_message();
    			} else {
    				$_ids[] = $attachment_id2;
    			}
    		}
    	}
    
    	if ( ! empty( $_ids ) ) {
    		update_field( 'rev_foto', $_ids, $post_id );
    	}
    
    	if ( ! empty( $_errors ) ) {
    		sprintf( 'А вот, что пошло не так: %s', implode( ' ,', $_errors ) );
    	}


    И пользуйтесь уже нормальными функциями из движка а не всяким get_field, update_field и иже с ним
    Ответ написан
    1 комментарий
  • Gutenberg Как задать css класс по умолчанию блокам?

    @Flying
    Есть несколько вариантов решения:

    1. Патчинг HTML отрендеренного блока

    Самый простой в реализации, но далеко не самый стабильный вариант. Определите фильтр для рендера вашего типа блока, в данном случае:

    add_filter('render_block_core/video', function (string $content, array $block) {
        // Здесь вам нужно изменить содержимое переменной $content
        // она содержит уже отрендеренный HTML код блока.
        return $content;
    }, 10, 2);


    Для корректной работы с HTML лучше использовать расширение DOM.

    2. Переопределить рендер блока целиком

    Для этого вам нужно зарегистрировать блок с точно таким же названием и переопределить его рендер. Подробнее смотрите в документации.

    3. Сделать свой блок

    Также, через register_block_type определяете свой собственный блок и пишете свой рендер для него.
    Ответ написан
    Комментировать
  • Изменить порядок вывода атрибутов в шаблоне?

    wppanda5
    @wppanda5 Куратор тега WordPress
    WordPress Mедведь
    Как сказал Антон Литвиненко до цикла изменить порядок элементов.

    Но можно тупо в лоб.

    $out = '';
    $html = <<<HTML
    	<tr class="woocommerce-product-attributes-item woocommerce-product-attributes-item--%s">
    		<th class="woocommerce-product-attributes-item__label">%s</th>
    		<td class="woocommerce-product-attributes-item__value">%s</td>
    	</tr>
    HTML;
    
    $i = 1;
    foreach ( $product_attributes as $attribute ):
    	$attribute_data = $attribute->get_data();
    
    	if ( $i !== 3 ) {
    		$out .= sprintf( $html, esc_attr( $attribute_data['name'] ), wc_attribute_label( $attribute_data['name'], $product->get_attribute( $attribute_data['name'] ) ) );
    	} else {
    		printf( $html, esc_attr( $attribute_data['name'] ), wc_attribute_label( $attribute_data['name'], $product->get_attribute( $attribute_data['name'] ) ) );
    	}
    
    	$i ++;
    endforeach;
    echo $out;
    Ответ написан
    4 комментария
  • Как обновить блок с помощью ajax?

    @zkrvndm
    Софт для автоматизации
    Пример функции для выборочного обновления контента:
    async function elementUpdate(selector) {
    	try {
    		var html = await (await fetch(location.href)).text();
    		var newdoc = new DOMParser().parseFromString(html, 'text/html');
    		document.querySelector(selector).outerHTML = newdoc.querySelector(selector).outerHTML;
    		console.log('Элемент '+selector+' был успешно обновлен');
    		return true;
    	} catch(err) {
    		console.log('При обновлении элемента '+selector+' произошла ошибка:');
    		console.dir(err);
    		return false;
    	}
    }

    Вызывайте функцию elementUpdate() передав внутрь него CSS-селектор того элемента, который вы хотите обновить. Например, если взять блок, который имеет id равный block, то достаточно выполнить:
    elementUpdate('div#block');

    Если хотите делать это циклически, каждую секунду, то можно использовать while:
    // Запуск асинхронного кода:
    
    (async function() {
    	
    	// Бесконечный цикл:
    	
    	while (true) {
    		
    		await elementUpdate('div#block'); // Обновляем блок
    		
    		// Выжидаем 1000 миллисекунд, а потом код внутри while выполняется вновь:
    		await new Promise(function(success) { setTimeout(success, 1000); });
    		
    	}
    
    })();


    P. S. Но так обычно не делают, но если вам прям сильно надо, можно использовать этот лобовой метод.
    Ответ написан
    Комментировать
  • Форма подбора wordpress?

    artzolin
    @artzolin Куратор тега WordPress
    php, WordPress разработка сайтов artzolin.ru
    1. Регистрируете гет-переменные

    add_filter( 'query_vars', 'add_query_vars' );
    function add_query_vars( $qvars ) {
    
    	$qvars[] = 'brand';
    	$qvars[] = 'model';
    	$qvars[] = 'price';
    	$qvars[] = 'location';
    
    	return $qvars;
    }


    2. Собираете и выводите html-форму
    <form method="get" class="block obj-filter">
    	<div class="row d-flex align-items-center">
    		<div class="col-12 col-md-6 col-lg-3 col-margin-bottom-small col-lg-margin-bottom-none">
    			<select name="brand" id="brand" class="obj-select">
    				<option value="audi">Audi</option>
    				<option value="volkswagen">Volkswagen</option>
    				<option value="mercedes">Mercedes</option>
    				<option value="bmw">BMW</option>
    			</select>
    		</div>
    		<div class="col-12 col-md-6 col-lg-3 col-margin-bottom-small col-lg-margin-bottom-none">
    			<select name="price" id="price" class="obj-select">
    				<option value="20">$20 000</option>
    				<option value="50">$50 000</option>
    				<option value="75">$75 000</option>
    				<option value="100">$100 000</option>
    			</select>
    		</div>
    		<div class="col-12 col-md-6 col-lg-3 col-margin-bottom-small col-lg-margin-bottom-none">
    			<input type="text" name="location" id="location" class="obj-filter-input" value="">
    		</div>
    		<div class="col-12 col-md-6 col-lg-3 col-margin-bottom-small col-lg-margin-bottom-none">
    			<input id="obj-filter-submit" type="submit" class="button" value="Фильтровать">
    		</div>
    	</div>
    </form>


    3. При нажатии кнопки Фильтровать страница перезагружается, вы получаете ссылку вида https://example.loc/?brand=audi&price=50. На хуке pre_get_postsможно поправить основной запрос вытянув данные из гет-параметров. Вам нужно установить новые tax_query или meta_query в зависимости от логики сайта

    add_action( 'pre_get_posts', 'custom_pre_get_posts', 1 );
    function custom_pre_get_posts( $query ) {
    	// Выходим, если это админ-панель или не основной запрос
    	if( is_admin() || ! $query->is_main_query() )
    		return;
    
    	// предположим, что это таксономия с машинами
    	if ( $query->is_tax( 'cars' ) ) {
    		
    		$meta = array();
    		$meta['meta_query']['relation'] = 'AND';
    
    		// выбираем записи с GET запросами
    		$query_vars = ['brand', 'model', 'price', 'location'];
    		foreach ( $query_vars as $key => $query_var ) {
    			if ( $var = get_query_var( $query_var, false ) ) {
    				// тут пишем логику по которой собирается переменная meta_query и/или tax_query
    			}
    		}
    		$query->set( 'meta_query', $meta );
    
    	}
    }
    Ответ написан
    Комментировать
  • Как сделать чередование постов из разных циклов(условий/такс)?

    artzolin
    @artzolin Куратор тега WordPress
    php, WordPress разработка сайтов artzolin.ru
    Проще всего заказать из базы конкретные ids в определенном вами порядке, иначе вы вряд ли сможете гарантировать, что записи разных типов придут вам в нужном порядке

    $args = [
    	'post_type' => ['post','service'],
    	'post__in' => [5,12,2,14,7],
    	'orderby' => 'post__in',
    ];
    
    $loop = new WP_Query( $args );


    При выводе проверяете тип записи и подключаете нужный шаблон

    if ( get_post_type() === 'service' ) {
    	get_template_part( 'templates/archive/archive-service' );
    } else {
    	get_template_part( 'templates/archive/archive-common' );
    }


    Если типов записей много, то можно сделать так

    $post_type = get_post_type();
    
    if ( file_exists( get_theme_file_path( 'templates/archive/archive-' . $post_type . '.php' ) ) ) {
    	get_template_part( 'templates/archive/archive-' . $post_type );
    } else {
    	get_template_part( 'templates/archive/archive-common' );
    }
    Ответ написан
    Комментировать
  • Есть ли хорошие готовые preloader с печатающимся текстом?

    Stalker_RED
    @Stalker_RED
    Там кода на пять строк. Что вам нужно от "готового"?
    Ответ написан
    1 комментарий
  • Как сделать динамический запрос в WP_Query?

    Ну по сути - здесь можно сделать шорткод

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

    // Shortcode for projects [projects-list posts="3"]
    function projects_listing_parameters_shortcode( $atts ) {
        ob_start();
    
        $args = shortcode_atts( array (
            'type' => 'projects',
            'posts' => 6,
            'cat' => ''
        ), $atts );
    
        $options = array(
            'post_type' => $args['type'],
            'posts_per_page' => $args['posts'],
            'tax_query' => array(
                array (
                    'taxonomy' => 'project',
                    'field' => 'slug',
                    'terms' => $args['cat'],
                )
            ),
        );
    
        $query = new WP_Query( $options );
    
        if ( $query->have_posts() ) $item = 0; {
            while ( $query->have_posts() ) : $query->the_post(); $item++;
                echo '<div class="item item-' . $item . '">';
                    get_template_part( 'template-parts/project-cards', get_post_format() );
                echo '</div>';
            endwhile;
            wp_reset_postdata();
            $myvariable = ob_get_clean();
            return $myvariable;
        }
    }
    add_shortcode( 'projects-list', 'projects_listing_parameters_shortcode' );
    Ответ написан
    Комментировать
  • Как вставить div в тему WordPress?

    artzolin
    @artzolin Куратор тега WordPress
    php, WordPress разработка сайтов artzolin.ru
    Чтобы файлы не затерлись при обновлении нужно создать дочернюю тему

    В functions.php нужно добавить подключение скриптов и стилей на хуке wp_enqueue_scripts так:

    add_action( 'wp_enqueue_scripts', 'custom_scripts' );
    function custom_scripts() {
    
    	// Сюда стили
    	wp_enqueue_style( 'newstyle', get_template_directory_uri() . '/assets/css/custom_style.min.css' );
    
    	// Сюда скрипты
    	wp_enqueue_script( 'newscript', get_template_directory_uri() . '/assets/js/custom_script.min.js' );
    
    	// сюда инициализацию или отдельным файлом как выше
    	$newscript_init = 'jQuery(function($) {
    
    	});';
    	wp_add_inline_script( 'newscript', $newscript_init );
    
    }


    Вывод формы можно добавить на хук wp_footer так:

    add_action( 'wp_footer', 'the_popup_form', 1 );
    function the_popup_form() { ?>
    
    	<div id="popup" class="mfp-hide popup">
    		<form id="popup-form" class="popup-form">
    
    			<!-- ... -->
    
    		</form>
    	</div>
    
    <?php }
    Ответ написан
    9 комментариев