Wordpress Modification To A Five-Star Rating Script - javascript

I have added custom javascript code to the header.php file of my wordpress site. I have tested this code on a basic html file and it works fine, but I cannot seem to make the vote recording function work on a wordpress post. The other components of the script are working fine (hover, vote display from a .txt file), but I cannot get the function to record the vote working. All files have read/write access.
I would greatly appreciate it if anyone could assist me or point me in the right direction to solve this.
Here is the part of the script that records the vote, I am fairly new to php and was wondering if there is something I can add/replace to modify so the code so it will work properly on Wordpress.
$('.ratings_stars').bind('click', function() {
var star = this;
var widget = $(this).parent();
var clicked_data = {
clicked_on : $(star).attr('class'),
widget_id : $(star).parent().attr('id')
};
$.post(
'http://localhost/url/wordpress/wp-content/ratings.php',
clicked_data,
function(INFO) {
widget.data( 'fsr', INFO );
set_votes(widget);
},
'json'
);
});
});
function set_votes(widget) {
var avg = $(widget).data('fsr').whole_avg;
var votes = $(widget).data('fsr').number_votes;
var exact = $(widget).data('fsr').dec_avg;
window.console && console.log('and now in set_votes, it thinks the fsr is ' + $(widget).data('fsr').number_votes);
$(widget).find('.star_' + avg).prevAll().andSelf().addClass('ratings_vote');
$(widget).find('.star_' + avg).nextAll().removeClass('ratings_vote');
$(widget).find('.total_votes').text( votes + ' votes recorded (' + exact + ' rating)' );
}
Here is a visual example for reference
Thank you for taking time to look at this, if there is any additional information that I can provide please let me know.
Here is the ratings.php that was mentioned in the script that was placed in the header.php.
ratings.php:
<?php
$rating = new ratings($_POST['widget_id']);
isset($_POST['fetch']) ? $rating->get_ratings() : $rating->vote();
class ratings {
var $data_file = 'http://localhost/url/wordpress/wp-content/ratings.data.txt';
private $widget_id;
private $data = array();
function __construct($wid) {
$this->widget_id = $wid;
$all = file_get_contents($this->data_file);
if($all) {
$this->data = unserialize($all);
}
}
public function get_ratings() {
if($this->data[$this->widget_id]) {
echo json_encode($this->data[$this->widget_id]);
}
else {
$data['widget_id'] = $this->widget_id;
$data['number_votes'] = 0;
$data['total_points'] = 0;
$data['dec_avg'] = 0;
$data['whole_avg'] = 0;
echo json_encode($data);
}
}
public function vote() {
preg_match('/star_([1-5]{1})/', $_POST['clicked_on'], $match);
$vote = $match[1];
$ID = $this->widget_id;
if($this->data[$ID]) {
$this->data[$ID]['number_votes'] += 1;
$this->data[$ID]['total_points'] += $vote;
}
else {
$this->data[$ID]['number_votes'] = 1;
$this->data[$ID]['total_points'] = $vote;
}
$this->data[$ID]['dec_avg'] = round( $this->data[$ID]['total_points'] / $this->data[$ID]['number_votes'], 1 );
$this->data[$ID]['whole_avg'] = round( $this->data[$ID]['dec_avg'] );
file_put_contents($this->data_file, serialize($this->data));
$this->get_ratings();
}
}
?>
Here is the complete javascript code added to the header.php, the mouseover/mouseout seem to be working properly, so I think the javascript should be running.
Javascript added to header.php:
<?php wp_head(); ?>
<script type="text/javascript">
$(document).ready(function() {
$('.rate_widget').each(function(i) {
var widget = this;
var out_data = {
widget_id : $(widget).attr('id'),
fetch: 1
};
$.post(
'http://localhost/url/wordpress/wp-content/ratings.php',
out_data,
function(INFO) {
$(widget).data( 'fsr', INFO );
set_votes(widget);
},
'json'
);
});
$('.ratings_stars').hover(
function() {
$(this).prevAll().andSelf().addClass('ratings_over');
$(this).nextAll().removeClass('ratings_vote');
},
function() {
$(this).prevAll().andSelf().removeClass('ratings_over');
set_votes($(this).parent());
}
);
$('.ratings_stars').bind('click', function() {
var star = this;
var widget = $(this).parent();
var clicked_data = {
clicked_on : $(star).attr('class'),
widget_id : $(star).parent().attr('id')
};
$.post(
'http://localhost/url/wordpress/wp-content/ratings.php',
clicked_data,
function(INFO) {
widget.data( 'fsr', INFO );
set_votes(widget);
},
'json'
);
});
});
function set_votes(widget) {
var avg = $(widget).data('fsr').whole_avg;
var votes = $(widget).data('fsr').number_votes;
var exact = $(widget).data('fsr').dec_avg;
window.console && console.log('and now in set_votes, it thinks the fsr is ' + $(widget).data('fsr').number_votes);
$(widget).find('.star_' + avg).prevAll().andSelf().addClass('ratings_vote');
$(widget).find('.star_' + avg).nextAll().removeClass('ratings_vote');
$(widget).find('.total_votes').text( votes + ' votes recorded (' + exact + ' rating)' );
}
</script>

To solve this all I had to do was place my ratings.php file and ratings.data.txt within my wordpress theme folder and link the custom javascript to these files within my header.php file. The javascript now operates properly. This is not the proper way to do this though, ideally I should use the wp_enqueue_scripts hook in the header.php and have the custom css and js in the css/js folders. But for now this temporary fix works and I can continue experimenting.

Related

Woocommerce: How to show Product Attribute name and Category name on title

Using the answer provided in this thread (Woocommerce: How to show Product Attribute name on title when in a category page and "filtering" products via '?pa_attribute=' on address bar) I would like to display the category as well as the attribute name. I have a separate JS function that is currently updating the page_title when a filter is applied but that is only loading after ajax has finished. So in this event it would not load till after the filter is applied.
In the event that a user uses the nav to get to the category, currently only the attribute is displaying in the page_title. Looking to also display the category. I believe this would work out of the box if I organized my products in to subcategories but due to how the filtering is being set up I elected not to go this route. I can explain in further detail why I had to take this approach if anyone is interested.
I have left the commented out code in so that you can see the approach I was attempting to take. If this is confusing can edit it out.
add_filter( 'woocommerce_page_title', 'custom_woocommerce_page_title', 15, 2 );
function custom_woocommerce_page_title( $page_title ) {
if ( is_archive() ) {
$exists_attr = false;
foreach ( $_GET as $index => $value ) {
if ( substr( $index, 0, 3 ) === 'pa_' ) {
//$cat_id = wc_category_taxonomy_id_by_name( $index );
$attr_id = wc_attribute_taxonomy_id_by_name( $index );
if ( $attr_id === 0 && $cat_id ) {
continue;
}
if ( ! $exists_attr /* && ! $exists_cat */) {
$exists_attr = true;
//$exists_cat = true;
$page_title .= ' ';
} else {
$page_title .= ' ';
}
//$terms = get_the_terms( $post->ID, 'product_cat' );
$term = get_term_by( 'slug', esc_html( $value ), $index );
$page_title = /*$terms->name . ': ' . */ $term->name;
}
}
}
// Need to add category name after attribute term name.
return $page_title;
}
Also, I have included the JS I am using to apply page_title in the event a filter selection occurs. Ideally it would be great if I could handle it all via a JS file as I am much more familiar with JS and just starting to dive in to php. I am using the WOOF - WooCommerce Products Filter and modifying some of the code to accomplish what I need.
(function() {
var machineEl = document.getElementsByClassName('woof_select woof_select_pa_machine')[0];
var processEl = document.getElementsByClassName('woof_select woof_select_pa_processing')[0];
var optionMachine = machineEl.querySelector("option[selected='selected']");
var optionProcess = processEl.querySelector("option[selected='selected']");
var machineValue = optionMachine.innerHTML;
var processValue = optionProcess.innerHTML;
var result = document.getElementsByClassName('woocommerce-products-header__title page-title')[0];
if (machineValue != 'Product Machine' && processValue != 'Product Processing') {
result.innerHTML = machineValue + " " + processValue;
}
else if (machineValue != 'Product Machine') {
result.innerHTML = machineValue;
}
else if (processValue != 'Product Processing') {
result.innerHTML = processValue;
}
})()
So was able to get this to work by taking my JS and adding it in as a script within my functions.php. So essentially I was able to eliminate the custom_woocommerce_page_title filter.
Function.php
<?php
add_action('wp_footer', 'onLoadPageTitle');
function onLoadPageTitle() {
?>
<script>
machineEl = document.getElementsByClassName('woof_select woof_select_pa_machine')[0];
processEl = document.getElementsByClassName('woof_select woof_select_pa_processing')[0];
optionMachine = machineEl.querySelector("option[selected='selected']");
optionProcess = processEl.querySelector("option[selected='selected']");
if (optionMachine != null) {
machineValue = optionMachine.innerHTML;
}
else {
machineValue = "";
}
if (optionProcess != null) {
processValue = optionProcess.innerHTML;
}
else {
processValue = "";
}
result = document.getElementsByClassName('woocommerce-products-header__title page-title')[0];
result.innerHTML = machineValue + " " + processValue;
</script>
<?php
}
?>
Then the woof woocommerce filter js that updates the title when a new select occurs after the AJAX.
(function() {
machineEl = document.getElementsByClassName('woof_select woof_select_pa_machine')[0];
processEl = document.getElementsByClassName('woof_select woof_select_pa_processing')[0];
optionMachine = machineEl.querySelector("option[selected='selected']");
optionProcess = processEl.querySelector("option[selected='selected']");
if (optionMachine != null) {
machineValue = optionMachine.innerHTML;
}
else {
machineValue = "";
}
if (optionProcess != null) {
processValue = optionProcess.innerHTML;
}
else {
processValue = "";
}
result = document.getElementsByClassName('woocommerce-products-header__title page-title')[0];
result.innerHTML = machineValue + " " + processValue;
})()
will probably pare it down by just calling the script function from within the woof js after ajax.

Alternative to AJAX setTimeout?

I have a script that uses ajax to retrieve PHP data for video files on my server (godaddy shared hosting), and then play the video file on my php page if it is the highest ranked video, like so:
<script id="source" language="javascript" type="text/javascript">
$(function refreshscreen ()
{
$.ajax({
url: 'screen.php',
data: "",
pass to api.php
dataType: 'json',
success: function(data)
{
var id = data[0];
var name = data[1];
var votes = data[2];
var video = data[3];
var image = data[4];
$('.screen').hide(); $("#video"+id+"").show();
var whichvideo = "thevideo" + id;
var videoplay = document.getElementById(whichvideo);
var killvideo = document.getElementsByClassName('videobg');
var allvideos = document.getElementsByClassName("videobg");
for(var x=0; x < allvideos.length; x++)
{
var allvideosid = document.getElementById(allvideos[x]);
if ($(allvideos[x]).attr("id") == whichvideo) {
allvideos[x].play();
} else {
allvideos[x].pause();
}
}
},
complete: function() {
// Schedule the next request when the current one's complete
setTimeout(refreshscreen, 5000);
}
});
});
And then the screen.php referenced above:
<?php
$host = "localhost";
$user = "myuserhere";
$pass = "mypasshere";
$databaseName = "mydbnamehere";
$tableName = "mytablenamehere";
$con = mysql_connect($host,$user,$pass);
$dbs = mysql_select_db($databaseName, $con);
$result = mysql_query("SELECT * FROM $tableName ORDER BY votes DESC");
$array = mysql_fetch_row($result);
echo json_encode($array);
?>
This all works fine, and the video switches as it should when a new higher ranked video is voted in, however, periodically, the video will freeze when playing, completely at random. My guess is that we are overloading the server with the setTimeout function of the ajax script, so I am wondering if there is a way I can clean up this script to avoid the freezing, or an alternative method.
Thanks in advance.
I've cleaned up the code:
var currentID = -1;
function refreshscreen() {
$.getJSON('screen.php', data => {
var topID = data[0];
// Schedule the next request
setTimeout(refreshscreen, 5000);
if (topID === currentID) return; // top rated video hasn't changed
$('.screen').hide();
$("#video" + topID).show();
var pauseID = "thevideo" + currentID;
var playID = "thevideo" + topID;
$(".videobg").each(function() {
if (this.id === pauseID) this.pause();
if (this.id === playID) this.play();
});
currentID = topID;
});
}
$(document).ready(function () {
refreshscreen();
});
The biggest change is keeping track of the currently playing video and exiting right away if it hasn't changed. Other than that I got rid of all the unused variables and used jQuery throughout. This should be much easier to debug at the least and might fix the error to boot.

Twitch Button (HTML/JScript w bootstrap)

Hello everyone I've tried everything I can think of to make this work. I know it does return stream = null or active through use in the browser, but It will not apply my buttons to my page. Not so good with javascript can anyone point me in the right direction.
<script type="text/javascript">
(function() {
var user_name, api_key;
user_name = "Undead_Atomsk";
api_key = "************************";
twitch_widget.attr("href","https://twitch.tv/" + user_name);
$.getJSON('https://api.twitch.tv/kraken/streams/' + user_name + '?client_id=' + api_key + '&callback=?', function(data) {
if (data.stream) {
document.write(Live!);
} else {
document.write(Offline!);
}
});
})();
</script
Took your advice and used browser tools "Completely forgot about those".
I added this line to my html.
I then made a .js file and used the following code everything works now the twitch API is just slow!
(function() {
var user_name, api_key, twitch_widget;
user_name = "Undead_Atomsk";
api_key = "********************";
twitch_widget = $("#twitch-widget");
twitch_widget.attr("href","https://twitch.tv/" + user_name);
$.getJSON('https://api.twitch.tv/kraken/streams/' + user_name +'?client_id=' + api_key + '&callback=?', function(data) {
if (data.stream) {
document.getElementById("twitch-btn").innerHTML = 'Live!';
} else {
document.getElementById("twitch-btn").innerHTML = 'Offline!';
}
});
})();

Javascript - callback function

This seems in my head like it should work but I cant figure out why it doesn't:
(function ($) {
$.fn.extend({
facebook: function (opts, callbackFnk) {
var $this = this;
...
...
...
$this.fbGetFriends = function( clback ){
jsonUrl = fbMe + '/friends?access_token=' + token + '&callback=?';
$.getJSON( jsonUrl, function( json ){
console.log(json.data[0].name);
clback.call(json);
});
}
...
...
...
In the console log the first name appears
In my other script:
var facebook = $.fn.facebook(
{
myClientId : '###############',
mySecret : '##############'
}
);
facebook.fbOnLogin = function(){
user = facebook.userDetails();
token = facebook.getToken();
facebook.fbGetFriends(function( json ){
for ( var i in json ) {
console.log( 'friends: ' + i + ' ' + json[i] );
}
});
}
In console log im getting nothing displayed and in previous tests its displaying errors data undefined.
Can anyone tell me where im going wrong?
regards
You don't need clback.call, just clback(json) is enough.

JavaScript jQuery binding

I am using jQuery to create an anchor and bind it with JavaScript function as follow:
$(document).ready
(
function()
{
var test = function(arg)
{
alert(arg);
}
var anotherTest = function(arg)
{
do something;
}
$('#id').click
(
var content = "Hello world";
var anchor = "<a href='javascript:void(0);' onclick='test(\"" + content + "\")' >test</a>";
$('#DivToBind').prepend(anchor);
);
}
);
And the problem is: the test function always alerts "a", no matter what the value of content is. If I change onclick function test to anotherTest, nothing happens but "anotherTest is not defined" appeared in the error console
Edit
To better identify my problem, I summarise my real code as follow
$(document).ready
(
function()
{
var deleteComment = function (comment)
{
commentInfo = comment.split('_');
var postid = commentInfo[0];
var enum = commentInfo[1];
var parentid = commentInfo[2];
var user = commentInfo[3];
var author = commentInfo[4];
var date = commentInfo[5];
$.get
(
"ajaxhandle.php",
{ref: 'commentdelete', pid: postid, d: date},
function(text)
{
if (text)
{
//alert(comment);
$('#' + comment).html('');
}
else
{
alert("Something goes wrong");
}
},
'text'
);
};
var test = function(arg) {alert(arg);};
$('#postCommentButton').click
(
function ($e)
{
$e.preventDefault();
var comment = $('#postdata').val();
var data = $('form#commentContent').serialize();
//alert(data);
$.post
(
"ajaxhandle.php",
data,
function($xml)
{
$xml = $($xml);
if ($xml)
{
//alert(45);
var success = $xml.find("success").text();
if (success == 1)
{
$('#postdata').val("");
var id = $xml.find("id").text();
var reference = $xml.find("reference").text();
var parentid = $xml.find("parentid").text();
var user = $xml.find("user").text();
var content = $xml.find("content").text();
var authorID = $xml.find("authorid").text();
var authorName = $xml.find("authorname").text();
var converteddate = $xml.find("converteddate").text();
var date = $xml.find("date").text();
var avatar = $xml.find("avatar").text();
comment = id + '\_wall\_' + parentid + '\_' + user + '\_' + authorID + '\_' + date;
//alert(comment);
var class = $('#wallComments').children().attr('class');
var html = "<div class='comment' id='" + comment + "' ><div class='postAvatar'><a href='profile.php?id=" + authorID + "'><img src='photos/60x60/" + avatar +"' /></a></div><div class='postBody' ><div class='postContent'><a href='profile.php?id=" + authorID + "'>" + authorName + " </a> <span>" + content + "</span><br /><div class='timeline'>Posted " + converteddate + "<br /><a href=''>Comment</a> | <a href=''>Like</a> | <a href='javascript:void(0);' onclick='deleteComment(\"" + comment + "\")' class='commentDelete' >Delete</a></div></div></div><div style='clear:both'></div><hr class='hrBlur' /></div>";
if (class == 'noComment')
{
//alert($('#wallComments').children().text());
//alert(comment);
$('#noComment').html('');
$('#wallComments').prepend(html);
}
else if(class = 'comment')
{
//alert(comment);
$('#wallComments').prepend(html);
}
}
else
{
alert("Something goes wrong");
}
}
else
alert("Something goes wrong");
},
'xml'
);
}
);
$(".comment").find('.commentDelete').click
(
function($e)
{
$e.preventDefault();
var comment = $(this).parent().parent().parent().parent().attr('id');
deleteComment(comment);
}
);
}
);
var test=... is inside a function, it's not going to be in scope on the page when you want to call it onclick the anchor.
to make it global you can leave off the var.
you could also do something like:
$(document).ready
(
function()
{
var test = function(arg)
{
alert(arg);
}
var anotherTest = function(arg)
{
//do something;
}
$('#id').click
(
function(){
var content = "Hello world";
var anchor = "<a href='javascript:void(0);'>test</a>";
$(anchor).click(function(){ test(content); });
$('#DivToBind').prepend(anchor);
});
}
);
Your example is incomplete. The call to bind click is missing a function wrapper (so it's a syntax error and won't even parse); there is no reference to calling anotherText;, and the anchor is never actually created, only a string. So it's not really possible to fix from there.
In general avoid creating dynamic content from HTML strings. As you are not HTML-escaping content, if it contains various special characters (<"'&) your script will fail and you may have a cross-site-scripting security hole. Instead, create the anchor and then write any dynamic attributes or event handlers from script:
$(document).ready(function() {
function test(arg) {
alert(arg);
}
$('#id').click(function() {
var content= 'Hello world';
$('test').click(function(event) {
test(content);
event.preventDefault();
}).appendTo('#somewhere');
});
});
It may be preferable to use a <button> styled like a link rather than a real link, since it doesn't go anywhere. A <span> styled as a link is another possibility, preferably with a tabindex attribute to make it keyboard-accessible in that case.
I think a lot of code is missing here.
But anyway, why won't you use jQuery power to bind events?
$(document).ready(function() {
var test = function(arg) {
alert(arg);
}
var anotherTest = function(arg) {
alert("another: " + arg);
}
$('#id').click(function() {
var content = "Hello world";
var anchor = $("<a href='#'>test</a>").click(function() { test(content); });
//apply anchor to DOM
});
});
I think this is what you're looking for:
$(document).ready(function() {
var test = function(arg) {
alert(arg);
};
var anotherTest = function(arg) {
alert("we did something else:" + arg);
};
$('#id').click(function() {
var content = "Hello world";
var anchor = $("<a>test</a>").click(function(event) {
event.stopPropagation();
// test(content);
anotherTest(content);
});
$('#DivToBind').prepend(anchor);
});
}
);
This example shows good use of event.stopPropagation(). Setting an anchor's href to void() or # is often a mistake.
If you're using jQuery, I would recommend using its event handler functions like so:
$(document).ready(function() {
var test = function(arg){
alert(arg);
}
var anotherTest = function(arg){
// do something;
}
$('#id').click( function(event){
var content = "Hello world";
var anchor = $("<a>test</a>");
anchor.click(function(event){
event.preventDefault(); // instead of javascript:void();
test(content);
});
$('#DivToBind').prepend(anchor);
});
});

Categories

Resources