Commit b5b9b0c4 authored by Bruno Antunes Magrini's avatar Bruno Antunes Magrini

merge see-also

parents 7b81b5bd 4b02c6fb
# Page Builder Components
\ No newline at end of file
# Guaraci WordPress Plugin
Plugin Base para os projetos WordPress
## Componentes Page Buider
Componentes do Site Origin Page Builder
### Custom Fields
- **draggable-posts** -
- **taxonomy-select** -
### Widgets
- **features-videos** - componente que exibe os vídeos mais recentes de um canal, botão de se inscrever no canal e um botão de ver mais
- **feed-rss** - exibe uma lista de posts de um feed RSS
- **posts-list** - exibe uma lista de posts
## Outros
- **guaraci\related_posts** - classe com funcionalidades para posts relacionados
- **guaraci\authors** - classe com funcionalidades para ligar com taxonomia de autores
- **guaraci\images** - classe com funcionalidades para imagens
- **guaraci\get_terms_order_by_posts_publish_date** - função que retorna uma lista de termos de uma determinada taxonomia ordenados pela data de utilização
- **guaraci\template_part** - função que substitui o get_template_part nativo do WordPress resolvendo o problema exposto em https://mekshq.com/passing-variables-via-get_template_part-wordpress/
\ No newline at end of file
<?php
/*
Plugin Name: Guaraci
Description:
Version: 1.0.0
Author: hacklab/
Author URI: https://hacklab.com.br/
License: GPL2
*/
require 'library/functions.php';
require 'library/images.php';
require 'library/related-posts.php';
require 'library/authors.php';
require 'pagebuilder-components/index.php';
\ No newline at end of file
<?php
namespace guaraci;
class authors {
static function get_avatar ($author) {
$avatar = get_term_meta($author->term_id, 'avatar', true);
if (empty($avatar)) {
return null;
}
return $avatar['guid'];
}
static function get ($author_taxonomy, $single = false, $post = null) {
if(is_int($post)){
$post_id = $post;
} else if(is_object($post)){
$post_id = $post->ID;
} else {
$post_id = get_the_ID();
}
$authors = wp_get_post_terms($post_id, $author_taxonomy);
if($authors instanceof \WP_Error){
return $single ? null : [];
}
if ($single) {
return $authors[0];
}
return $authors;
}
static function display ($author_taxonomy) {
$authors = self::get($author_taxonomy, false);
if (!empty($authors)) {
echo implode(', ', array_map(function ($author) {
$url = get_term_link($author);
return "<a href='$url'>$author->name</a>";
}, $authors));
}
}
}
\ No newline at end of file
<?php
namespace guaraci;
/**
* Função para resolver o problema exposto em https://mekshq.com/passing-variables-via-get_template_part-wordpress/
* @param string $template_name nome do template localizado dentro pasta template-parts do tema
* @param array $params
*/
function template_part($template_name, $params = []){
global $wp_query;
$template_filename = locate_template("template-parts/{$template_name}.php");
if(empty($template_filename)){
return;
}
extract($params);
include $template_filename;;
}
/**
* Pagination
*/
function pagination_links() {
global $wp_query;
if ( $wp_query->max_num_pages > 1 ) {
$big = 999999999; // need an unlikely integer
echo paginate_links( array(
'base' => str_replace( $big , '%#%' , esc_url( get_pagenum_link( $big ) ) ) ,
'format' => '?paged=%#%' ,
'current' => max( 1 , get_query_var( 'paged' ) ) ,
'total' => $wp_query->max_num_pages ,
'prev_text' => __( '<' , 'green' ) ,
'next_text' => __( '>' , 'green' )
) );
}
}
/**
* Retorna uma lista de termos ordenados pela data de utilização.
*
* @param string $taxonomy
* @param integer $limit
* @param integer $paged
* @return \WP_Term[]
*/
function get_terms_order_by_posts_publish_date(string $taxonomy, int $limit = 10, int $paged = 1){
global $wpdb;
if(false) $wpdb = new \wpdb(1,2,3,4);
$offset = $limit * ($paged - 1);
$sql = "
SELECT
t.term_id,
t.name,
t.slug,
tx.term_taxonomy_id,
tx.taxonomy,
tx.description,
tx.parent,
tx.count
FROM
$wpdb->terms t
LEFT JOIN $wpdb->term_taxonomy tx ON tx.term_id = t.term_id
LEFT JOIN $wpdb->term_relationships tr ON tr.term_taxonomy_id = tx.term_taxonomy_id
LEFT JOIN $wpdb->posts p ON p.ID = tr.object_id
WHERE
tx.taxonomy = '$taxonomy' AND
p.post_type = 'coluna' AND
tr.object_id IN (
SELECT
MAX(object_id)
FROM
$wpdb->term_relationships
WHERE
term_taxonomy_id = tr.term_taxonomy_id
)
GROUP BY tx.term_taxonomy_id
ORDER BY p.post_date DESC
LIMIT $limit
OFFSET $offset
";
$results = $wpdb->get_results($sql);
$terms = array_map(function($term){ return new \WP_Term($term); }, $results);
return $terms;
}
\ No newline at end of file
<?php
namespace guaraci;
class images {
static function url($size, $class = '', $image_id = null) {
if (is_null($image_id)) {
$image_id = get_post_thumbnail_id();
}
$url = get_stylesheet_directory_uri() . '/assets/images/img_default.png';
$thumb = wp_get_attachment_image_src($image_id, $size, false);
if ($thumb) {
$url = $thumb[0];
}
return $url;
}
static function size($url = null){
$attachment_url = get_attached_file(\attachment_url_to_postid($url));
$bytes = filesize($attachment_url);
$s = array('b', 'Kb', 'Mb', 'Gb');
$e = floor(log($bytes)/log(1024));
return sprintf('%.2f '.$s[$e], ($bytes/pow(1024, floor($e))));
}
static function tag($size, $class = '', $image_id = null, $img_props = []) {
// @TODO: gerar tag alt
$output = '';
if ($url = self::url($size, $class, $image_id)) {
$props = "";
foreach ($img_props as $key => $val) {
$val = htmlentities($val);
$props .= " {$key}=\"{$val}\"";
}
$output = "<img src='{$url}' class='{$class}' {$props}/>";
}
return $output;
}
}
\ No newline at end of file
<?php
namespace guaraci;
class related_posts {
static function init() {
add_action( 'admin_init', 'guaraci\\related_posts::settings_api_init' );
}
static function settings_api_init() {
add_settings_field(
'related_posts__use',
__('Posts Relacionados', 'guaraci'),
'guaraci\\related_posts::settings',
'reading',
);
register_setting( 'reading', 'related_posts__use' );
register_setting( 'reading', 'related_posts__tags_weight' );
register_setting( 'reading', 'related_posts__categories_weight' );
}
static function settings() {
?>
<p>
<label>
<input name="related_posts__use" id="related_posts__use" type="checkbox" value="1" class="code" <?= checked( 1, get_option( 'related_posts__use' ), false ) ?> /> <?php _e('Usar posts relacionados') ?>
</label>
</p>
<p>
<label>
<?php _e('Peso das tags') ?><br>
<input name="related_posts__tags_weight" id="related_posts__tags_weight" type="number" step="0.1" value="<?= get_option('related_posts__tags_weight', 2) ?>" class="code" />
</label>
</p>
<p>
<label>
<?php _e('Peso das categorias') ?><br>
<input name="related_posts__categories_weight" id="related_posts__categories_weight" type="number" step="0.1" value="<?= get_option('related_posts__categories_weight', 1.5) ?>" class="code" />
</label>
</p>
<?php
}
static function get_post_taxonomy_terms($post_id, $taxonomy){
$_terms = get_the_terms($post_id, $taxonomy) ?: [];
$_terms = array_map(function($el) {
return $el->term_taxonomy_id;
}, $_terms);
$result = implode(',', $_terms);
return $result ?: -1;
}
static function get_posts($post_id = null, $num = 6, $post_types = ['post']){
global $wpdb;
$post_types = implode("','", $post_types);
if(is_null($post_id)){
$post_id = get_the_ID();
}
$tags_multiplier = get_option('related_posts__tags_weight', 2);
$categories_multiplier = get_option('related_posts__categories_weight', 1.5);
$categories = self::get_post_taxonomy_terms($post_id, 'category');
$tags = self::get_post_taxonomy_terms($post_id, 'post_tag');
$tags_sql = "((SELECT COUNT(t1.term_taxonomy_id) * $tags_multiplier FROM $wpdb->term_relationships t1 WHERE t1.object_id = p.ID AND t1.term_taxonomy_id IN ($tags)))";
$cats_sql = "((SELECT COUNT(t2.term_taxonomy_id) * $categories_multiplier FROM $wpdb->term_relationships t2 WHERE t2.object_id = p.ID AND t2.term_taxonomy_id IN ($categories)))";
$date_sql = "
(3/ABS(datediff(
(SELECT post_date FROM $wpdb->posts WHERE ID = $post_id),
p.post_date
)))";
$sql = "
SELECT
p.ID,
(
$tags_sql +
$cats_sql +
$date_sql
) AS num
FROM $wpdb->posts p
WHERE
p.post_type IN ('$post_types') AND
p.post_status = 'publish' AND
p.ID <> $post_id
GROUP BY p.ID
ORDER BY num DESC, ID ASC
LIMIT $num";
$result = $wpdb->get_results($sql);
// echo '<pre>';
// echo $sql;
// print_r($result);
// echo '</pre>';
$ids = array_map(function($el) { return $el->ID; }, $result);
if(!$ids) {
$ids = [-1];
}
$query = new \WP_Query([
'post__in' => $ids,
'post_type' => ['post'],
'posts_per_page' => -1,
'orderby' => 'post__in'
]);
return $query;
}
}
related_posts::init();
\ No newline at end of file
<?php
/*
Plugin Name: Page Builder Components
Description:
Version: 1.0.0
Author: hacklab/
Author URI: https://hacklab.com.br/
License: GPL2
*/
add_action('after_setup_theme', function(){
if(!defined('WIDGETGROUP_MAIN')){
define('WIDGETGROUP_MAIN', 'Widgets Guaraci');
}
if(!defined('WIDGETGROUP_SIDEBAR')){
define('WIDGETGROUP_SIDEBAR', 'Widgets Guaraci - Sidebar');
}
}, 0);
add_filter('siteorigin_panels_widget_dialog_tabs', function ($tabs) {
$tabs[] = [
'title' => WIDGETGROUP_MAIN,
'filter' => [
'groups' => [ WIDGETGROUP_MAIN ]
]
];
$tabs[] = [
'title' => WIDGETGROUP_SIDEBAR,
'filter' => [
'groups' => [ WIDGETGROUP_SIDEBAR ]
]
];
return $tabs;
}, 20);
/** Add SiteOrigin Page Builder custom fields class prefixes */
add_filter('siteorigin_widgets_field_class_prefixes', function($class_prefixes) {
......@@ -16,12 +34,12 @@ add_filter('siteorigin_widgets_field_class_prefixes', function($class_prefixes)
/** Add SiteOrigin Page Builder custom fields */
add_filter('siteorigin_widgets_field_class_paths', function($class_paths) {
$class_paths[] = __DIR__ . '/pagebuilder-custom-fields/';
$class_paths[] = __DIR__ . '/custom-fields/';
return $class_paths;
});
/** Add SiteOrigin Page Builder custom widgets */
add_filter('siteorigin_widgets_widget_folders', function($folders) {
$folders[] = __DIR__ . '/pagebuilder-widgets/';
$folders[] = __DIR__ . '/widgets/';
return $folders;
});
\ No newline at end of file
......@@ -12,9 +12,13 @@ namespace widgets;
class FeaturedVideos extends \SiteOrigin_Widget {
function __construct() {
wp_enqueue_script('featured-videos', get_stylesheet_directory_uri() . '/library/pagebuilder-widgets/featured-videos/featured-videos.js', ['jquery']);
wp_enqueue_script('featured-videos', plugins_url('/featured-videos.js', __FILE__), ['jquery']);
$fields = [
'header' => [
'type' => 'text',
'label' => 'Texto do header',
],
'title' => [
'type' => 'text',
'label' => 'Título da seção',
......
......@@ -3,6 +3,10 @@
$api_key = $instance['youtube_api_key'];
$list_id = $instance['youtube_list_id'];
if(!$api_key || !$list_id){
return;
}
$num = 4;
if($instance['youtube_list'] == 'playlist'){
$url = "https://www.googleapis.com/youtube/v3/playlistItems?key={$api_key}&playlistId={$list_id}&maxResults={$num}&part=snippet,id&order=date";
......@@ -10,16 +14,19 @@ if($instance['youtube_list'] == 'playlist'){
$url = "https://www.googleapis.com/youtube/v3/search?key={$api_key}&channelId={$list_id}&maxResults={$num}&part=snippet,id&order=date";
}
$cache_key = __FILE__ . ':' . $url;
if(apcu_exists($cache_key)){
$result = apcu_fetch($cache_key);
} else {
$cache_key = "featured-videos:" . md5($url);
if(!($result = wp_cache_get($cache_key))){
$result = json_decode(file_get_contents($url));
apcu_store($cache_key, $result, 300);
if(is_object($result) && !$result->error){
wp_cache_add($cache_key, $result, '', 30 * MINUTE_IN_SECONDS);
} else {
$result = (object) ['items' => []];
wp_cache_add($cache_key, $result, '', 3 * MINUTE_IN_SECONDS);
}
}
if (!is_object($result) || count($result->items) === 0) {
$result = (object) ['items' => []];
if(!$result->items){
return;
}
$extract_vid = function($video){
......@@ -34,10 +41,12 @@ $extract_vid = function($video){
<div class="custom-so-widget alignfull featured-videos">
<div class="row entry-content">
<div class="column medium-5 small-12 p-0">
<?php if($instance['header']): ?>
<div class="featured-videos--logo">
<i class="home-section-icon fas fa-tv"></i>
<span class="home-section-title">Vermelho TV</span>
<span class="home-section-title"><?= $instance['header'] ?></span>
</div>
<?php endif; ?>
<h3 class="featured-videos--title"><?= $instance['title'] ?></h3>
<div class="featured-videos--description"><?= $instance['text'] ?></div>
<div class="featured-videos--buttons">
......@@ -51,7 +60,9 @@ $extract_vid = function($video){
</div>
<div class="column medium-7 small-12 mt-sm-20 p-0">
<div class="row">
<iframe class="column small-12 medium-12 js-featured-videos--iframe p-0" src="https://www.youtube.com/embed/<?= $extract_vid($result->items[0]) ?>" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
<div class="featured-videos--iframe-wrapper">
<iframe class="column small-12 medium-12 js-featured-videos--iframe featured-videos--iframe" src="https://www.youtube.com/embed/<?= $extract_vid($result->items[0]) ?>" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
</div>
</div>
<div class="row">
<?php foreach($result->items as $index => $video): ?>
......
......@@ -22,18 +22,18 @@ class FeedRSS extends \SiteOrigin_Widget {
'label' => 'Número de posts',
'default' => '5'
],
'link_section' => [
'link' => [
'type' => 'section',
'label' => 'link para o site do feed',
'hide' => true,
'fields' => [
'link_url' => [
'url' => [
'type' => 'text',
'label' => 'URL do link para o site do feed',
'placeholder' => 'https://sitedomain.com/',
'description' => 'deixe em branco para não utilizar o link'
],
'link_label' => [
'label' => [
'type' => 'text',
'label' => 'Texto do link para o site do feed',
'default' => 'Ir para o site'
......@@ -66,11 +66,7 @@ class FeedRSS extends \SiteOrigin_Widget {
return [
'items' => $feed->get_items(0,$instance['posts']),
'show_excerpt' => $instance['show_excerpt'],
'link' => (object) [
'url' => isset($instance['link_url']) ? $instance['link_url'] : '',
'label' => isset($instance['link_label']) ? $instance['link_label'] : ''
]
'link' => (object) $instance['link']
];
}
}
......
<?php
/*
Widget Name: Lista de posts mais lidos
Description: Adiciona Lista de posts mais lidos
Author: hacklab/
Author URI: https://hacklab.com.br/
*/
namespace widgets;
if(!class_exists('\\AjaxPageviews')){
return;
}
class MostReadPostsList extends PostsList {
function __construct() {
parent::__construct('most-read-posts-list', 'Lista de posts Mais lidos', '', '', '', plugin_dir_path(__FILE__));
}
function get_template_variables($instance, $args) {
if (isset($instance['conteudo'])) {
parse_str($instance['conteudo'], $conteudo);
$date = json_decode($conteudo['date_query']);
}
$posts_query_args = siteorigin_widget_post_selector_process_query($instance['conteudo']);
$most_read = \AjaxPageviews::get_top_viewed(1000, ['post_type' => $conteudo['post_type'], 'from' => $date->after]);
$ids = array();
foreach ($most_read as $post => $value) {
array_push($ids, $value->post_id);
}
$posts_query_args['post__in'] = $ids;
$posts_query_args['orderby'] = 'post__in';
$most_read_query = new \WP_Query($posts_query_args);
return [
'query' => $most_read_query,
'link' => (object) $instance['link'],
'show_excerpt' => $instance['show_excerpt'],
'hide_categories' => $instance['hide_categories'],
'css_classes' => $instance['css_class'],
'show_images' => $instance['show_images']
];
}
}
Siteorigin_widget_register('most-read-posts-list', __FILE__, 'widgets\\MostReadPostsList');
<?php
use guaraci\images;
$i = 0;
?>
<div class="posts-list <?= $css_classes ?>">
<div class="row">
<?php
while ($query->have_posts()):
$i++;
$query->the_post();
$img_tag = images::tag('card-large', 'card--image');
?>
<div class="column large-<?= 12 / $instance['columns'] ?> mb-15">
<div class="card">
<?php if( $img_tag != '' && ( $show_images == 'all_images' || ( $show_images == 'first_image' && $i == 1 ) ) ) : ?>
<a tabindex="-1" href="<?= get_the_permalink() ?>" class="card--image-wrapper">
<?= $img_tag ?>
</a>
<?php endif; ?>
<div class="card--content">
<?php if(!$hide_categories) : ?>
<div class="categories-list">
<?php
$post_categories = wp_get_post_categories( get_the_ID() );
foreach($post_categories as $category_id){
$category = get_category($category_id);
?>
<div class="categories-list--category category-<?= $category->slug ?>">
<a href="<?= esc_url(get_term_link($category, 'category')) ?>"><?= $category->name ?></a>
</div>
<?php
}
?>
</div>
<?php endif;?>
<h4 class="card--title">
<a href="<?= get_the_permalink() ?>"><?php the_title() ?></a>
</h4>
<?php if( ( $show_excerpt == 'all_excerpts' || ( $show_excerpt == 'first_excerpt' && $i == 1 ) ) ) : ?>
<div class="card-excerpt"><?php echo get_the_excerpt() ?></div>
<?php endif; ?>
</div>
</div>
</div>
<?php
endwhile;
wp_reset_postdata();
?>
</div>
<?php if($link->url): ?>
<div class="read-more" >
<a class="read-more-link" href="<?= $link->url ?>" class="goto"><?= $link->label ?></a>
</div>
<?php endif; ?>
</div>
......@@ -9,59 +9,82 @@
namespace widgets;
class PostsList extends \SiteOrigin_Widget {
function __construct($id='', $name='', $widget_options = array(), $control_options = array(), $form_options = array(), $base_folder = false) {
$css_classes = [
'featured' => __('Destaque', 'guaraci'),
'horizontal' => __('Lista horizontal', 'guaraci'),
'list' => __('Lista vertical', 'guaraci'),
];
function __construct() {
$css_classes = apply_filters(__CLASS__ . ':' . 'estilo', $css_classes);
$fields = [
'exibicao' => [
'css_class' => [
'type' => 'select',
'label' => 'Exibição',
'options' => [
'featured' => 'Destaque',
'block' => 'Bloco',
'list' => 'List',
]
'label' => __('Selecione o estilo', 'guaraci'),
'default' => 'featured',
'options' => $css_classes
],
'columns' => [
'type' => 'number',
'label' => 'Cards por linha',
'label' => __('Cards por linha', 'guaraci'),
'default' => '1'
],
'hide_images' => [
'hide_categories' => [
'type' => 'checkbox',
'label' => 'Esconder imagem'
'label' => __('Não exibir categorias', 'guaraci'),
],
'hide_excerpt' => [
'type' => 'checkbox',
'label' => 'Esconder resumo'
'show_images' => [
'type' => 'radio',
'label' => __( 'Exibição de imagens', 'guaraci' ),
'default' => 'all_images',
'options' => [
'all_images' => __( 'Mostrar todas', 'guaraci' ),
'first_image' => __( 'Mostrar a primeira', 'guaraci' ),
'hide_images' => __( 'Esconder as imagens', 'guaraci' )
]
],
'link_section' => [
'show_excerpt' => [
'type' => 'radio',
'label' => __( 'Exibição de Resumo', 'guaraci' ),
'default' => 'all_excerpts',
'options' => [
'all_excerpts' => __( 'Mostrar todos', 'guaraci' ),
'first_excerpt' => __( 'Mostrar o primeiro', 'guaraci' ),
'hide_excerpt' => __( 'Esconder resumos', 'guaraci' )
]
],
'link' => [
'type' => 'section',
'label' => 'link Ver mais',