How to separate gallery from content in wordpress? - php

What I want to do
I have a website that uses a CMS I wrote some time ago, and now I am trying to migrate it to wordpress.
At the existing implementation, when someone writes a post, they can add some extra images that are shown as a gallery at the end of the post, as you can see in this page for example (sorry for non english page): http://apollonpatras.gr/news/562/i-bradia-ton-xorigon-parousiasi-xorigikou-programmatos-kai-eisitirion-diarkeias/.
How I think I can do it
I am thinking about letting the users create wordpress galleries and at post save time intercept the post contents and store the gallery image ids in a postmeta field so I can show them however I want.
Also, I will have to strip the galleries from the content before they are shown, since I will show them in my own way later.
What I am trying so far
add_filter('content_save_pre', 'intercept_galleries', 99);
function intercept_galleries($content) {
if (get_post_type() !== 'post') {
return $content;
}
if (has_shortcode($content, 'gallery')) {
// The [gallery] short code exists.
$a = get_post_gallery(0, false);
update_post_meta(get_the_ID(), 'has_gallery', 1);
update_post_meta(get_the_ID(), 'gallery_items', $a['ids']);
} else {
update_post_meta(get_the_ID(), 'has_gallery', 0);
update_post_meta(get_the_ID(), 'gallery_items', "");
}
return $content;
}
add_filter('the_content', 'remove_shortcodes_from_content');
function remove_shortcodes_from_content($content) {
return strip_shortcodes($content);
}
Where it goes wrong
Looks like when the post is originally saved, the postmeta field "has_gallery" is set to 1, but the field "gallery_items" is empty.
When I go to the wordpress editor and just hit update, the fields are absolutely correct.
Also the hook to remove shortcodes from the content is working.
What am I looking for
How can I fix this problem? Also, is there something wrong/stupid with the way I decided to do this? Would some other way be cleaner/easier/faster etc?
Thank you for your time

I've done this a few times and here's how I do it.
First I create a function that will display the gallery in the way that I want. You can modify this according to how you require you gallery markup to be:
function my_gallery_shortcode( $attr ) {
$post = get_post();
if ( ! empty( $attr['ids'] ) ) {
$attr['include'] = $attr['ids'];
}
extract( shortcode_atts( array(
'order' => 'ASC',
'orderby' => 'post__in',
'id' => $post->ID,
'columns' => 3,
'size' => 'large',
'include' => '',
), $attr));
$id = (int) $id;
$columns = (int) $columns;
if ( 'RAND' == $order ) {
$orderby = 'none';
}
if ( ! empty( $include ) ) {
$_attachments = get_posts( array( 'include' => $include, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby ) );
$attachments = array();
foreach ( $_attachments as $key => $val ) {
$attachments[$val->ID] = $_attachments[$key];
}
}
if ( empty( $attachments ) ) {
return '';
}
$output = '<div class="slideshow"><ul>';
foreach ( $attachments as $id => $attachment ) {
$thumb = wp_get_attachment_image_src( $id, 'large', false );
$output .= '<li><img src="' . $thumb[0] . '" width="' . $thumb[1] . '" height="' . $thumb[2] . '" alt="' . get_post_meta( $id, '_wp_attachment_image_alt', true ) . '" /></li>';
}
$output .= '</ul></div>';
return $output;
}
You can complicate or simply the function above according to your requirements.
Then in your theme's functions.php add this:
add_shortcode( 'gallery', 'my_gallery_shortcode' );
Now you have two choices:
1) You can allow your user to add a gallery to the main page content by way of them editing the page in question and going to Media > Create Gallery
This will insert the gallery short code which will be formatted according to your function my_gallery_shortcode(), however the gallery can be managed via WordPress's gallery functionality in the admin area and is stored in the database by WordPress in the conventional way.
or
2) You could create a separate WYSIWYG field either through additional code in your functions.php file, or by using a plugin such as Advanced Custom Fields. You would then use this additional WYSIWYG field to allow the user to insert the gallery shortcode in the same way as above. This is virtually the same as option 1 above but you'd have more flexibility as to where you output and position the gallery on the page.
I hope this helps anyone looking to do the same thing.

Related

counting content with tag in foreach loop wordpress

I am trying to show only tags which have more than specific number of posts. To achieve this I modified my tag-links.php code as below. But with this code I got some weird behavior. My page don't show any tag below the number of content, it is ok, but sometimes it also hides other tags. when I refresh the page it will show different tags or don't show any tags. I am newbie with php syntax, so I am not sure but code seems correct. Can you tell me the code problem, or any practical approach to solve my problem.
PS: code also include this function, every tag redirect user to random post with this specific tag, it works well.
<?php
$tags = get_the_tags( $post->ID );
$separator = ' ';
$output = '';
if ( $tags ) {
$link = "";
$xnumber = 0; //number for contents with specific tag
echo '<div class="entry-tags">';
echo "<p><span>" . __( ) . "</span>";
foreach ( $tags as $tag ) {
$posts = get_posts("post_type=post&orderby=rand");
foreach($posts as $post) {
if(has_tag($tag->term_id)) {
$xnumber++;
if($xnumber >= 1) {
$link = get_permalink($post);
break 1;
} else { }
} else { }
}
if($xnumber >= 1) {
$output .= '<a href="' . esc_url( $link ) . '" title="'
. esc_attr( sprintf( __( "View all posts tagged %s",
'tracks' ), $tag->name ) ) . '">' . esc_html( $tag->name )
. '</a>' . $separator;
unset($link);
unset($xnumber);
} else {
unset($link);
unset($xnumber);
}
}
echo trim( $output, $separator );
echo "</p>";
echo "</div>";
}
Ok, so a couple of things:
1) You arent using the get_posts function the way it's documented. You should be passing in an array of settings. Here's the link to documentation: https://developer.wordpress.org/reference/functions/get_posts/
2) The get_posts() function has a default limit of 5 records. And you're bringing back the list in random order. So, sometimes the 5 records you get will have the tag you're looking for, and sometimes it wont. If you want it to check more records, you'll need to change the numberposts.
Following example displays posts tagged with 'jazz', under 'genre' custom taxonomy, using 'tax_query':
$args = array(
'tax_query' => array(
array(
'taxonomy' => 'genre',
'field' => 'slug',
'terms' => 'jazz'
)
)
);
$postslist = get_posts( $args );
That may be more what you're looking for...
A better example using post tags:
$args = array(
'tax_query' => array(
array(
'taxonomy' => 'post_tag',
'field' => 'slug',
'terms' => $tag
)
)
};

Custom Fields not showing in custom post type post

I have a custom post type named "Designer" Each posts will be using different unique Advanced Custom Fields as each posts has unique templates.With the below code I am able to give rules for each posts in Designer post type and save but the custom fields are not displaying on post edit pages on backend.
Normally this code should ork but no idea what happend to the code
Please Help.
add_filter('acf/location/rule_types', 'acf_location_rules_types');
function acf_location_rules_types( $choices )
{
$choices['Custom Post types']['cpt_parent'] = 'Custom post type parent';
return $choices;
}
add_filter('acf/location/rule_values/cpt_parent', 'acf_location_rules_values_cpt_parent');
function acf_location_rules_values_cpt_parent( $choices )
{
$args = array(
'hierarchical' => true,
'_builtin' => false
);
$posttypes = get_post_types( $args );
if( $posttypes )
{
foreach( $posttypes as $posttype ):
if( $posttype != 'acf' ):
$args = array(
'post_type' => 'designer',
'posts_per_page' => -1,
'post_status' => 'publish'
);
$customposts = get_posts( $args );
if ( $customposts ) {
foreach( $customposts as $custompost ){
$choices[ $custompost->ID] = $custompost->post_title;
}
}
endif;
endforeach;
}
return $choices;
}
//MATCH THE RULE
add_filter('acf/location/rule_match/cpt_parent', 'acf_location_rules_match_cpt_parent', 10, 3);
function acf_location_rules_match_cpt_parent( $match, $rule, $options )
{
global $post;
$selected_post = (int) $rule['value'];
// post parent
$post_parent = $post->post_parent;
if( $options['page_parent'] ) {
$post_parent = $options['page_parent'];
}
if ($rule['operator'] == "=="){
$match = ( $post_parent == $selected_post );
}
elseif ($rule['operator'] != "!="){
$match = ( $post_parent != $selected_post );
}
return $match;
}
Your Artist Collection field group is set to only appear on one post, the post Designer Post 1 which is a Designer Post type.
I don't understand what all the code is for? Just create a different field group for each post that needs a different field group and a separate rule for each.
Ok sorry I understand the issue now and I have recreated the issue on my local install.
On the line of code below you are looking for the post_parent but I think you should be looking for the ID.
I changed this:
$post_parent = $post->post_parent;
to this:
$post_parent = $post->ID;
and it's working for me.
If I understand your problem correctly, in wp-admin post edit page click on screen options on the upper right corner. In the menu that appears make sure the Custom fields is selected. This will make the custom fields appear for edit.

How to have an empty post title and content when creating a new WordPress post via the front-end

My aim is to insert a new draft post into the database via a custom front-end form I've created. I need the post title and content to be empty. Is this possible?
I've tried the following which doesn't work:
$post_data = array(
'post_title' => '',
'post_type' => 'post',
'post_content' => '',
'post_status' => 'draft',
'post_author' => 1
);
$post_id = wp_insert_post( $post_data );
Note: You can create a new post using the back-end editor with empty title and content so I am wondering how they guys at WordPress do it.
You can not insert a blank post with wp_insert_post, Wordpress will prevent it with wp_insert_post_empty_content hook, you can see it in the source code : https://developer.wordpress.org/reference/functions/wp_insert_post/
The only way to do it is to overpass this hook with a custom function
Here is an example (source)
add_filter('pre_post_title', 'wpse28021_mask_empty');
add_filter('pre_post_content', 'wpse28021_mask_empty');
function wpse28021_mask_empty($value)
{
if ( empty($value) ) {
return ' ';
}
return $value;
}
add_filter('wp_insert_post_data', 'wpse28021_unmask_empty');
function wpse28021_unmask_empty($data)
{
if ( ' ' == $data['post_title'] ) {
$data['post_title'] = '';
}
if ( ' ' == $data['post_content'] ) {
$data['post_content'] = '';
}
return $data;
}
There is a filter in WordPress core that can be used to prevent this.
wp_insert_post_empty_content
https://developer.wordpress.org/reference/hooks/wp_insert_post_empty_content/
Which you should be able to use like:
add_filter( 'wp_insert_post_empty_content', '__return_false' );
$post = wp_insert_post( $post_args );

Check if there are any Posts written with certain Post Format

I'm building a wordpress theme and I need to check if there are any Post written within certain Post Format.
This is what I have in my functions.php
add_theme_support( 'post-formats', array( 'image', 'link', 'quote', 'status', 'video', 'audio', 'gallery' ) );
And this little piece of code in page template file.
if ( current_theme_supports( 'post-formats' ) ){
$post_formats = get_theme_support( 'post-formats' );
if ( is_array( $post_formats[0] ) ) {
foreach ($post_formats[0] as $post_format) {
echo ''.$post_format.'';
}
}
}
So, currently I have ALL Post Formats displayed as links. What I need is to display ONLY the ones that have Posts with that Post Format assigned.
Example:
If there are no Posts with Post Format Quote assigned, don't display quote link.
I've tried to search the web but without success. Does anyone know how to accomplish this? Thank you!
$terms = get_terms("post_format");
$count = count($terms);
if ( $count > 0 ){
echo '<ul class="list-group">';
foreach ( $terms as $term ) {
if($term->count > 0)
echo ''.$term->name.'';
}
echo '</ul>';
}
Try This

Can't get an echo to do what I want in Wordpress plugin

So I'm trying to write a new plugin since I haven't been able to find one that does exactly what I want with the extensibility that I desire. The goal of the plugin is to be able to use a simple shortcode to display an image slider that automatically populates with your blog's latest posts.
I've got the basic plugin files ready and the shortcode implemented and tested. I had a snafu solved yesterday on SO but the solution highlighted a new problem. Here's the code:
function slyd( $category, $slydcount ) {
global $post;
$tmp_post = $post; // Create $tmp_post to empty $post once Slyd is done with it
$args = array(
'category' => $category,
'numberposts' => $slydcount
);
$slydposts = get_posts( $args );
foreach( $slydposts as $post ) : setup_postdata($post);
$post_title = get_the_title(); // Get the post's title
$post_content = get_the_content(); // Get the post's content - will write code to get excerpt later
$post_thumb = wp_get_attachment_image_src( get_post_thumbnail_id(), 'full' ); // Get the post's featured image's src
$post_permalink = get_permalink(); // Get the post's permalink
echo '<h2>' . $post_title . '</h2>'
. '<p>' . $post_content . '</p>'
. '<p>' . $post_thumb . '</p>';
endforeach;
$post = $tmp_post; // Empty $post once Slyd is done with it
}
// Create the shortcode
function slyd_shortcode( $atts ) {
// $atts ::= array of attributes
// examples: [slyd]
// [slyd category='slide']
// [slyd slydcount='5']
// [slyd theme='default']
/* Retrieve attributes set by the shortcode and set defaults for
unregistered attributes. */
extract( shortcode_atts( array(
'category' => 'slyd', // Which category(s) to display posts from
'slydcount' => '5', // How many Slyds to display
'theme' => 'default' // Which Slyd theme to use
), $atts ) );
return "<p>category = {$category}, count = {$slydcount}</p>"
. slyd( $category, $slydcount );
}
add_shortcode( 'slyd', 'slyd_shortcode' );
The issue is in the foreach loop in function slyd();. I was originally using a return where the echo is now to put the result on the screen. That worked to display the first post but it would, of course, escape the function. I need it to cycle through and display all of the posts.
From researching the PHP documentation I found that I could use print in place of echo or return but it's giving me the same result as echo. What's happening is the code seems to be executing twice. It places itself where it needs to be the first time, then it also echoes to the browser and places it just below the head of the page.
I suppose my question is whether there's an alternative to return, echo, or print that would solve my problem?
Thanks in advance.
Now I'm trying to get the plugin to pull in the blog's latest posts but I'm running into a bit of a snafu. When I use the_title() and the_permalink() they display outside of the code I'm trying to contain them in. Further, the_content() is displaying once with the_permalink() and the_title() and then a second time where it's supposed to.
You can see the behavior here.
return is what you want in this case. You want to return a value (i.e. html code) from the slyd function so you can use it (in this case append it) in the slyd_shortcode function. However, you need to first collect all output into an additional variable ($ret below), and then return that value:
function slyd( $category, $slydcount ) {
global $post;
$tmp_post = $post;
$args = array(
'category' => $category,
'numberposts' => $slydcount
);
$slydposts = get_posts( $args );
$ret = '';
foreach( $slydposts as $post ) {
setup_postdata($post);
$post_title = get_the_title();
$post_content = get_the_content();
$post_thumb = wp_get_attachment_image_src( get_post_thumbnail_id(), 'full' );
$post_permalink = get_permalink();
$ret .= '<h2>' . $post_title . '</h2>'
. '<p>' . $post_content . '</p>'
. '<p>' . $post_thumb . '</p>';
}
$post = $tmp_post;
return $ret;
}
As you see you should first initialize the $ret variable with an empty string, then append to it on each iteration of the foreach loop. return is used to return the whole string after the loop.

Categories