• За счёт чего такая скорость переключения между страницами сайта?

    JRK_DV
    @JRK_DV
    Рецепты https://codepen.io/jrkdv/full/LKLXdq
    Точно не ajax

    ок, пусть будет fetch

    upd
    если присмотритесь, то загрузка страницы начинается при ховере на любой ссылке сайта, то есть ещё до самого "шелчка" мыши данные уже запрашиваются с сервера
    Ответ написан
  • Почему array_map и sanitize_text_field удаляют вложенный массив?

    @FanatPHP
    Потому что надо выкинуть на помойку бессмысленную функцию sanitize_text_field и забыть о её существовании.

    Ну и на досуге почитать в документации, что array_map работает с одномерными массивами.
    Ответ написан
  • Оценка и анализ сайта?

    xmoonlight
    @xmoonlight Куратор тега Веб-разработка
    https://sitecoder.blogspot.com
    Заброшенные и перспективные проекты всегда лучше создавать с "нуля".
    Ответ написан
  • Как в Contact Form 7 скрывать кнопку пока он думает?

    deniscopro
    @deniscopro Куратор тега WordPress
    WordPress-разработчик, wpcute.ru
    Возможно, событие wpcf7submit подойдет.
    Ответ написан
  • Как подключить js-файл из записи?

    anatoly_kulikov
    @anatoly_kulikov
    Помог ответ? Отметь решением!
    В своём случае просто добавил кастомное метаполе и запихнул код туда. Потому что вставлять код в само тело можно, но едва мы переключаемся в визуальный режим, происходит вот эта неприятная магия с форматированием.
    Ответ написан
  • Как подключить все одинаковые id div'ов?

    Dnebl
    @Dnebl
    Атрибут id должен быть уникальным. Не должно быть элементов у которых одинаковые id
    Ответ написан
  • Скажите хорошие видеоуроки по JUnit тестированию в андроид аппликациях?

    gbg
    @gbg
    Баянист. Тамада. Услуги.
    Начните называть приложение приложением. Полезно будет.
    Аппликация - это вот:
    19127_9096d2a30043af39f449e7d5f8acca3e.j
    Ответ написан
  • Что представляет собой тестирование ?

    Fesor
    @Fesor
    Full-stack developer (Symfony, Angular)
    Вообще вики можно для начала, а потом уже углубляться в литературу. Вот вам кратенькое описание, цель которого больше предоставить ключевые слова для поиска.

    Модульные, они же юнит тесты, предназначены для тестирования отдельных модулей/классов. Суть их в том, что мы тестируем поведение только одного класса за раз. Если класс ссылается на инстансы других классов - мы их мокаем. То есть подсовываем им фэйковый класс, который имеет тот же интерфейс, но внутри не реализациа методов, а проверка, вызывали ли метод, с каким аргументами, сколько раз вызывали и т.д. Так же методы мока могут возвращать стабы (заглушки), какие-то захардкоженные под какой-то кейс данные. То есть если мы пишем класс по работе с базой данных, сокет-сервер и т.д., нам стоит соединение с базой, сокеты и т.д. оборачивать в классы, что бы можно было потом подменить на моки это добро. Если у вас в юнит тестах идет реальная работа с файловой системой или что-либо в этом духе, то это уже попахивает интеграционными тестами. Подробнее можно почитать в документации к phpunit. Так же есть такая методология разработки как TDD, советую почитать "Экстримальное программирование" Кента Бэка в этом ключе.

    Сразу хочу отметить что юнит тесты это хорошо, но вот только рядовой разработчик на PHP редко пишет что-то, что стоит покрывать юнит тестами. Времени на их поддержку нужно не мало, а требования у заказчиков частенько меняются. В итоге тесты начинают комментить и толку от них становится ноль. А вот если вы пишите компонент/библиотеку, то тут юнит тесты обязательны (ну... не то что бы, но желательны). Так что я бы на вашем месте сконцентрировал внимание на первом этапе на интеграционных и приемочных тестах.

    Интеграционное тестирование - тестирование нескольких модулей в связке. То есть мы тестируем наш компонент или его самодостаточный кусок в реальных условиях. Если этот компонент для работы с файлами - разрешаем ему доступ к файлам. Если база данных - то даем реальное соединение с базой. А можем что-то и замокать. Это как говорится, зависит от задачи. Скажем обращение к сторонним апишкам стоит мокать и стабить. Главная цель этих тестов, удостовериться что модули вместе работают хорошо. Особенно важно это когда модули пишут разные люди.

    Функциональное тестирование - это тестирования всего приложения в сборе. Если это REST API, то у нас через curl дергаются реальные методы, отправляются более менее реальные запросы и валидируются ответы. Если web-страничка, то это UI тесты с силениумом/phantom.js/zombi.js или, если нам не нужно еще и js тестить, просто curl + какой виртуальный браузер на том же php. Вообще по хорошему функциональные тесты не допускают никаких моков и т.д. но опять же если очень хочется то можно (опять же обращение к сторонним сервисам, контроля за которыми у нас нету).

    Но реалии таковы, что UI тестами покрывать проект не слишком удобно. Вопервых UI может меняться, а поддерживать их так же нужно. Во вторых это скучно. В третьих тесты могут просто падать... вот взяли и упали. И потом начинается, так, тесты опять упали... что там упало? А, не страшно, можно релизить. Так же на больших проектах UI тесты отрабатывают долго, очень долго, некоторых их просто ночью гоняют. Толку от тестов при таком подходе не слишком много, ибо разработчику стоит знать о том что что-то сломалось как можно быстрее. А так он приходит, видит что тесты опять красные, чинит эти красные тесты, и запускает... ждет... проходит пол часа к примеру, и где-то в другом месте отвалилось... Короче сами понимаете.

    Приемочное тестирование - по сути те же функциональные тесты, но подаются в контексте фича-спеков. Если вы работали когда-нибудь с QA отделом, то возможно слышали про такие штуки как acceptance criteria. То есть это тот чек лист, который должен проверить тестировщик что бы удостовериться что все хорошо. На основе этого чек листа можно написать функциональные тесты. Так же есть инструменты вроде Cucumber/Behat, которые позволяют писать спецификации в виде стэпов. В этом случае спецификации для этих инструментов могут писать QA а вы просто имплементите для них степы. То есть уменьшается прослойка между "acceptance criteria" и готовыми к выполнению тестов. Более того, стэпы можно реюзать, комбинировать, масса стэпов есть готовых, вам же необходимо только предоставить стэпы подготвалливающие систему (загрузка/генерация фикстур и т.д.). Короче лепота и удобно. Но медленнее интеграционных, зато не такие жесткие как функциональные, за счет этого их проще поддерживать. QA пишут спеку, реализуем тесты под эту спеку, пишем код под тесты, тесты зеленые - функционал готов.

    Ну и есть еще всякие термины типа пирамида тестов и т.д. Мол лучше много юнит тестов, чуть поменьше интеграционных и мало функциональных. Тогда тесты выполняются быстрее, а покрывать все и вся функциональными тестами обычно перебор.

    Ну и опять же, есть такая вещь как здравый смысл. Некоторые вещи скажем можно вообще забить и не покрывать тестами, некоторые стоит покрыть. Некоторые не полностью, некоторые с как можно большим покрытием.... Скажем тестить UI (именно как выглядит, где какой элемент) вообще бессмысленно. На это нужно куча ресурсов. Хотя может и есть проекты где это оправдано.

    Короче почитайте про TDD и ATDD (можно и BDD затронуть, но тут не только от программиста зависит, менеджеры, заказчик или продукт-оунер тоже должны быть вовлечены, по сути этот подход хорошо работает в рамках продукта какого-то, на фрилансе и в аутсорсе редко можно встретить) , Continious Integration и Continious Delivery.
    Ответ написан
  • Перемешать вывод товаров в магазине woocommerce?

    deniscopro
    @deniscopro Куратор тега WordPress
    WordPress-разработчик, wpcute.ru
    Добавлю к ответу WP Panda ещё парочку более лайтовых вариантов:
    1. Мешать товары на каждой странице отдельно. Тогда визуально они будут меняться, но пагинация не сломается и не будет некешируемого RAND.
    2. Периодически через cron дергать скрипт, который будет менять порядок товаров в базе. На сайте порядок товаров будет меняться не при каждом открытии, а через заданный интервал времени, но опять же нет возни с пагинацией и проблем с RAND.

    Не знаю какая у Вас точная задача по ТЗ, но если использовать один из способов или совместить их, то можно добиться неплохого визуального эффекта псевдослучайности.

    P.S. Способ №2 содержит потенциальную проблему в случае, если порядок товаров в базе изменится во время того, как пользователь просматривает каталог. Поэтому этот сценарий тоже стоит как-то обрабатывать.
    Ответ написан
  • Как исключить из выборки посты в WP_Query?

    @HectoR_UA
    Получи все внутренние связи
    global $wpdb;
    $connections = $wpdb->get_col("SELECT meta_value FROM $wpdb->postmeta WHERE meta_key='connections'");

    Должно вернуть массив с айдишниками постов выбранных в селекте. Если там какая-то другая структура - преобразуй его в массив если необходимо. В итоге должно получиться что-то вроде
    $formatted_conns = array(10,23,50,47);
    Ну а потом просто исключить этот массив из выборки
    $query = new WP_Query(array(
    ...
    'post__not_in' => $formatted_conns,
    ...
    ));
    Ответ написан
  • Как скрыть товары без фото и описания Woocommerce?

    mihdan
    @mihdan
    WordPress-евангелист, ведущий РНР - разработчик
    Воспользуйтесь фильтром woocommerce_product_is_visible, написав внутри проверку на пустоту описания иили отсутствие фото.

    add_filter( 'woocommerce_product_is_visible', function( $visible, $id ) {
        // Если у товара нет фото - скроем товар.
        if ( ! has_post_thumbnail( $id ) ) {
            return false;
        }
    
        return $visible;
    }, 10, 2 );
    Ответ написан
  • Чувствуется ли избыток специалистов по разработке на WordPress?

    Moskus
    @Moskus
    Избыток специалистов - нонсенс, так не бывает ни в какой области.
    Избыток безграмотных кодеров, которые делают всё по гайдам, туториалам и видео с Youtube - да.
    Ответ написан
  • С какими подводными камнями можно столкнуться при разработке интернет-магазина на WooCommerce?

    @azerphoenix
    Все строго индивидуально.
    Если решили делать магазин на ВП, то однозначно woocommerce
    Если есть острая необходимость сделать на фреймворке и позволяет бюджет, то выберите тот фреймворк, которым вы лучше владеете. Yii2, Laravel, Symfony, Django, Spring, R&R и т.д.
    Вопрос в том, нужен ли фреймворк (что нужно вам такого специфического, чего нет в ВП и вукомер и нужно написать с нуля)
    Ответ написан
  • Имеется ли плагин для вордпресса, который автоматом выбирает картинки по тайтлу при добавлении в запись?

    Такое не встречал,
    Но писал код подгрузки картинок из определенной папки, добавление их в медиа-библиотеку, и подключение к постам (к товарам Woocommerce) по соответствию артикула и в названии картинки.

    Если будете править, то вот
    php
    <?php 
    
    /**
    *	Класс для подключения изображения к товару
    */
    class Hml_Img_Connector {
    	
    	/**
    	*	
    	*/
    	public static function init(){
    		
    		add_action('tesp_show_widget', array('Hml_Img_Connector', 'get_html_widget') );
    		
    		// подключаем ajax хуки
    		if( defined('DOING_AJAX') && DOING_AJAX ){
    			add_action('wp_ajax_img_connector_dostep', array('Hml_Img_Connector', 'dostep_ajax_handler') );
    		}
    						
    	}
    	
    	public static function dostep_ajax_handler(){
    
    		$imgs = self::get_array_images(TEST__PLUGIN_DIR . 'imgs/');
    		
    		// сортировка по убыванию
    		usort($imgs, function($a, $b){
    			    if ($a['name'] == $b['name']) {
    					return 0;
    				}
    				return ($a['name'] > $b['name']) ? -1 : 1;
    		});
    
    		$msgs = self::process_images($imgs, 2);
    		
    		$aAns = array('left'=>count($imgs), 'msgs'=>$msgs);
    
    		echo json_encode($aAns);
    		
    		wp_die(); 
    		
    	}
    
    	/**
    	 * Запускает процесс подключения картинок
    	 * 
    	 */
    	private static function process_images(&$imgs, $step){
    
    		$msgs = array();
    
    		if ( $step < 1 ) { $step = 1; }
    		
    		for ($i = count($imgs) - 1; $i >= 0 ; $i--) {
    			$sku = '9999';
    
    			// отделяем все, что после символа "_"
    			$fn = explode( '_', $imgs[$i]['name'])[0];
    			$sku_parts = explode('-', $fn);
    			if (count($sku_parts) >= 4 && '111' == $sku_parts[3] ) {
    				$sku = implode( '-', array_slice($sku_parts, 0,4) );
    			} else {
    				$sku = implode( '-', array_slice($sku_parts, 0,3) );
    			}
    			// $sku = substr($imgs[$i]['name'], 0, 12);
    
    			$id = wc_get_product_id_by_sku($sku);
    
    			if ( !$id ){
    
    				$msgs[] = $imgs[$i]['name']. ' - ошибка, артикул "' . $sku . '" не найден.';
    				$edir = dirname(dirname($imgs[$i]['path'])) . '/notfound/';
    				$newpath = $edir . $imgs[$i]['name'];
    				if ( is_dir($edir) ) {
    					rename($imgs[$i]['path'],  $newpath);	
    				} else {
    					if ( mkdir($edir) ) {
    						rename($imgs[$i]['path'],  $newpath);							
    					} else {
    						@unlink( $imgs[$i]['path'] );
    					}
    				}
    
    			} else {
    				$media_id = self::atach_image($imgs[$i], $id);
    				if( is_wp_error($media_id) ) {
    					$msgs[] = $imgs[$i]['name']. ' - ошибка загрузки.';
    				} else {
    					$msgs[] = $imgs[$i]['name']. ' - успешно.';				
    				}
    				
    				array_pop($imgs);
    				$step --;
    				if ( 0 == $step ) break;
    			}
    		}
    		return $msgs;
    	}
    	
    	/**
    	* собираем все файлы картинок в директории
    	*/
    	private static function get_array_images($dir){
    		$ret = array();
    		
    		if ($handle = opendir($dir)) {
    
    			while (false !== ($file = readdir($handle))) { 
    				$fullpath = $dir .  $file;
    				if ( !is_dir( $fullpath ) ) {
    					$ext = pathinfo($fullpath)['extension'];
    					if ( 'jpg' == strtolower($ext) ) {
    						$ret[] =  array('name' => $file, 'path' => $fullpath);
    					}
    				}
    			}
    			clearstatcache();	// очистка кэша
    			closedir($handle); 
    		}
    		return $ret;
    	}
    	
    	
    
    	/**
    	 *	By Pytex
    	 * Добавляет картинку в медиабиблиотеку и 
    	 * прикрепляет ее к посту как миниатюру, если не задано
    	 * или в галерею поста
    	 *
    	 * @param  string  $img 
    	 * @param  number  $post_id
    	 */
    	private static function atach_image( $img, $post_id ) {
    		
    		// Установим данные файла
    		$file_array = array();
    		 
    		// Получаем имя файла
    		$file_array['name'] = $img['name'] ;
    		$file_array['tmp_name'] = $img['path'];
    		 
    		// загружаем файл
    		$media_id = media_handle_sideload( $file_array, $post_id);
    		 
    		// Проверяем на наличие ошибок
    		if( !is_wp_error($media_id) ) {
    		 
    			// Файл сохранён и добавлен в медиатеку WP. 
    			
    			$thumbnail_id = get_post_thumbnail_id( $post_id );
    			// Если нет прикрепленной миниатюры 
    			if ( !$thumbnail_id ){
    				// назначаем в качестве обложки
    				set_post_thumbnail($post_id, $media_id);
    			} else {
    				$media = get_attached_media('image', $post_id);
    				$imgs = array_diff(array_keys($media), array($thumbnail_id));
    				update_post_meta($post_id, '_product_image_gallery', implode(',', $imgs));
    			}		
    		}
    		return $media_id;
    	}
    
    	/**
    	*  Выводит на экран форму запуска процесса добавления картинок
    	*/
    	public static function get_html_widget(){
    
    		?>
    		<form action="" method="POST">
    			<h4>Подключение картинок</h4>
    			<table>
    				<tr>
    					<td>Затраченное время:</td>
    					<td><span id="time-elapsed" class="tsb-value"></span></td></tr>
    				<tr>
    					<td>Осталось времени:</td>
    					<td><span id="time-left" class="tsb-value"></span></td></tr>
    				<tr>
    					<td>Осталось обработать файлов:</td>
    					<td><span id="files-left" class="tsb-value"></span></td></tr>
    			</table>
    			<br/>
    			<?php
    				echo '<input type="button" id="btn-start-parsing" value="Запустить разбор картинок" class="button button-primary" ' ;?>
    		</form>
    		<div id="status-msg"></div>
    		<?php
    		require_once( 'img-connector-js.php' );
    	}
    	
    }
    
    Hml_Img_Connector::init();


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

    js
    <script type="text/javascript" >
    	var gIMGCONNApp = {
    			nTimerID 	: 0,		// Идентификатор таймера
    			nTimerInt	: 2000,		// Интервал таймера
    			bIsFree	 	: true,		// Сервер закончил! можно делать след. шаг
    			nStep 	 	: 10,		// Количество обработки записей за один шаг
    			nTimeStart	: 0			// время cтарта генерации xml
    		};
    		
    	jQuery(document).ready(function($) {
    		
    		//получаем идентификатор элемента состояния
    		var objProc = document.getElementById("files-left");
    			// Если не определен то выход
    			if(objProc == null){	return false;	}
    		
    		$("#btn-start-parsing").click(function(){
    			// начать повторы с интервалом 2 сек
    			gIMGCONNApp.nTimerID = setInterval(timer_tick, gIMGCONNApp.nTimerInt);
    			// Сохраняем временную точку старта
    			gIMGCONNApp.nTimeStart = getSecondsToday();
    			timeStatusBarInvalidate(0);
    			//var date = new Date();
    			//console.log(date);
    		});
    	});
    	
    	
    	
    	// получаем кол-во сегунд от начала суток
    	function getSecondsToday() {
    		var d = new Date();
    		return d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds();
    	};
    	
    	// Обработчик прерываний таймера
    	function timer_tick(){
    		if (gIMGCONNApp.bIsFree){ sendAjaxStep(); }
    		//console.log('timer_tick');
    	};
    	
    	function sendAjaxStep(){
    		gIMGCONNApp.bIsFree = false;
    		var data = {
    			action: 'img_connector_dostep',
    			step: gIMGCONNApp.nStep
    		};
    		
    		// с версии 2.8 'ajaxurl' всегда определен в админке
    		jQuery.post( ajaxurl, data, function(response, status) {
    			if (status == 'success'){
    				//console.log('Получено с сервера: ' + response + ': Статус: ' + status +'\n');
    				var rsp = JSON.parse(response);
    				//console.log(rsp);
    				//document.getElementById("ew-processed-value").innerText = rsp['completed'];
    				// обновление прогерсс бара
    				// processInvalidate(rsp['completed']);
    				timeStatusBarInvalidate(rsp['left']);
    				jQuery("#files-left").text(rsp['left']);
    				printMessages(rsp['msgs']);			
    				gIMGCONNApp.bIsFree = true;
    				if (rsp['left'] == 0) { 
    					clearInterval(gIMGCONNApp.nTimerID);
    					//jQuery("#btn-download-xml").css({display: "inline-block"});
    				}
    			}
    		})
    	};
    
    	function printMessages(arrMsgs){
    		var s = '';
    		
    		for (var i = 0; i < arrMsgs.length; i++) {
    			s += arrMsgs[i] + '<br/>';
    		}
    		jQuery("#status-msg").prepend(s);
    	}
    
    	function timeStatusBarInvalidate(completed){
    		var nTimeNow = getSecondsToday();
    		
    		if (nTimeNow < gIMGCONNApp.nTimeStart){
    			nTimeNow += 86400; }	// =24*60*60
    		var nTimeElapsed = nTimeNow - gIMGCONNApp.nTimeStart;
    		
    		// var nTimeLeft = 0;
    		// if(completed > 0){
    			// nTimeLeft = nTimeElapsed*(100-completed)/completed; }
    		
    		// var sBarText = "Затраченное время: " + formatTime(nTimeElapsed) + 
    					   // "; Осталось времени: " + formatTime(nTimeLeft);
    		jQuery("#time-elapsed").text(formatTime(nTimeElapsed));
    		// jQuery("#time-left").text(formatTime(nTimeLeft));
    	};
    	
    	function formatTime(secnum){
    		secnum = Math.floor(secnum);
    		var hours   = Math.floor(secnum / 3600);
    		var minutes = Math.floor((secnum - (hours * 3600)) / 60);
    		var seconds = secnum - (hours * 3600) - (minutes * 60);
    
    		if (hours   < 10) {hours   = "0"+hours;}
    		if (minutes < 10) {minutes = "0"+minutes;}
    		if (seconds < 10) {seconds = "0"+seconds;}
    		return hours+' : '+minutes+' : '+seconds;
    	};
    	
    	function processInvalidate(percent){
    		document.getElementById('progress-text').innerHTML = percent + ' %';
    		document.getElementById('progress-bar').style.width = percent * 7 + 'px';
    	};
    	
    </script>


    Для запуска отображения формы в админке просто добавьте код do_action('tesp_show_widget'); в нужное админки.
    Ответ написан
  • Что делать если element.style мешает на определенной странице?

    svistiboshka
    @svistiboshka
    живые веб интерфейсы
    и php и html и css и jquery этого точно достаточно? может нужны еще серверные конфиги? выложите минимальную проблему в песочницу. будем смотреть
    Ответ написан
  • Не работает код вывода рубрик Вордпресс как исправить?

    @weart
    Интересно, насколько надо быть упоротым, чтобы в коде писать на русском ))

    $args = array(
    	'post_type' => 'post',
    	'post_status' => 'publish',
    	'tax_query' => array(
    		array(
    			'taxonomy' => 'category',
    			'field' => 'id',
    			'terms' => array(3) // id нужных категорий
    		)
    	)
    );
    
    $q = new WP_Query( $args );
    
    if ( $q->have_posts() ) {
    
    	while ( $q->have_posts() ) {
    
    		$q->the_post();
    
    		the_title();  // выводим нужную инфу 
    
    	}
    }
    Ответ написан
  • Как быстро поднять интернет-магазин на WooCommerce?

    @azerphoenix
    Здравствуйте!
    Как я понял у вас имеется уже верстка. Осталось для начала создать тему, а потом уже адаптировать под Woocommerce.
    https://codex.wordpress.org/Theme_Development
    Создайте тему -
    создайте файл style.css и добавьте:
    /*   
    Theme Name: MyTheme
    Theme URI: mytheme.loc
    Description: Individual WP Theme
    Author: AuthorName
    Author URI: mytheme.loc
    Version: 1.0
    */

    Внесите свои правки...

    Создайте файл functions.php и подключите все скрипты, стили и шрифты через код. Например,
    // подключаем стили и скрипты
    function register_styles_scripts() {
    	//стили
    	wp_enqueue_style('customCSS', get_template_directory_uri() .
    		'/custom.css');
    	
    	//скрипты
    	wp_enqueue_script('jquery', get_template_directory_uri() .
    		'.js/script.js');
    }
    add_action('wp_enqueue_scripts', 'register_styles_scripts');


    Создайте необходимый набор файлов рнр (index.php, header.php, footer.php, page.php, single.php, archive.php). Смотря, какие страницы вам нужны...
    https://developer.wordpress.org/themes/basics/temp...

    Создайте меню в functions.php Например:
    register_nav_menu ('menu', 'Main menu');
    и выведите меню через - wp_nav_menu()
    https://wp-kama.ru/function/register_nav_menu
    https://wp-kama.ru/function/wp_nav_menu

    Включите поддержку миниатюр для записей -
    add_theme_support( 'post-thumbnails' );

    Далее по шаблонам:
    - вставляем <?php wp_head(); ?> перед </head>
    - вставляем <?php wp_footer(); ?> перед </body>
    - Копируем header вырезаем и вставляем в header.php
    - Взамен добавляем код <?php get_header(); ?>
    - Копируем sidebar вырезаем и вставляем в sidebar.php
    - Взамен добавляем код <?php get_sidebar(); ?>
    - Копируем footer вырезаем и вставляем в footer.php
    - Взамен добавляем код <?php get_footer(); ?>
    - в index.php изменяем url изображений на <?php bloginfo('template_url'); ?>/
    - вставляем между <title><?php bloginfo('name');?> | <?php wp_title(); ?></title>


    В шаблоны добавьте цикл ВП:
    <?php if (have_posts()) :  while (have_posts()) : the_post(); ?>
    
    <?php the_content (); ?>
    
    <?php endwhile; ?>
    <?php endif; ?>


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

    Для корректного применения стилей вукомерца в тег body надо добавить body_class()
    https://wp-kama.ru/function/body_class

    Далее установите плагин Woocommerce. В папке с плагином есть папка templates. Скопируйте ее в директорию вашей темы и переименуйте в woocommerce

    Цикл вукомерца отличается от стандартного цикла ВП. Подробная информация:
    https://docs.woocommerce.com/document/third-party-...

    Шаблоны вукомерца работают используют хуки. Используйте их для кастомизации.
    https://docs.woocommerce.com/document/introduction...
    Ответ написан