I am trying to write a content rating script where the user can select what type of rating to give to their article (for instance, what age group the articles suits for).
I am using a Wordpress star rating script as a template.
This part of the script is where the user selects the rating:
function pn_apr_meta_box_form( $post )
{
wp_nonce_field( 'pn_apr_meta_box_nonce', 'pn_apr_meta_box_nonce_field' );
$current_post_rating = get_post_meta( $post->ID, PN_APR_RATING_META_KEY, true );
echo '<label for="pn_apr_rating">' . __( 'Choose a rating for this post:', 'author-post-ratings' ) . '</label> ';
echo '<select name="pn_apr_rating" id="pn_apr_rating">';
echo '<option value="unrated"' . selected( $current_post_rating, 0, false ) . '>' . __( 'Unrated', 'author-post-ratings' ) . '</option>';
for ( $i = 1; $i <= 5; $i++ ) {
echo '<option value="' . $i . '"' . selected( $current_post_rating, $i, false ) . '>' . sprintf( _n( '%1s Star', '%1s Stars', $i, 'author-post-ratings' ), $i ) . '</option>';
}
echo '</select>';
}
This part of the script outputs the ratings:
if ( $rating ) {
$output = null;
$output .= '<div class="author-post-rating">';
$output .= '<span class="author-post-rating-label">' . esc_attr( $pn_apr_settings['label_text'] ) . '</span> ';
$output .= '<span class="author-post-rating-stars" title="' . sprintf( __( '%1$d out of %2$d stars', 'author-post-ratings' ), $rating, 5 ) . '">';
// Output active stars
for ( $i = 1; $i <= $rating; $i++ ) {
$output .= '<img src="' . PN_APR_PLUGIN_DIR_URL . 'images/star-active.png" />';
}
// Output inactive stars
for ( $i = $rating + 1; $i <= 5; $i++ ) {
$output .= '<img src="' . PN_APR_PLUGIN_DIR_URL . 'images/star-inactive.png" />';
}
$output .= '</span>' . "\n";
$output .= '</div><!-- .author-post-rating -->';
if ( true == $return ) { return $output; }
// We don't need to use "else" here, since calling return will automatically stop further execution of this function.
echo $output;
}
Now, I want to change this script so that it becomes a content rating script (rather than star rating one). I want to offer these choices for the user:
G — Suitable for all audiences
PG — Possibly offensive, usually for audiences 13 and above
R — Intended for adult audiences above 17
X — Even more mature than above
Question: How can I change the script so that if the user selects for instance PG, then it will output the text Suitable for age 13 and up.
EDIT:
To Shawn, observe the following code:
function rating_select_cb( $post ) {
global $wpdb;
$value = get_post_meta($post->ID, 'rating', true);
echo '<div class="misc-pub-section misc-pub-section-last"><span id="timestamp"><label>Select a rating:<br></label>';
// build an array of each available rating
$ratings = array(
1 => 'G — Suitable for all audiences',
2 => 'PG — Possibly offensive, usually for audiences 13 and above',
3 => 'R — Intended for adult audiences above 17',
4 => 'X — Even more mature than above'
);
echo '<select name="rating">';
echo '<option value=""' . ((($value == '') || !isset($ratings[$value])) ? ' selected="selected"' : '') . '> None... </option>';
// output each rating as an option
foreach ($ratings as $id => $text) {
echo '<option value="' . $id . '"' . (($value == $id) ? ' selected="selected"' : '') . '">' . $text. '</option>';
}
echo '</select>';
echo '</span></div>';
}
Here's something that should get you to where you need to be:
Add to your functions.php:
add_action( 'add_meta_boxes', 'rating_select_box' );
function rating_select_box() {
add_meta_box(
'rating_select_box', // id, used as the html id att
__( 'Select rating:' ), // meta box title, like "Page Attributes"
'rating_select_cb', // callback function, spits out the content
'post', // post type or page. We'll add this to posts only
'side', // context (where on the screen
'low' // priority, where should this go in the context?
);
}
function rating_select_cb( $post )
{
global $wpdb;
$value = get_post_meta($post->ID, 'rating', true);
echo '<div class="misc-pub-section misc-pub-section-last">
<span id="timestamp">'
. '<label>Select a rating:<br></label>';
$selected = ($value == $result->post_name) ? ' selected="selected" ' : null;
echo '<select name="rating">';
echo '<option value="" default="default"> None... </option>';
echo '<option value="0" '.$selected.'> G — Suitable for all audiences </option>';
echo '<option value="1" '.$selected.'> PG — Possibly offensive, usually for audiences 13 and above </option>';
echo '<option value="2" '.$selected.'> R — Intended for adult audiences above 17 </option>';
echo '<option value="3" '.$selected.'> X — Even more mature than above </option>';
echo '</select>';
echo '</span></div>';
}
add_action( 'save_post', 'save_metadata');
function save_metadata($postid)
{
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return false;
if ( !current_user_can( 'edit_page', $postid ) ) return false;
if( empty($postid) ) return false;
if ( is_null($_REQUEST["rating"]) ) {
delete_post_meta($postid, 'rating');
} else {
update_post_meta($postid, 'rating', $_REQUEST['rating']);
}
}
The above code does this:
1. Adds a new metabox to your posts
2. Adds a select box with the rating values
3. Saves the metadata with the post
To access your metadata in your templates:
$meta = get_post_custom($post->ID);
echo $meta['rating'][0];
To have your template display a custom string use something like:
switch ( $meta['rating'][0] ) {
case 0:
echo "This is rated PG";
break;
case 1:
echo "This is rated G";
break;
case 2:
echo "This is rated R";
break;
case 3:
echo "Ug oh! This is rated X!";
break;
default:
echo "This is not yet rated.";
}
**Edit: This code provides full functionality.. you could abandon your current solution if it works for you
Related
I am working on a solution to have specific product attributes on a single product page. Based on Display specific custom product attributes on single product pages in Woocommerce answer code, I made some little changes here below
to display the selected attribute on single product pages:
add_action( 'woocommerce_single_product_summary', 'display_some_product_attributes', 25 );
function display_some_product_attributes(){
// HERE define the desired product attributes to be displayed
$defined_attributes = array('attributeB', 'attributeC', 'attributeD');
global $product;
$attributes = $product->get_attributes();
echo '<div style="font-size: 20px; font-weight: 500; margin-bottom: 5px; text-transform: uppercase;"><span>Sensorik</span></div>';
if ( ! $attributes ) {
return;
}
$out = '<ul class="taste-attributes">';
foreach ( $attributes as $attribute ) {
// Get the product attribute slug from the taxonomy
$attribute_slug = str_replace( 'pa_', '', $attribute->get_name() );
// skip all non desired product attributes
if ( ! in_array($attribute_slug, $defined_attributes) ) {
continue;
}
// skip variations
if ( $attribute->get_variation() ) {
continue;
}
$name = $attribute->get_name();
if ( $attribute->is_taxonomy() ) {
$terms = wp_get_post_terms( $product->get_id(), $name, 'all' );
// get the taxonomy
$tax = $terms[0]->taxonomy;
// get the tax object
$tax_object = get_taxonomy($tax);
// get tax label
if ( isset ( $tax_object->labels->singular_name ) ) {
$tax_label = $tax_object->labels->singular_name;
} elseif ( isset( $tax_object->label ) ) {
$tax_label = $tax_object->label;
// Trim label prefix since WC 3.0
if ( 0 === strpos( $tax_label, 'Product ' ) ) {
$tax_label = substr( $tax_label, 8 );
}
}
$out .= '<p class="' . esc_attr( $name ) . '">';
$out .= '<span class="attribute-label">' . esc_html( $tax_label ) . ': </span>';
$tax_terms = array();
foreach ( $terms as $term ) {
$single_term = esc_html( $term->name );
// Insert extra code here if you want to show terms as links.
array_push( $tax_terms, $single_term );
}
$out .= '<span class="attribute-value">' . implode(', ', $tax_terms) . '</span></p>';
} else {
$value_string = implode( ', ', $attribute->get_options() );
$out .= '<span class="' . sanitize_title($name) . ' ' . sanitize_title( $value_string ) . '">';
$out .= '<p class="attribute-label">' . $name . ': </p></span>';
}
}
$out .= '</ul>';
echo $out;
}
Then to transform text to an image for some attributes, I use the code below:
``` /**
* Insert JavaScript to replace WooCommerce product attributes text with images.
*/
function my_woocommerce_attributes_images(){
?>
<script>(function() {
var list, index, element, attValue, imgURL;
list = document.getElementsByClassName("attributeA");
for (index = 0; index < list.length; ++index) {
element = list[index];
attValue = element.getElementsByClassName("attribute-value")[0].innerText;
switch (attValue.trim()) {
case "valueA":
imgURL = "/wp-content/uploads/2020/10/cigar.png";
break;
case "valueB":
imgURL = "/wp-content/uploads/2020/10/fish.png";
break;
}
element.innerHTML = '<span class="attribute-label">Atteibute A: </span><img src="' + imgURL + '" width="20" height="20" />';
}
})();</script>
<?php
}
add_action('wp_footer', 'my_woocommerce_attributes_images'); ```
But I have the following problems:
Currently, only one case can be possible. If two ore more are true, it will not load any images. So we need a for each loop here and out put all true values => images. But all of my tryout was not sucessfull.
Currently we have to insert the code multiple times when we want to transform text to images from more than one attribute. I already tried to add a for each loop for list = document.getElementsByClassName("attributeA"); in order taht we can have there something like list = document.getElementsByClassName("attributeA", "attributeB", "attributeB"); But I'm not able to get this to work.
In order to make this more generic, also the element.innerHTML = '<span class="attribute-label">Attribute A: </span><img src="' + imgURL + '" width="20" height="20" />'; should be display the generic current Attribute lable name. But yeah, here I not able to add this in a ore generic way.
Any suggestions are welcome to make it work.
this is my taxonamy code in word press
<?php
$terms = get_terms(['taxonomy' => 'listing_type', 'hide_empty' => false,]);
if ($terms) {
foreach ($terms as $term) {
$selected = 'selected';
echo '<option value="' . $term->name . '" '.$selected.' >' .esc_attr($term->name) . '</option>';
}
} ?>
Instead of writing this manually you can just use wp_dropdown_categories()
Docs here — https://codex.wordpress.org/Function_Reference/wp_dropdown_categories
Thanks,
Tom
I have a theme options page and a loop which grabs my categories. This code works fine and I am able to save my options. The code like this:
function drop_elements_function(){
$my_cats = get_categories();
$i = 1;
foreach( $my_cats as $my_cat ) :
$my_categories[$my_cat->cat_ID] = array(
'value' => $my_cat->cat_ID,
'label' => $my_cat->cat_name
);
$i++;
endforeach;
$options = get_option('sandbox_theme_social_options');
echo'<select id="featured_cat" name="sandbox_theme_social_options[Drop_Elements]">';
foreach ( $my_categories as $category ){
$label = $category['label'];
$selected = '';
if ( $options['Drop_Elements'] == $category['value'] )
$selected = 'selected="selected"';
echo '<option style="padding-right: 10px;" value="' . esc_attr( $category['value'] ) . '" ' . $selected . '>' . $label . '</option>';
}
echo '</select>';
//print_r($options['Drop_Elements']);
}/*Function end*/
The output looks like this:
http://www.vasinternetposao.com/img.png
Problem: Now when my theme is installed for the first time i am getting the output like the screen shot above but obviously my option is not yet saved to the database (user must click the save button in order to select that category). So i was thinking to do something like this:
1.) User install the theme for the first time and then output looks like this:
http://www.vasinternetposao.com/img2.png
2.) If user unintentionally select "Choose your category" and clicks the "save button"
the output will be again:
http://www.vasinternetposao.com/img2.png
3.) If the user select the real category (not "Choose Your Category") then "Choose Your Category" Disappears:
http://www.vasinternetposao.com/img.png
This is my attempt but it is not working:
function drop_elements_function(){
$my_cats = get_categories();
$i = 1;
foreach( $my_cats as $my_cat ) :
$my_categories[$my_cat->cat_ID] = array(
'value' => $my_cat->cat_ID,
'label' => $my_cat->cat_name
);
$i++;
endforeach;
$options = get_option('sandbox_theme_social_options');
echo'<select id="featured_cat" name="sandbox_theme_social_options[Drop_Elements]">';
foreach ( $my_categories as $category ){
$label = $category['label'];
$selected = '';
if ( $options['Drop_Elements'] == $category['value'] ){
$selected = 'selected="selected"';
echo '<option style="padding-right: 10px;" value="' . esc_attr( $category['value'] ) . '" ' . $selected . '>' . $label . '</option>';
}
elseif(!isset($options['Drop_Elements'])){
$selected = 'selected="selected"';
echo '<option selected="selected" value="Choose Your Category">Choose Your Category</option>';
echo '<option style="padding-right: 10px;" value="' . esc_attr( $category['value'] ) . '" ' . '>' . $label . '</option>';
}
}/*Foreach close*/
echo '</select>';
//print_r($options['Drop_Elements']);
}/*Function end*/
Can it be done with PHP? Any help is appreciated! Thank you!
I think what you want to do is something like the following example:
echo '<select id="featured_cat" name="sandbox_theme_social_options[Drop_Elements]">';
echo '<option selected="selected" value="Choose Your Category">Choose Your Category</option>';
foreach ( $my_categories as $category ){
$label = $category['label'];
$selected = ( $options['Drop_Elements'] == $category['value'] ) ? " selected='selected' " : "";
echo '<option style="padding-right: 10px;" value="' . esc_attr( $category['value'] ) . '" ' . $selected . '>' . $label . '</option>';
}
echo "</select>";
I added a content rating system to my platform where the authors can select which audience their post is appropriate for. Currently, these options are available:
Unrated
G
PG
R
The code that I use to display the rating options on the post edit page is:
// Article Content Rating
add_action( 'add_meta_boxes', 'rating_select_box' );
function rating_select_box() {
add_meta_box(
'rating_select_box', // id, used as the html id att
__( 'Content Rating (optional)' ), // meta box title
'rating_select_cb', // callback function, spits out the content
'post', // post type or page. This adds to posts only
'side', // context, where on the screen
'low' // priority, where should this go in the context
);
}
function rating_select_cb( $post ) {
global $wpdb;
$value = get_post_meta($post->ID, 'rating', true);
echo '<div class="misc-pub-section misc-pub-section-last"><span id="timestamp"><label>Article Content Rating: </label>';
$ratings = array(
1 => ' G ',
2 => ' PG ',
3 => ' R ',
);
echo '<select name="rating">';
echo '<option value=""' . ((($value == '') || !isset($ratings[$value])) ? ' selected="selected"' : '') . '> Unrated </option>';
// output each rating as an option
foreach ($ratings as $id => $text) {
echo '<option value="' . $id . '"' . (($value == $id) ? ' selected="selected"' : '') . '">' . $text. '</option>';
}
echo '</select>';
echo '</span></div>';
}
add_action( 'save_post', 'save_metadata');
function save_metadata($postid)
{
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return false;
if ( !current_user_can( 'edit_page', $postid ) ) return false;
if( empty($postid) ) return false;
if ( is_null($_REQUEST["rating"]) ) {
delete_post_meta($postid, 'rating');
} else {
update_post_meta($postid, 'rating', $_REQUEST['rating']);
}
}
// END Article Content Rating
Now, the problem is, what code do I add to single.php to display their choice? So for instance, if the author selected PG, then I want to echo 'Content Rating: PG'; or if it was on default (unrated), I want to echo 'Content Rating: Unrated';. How is this possible? Ideally, a solution that is light on the server as my platform is heavily trafficked.
You already use the delete_post_meta() and update_post_meta() functions to remove and modify the custom values. Simply use the get_post_meta() function to obtain the value for the current post, and echo it out as you see fit.
If you're in The Loop, it would be something like:
$rating = get_post_meta(get_the_ID(), 'rating', TRUE);
Edit:
You already know your ID to rating mapping (I might make this mapping a global array, or some defines, or something similar). Simply use that to look up the string to output:
$ratings = array(
1 => 'G',
2 => 'PG',
3 => 'R'
);
if(array_key_exists($rating, $ratings)) {
echo "Content Rating: $ratings[$rating]";
} else {
echo "Content Rating: Unrated";
}
It looks as if you're saving the key to your custom field rather than its value. I suppose this would be alright if you planned on redeclaring your $ratings array, or (God forbid) use it globally. But still, it would probably be best if you saved the actual Rating rather than its ID number.
So change this line:
foreach ($ratings as $id => $text) {
echo '<option value="' . $id . '"' . (($value == $id) ? ' selected="selected"' : '') . '">' . $text. '</option>';
}
To this:
echo '<option value="Unrated"' . ((!$value || $value == 'Unrated' ? ' selected="selected"' : '') . '">Unrated</option>';
foreach ($ratings as $id => $text) {
echo '<option value="' .trim($text). '"' . (($value == trim($text)) ? ' selected="selected"' : '') . '">' . $text. '</option>';
}
After setting your value within the post, you can add this in single.php:
if(have_posts()) : while(have_posts()) : the_post();
echo 'Content Rating: '.get_post_meta($post->ID, 'rating', true);
endwhile;endif;
UPDATE:
As mentioned in my comments, I personally try to avoid globals and redeclaring things as much as possible. So if you would prefer to still reference your ratings by Key, you can get around globals and redeclaring your ratings array by adding a few simple functions:
functions.php
function gw_get_ratings_array()
{
$ratings = array(
1 => 'G',
2 => 'PG',
3 => 'R'
);
return $ratings;
}
function gw_get_rating($key=0)
{
$i = (int)$key;
$ratings = gw_get_ratings_array();
return isset($ratings[$i]) && $ratings[$i] ? $ratings[$i] : 'Unrated';
}
single.php
if(have_posts()) : while(have_posts()) : the_post();
$rating_id = get_post_meta($post->ID, 'rating', true);
echo 'Content Rating: '.gw_get_rating($rating_id);
endwhile;endif;
This way, if you ever need to add more Rating Types, you only need to alter the gw_get_ratings_array function rather than searching for each declaration of the array itself.
Adding the following script to the function.php file in Wordpress:
add_action( 'add_meta_boxes', 'rating_select_box' );
function rating_select_box() {
add_meta_box(
'rating_select_box', // id, used as the html id att
__( 'Select rating:' ), // meta box title, like "Page Attributes"
'rating_select_cb', // callback function, spits out the content
'post', // post type or page. We'll add this to posts only
'side', // context (where on the screen
'low' // priority, where should this go in the context?
);
}
function rating_select_cb( $post )
{
global $wpdb;
$value = get_post_meta($post->ID, 'rating', true);
echo '<div class="misc-pub-section misc-pub-section-last">
<span id="timestamp">'
. '<label>Select a rating:<br></label>';
$selected = ($value == $result->post_name) ? ' selected="selected" ' : null;
echo '<select name="rating">';
echo '<option value="" default="default"> None... </option>';
echo '<option value="0" '.$selected.'> G — Suitable for all audiences </option>';
echo '<option value="1" '.$selected.'> PG — Possibly offensive, usually for audiences 13 and above </option>';
echo '<option value="2" '.$selected.'> R — Intended for adult audiences above 17 </option>';
echo '<option value="3" '.$selected.'> X — Even more mature than above </option>';
echo '</select>';
echo '</span></div>';
}
add_action( 'save_post', 'save_metadata');
function save_metadata($postid)
{
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return false;
if ( !current_user_can( 'edit_page', $postid ) ) return false;
if( empty($postid) ) return false;
if ( is_null($_REQUEST["rating"]) ) {
delete_post_meta($postid, 'rating');
} else {
update_post_meta($postid, 'rating', $_REQUEST['rating']);
}
}
Will add a box in the post page with a drop down list. I want the default option to be on None... so I added a default="default" to that option, but it does not work. By default, the highest number value is selected, in this case, it is X — Even more mature than above.
What am I doing wrong? How can I make it so that the None... option is selected by default?
In a select list, the correct way to "select" an option is with selected="selected", not default="default". Changing your 'None' option to the following should fix it:
echo '<option value="" selected="selected"> None... </option>';
However, you're not dynamically creating your select list, you're just outputting a full list and you'll run into issues selecting the other values too. To fix this, if the options won't be changing, you can put them in an array to loop through them. You can modify your rating_select_cb() method with the following new code to achieve this:
function rating_select_cb( $post ) {
global $wpdb;
$value = get_post_meta($post->ID, 'rating', true);
echo '<div class="misc-pub-section misc-pub-section-last"><span id="timestamp"><label>Select a rating:<br></label>';
// build an array of each available rating
$ratings = array(
1 => 'G — Suitable for all audiences',
2 => 'PG — Possibly offensive, usually for audiences 13 and above',
3 => 'R — Intended for adult audiences above 17',
4 => 'X — Even more mature than above'
);
echo '<select name="rating">';
echo '<option value=""' . ((($value == '') || !isset($ratings[$value])) ? ' selected="selected"' : '') . '> None... </option>';
// output each rating as an option
foreach ($ratings as $id => $text) {
echo '<option value="' . $id . '"' . (($value == $id) ? ' selected="selected"' : '') . '">' . $text. '</option>';
}
echo '</select>';
echo '</span></div>';
}
This method will default-select the "None" option if the selected $value is not in the available list of ratings. After that, it will loop through each rating and output it as an option. If the rating's $id matches the selected $value, it will be marked as selected.
You should use it like this:
echo '<option value="" selected="selected"> None... </option>';