Все записи с тегом: wordpress

Стандартные галереи WordPress’a можно легко приспособить под Ekko lightbox.

Ekko lightbox

Содержание статьи:

  • Замена шорткода вывода галереи.
  • CSS правки для изображений.

1. Замена шорткода вывода галереи

За основу взята стандартная функция вывода галереи WordPress:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//Модернизируем галерею
remove_shortcode('gallery');
add_shortcode('gallery', 'new_gallery_shortcode');
function new_gallery_shortcode( $attr ) {
	$post = get_post();
	static $instance = 0;
	$instance++;
	if ( ! empty( $attr['ids'] ) ) {
            if ( empty( $attr['orderby'] ) ) {
                    $attr['orderby'] = 'post__in';
            }
            $attr['include'] = $attr['ids'];
	}
	$output = apply_filters( 'post_gallery', '', $attr, $instance );
	if ( $output != '' ) {
            return $output;
	}
	$html5 = current_theme_supports( 'html5', 'gallery' );
	$atts = shortcode_atts( array(
		'order'      => 'ASC',
		'orderby'    => 'menu_order ID',
		'id'         => $post ? $post->ID : 0,
		'itemtag'    => $html5 ? 'figure'     : 'dl',
		'icontag'    => $html5 ? 'div'        : 'dt',
		'captiontag' => $html5 ? 'figcaption' : 'dd',
		'columns'    => 3,
		'size'       => 'thumbnail',
		'include'    => '',
		'exclude'    => '',
		'link'       => ''
	), $attr, 'gallery' );
	$id = intval( $atts['id'] );
	if ( ! empty( $atts['include'] ) ) {
            $_attachments = get_posts( array( 'include' => $atts['include'], 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $atts['order'], 'orderby' => $atts['orderby'] ) );
            $attachments = array();
            foreach ( $_attachments as $key => $val ) {
                $attachments[$val->ID] = $_attachments[$key];
            }
	} elseif ( ! empty( $atts['exclude'] ) ) {
            $attachments = get_children( array( 'post_parent' => $id, 'exclude' => $atts['exclude'], 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $atts['order'], 'orderby' => $atts['orderby'] ) );
	} else {
            $attachments = get_children( array( 'post_parent' => $id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $atts['order'], 'orderby' => $atts['orderby'] ) );
	}
	if ( empty( $attachments ) ) {
            return '';
	}
	if ( is_feed() ) {
            $output = "\n";
            foreach ( $attachments as $att_id => $attachment ) {
                    $output .= wp_get_attachment_link( $att_id, $atts['size'], true ) . "\n";
            }
            return $output;
	}
	$itemtag = tag_escape( $atts['itemtag'] );
	$captiontag = tag_escape( $atts['captiontag'] );
	$icontag = tag_escape( $atts['icontag'] );
	$valid_tags = wp_kses_allowed_html( 'post' );
	if ( ! isset( $valid_tags[ $itemtag ] ) ) {
		$itemtag = 'dl';
	}
	if ( ! isset( $valid_tags[ $captiontag ] ) ) {
		$captiontag = 'dd';
	}
	if ( ! isset( $valid_tags[ $icontag ] ) ) {
		$icontag = 'dt';
	}
	$columns = intval( $atts['columns'] );
	$itemwidth = $columns > 0 ? floor(100/$columns) : 100;
	$float = is_rtl() ? 'right' : 'left';
	$selector = "gallery-{$instance}";
	$gallery_style = '';
	if ( apply_filters( 'use_default_gallery_style', ! $html5 ) ) {
		$gallery_style = "
		<style type='text/css'>
			#{$selector} {
				margin: auto;
			}
			#{$selector} .gallery-item {
				float: {$float};
				margin-top: 10px;
				text-align: center;
				width: {$itemwidth}%;
			}
			#{$selector} img {
				border: 2px solid #cfcfcf;
			}
			#{$selector} .gallery-caption {
				margin-left: 0;
			}
			/* see gallery_shortcode() in wp-includes/media.php */
		</style>\n\t\t";
	}
	$size_class = sanitize_html_class( $atts['size'] );
	$gallery_div = "<div id='$selector' class='gallery galleryid-{$id} gallery-columns-{$columns} gallery-size-{$size_class}'>";
        $gal_id = $id;
	$output = apply_filters( 'gallery_style', $gallery_style . $gallery_div );
	$i = 0;
	foreach ( $attachments as $id => $attachment ) {
 
		$attr = ( trim( $attachment->post_excerpt ) ) ? array( 'aria-describedby' => "$selector-$id" ) : '';
		if ( ! empty( $atts['link'] ) && 'file' === $atts['link'] ) {
                    $image_output = wp_get_attachment_link( $id, $atts['size'], false, false, false, $attr );
                    $image_output = str_replace('<a', '<a href="'. wp_get_attachment_image_url( $id, 'full' ) .'" data-toggle="lightbox" data-gallery="gallery-'. $gal_id .'"', $image_output); //Изменяем вывод ссылок на изображения
		} elseif ( ! empty( $atts['link'] ) && 'none' === $atts['link'] ) {
                    $image_output = wp_get_attachment_image( $id, $atts['size'], false, $attr );
		} else {
                    $image_output = wp_get_attachment_link( $id, $atts['size'], true, false, false, $attr );
                    $image_output = str_replace('<a', '<a href="'. wp_get_attachment_image_url( $id, 'full' ) .'" data-toggle="lightbox" data-gallery="gallery-'. $gal_id .'"', $image_output); //Изменяем вывод ссылок на изображения
		}
		$image_meta  = wp_get_attachment_metadata( $id );
		$orientation = '';
		if ( isset( $image_meta['height'], $image_meta['width'] ) ) {
                    $orientation = ( $image_meta['height'] > $image_meta['width'] ) ? 'portrait' : 'landscape';
		}
		$output .= "<{$itemtag} class='gallery-item'>";
		$output .= "
                    <{$icontag} class='gallery-icon {$orientation}'>
                            $image_output
                    </{$icontag}>";
		if ( $captiontag && trim($attachment->post_excerpt) ) {
                    $output .= "
                        <{$captiontag} class='wp-caption-text gallery-caption' id='$selector-$id'>
                        " . wptexturize($attachment->post_excerpt) . "
                        </{$captiontag}>";
		}
		$output .= "</{$itemtag}>";
		if ( ! $html5 && $columns > 0 && ++$i % $columns == 0 ) {
			$output .= '<br style="clear: both" />';
		}
	}
	if ( ! $html5 && $columns > 0 && $i % $columns !== 0 ) {
		$output .= "
			<br style='clear: both' />";
	}
	$output .= "
		</div>\n";
 
	return $output;
}

2. CSS правки для изображений

Теперь делаем сами изображения адаптивными: задаем 100% ширины и высоту авто.

1
2
3
4
5
6
7
.gallery {
    width: 100%;
}
.gallery .gallery-item .gallery-icon img {
    width: 100%!important;
    height: auto!important;
}
23 мая
Теги: ,

Фикс, позволяет изменить стандартный функционал кнопки «Добавить медиафайл», а class=’img-responsive’ делает их адаптивными под bootstrap.

1
2
3
4
5
6
7
8
9
//Адаптивные изображения
function adaptive_img_fix( $html, $id, $caption, $title, $align, $url, $size, $alt ) {
 
    $image_thumb = wp_get_attachment_image_src( $id, $size);
    $image_alt = '';
    $out_img .= '<img src="'. $image_thumb[0] .'" alt="'.$image_alt.'" class="img-responsive"/>';
    return $out_img; 
}
add_filter('image_send_to_editor', 'adaptive_img_fix', 1, 8);
Теги: ,

Кастомизация админки вордпресса, при разработке сайта под клиента, играет огромную роль. Довольно часто контактную информацию компании клиент может менять на лету, и чтобы не править каждый раз footer и header, нужно дать возможность клиенту менять эту информацию самому. На помощь нам приходит замечательный плагин CMB2. Кстати, в предыдущих статьях, мы научились создавать различные поля, типа: текст, переключатели, файл и чекбокс.

Скачать плагин CMB2

Содержание статьи:

  • Создание страницы с контактными данными.
  • Функция получения данных со страницы с контактами.
  • Показ контактных данных.

Создание страницы с контактными данными.

Следующий код создаст в админке страницу «Контакты компании» с двумя контактными телефонами, email и скриптом Яндекс карт. Используем всего два типа полей: text_medium и textarea_code. Код нужно поместить в файл function.php активной темы.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//Страница контактов компании
function company_page_options() {
    $company_options = new_cmb2_box( array(
        'id'           => 'company-options',
        'title'        => esc_html__( 'Контакты компании' ),
        'object_types' => array( 'options-page' ),
        'option_key'      => 'company-options', // Ключ опций и слаг.
        'icon_url'        => 'dashicons-image-filter', //Иконка в меню
    ) );
    $company_options->add_field( array(
        'name' => esc_html__( 'Контактный телефон 1:' ), 
        'desc' => esc_html__( 'Например: +79998885522' ), 
        'id'   => 'tell1', 
        'type' => 'text_medium', 
    ) );
    $company_options->add_field( array(
        'name' => esc_html__( 'Контактный телефон 2:' ), 
        'desc' => esc_html__( 'Например: +79998885522' ), 
        'id'   => 'tell2', 
        'type' => 'text_medium', 
    ) );
    $company_options->add_field( array(
        'name' => esc_html__( 'Email:' ), 
        'desc' => esc_html__( 'Например: email@email.ru' ), 
        'id'   => 'email', 
        'type' => 'text_medium', 
    ) );
    $company_options->add_field( array(
        'name' => esc_html__( 'Скрипт Яндекс карты:' ), 
        'desc' => esc_html__( 'Генерируется по ссылке: https://yandex.ru/map-constructor/' ), 
        'id'   => 'ymap', 
        'type' => 'textarea_code', 
    ) );
}
add_action( 'cmb2_admin_init', 'company_page_options' );

Результат:

CMB2 - страницы с контактами компании в админке

Функция получения данных со страницы с контактами.

Следующая функция позволит нам получать сохраненные данные со страницы.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
add_action( 'cmb2_admin_init', 'company_page_options' );
function cp_get_option( $key = '', $default = false ) {
    if ( function_exists( 'cmb2_get_option' ) ) {
        return cmb2_get_option( 'company-options', $key, $default );
    }
    $opts = get_option( 'company-options', $default );
    $val = $default;
    if ( 'all' == $key ) {
        $val = $opts;
    } elseif ( is_array( $opts ) && array_key_exists( $key, $opts ) && false !== $opts[ $key ] ) {
        $val = $opts[ $key ];
    }
    return $val;
}

Показ контактных данных.

Теперь нам осталось получить и вывести данные в нужном месте сайта, например в header.php.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div class="contacts">
    <?php 
        $tell = cp_get_option( 'tell1' );
        $tell2 = cp_get_option( 'tell2' );
        $email = cp_get_option( 'email' );
        $ymap = cp_get_option( 'ymap' );
    ?>
    <div>
        <b>Телефон 1:</b><br>
        <?php echo $tell; ?>
    </div>
    <div>
        <b>Телефон 2:</b><br>
        <?php echo $tell2; ?>
    </div>
    <div>
        <b>Email:</b><br>
        <?php echo $email; ?>
    </div>
    <div>
        <b>Яндекс карта:</b><br>
        <?php echo $ymap; ?>
    </div>
</div>

Результат:

CMB2 - страницы с контактами компании в админке

Итоги

Таким образом мы можем создавать любые страницы в админке, управляя как контентом, так и самим отображением сайта.

05 апреля
Теги: , ,

В статье рассмотрим 5 необходимых функций WordPress, которые, по моему мнению, наиболее часто участвуют в разработке.

Содержание статьи:

  • Подключение скриптов (js) и стилей (css) в functions.php.
  • Регистрация и вывод кастомного меню.
  • Регистрация и вывод собственной панели виджетов.
  • Создание пользовательского типа записи.
  • Регистрация шорткодов.
  • Бонус: mu-plugins (обязательные плагины).

1. Подключение скриптов (js) и стилей (css) в functions.php.

При разработке сайта, очень часто бывает необходимо подключить сторонний скрипт, либо файл стилей. Можно конечно пойти по старинке — прикручивать все это дело прямо в шапке (header), но с этим потом возникнут трудности при переносе на хостинг, да и в целом не красиво. Давайте узнаем как это делается на примере подключения bootstrap версии 3.3.7. Все действия делаем в файле functions.php активной темы. Сами файлы bootstrap’a будут располагаться в папке /активная_тема/bootstrap/.

1
2
3
4
5
function bootstrap_scripts() {
    wp_enqueue_style( 'bootstrap-css', get_template_directory_uri() . '/bootstrap/css/bootstrap.css', array(), '3.3.7' );
    wp_enqueue_script( 'bootstrap-js', get_template_directory_uri() . '/bootstrap/js/bootstrap.min.js', array(), '3.3.7' );
}
add_action( 'wp_enqueue_scripts', 'bootstrap_scripts' );

Таким образом можно подключать любые файлы скриптов и стилей, всяческие слайдеры и другие примочки.

2. Регистрация и вывод кастомного меню.

Регистрация кастомных меню возможна функцией register_nav_menus(). Можно создавать сразу несколько дополнительных меню и выводить их на сайте на свое усмотрение. Следующий код следует разместить в файле functions.php активной темы.

1
2
3
4
5
6
add_action('after_setup_theme', function(){
    register_nav_menus( array(
        'main_menu' => 'Основное меню',
        'additional_menu' => 'Дополнительное меню'
    ) );
});

Таким образом, мы создали два новых меню: основное и дополнительное.

WordPress - register_nav_menus

Теперь нужно настроить их в админке и вывести на сайте. Вывод осуществляется в любом месте сайта функцией wp_nav_menu().

1
2
3
4
5
6
7
8
<?php 
    wp_nav_menu ( array (
        'theme_location'  => 'main_menu', //Идентификатор меню, мы его регистрировали ранее.
        'container' => '', //Оберточный контейнер для нашего меню. Пусто, либо false выведет меню без контейнера.
        'depth' => '2', //Сколько показывать уровней вложенности. 0 - показывать все.
        'menu_id' => 'primary-menu', //Значение id у списка меню.
    )); 
?>

3. Регистрация и вывод собственной панели виджетов.

register_sidebar() — регистрирует собственную панель виджетов.

1
2
3
4
5
6
7
8
9
10
11
12
13
add_action( 'widgets_init', 'my_widgets_panel' );
function my_widgets_panel(){
    register_sidebar( array(
        'name'          => 'Моя панель виджетов', //Название панели виджетов. 
        'id'            => "my_widgets_panel", //Идентификатор.
        'description'   => '', //Описание.
        'class'         => '', //CSS класс панели виджетов.
        'before_widget' => '', //Текст или html код, который будет показываться до панели.
        'after_widget'  => '', //Текст или html код, который будет показываться после панели.
        'before_title'  => '', //Текст перед заголовком панели.
        'after_title'   => '', //Текст после заголовка панели.
    ) );
}

Результат:

WordPress - регистрация и вывод собственной панели виджетов

Выводим в любом месте сайта с помощью следующего кода:

1
2
3
4
5
<?php
    if ( function_exists('dynamic_sidebar') ) {
        dynamic_sidebar('my_widgets_panel');
    } 
?>

4. Создание пользовательского типа записи.

Создание пользовательских типов записей подразумевает расширение функционала вордпресса. Следующий код создаст произвольные типы записей «фильмы».

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// Пользовательский тип записи "фильмы"
add_action( 'init', 'create_post_type' );
function create_post_type() {
    register_post_type( 'films',
         array(
                'labels' => array(
                    'name' => _x('Фильмы', 'post type general name'), //Основное название типа записи.
                    'singular_name' => _x('Фильм', 'post type singular name'), //Название для одиночного элемента.
                    'add_new' => _x('Новый фильм', 'Event'), //Имя для кнопки создания нового элемента.
                    'add_new_item' => __('фильм'), //Имя в верхней админ панели.
                    'edit_item' => __('Редактировать фильм'), //Имя для редактирования элемента.
                    'new_item' => __('Новый фильм'), //Имя для создания нового элемента.
                    'view_item' => __('Посмотреть фильм'), //Имя для кнопки просмотра элемента.
                    'search_items' => __('Искать фильм'), //Имя для поиска по элементам.
                    'not_found' =>  __('Ничего не найдено'), //Текст для пустого результата поиска.
                    'not_found_in_trash' => __('Корзина пуста'), //Текст для пустой корзины.
                ),
                'menu_position'       => 5, //Позиция в меню.
                'menu_icon'           => 'dashicons-video-alt', //Иконка. Полный набор иконок доступен по ссылке: https://developer.wordpress.org/resource/dashicons/
                'public' => true,
                'capability_type' => 'post',
                'supports' => array( //Включаем поддержку стандартного функционала: изображения записи, цитату и тп. Все значения: title','editor','author','thumbnail','excerpt','trackbacks','custom-fields','comments','revisions','page-attributes','post-formats'.
                    'title',
                    'thumbnail',
                    'editor',
                    'excerpt',
                ),
                'has_archive'   => false,
            ));
}

Результат:

WordPress - пользовательский тип записи

Вывод таких постов возможно с помощью WP_Query, заменив post на films.

5. Регистрация шорткодов.

Шорткоды в вордпрессе позволяют выводить функции прямо в тексте статьи, массово используются плагинами (например: contact form 7, meta slider и др.) и позволяют выводить функции php или js прямо в тексте статьи. Для примера, зарегистрируем шорткод показа рекламных объявлений Adsense. Как всегда правим файл functions.php активной темы.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Регистрация шорткода Adsense
function add_adsense_shortcode() {
    return '
        <div id="google-adsense">
        <ins class="adsbygoogle"
             style="display:block; text-align:center;"
             data-ad-layout="in-article"
             data-ad-format="fluid"
             data-ad-client="ca-pub-3865389427490622"
             data-ad-slot="9907310963"></ins>
        <script>
             setTimeout(function(){(adsbygoogle = window.adsbygoogle || []).push({})}, 1000);
        </script>
        </div>
    ';
}
add_shortcode( 'adsense-article', 'add_adsense_shortcode' );

Использование:

1
[adsense-article]

Такой шорткод позволит выводить рекламу adsense в любом месте статьи.

Бонус: mu-plugins (обязательные плагины).

Мало кто знает о существовании такой полезной штуки как mu-plugins, по русски — обязательные плагины. Они работают так же как и обычные плагины за рядом отличий: обязательные плагины не требуют активации (по умолчанию активны всегда), их нельзя отключить, лежат в папке /wp-content/mu-plugins, должны состоять всего из одного файла и никогда не будут обновляться. Их использование подразумевает что сайт без их функционала работать не будет. Очень полезная штука при работе с заказчиками, которые везде суют свой нос.

WordPress - mu-plugins (обязательные плагины)

04 апреля
Теги: ,

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

Основные понятия статьи:

  • Цикл WordPress — это цикл, который перебирает массив данных содержащих в себе информацию о каждом посте.
  • WP_Query — класс, позволяющий получать посты из базы данных с необходимыми параметрами.
  • Темплейт — шаблон вывода постов.
  • Фильтрация — изменение вывода постов с заданными параметрами. Можно фильтровать посты по наличию или значению произвольных полей, числа даты, и др.
  • Метаполе — произвольное поле записи.

Пример цикла на основе WP_Query:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php 
    $related_posts = new WP_Query( array(
        'post_type' => 'post', //Тип записи
    ) );
    if ( $related_posts->have_posts() ) {
        while ( $related_posts->have_posts() ) {
            $related_posts->the_post();
                get_template_part( 'templates/related-posts', get_post_format() ); //Темплейт вывода постов. Лежит в папке templates активной темы.
            }
    } else {
        echo '<p>Записей не найдено.</p>'; //На случай, если записей нет.
    }
    wp_reset_postdata(); //Сбрасываем цикл.
?>

Таким способом мы можем получить все записи за все время, и, если их будет очень много, скорее всего уроним сайт. Поэтому мы должны ограничить количество постов для вывода, либо отфильтровать их по заданным параметрам. А для вывода постов, будем использовать темплейт related-posts, который будет лежать в папке templates активной темы.

Параметры фильтрации постов:

  • order — направление сортировки по параметру orderby. Бывает: ASC — по порядку, DESC — в обратном порядке.
  • orderby — сортировка по: none — без сортировки, ID — по ID (номеру поста), author — по id автора (номера автора), title — по загловку, name — по названию поста, date — дате публикации, modified — дате изменения, type — по типу контента, rand — случайный порядок, comment_count — количеству комментариев, meta_value — значению произвольного поля, meta_value_num — значению числового произвольного поля.
  • posts_per_page — количество записей на страницу.
  • meta_query — массив параметров метаполей постов.

Теперь изменим наш цикл, и попробуем вывести 8 последних постов, отсортированных по дате.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php 
    $related_posts = new WP_Query( array(
        'post_type'      => 'post', //Тип записи.
        'posts_per_page' => 8, //Выведем первые 8 записей. 
        'orderby'        => date, //Сортировка по дате.
    ) );
    if ( $related_posts->have_posts() ) {
        while ( $related_posts->have_posts() ) {
            $related_posts->the_post();
                get_template_part( 'templates/related-posts', get_post_format() ); //Темплейт вывода постов. Лежит в папке templates активной темы.
            }
    } else {
        echo '<p>Записей не найдено.</p>'; //На случай, если записей нет.
    }
    wp_reset_postdata(); //Сбрасываем цикл.
?>

Усложним задачу: будем фильтровать посты по наличию поля meta_featured, с выводом 8 постов на страницу. Например: с помощью CMB2 можно создать метаполе типа чекбокс, и выводить на главную только заданные посты.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php 
    $related_posts = new WP_Query( array(
        'post_type'      => 'post', //Тип записи.
        'posts_per_page' => 8, //Выведем первые 8 записей. 
        'meta_query' => array( //Выберем посты, в которых есть произвольное поле meta_featured.
            array(
                'key' => 'meta_featured',
                'compare' => 'IN'
            )
        )
    ) );
    if ( $related_posts->have_posts() ) {
        while ( $related_posts->have_posts() ) {
            $related_posts->the_post();
                get_template_part( 'templates/related-posts', get_post_format() ); //Темплейт вывода постов. Лежит в папке templates активной темы.
            }
    } else {
        echo '<p>Записей не найдено.</p>'; //На случай, если записей нет.
    }
    wp_reset_postdata(); //Сбрасываем цикл.
?>

Более сложный пример: будем фильтровать посты по числовому метаполю meta_votes, с выводом 8 постов на страницу.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php 
    $related_posts = new WP_Query( array(
        'post_type'      => 'post', //Тип записи.
        'posts_per_page' => 8, //Выведем первые 8 записей. 
        'order'          => 'DESC', //В сторону уменьшения.
        'orderby'        => 'meta_value_num', //Числовое метаполе.
        'meta_key'       => 'meta_votes' //Имя метаполя.
    ) );
    if ( $related_posts->have_posts() ) {
        while ( $related_posts->have_posts() ) {
            $related_posts->the_post();
                get_template_part( 'templates/related-posts', get_post_format() ); //Темплейт вывода постов. Лежит в папке templates активной темы.
            }
    } else {
        echo '<p>Записей не найдено.</p>'; //На случай, если записей нет.
    }
    wp_reset_postdata(); //Сбрасываем цикл.
?>

Итоги

Понимание и принципы работы фильтрации постов, дает неограниченный простор к кастомизации вордпресса.

03 апреля
Теги: , ,

Как мы узнали ранее, замечательный плагин CMB2 позволяет создавать произвольные поля различных типов.

Скачать плагин CMB2

Основные понятия статьи:

  • Типы контента — WordPress использует несколько типов контента: post — записи, page — страницы, custom post types — пользовательские типы записей. И несколько других, в рамках этой статьи невостребованных.
  • Произвольные поля — дополнительные данные записей или станиц, можно указывать любые типы, от чисел и текста, до файлов и галерей изображений. В статье будем их называть метаполями. Просто потому что мне так захотелось.
  • CMB2 — плагин, для создания любых метаполей.
  • Темплейт single.php — шаблон вывода записей (post).

Давайте подробнее разберем его работу на базовых примерах, создадим дополнительные поля для записей (post).

Инициализируем наши поля в файле functions.php активной темы:

1
2
3
4
5
6
7
8
9
10
11
12
add_action( 'cmb2_admin_init', 'cmb2_metaboxes' );
function cmb2_metaboxes() {
    $post_prefix = 'postmeta_'; //Префикс, на случай если мы будет использовать разные метаполя для разных типов постов.
    $cmb_post = new_cmb2_box( array(
        'id'            => 'metaboxes',
        'title'         => __( 'Дополнительные поля' ),
        'object_types'  => array( 'post', ), //Выводим метаполя для записей (post). Или page для страниц.
        'context'       => 'normal',
        'priority'      => 'high',
        'show_names'    => true, // Показывать название полей слева.
    ) );
}

Теперь прикрутим новое метаполе типа текст.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
add_action( 'cmb2_admin_init', 'cmb2_metaboxes' );
function cmb2_metaboxes() {
    $post_prefix = 'postmeta_'; //Префикс, на случай если мы будет использовать разные метаполя для разных типов постов.
    $cmb_post = new_cmb2_box( array(
        'id'            => 'metaboxes',
        'title'         => __( 'Дополнительные поля' ),
        'object_types'  => array( 'post', ), //Выводим метаполя для записей (post). Или page для страниц.
        'context'       => 'normal',
        'priority'      => 'high',
        'show_names'    => true, // Показывать название полей слева.
    ) );
    //Поле типа текст.
    $cmb_post->add_field( array(
        'name' => esc_html__( 'Год выхода:' ), //Название поля в админке.
        'desc' => esc_html__( 'Например: 1995.' ), //Описание поля в админке.
        'id'   => $post_prefix . 'year', //Используем наш префикс и добавляем уникальное название year.
        'type' => 'text_small', //Поле типа текст.
    ) );
}

Результат в админке:

CMB2 - Поле типа текст.

Получение этого поля возможно в теплейте single.php, или в прямо в цикле довольно простым кодом:

1
2
$year = get_post_meta($post->ID, 'postmeta_year', true);
echo $year;

Усложним задачу, добавим еще одно поле типа переключатели (radio button).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
add_action( 'cmb2_admin_init', 'cmb2_metaboxes' );
function cmb2_metaboxes() {
    $post_prefix = 'postmeta_'; //Префикс, на случай если мы будет использовать разные метаполя для разных типов постов.
    $cmb_post = new_cmb2_box( array(
        'id'            => 'metaboxes',
        'title'         => __( 'Дополнительные поля' ),
        'object_types'  => array( 'post', ), //Выводим метаполя для записей (post). Или page для страниц.
        'context'       => 'normal',
        'priority'      => 'high',
        'show_names'    => true, // Показывать название полей слева.
    ) );
    //Поле типа текст.
    $cmb_post->add_field( array(
        'name' => esc_html__( 'Год выхода:' ), //Название поля в админке.
        'desc' => esc_html__( 'Например: 1995.' ), //Описание поля в админке.
        'id'   => $post_prefix . 'year', //Используем наш префикс и добавляем уникальное название year.
        'type' => 'text_small', //Поле типа текст.
    ) );
    //Поле типа переключатели.
    $cmb_post->add_field( array(
        'name'             => esc_html__( 'Выберите жанр:' ), //Название поля в админке.
        'desc'             => esc_html__( 'Можно выбрать только один жанр.' ), //Описание поля в админке.
        'id'               => $post_prefix . 'genre',
        'type'             => 'radio_inline', //Поле типа переключатели. Может быть двух типов: radio и radio_inline.
        'show_option_none' => 'Не указано', //Показывать пустое значение. 
        'options'          => array(
            'Драма' => esc_html__( 'Драма' ),
            'Триллер' => esc_html__( 'Триллер' ),
            'Ужасы' => esc_html__( 'Ужасы' ),
        ),
    ) );
}

Может быть двух типов: radio (вертикальный вывод) и radio_inline (вывод в строку). Получаем их так же как и в случае с полем типа текст:

1
2
$genre = get_post_meta($post->ID, 'postmeta_genre', true);
echo $genre;

Результат в админке:

CMB2 - Поле типа переключатели.

Сделаем еще одно поле, добавим возможность прикреплять файл (file).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
add_action( 'cmb2_admin_init', 'cmb2_metaboxes' );
function cmb2_metaboxes() {
    $post_prefix = 'postmeta_'; //Префикс, на случай если мы будет использовать разные метаполя для разных типов постов.
    $cmb_post = new_cmb2_box( array(
        'id'            => 'metaboxes',
        'title'         => __( 'Дополнительные поля' ),
        'object_types'  => array( 'post', ), //Выводим метаполя для записей (post). Или page для страниц.
        'context'       => 'normal',
        'priority'      => 'high',
        'show_names'    => true, // Показывать название полей слева.
    ) );
    //Поле типа текст.
    $cmb_post->add_field( array(
        'name' => esc_html__( 'Год выхода:' ), //Название поля в админке.
        'desc' => esc_html__( 'Например: 1995.' ), //Описание поля в админке.
        'id'   => $post_prefix . 'year', //Используем наш префикс и добавляем уникальное название year.
        'type' => 'text_small', //Поле типа текст.
    ) );
    //Поле типа переключатели.
    $cmb_post->add_field( array(
        'name'             => esc_html__( 'Выберите жанр:' ), //Название поля в админке.
        'desc'             => esc_html__( 'Можно выбрать только один жанр.' ), //Описание поля в админке.
        'id'               => $post_prefix . 'genre',
        'type'             => 'radio_inline', //Поле типа переключатели. Может быть двух типов: radio и radio_inline.
        'show_option_none' => 'Не указано', //Показывать пустое значение. 
        'options'          => array(
            'Драма' => esc_html__( 'Драма' ),
            'Триллер' => esc_html__( 'Триллер' ),
            'Ужасы' => esc_html__( 'Ужасы' ),
        ),
    ) );
    //Поле типа файл.
    $cmb_post->add_field( array(
        'name'    => 'Файл:', //Название поля в админке.
        'desc'    => 'Загрузите новый Файл.', //Описание поля в админке.
        'id'      => $post_prefix . 'file',
        'type'    => 'file', //Поле типа файл.
        'options' => array(
            'url' => true, //Показывает url файла, можеть быть true - показывать и false - скрыть.
        ),
        'text'    => array(
            'add_upload_file_text' => 'Добавить файл' //Текст кнопки.
        ),
	'query_args' => array( //Мы можем сами выбирать форматы файла, наример: 'type' => 'application/pdf', разрешит добавлять только файлы в формате pdf.
            'type' => array(
                'image/gif',
                'image/jpeg',
                'image/png',
            ),
	),
        'preview_size' => 'large', //Размер превью. Возможно несколько значений: small, medium, large. Либо свой размер: array( 100, 100 ).
    ) );
}

Результат в админке:

CMB2 - Поле типа файл.

Сделаем возможность скачать этот файл в темплейте single.php:

1
2
$file = get_post_meta($post->ID, 'postmeta_file', true);
echo '<a href="'. $file .'">Скачать файл</a>';

Сделаем дополнительное поле типа чекбокс. Например, можно использовать его в цикле вордпресса для вывода featured постов на главной странице.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
add_action( 'cmb2_admin_init', 'cmb2_metaboxes' );
function cmb2_metaboxes() {
    $post_prefix = 'postmeta_'; //Префикс, на случай если мы будет использовать разные метаполя для разных типов постов.
    $cmb_post = new_cmb2_box( array(
        'id'            => 'metaboxes',
        'title'         => __( 'Дополнительные поля' ),
        'object_types'  => array( 'post', ), //Выводим метаполя для записей (post). Или page для страниц.
        'context'       => 'normal',
        'priority'      => 'high',
        'show_names'    => true, // Показывать название полей слева.
    ) );
    //Поле типа чекбокс.
    $cmb_post->add_field( array(
        'name' => esc_html__( 'Показывать на главной' ), //Название поля в админке.
        'desc' => esc_html__( '' ), //Описание поля в админке.
        'id'   => $post_prefix . 'featured', //Используем наш префикс и добавляем уникальное название featured.
        'type' => 'checkbox', //Поле типа чекбокс.
    ) );
    //Поле типа текст.
    $cmb_post->add_field( array(
        'name' => esc_html__( 'Год выхода:' ), //Название поля в админке.
        'desc' => esc_html__( 'Например: 1995.' ), //Описание поля в админке.
        'id'   => $post_prefix . 'year', //Используем наш префикс и добавляем уникальное название year.
        'type' => 'text_small', //Поле типа текст.
    ) );
    //Поле типа переключатели.
    $cmb_post->add_field( array(
        'name'             => esc_html__( 'Выберите жанр:' ), //Название поля в админке.
        'desc'             => esc_html__( 'Можно выбрать только один жанр.' ), //Описание поля в админке.
        'id'               => $post_prefix . 'genre',
        'type'             => 'radio_inline', //Поле типа переключатели. Может быть двух типов: radio и radio_inline.
        'show_option_none' => 'Не указано', //Показывать пустое значение. 
        'options'          => array(
            'Драма' => esc_html__( 'Драма' ),
            'Триллер' => esc_html__( 'Триллер' ),
            'Ужасы' => esc_html__( 'Ужасы' ),
        ),
    ) );
    //Поле типа файл.
    $cmb_post->add_field( array(
        'name'    => 'Файл:', //Название поля в админке.
        'desc'    => 'Загрузите новый Файл.', //Описание поля в админке.
        'id'      => $post_prefix . 'file',
        'type'    => 'file', //Поле типа файл.
        'options' => array(
            'url' => true, //Показывает url файла, можеть быть true - показывать и false - скрыть.
        ),
        'text'    => array(
            'add_upload_file_text' => 'Добавить файл' //Текст кнопки.
        ),
	'query_args' => array(//Мы можем сами выбирать форматы файла, наример: 'type' => 'application/pdf', разрешит добавлять только файлы в формате pdf.
            'type' => array(
                'image/gif',
                'image/jpeg',
                'image/png',
            ),
	),
        'preview_size' => 'large', //Размер превью. Возможно несколько значений: small, medium, large. Либо свой размер: array( 100, 100 ).
    ) );
}

Результат в админке:

CMB2 - Поле типа чекбокс.

Итоги

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

Часто, когда разрабатываешь сайт под клиента, необходимо кастомизировать левое меню в админке WordPress. Следующий код позволит изменить название «Записи» в «Новости». Код нужно вставить в functions.php активной темы.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//Переименовываем записи
function edit_admin_menus() {
    global $menu;
    global $submenu;
    $menu[5][0] = 'Новости';
    $submenu['edit.php'][5][0] = 'Все новости';
    $submenu['edit.php'][10][0] = 'Добавить новость';
}
add_action( 'admin_menu', 'edit_admin_menus' );
function change_post_object_label() {
    global $wp_post_types;
    $labels = &$wp_post_types['post']->labels;
    $labels->name = 'Новости';
    $labels->singular_name = 'Новости';
    $labels->add_new = 'Добавить новость';
    $labels->add_new_item = 'Добавить новость';
    $labels->edit_item = 'Изменить';
    $labels->new_item = 'Новость';
    $labels->view_item = 'Посмотреть новость';
    $labels->search_items = 'Искать новость';
    $labels->not_found = 'Новостей не найдено';
    $labels->not_found_in_trash = 'Корзина пуста';
}
add_action( 'admin_menu', 'change_post_object_label' );

Результат:

WordPress - кастомизация админки. Переименовываем элемент меню записи.

09 февраля
Теги: ,

Плагин электронной коммерции Woocommerce, версии 3 и выше, изменил работу и вывод рекомендуемых товаров. Теперь рекомендованные товары можно получить так:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
    $args = array(
        'post_type' => 'product',
        'posts_per_page' => 3,
        'tax_query' => array(
                array(
                    'taxonomy' => 'product_visibility',
                    'field'    => 'name',
                    'terms'    => 'featured',
                ),
            ),
        );
    $featured_products = new WP_Query( $args );
    if ( $featured_products->have_posts() ) {
        while ( $featured_products->have_posts() ) : $featured_products->the_post();
            wc_get_template_part( 'content', 'product' ); // Можно заменить на свой шаблон вывода, например: get_template_part( 'template-parts/featured-products', get_post_format() ); 
        endwhile;
    } else {
        echo 'Рекомендуемых товаров нет.';
    }
    wp_reset_postdata();
?>
28 декабря

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

Скачать плагин CMB2

Сделаем выбор рубрики пользователя в профиле:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function cmb2_get_term_options( $field ) {
    $args = $field->args( 'get_terms_args' );
    $args = is_array( $args ) ? $args : array();
 
    $args = wp_parse_args( $args, array( 'taxonomy' => 'category' ) );
 
    $taxonomy = $args['taxonomy'];
 
    $terms = (array) cmb2_utils()->wp_at_least( '4.5.0' )
        ? get_terms( $args )
        : get_terms( $taxonomy, $args );
    $term_options = array();
    if ( ! empty( $terms ) ) {
        foreach ( $terms as $term ) {
            $term_options[ $term->term_id ] = $term->name;
        }
    }
    return $term_options;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function cmb2_sample_metaboxes() {
        //USERMETA
	$prefix = 'usermeta_';
	$cmb = new_cmb2_box( array(
            'id'            => 'first_box',
            'title'         => __( 'Мета поля' ),
            'object_types'  => array( 'user', ),
            'context'       => 'normal',
            'priority'      => 'high',
            'show_names'    => true,
	) );
        $cmb->add_field( array(
            'name'       => 'Сайт',
            'desc'           => 'Выберите рубрику пользователя.',
            'id'             => $prefix . 'tax',
            'type'           => 'select',
            'options_cb'     => 'cmb2_get_term_options',
            'get_terms_args' => array(
                'taxonomy'   => 'category',
                'hide_empty' => false,
            ),
        ) );
}

Получаем номер рубрики:

1
$user_tax = get_user_meta($user_ID, 'usermeta_tax', true);
15 декабря

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

1
2
3
4
5
6
7
8
9
10
11
12
$summ_args = array(
    'post_type' => 'post'
);
$query = new WP_Query( $summ_args );
$posts = $query->posts;
 
foreach ($posts as $post) {
    $summ += get_post_meta($post->ID, 'meta_key', true);
 
}
echo $summ;
wp_reset_postdata();
Теги: , ,
12