Rich snippets: ratings called by javascript do not appear in Google - php

I implemented a stars rating system on my one page html site. The system uses jQuery, AJAX and PHP. I found the code here and it works well regarding the storage of the ratings and the updating of the votes.
This is the Javascript code:
// STARS
$(document).ready(function() {
$('.rate_widget').each(function(i) {
var widget = this;
var out_data = {
widget_id : $(widget).attr('id'),
fetch: 1
};
$.post(
'ratings.php',
out_data,
function(INFO) {
$(widget).data( 'fsr', INFO );
set_votes(widget);
},
'json'
);
});
$('.ratings_stars').hover(
// Handles the mouseover
function() {
$(this).prevAll().andSelf().addClass('ratings_over');
$(this).nextAll().removeClass('ratings_vote');
},
// Handles the mouseout
function() {
$(this).prevAll().andSelf().removeClass('ratings_over');
// can't use 'this' because it wont contain the updated data
set_votes($(this).parent());
}
);
// This actually records the vote
$('.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(
'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);
$(widget).find('.avg_votes').text(exact);
}
// END STARS
There is a PHP script for storing and update the ratings:
$rating = new ratings($_POST['widget_id']);
isset($_POST['fetch']) ? $rating->get_ratings() : $rating->vote();
class ratings {
var $data_file = './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() {
# Get the value of the vote
preg_match('/star_([1-5]{1})/', $_POST['clicked_on'], $match);
$vote = $match[1];
$ID = $this->widget_id;
# Update the record if it exists
if($this->data[$ID]) {
$this->data[$ID]['number_votes'] += 1;
$this->data[$ID]['total_points'] += $vote;
}
# Create a new one if it doesn't
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();
}
# ---
# end class
}
And the ratings are obtained through this code inside my html page:
<div class='movie_choice'>
<div id="r1" class="rate_widget">
<div class="star_1 ratings_stars"></div>
<div class="star_2 ratings_stars"></div>
<div class="star_3 ratings_stars"></div>
<div class="star_4 ratings_stars"></div>
<div class="star_5 ratings_stars"></div>
<div itemprop="aggregateRating" itemscope itemtype="http://schema.org/AggregateRating">
<div class="avg_votes" style="display: table-cell; float: left;" itemprop="ratingValue"></div><div style="float:left;">/</div><div itemprop="bestRating" style="float:left;">5</div><div style="float: left;">, </div><div class="total_votes" style="display: table-cell; float:left;" itemprop="ratingCount"></div><div style="width: 200px;"> voti</div>
</div>
</div>
</div>
The method works and show the correct average ratings and the total number of votes. The problem is that Google does not recognize the ratingValue. In the testing tool for structured data, Google says me that "ratingValue field can't be empty". In other words, for Google the line of code <div class="avg_votes" style="display: table-cell; float: left;" itemprop="ratingValue"></div> means that ratingValue is empty, although the rating is correctly showed in the page.
I suppose the problem is that this method is based on jQuery and my page is in html, but I can't find the solution for this issue.
Do you know the source of the problem, please?

Google doesn't run javascript when indexing your webpage, so all it will see is the empty html elements on the page and not the rating (since the rating is generated by javascript). If you want google to see the rating, you will need to generate the correct html on the server when you serve the page. This way, google will see the html with the ratings.

Related

Why I don't See The Parameters Passed in Address Bar Using Get Request

I'm using javascript / query to send the content of a form using Ajax and Get request to PHP. Then php will return an array containing quotes and authors. I noticed that I don't see my parameters shown in the address bar even though I'm using a GET request. And everytime GET rquest is used you see something like "search.php?q=john+smith". But my code is not showing that.....Does anyone know why? Thanks
$(document).ready(function() {
var outputList = document.getElementById("list-output");
var outputHead = document.getElementById("quote-hd");
var quoteUrl = "http://localhost/quote/php/quote.php"
var plcImage = "https://via.placeholder.com/40x40.png";
var searchData;
//listener for search button
$("#search").click(function() {
outputList.innerHTML = ""; //empty html output
searchData = $("#search-box").val();
searchData = searchData.replace(' ', '+'); //for url
//handling empty search input field
if(searchData === "" || searchData === null) {
displayError();
}
else {
// console.log(searchData);
$.ajax({
type: 'GET',
url: 'php/search.php',
data: 'query='+searchData,
async: true,
dataType: "text",
success: function(res) {
if (res.totalItems === 0) {
alert("no result!.. try again")
}
else {
$("#title").animate({'margin-top': '5px'}, 1000); //search box animation
$(".book-list").css("visibility", "visible");
displayResults(res);
}
},
error: function () {
alert("Something went wrong.. <br>"+"Try again!");
}
});
}
$("#search-box").val(""); //clearn search box
});
function displayResults(res) {
var result = $.parseJSON(res);
outputHead.style.visibility = "visible";
for (var i = 0; i < result.length; i++) {
var quote = result[i].split('--')[0];
var author = result[i].split('--')[1];
// in production code, item.text should have the HTML entities escaped.
outputList.innerHTML += '<div class="row mt-4">' + formatOutput(quote, author, plcImage) + '</div>';
}
}
function formatOutput(quote, author, plcImage) {
var htmlCard = `<div class="col-lg-12">
<div class="card" style="">
<div class="row no-gutters">
<div class="col-md-2">
<img src="${plcImage}" class="card-img">
</div>
<div class="col-md-9">
<div class="card-body">
<h5 class="card-title quote-cls">${quote}</h5>
<p class="card-text author-cls">Author: ${author}</p>
</div>
</div>
</div>
</div>
</div>`
return htmlCard;
}
function displayError() {
alert("search term can not be empty!")
}
});
php
<?php
// require 'db/db_connection.php';
if($_GET['query']) {
$author = $_GET['query'];
$quotes = '[
"He who fights with monsters might take care lest he thereby become a monster. And if you gaze for long into an abyss, the abyss gazes also into you. --Nietzsche",
"To live is to suffer, to survive is to find some meaning in the suffering. --Nietzsche",
"One must still have chaos in oneself to be able to give birth to a dancing star. --Nietzsche",
"Reason is not automatic. Those who deny it cannot be conquered by it. Do not count on them. Leave them alone. --Ayn Rand",
"Contradictions do not exist. Whenever you think you are facing a contradiction, check your premises. You will find that one of them is wrong. --Ayn Rand"
]';
echo $quotes;
}
?>

Codeigniter scrollpagination

I am using jquery plugin scrollpagination in codeigniter i am facing problem that my loop does not terminate and alos not giving accurate result.
this is my html code
<div id="main">
<div id='friend_display'>
<?php if($list->num_rows() > 0 ){
foreach($list->result() as $show)
{ ?>
<div class="image-box" style="margin-left:30px" id='image-holder' >
<div class="photo-cover">
<img width="160px" height="117px" src="<?=base_url()?>uploads/user_images/friends/<?php echo $show->user_image;?>" alt="" />
</div>
<p class="photo-name"><b><?php echo $show->user_name;?></b></p>
</div>
<?php } } else { echo '<div align="center" style="color:#FF0000; font-size:17px; font-weight:bold">You have no Friends yet</div>';}?>
<div class="cl"> </div>
</div></div>
this is script
<script type="text/javascript">
var page_num = 1;
$(function(){
$('#friend_display').scrollPagination({
'contentPage': '<?=base_url()?>friends/load_more', // the url you are fetching the results
'contentData': {page_num:$('.image-box').size()}, // these are the variables you can pass to the request, for example: children().size() to know which page you are
'scrollTarget': $(window), // who gonna scroll? in this example, the full window
'heightOffset': 10, // it gonna request when scroll is 10 pixels before the page ends
'beforeLoad': function(){ // before load function, you can display a preloader div
$('#loading1').fadeIn();
},
'afterLoad': function(elementsLoaded){ // after loading content, you can use this function to animate your new elements
$('#loading1').fadeOut();
var i = 0;
$(elementsLoaded).fadeInWithDelay();
page_num:$('.image-box').size();
}
});
// code for fade in element by element
$.fn.fadeInWithDelay = function(){
var delay = 0;
return this.each(function(){
$(this).delay(delay).animate({opacity:1}, 200);
delay += 100;
});
};
});
</script>
and this is my php function
function load_more()
{
$offset = $this->input->post('page_num');
$list = $this->friends_model->show_friends($offset);
if($list->num_rows()>0)
{
foreach($list->result() as $show)
{?>
<div class="image-box" style="margin-left:30px" id='image-holder'>
<div class="photo-cover">
<img width="160px" height="117px" src="<?=base_url()?>uploads/user_images/friends/<?php echo $show->user_image;?>" alt="" />
</div>
<p class="photo-name"><b><?php echo $show->user_name;?></b></p>
</div>
<?php } ?>
<div class="cl"> </div>
<?php
}
else
{
//echo(333);
}
}
in db i jst shoing main query
$this->db->limit(12,$offset);
can someone tell me what i am missing?
Open this Link to wathch complete code.Scroll Pagination
I belive that the way you are fetching offset isn't correct. (Thought I'm not sure because I don't know what is in your POST['page_num'])
$offset = $this->input->post('page_num');
It looks like you fetch the page number, but the offset in limit function should be how much row has to be skipped. So if you are showing 12 results per "tick" offset should be 12*page_number
$this->db->limit(12,$offset*12);
If you leave offset to page number, you will get wrong results:
limit(12,[0,1,2,...]) // items 1-12, 2-13, 3-14 etc...
limit(12,[0,12,24....] //items 1-12, 13-24, 25-32 etc...
Here i solve this problem in my own way you can try this.In your script remove this line
'contentData': {page_num:$('.image-box').size()},
and add this line
'childClass' : '.image-box',
After open scrollpagination.js file then replace this line data: opts.contentData, with this data: {page_num : $(obj).children(opts.childClass).size()},. Again replace 'contentData' : {}, this line with 'childClass' : '.datalist',.
In your function display_friends() please replace exit; function with this line echo '<input type="hidden" id="nodata" value="1" />'; . After that write your script look like this :
$(function(){
$('#nomoreresult').hide();
$('#loading1').hide();
$('#friend_display').scrollPagination({
'contentPage': 'Your_Url', // the url you are fetching the results
// these are the variables you can pass to the request, for example: children().size() to know which page you are
'childClass' : '.image-box',
'scrollTarget': $(window), // who gonna scroll? in this example, the full window
'heightOffset': 10, // it gonna request when scroll is 10 pixels before the page ends
'beforeLoad': function(){ // before load function, you can display a preloader div
$('#loading1').show().fadeIn();
},
'afterLoad': function(elementsLoaded){
// after loading content, you can use this function to animate your new elements
$('#loading1').hide().fadeOut();
$(elementsLoaded).fadeInWithDelay();
if($('#nodata').val() == '1'){
$('#friend_display').stopScrollPagination();
$('#loading1').hide();
$('#nomoreresult').show().fadeIn();
}
}
});
// code for fade in element by element
$.fn.fadeInWithDelay = function(){
var delay = 0;
return this.each(function(){
$(this).delay(delay).animate({opacity:1}, 200);
delay += 1000;
});
};
Did you try jQuery.noConflict()?
<script type="text/javascript">
var page_num = 1;
jQuery.noConflict();
$(function(){...
Edit2:
It seems your offset works wrong. According to http://pastebin.com/MC1KZm8y
Find:
$offset = $this->input->post('page_num');
$list = $this->friends_model->find($offset);
Replace:
$page_line = 6; //for example
$page_num = $this->input->post('page_num');
$offset = ($page_num -1) * $page_line;
$list = $this->friends_model->find($offset);
Add this missing code inside the afterLoad:function(){.. code also this should stop looping your pagination make sure to add exactly same id that you entered for the scrollpagination id <div id='friend_display'>
if ($('#friend_display').children().size() > 100){ //set the condition to where to stop
// if more than 100 results already loaded, then stop pagination (only for testing)
$('#nomoreresults').fadeIn(); //if you want to show message like "No more result!" use this
$('#friend_display').stopScrollPagination();// this is the most important function call
}
inside .scrollPagination({.. change 'contentPage': '<?php echo base_url();?>controller/action' inside this action(){ $this->load->view('that_you_want_to_display'); it means your display_friends() method only should contain the view file that want to load and parse and the data that you want to display and inside that view echo your data using the foreach

Duplicate photos in instagram pagination

I'm trying to pull photos from specific tag. Found an awesome tutorial and I've managed to pull photos from Instagram with pagination.
The problem I'm facing now is duplicate photos being displayed if it reaches to the end of the photos.
HTML Source
<!DOCTYPE html>
<html>
<head>
<script src='http://code.jquery.com/jquery-1.7.2.min.js' type='text/javascript' charset='utf-8'></script>
<script src='javascripts/application.js' type='text/javascript' charset='utf-8'></script>
<link rel='stylesheet' href='stylesheets/application.css' type='text/css' media='screen'>
<title>Photo Stream </title>
<meta name="description" content="Search for instagram images online.">
<meta name="author" content="Omar Sahyoun">
</head>
<body>
<!--<form id='search'>
<button class="button" type="submit" id="search-button" dir="ltr" tabindex="2">
<span class="button-content">Search</span>
</button>
<div class='search-wrap'>
<input class='search-tag' type='text' tabindex='1' value='cats' />
</div>
</form>-->
<h2 id="search">Photo Stream </h2>
<div id='photos-wrap'>
</div>
<div class='paginate'>
<a class='button' style='display:none;' data-max-tag-id='' href='#'>View More...</a>
</div>
</body>
</html>
Javascript File
// Add trim function support for IE7/IE8
if(typeof String.prototype.trim !== 'function') {
String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, '');
}
}
// Instantiate an empty object.
var Instagram = {};
// Small object for holding important configuration data.
Instagram.Config = {
clientID: 'xxxx',
apiHost: 'https://api.instagram.com'
};
// Quick and dirty templating solution.
Instagram.Template = {};
Instagram.Template.Views = {
"photo": "<div class='photo'>" +
"<a href='{url}' target='_blank'><img class='main' src='{photo}' width='250' height='250' style='display:none;' onload='Instagram.App.showPhoto(this);' /></a>" +
"<span class='heart'><strong>{count}</strong></span><span class='comment'><strong>{count2}</strong></span>" +
"<span class='avatar'><iframe src='//www.facebook.com/plugins/like.php?href={url}&send=false&layout=button_count&width=40&show_faces=true&action=like&colorscheme=light&font&height=21&' scrolling='no' frameborder='0' style='border:none; overflow:hidden; width:80px; height:21px;' allowTransparency='true'></iframe></span>" +
"</div>"
};
Instagram.Template.generate = function(template, data){
var re, resource;
template = Instagram.Template.Views[template];
for(var attribute in data){
re = new RegExp("{" + attribute + "}","g");
template = template.replace(re, data[attribute]);
}
return template;
};
// ************************
// ** Main Application Code
// ************************
(function(){
function init(){
bindEventHandlers();
}
function toTemplate(photo){
photo = {
count: photo.likes.count,
count2: photo.comments.count,
avatar: photo.user.profile_picture,
photo: photo.images.low_resolution.url,
url: photo.link
};
return Instagram.Template.generate('photo', photo);
}
function toScreen(photos){
var photos_html = '';
$('.paginate a').attr('data-max-tag-id', photos.pagination.next_max_id)
.fadeIn();
$.each(photos.data, function(index, photo){
photos_html += toTemplate(photo);
});
$('div#photos-wrap').append(photos_html);
}
function generateResource(tag){
var config = Instagram.Config, url;
if(typeof tag === 'undefined'){
throw new Error("Resource requires a tag. Try searching for cats!");
} else {
// Make sure tag is a string, trim any trailing/leading whitespace and take only the first
// word, if there are multiple.
tag = String(tag).trim().split(" ")[0];
}
url = config.apiHost + "/v1/tags/" + tag + "/media/recent?callback=?&count=10&client_id=" + config.clientID;
return function(max_id){
var next_page;
if(typeof max_id === 'string' && max_id.trim() !== '') {
next_page = url + "&max_id=" + max_id;
}
return next_page || url;
};
}
function paginate(max_id){
$.getJSON(generateUrl(tag), toScreen);
}
function search(tag){
resource = generateResource(tag);
$('.paginate a').hide();
$('#photos-wrap *').remove();
fetchPhotos();
}
function fetchPhotos(max_id){
$.getJSON(resource(max_id), toScreen);
}
function bindEventHandlers(){
$('body').on('click', '.paginate a.button', function(){
var tagID = $(this).attr('data-max-tag-id');
fetchPhotos(tagID);
return false;
});
// Bind an event handler to the `click` event on the form's button
$('form#search button').click(function(){
// Extract the value of the search input text field.
var tag = $('input.search-tag').val();
// Invoke `search`, passing `tag`.
search(tag);
// Stop event propagation.
return false;
});
}
function showPhoto(p){
$(p).fadeIn();
}
Instagram.App = {
search: search,
showPhoto: showPhoto,
init: init
};
})();
$(function(){
Instagram.App.init();
// Start with a search on cats; we all love cats.
Instagram.App.search('hwplus');
});
Please help me to find a way to disable the 'View More' button if photos have reached the end.
And is there a way to add cache in JSON object and fetch variables from Javascript?
Thanks and appreciate.
Once you reach the end of the photos, the next_max_tag_id won't exist. You'll need to check if next_max_tag_id exists and if not, disable the button. You'll implement your new code on this line, maybe make a variable for photos.pagination.next_max_id and when the user clicks the button, check if the variable is defined.
Untested code:
var next_max = photos.pagination.next_max_id;
if (next_max == 'undefined') {
var next_max = 'end';
$('.paginate a').addClass('disabled');
}
//define .disabled in your CSS
$('.paginate a').attr('data-max-tag-id', next_max).fadeIn();

How can I display value of a div with a button click?

I am currently working with a wmd editor and jQuery-UI tabs. I have created an ajax/js function that will submit (when next button is clicked) the wmd-preview value and then php echo the result in tab 2. The problem is that I am not getting any results displayed. I am not looking for the textarea value but the div #wmd-preview value. How can I display the value of the div wmd-preview through my ajax/function?
JS
<script>
$(function () {
var $tabs = $('#tabs').tabs({
disabled: [0, 1],
select: function () {
$.ajax({
type: "POST",
url: "post_tabs.php",
data: {
"wmd": $("#wmd-preview").val(),
},
success: function (result) {
$("#tab-2").html(result);
}
});
}
});
$(".ui-tabs-panel").each(function (i) {
var totalSize = $(".ui-tabs-panel").size() - 1;
if (i != totalSize) {
next = i + 2;
$(this).append("<a href='#' class='next-tab mover' rel='" + next + "'>Next Page »</a>");
}
if (i != 0) {
prev = i;
$(this).append("<a href='#' class='prev-tab mover' rel='" + prev + "'>« Prev Page</a>");
}
});
$('.next-tab').click(function () {
var currentTab = $('#tabs').tabs('option', 'selected');
if (
(
currentTab == 0 && /*(B)*/
$.trim($('#wmd-input').val()).length > 0
)
) {
var tabIndex = $(this).attr("rel");
$tabs.tabs('enable', tabIndex).tabs('select', tabIndex).tabs("option", "disabled", [0, 1]);
} else {
switch (currentTab) {
case 0:
alert('Please fill out all the required fields.', 'Alert Dialog');
break;
}
}
console.log("preventing default");
return false;
});
$('.prev-tab').click(function () {
var tabIndex = $(this).attr("rel");
$tabs.tabs('enable', tabIndex).tabs('select', tabIndex).tabs("option", "disabled", [0, 1]);
return false;
});
});
</script>
PHP
<?
if (isset($_POST['wmd'])){
$wmd = $_POST['wmd'];
echo ('<div id="text_result"><span class="resultval"><h2>Textarea Echo result:</h2>'.$wmd.'</span></div>');
}
?>
HTML
<div id="tab-1" class="ui-tabs-panel ui-tabs-hide">
<div id="wmd-button-bar"></div>
<textarea id="wmd-input" name="wmd-input" cols="92" rows="15" tabindex="6"></textarea>
<div id="wmd-preview"></div>
</div>
<div id="tab-2" class="ui-tabs-panel ui-tabs-hide">
</div>
PHP code should start with <?php , yours start with <? which is incorrect.
When you see PHP code presented as text - it should tell you it is not running, this is why you keep getting output like '.$wmd.''); } ?> instead of real PHP echo output.
The other comment still stands as well - you should either use $("#wmd-preview").html() or $("#wmd-input").val() but you cannot use val on divs, it does not work.
In this scenario $("#wmd-input").val() is the better choice just because this is the reason input fields exist - to get input.
Let me know if there are more questions I can help with.

Animating a div height adjustment using javascript

I'm still a newbie when it comes to javascript but I am having trouble animating a div that I want to essentially slide up over an image from the bottom when a user runs their cursor over it. I have had success using an almost identical code to fade a div in and out of view, but for some reason it does not want to work in this context.. Here is the html/php side of it:
echo '
<div class="still" style="clear:left">
<div class="thumbnail" onmouseover="show_title('.$work['position'].');" onmouseout="hide_title('.$work['position'].');">
<div class="still_title" id="still_title'.$work['position'].'">
<br>'.$work['title'].'
</div>
<img src="'.$work['thumbnail'].'" class="still_img">
</div>
<div class="description"><p>'.$work['description'].'</p>
</div>
</div>
';
And here is the javascript that I'm having an issue getting to function properly..
var i = 0;
function show_title(position) {
var titledelay = setInterval(show_title_animation(position),30);}
function show_title_animation(position) {
still_id = "still_title" + position;
title_position = document.getElementById(still_id);
while (i<100) {
i++;
title_position.style.height = i + "px";
}
if (i==100) {
alert(title_position);
clearInterval(titledelay);
}
}
Edit: It works now but it isn't resetting after it completes the loop..
var i = 0;
function show_title(position) {
var titledelay = setInterval(function(){ show_title_animation(position); }, 10);
}
function show_title_animation(position) {
still_id = "still_title" + position;
title_position = document.getElementById(still_id);
while (i<50) {
i++;
title_position.style.height = i + "px";
break;
}
if (i==50) {
clearInterval(titledelay);
i=0;
}
}
The problem is with the line
var titledelay = setInterval(show_title_animation(position),30);
Instead of passing a function with parameter, you should only pass in a function reference, like
var titledelay = setInterval(show_title_animation, 30); // This would require position declared as global variable outside the scope of the function
or
var titledelay = setInterval(function(){ show_title_animation(position) }, 30);

Categories