Should be fairly simple and have had a good search around the web, but most solutions are too complex.
Trying to implement a jquery menu system and need to add a body ID to the main body of my Wordpress site in order to target by ID, easier I think that way.
I would like to add this via functions.php to avoid touching the theme header files directly in child theme incase of updates etc.
So far I have the below - doesn't seem to be working though haha, so I've clearly missed something obvious!
Trying to target all pages, then add the id 'st-container'
Thanks in advance:
// create a custom function
function my_custom_body_id($id) {
if ( is_page() ) $id = 'st-container';
return $id;
};
add_filter('body_id','my_custom_body_id');
From https://codex.wordpress.org/Function_Reference/body_class
add_filter( 'body_class', 'my_class_names' );
function my_class_names( $classes ) {
// add 'st-container' to the $classes array
if(is_page()) {
$classes[] = 'st-container';
}
// return the $classes array
return $classes;
}
Give that a go - you need to return an array
template (header.php)
<body <?php body_id(); ?>>
functions.php
function body_id() {
if( is_page_template('page-service.php') ) {
$id = 'id="service-page"';
}
echo $id;
}
my view-source output was
<body id="service-page">
Related
I want to hide the stars rating below the title on the products where the reviews are empty. I want to hide only the stars without the ability to leave a new review.
I found a similar solution for hiding a different element and tried to adopt it.
I added this using a snippets plugin to add a class "hide-empty-stars" in body_class when the reviews are empty.
function check_for_empty_stars( $classes ) {
global $product;
$id = $product->get_id();
$args = array ('post_type' => 'product', 'post_id' => $id);
$comments = get_comments( $args );
if(empty($comments)) {
$classes[] = 'hide-empty-stars';
}
return $classes;
}
add_filter( 'body_class', 'check_for_empty_stars' );
Then I hide the star-rating class using css
body.hide-empty-stars .star-rating{
display: none;
}
It works but after a while I get a critical error and the log says that
mod_fcgid: stderr: PHP Fatal error: Uncaught Error: Call to a member function get_id() on null in /var/www/vhosts/my-domain.gr/httpdocs/wp-content/plugins/code-snippets/php/snippet-ops.php(505) : eval()'d code:3
What could cause this? Is there anything wrong in my code?
It occurs when you are not on the product page. The body_class runs on every page but some pages do not have post ID - for example category pages. Your snippet should run only if there is an post ID defined. Let's say you are looking at page presenting some category - there is not $product variable but you try to call get_id(); on $product so you get the error.
Maybe try to wrap it in if statement?
function check_for_empty_stars( $classes ) {
global $product;
if (!is_null($product)) {
$id = $product->get_id();
$args = array ('post_type' => 'product', 'post_id' => $id);
$comments = get_comments( $args );
if(empty($comments)) {
$classes[] = 'hide-empty-stars';
}
}
return $classes;
}
add_filter( 'body_class', 'check_for_empty_stars' );
Or just look for filter which will run only on product pages.
Also - you don't need any plugin like code-snippets. You can just place this code in the functions.php of your child-theme. Read about child-themes, these are good if you want to modify the theme and you will not lost your changes after updates. https://developer.wordpress.org/themes/advanced-topics/child-themes/
I have about 60 landing pages that use different phone numbers on them. I am using a combination of WordPress and Advanced Custom Fields to place the phone numbers on their respective pages.
I am being asked to show a <div> based on the landing page URL that will not only show the phone number assigned to that page, but, keep showing the <div> (and phone number) regardless of what page the user navigates to on the website.
I have found little to no support on how to make the <div> remain visible throughout the entire session until the user closes the window.
I am thinking that this will somehow revolve around a cookie and Dynamic Number Insertion but I have no real progress to speak of. Should this be done using PHP or JS? Does a plugin exist that would allow for this on WordPress? I'm open to all suggestions.
Please try this code. Like #John C mentioned, WP Engine doesn't recommend Cookie nor PHP Session for the sake of performance and security. This is pure JavaScript code, and I think this will solve your problem.
Code in your Post/Page template file:
<div id="phone-number"></div>
<?php if( get_field('phone_number') ): ?>
<script type="text/javascript">
let phone_number = "<?php the_field('phone_number'); ?>";
</script>
<?php endif; ?>
Code in your theme JavaScript file:
<script type="text/javascript">
// in the case of the div data is persistent on the same site
// let storage = localStorage;
// in the case of the div data is persistent in the same tab, but not in new tab
let storage = sessionStorage;
let key = "phone_number"; // storage key
var global_phone_number = storage.getItem(key);
// check if storage data is set before
if (null === global_phone_number) {
// if not set the data on page into storage
global_phone_number = phone_number ? phone_number : '';
storage.setItem(key, global_phone_number);
}
document.getElementById('phone-number').innerHTML = global_phone_number;
</script>
You should use PHP and capture the session.
(untested code warning)
add_action('wp_footer', 'dynamic_phone_div');
function dynamic_phone_div() {
session_start;
if(isset($_SESSION['phone_div']) ? $phone_div = $_SESSION['phone_div'] :
$phone_div = '';
if($phone_div != '') {
echo '<div class="that_div_thing">';
echo $phone_div;
echo '</div>';
} else {
$_SESSION['phone_div'] = 123456789;
echo '<div class="that_div_thing">';
echo '123456789';
echo '</div>';
}
}
This is only raw logic. I am not sure where your div is (header/footer/page) - depending on where it is you should either use a hook (header/footer) or code it into a template (page/post).
The session will be destroyed after the user closes the tab/window.
I would probably do this with client side session storage. Providing all pages open in the same tab, the value will remain for the session, then be removed.
PHP code (in your functions.php file?) would be something like this:
function phone_script() {
$params = array(
'phone_number' => null, // Insert logic for current number. Can stay null if this is running on a non-landing page
'is_landing_page' => false // Change to true/false based on is current page a landing one or not
);
$params = json_encode( $params );
echo <<< EOT
<script>
let settings = $params;
document.addEventListener("DOMContentLoaded", function() {
if( settings.is_landing_page ) {
window.sessionStorage.setItem( 'phone-number', settings.phone_number );
} else {
settings.phone_number = window.sessionStorage.getItem( 'phone-number' );
}
if( settings.phone_number ) {
let div = document.createElement('div');
div.classList.add('phone-div');
// or add inline style
// div.style.cssText = 'position:fixed'; //etc
// Some logic here to actually add the number and any other content to the div
div.innerHTML = `The Phone number is: ${settings.phone_number}`;
document.body.appendChild(div);
}
});
</script>
EOT;
}
add_action( 'wp_footer', 'phone_script');
Note that the EOT; line MUST have no leading or trailing spaces.
The above is untested.
I am creating a WordPress widget that shows and advert. When the advert is clicked I want to record the clicks with some detail.
The database table is already created and entries can be saved correctly using the function f1_add_advert_click($advert_id) in save-advert-click.php, which resides in the same directory as the Widget's PHP that I want to call it from (the plugin's root directory).
Requirements:
link will be on a piece of text, just a plain a href
a visitor should see the target link when he hovers his cursor over the link, not appended by a parameter for the next page
no 'middle' page that registers the click then redirects onto the target page. Just straight from the origin to the target.
secure: the advert ID is passed on to the f1_add_advert_click function and then inserted into the database. I would like to be sure that it's the correct ID (not something a visitor could change).
there can be multiple instances of this Widget on a page
I have seen and tried a lot of examples on Stackoverflow, but either I don't get it or the situation there is different from mine. Would gladly appreciate a well commented code example that works in my situation. Please be aware that I am not a seasoned programmer, especially 'green' when it comes to JavaScript and jQuery.
From what I have read on the web I think I should be using AJAX to first register the click, then send the browser to the target page. Not sure if I have to use onclick or not, based on the bottom answer of this post.
Have put in about four hours so far on this part. Now asking for help. Not much code to show, because I deleted everything that didn't work.
This is what I have currently got within the widget function of the plugin (left out the regular php showing title and so on):
<script type="text/javascript">
function myAjax() {
$.ajax({
type: "POST",
url: './wp-content/plugins/facilitaire-advert-widget/save-advert-click.php',
data:{action:'call_this'},
success:function(html) {
alert(html);
}
});
}
</script>
Followed by the link and the click action
<p>Link of Advert
Then these are my contents for save-advert-click.php
// check for action signal
if($_POST['action'] == 'call_this') {
f1_add_advert_click ();
}
/**
* Records a click event in the database
*/
function f1_add_advert_click ()
{
$advert_id = random_int(1,300); // change to $clicked_advert_id later
$user_ip = get_user_ip();
global $wpdb;
$table_name = $wpdb->prefix . 'f1_advert_clicks';
$wpdb->insert( $table_name, array(
'advert_id'=> $advert_id,
'user_agent'=> $_SERVER['HTTP_USER_AGENT'],
'ip_address'=> $user_ip
),
array(
'%d',
'%s',
'%s'
)
);
}
/**
* Get user IP
*/
function get_user_ip()
{
$client = #$_SERVER['HTTP_CLIENT_IP'];
$forward = #$_SERVER['HTTP_X_FORWARDED_FOR'];
$remote = $_SERVER['REMOTE_ADDR'];
if ( filter_var($client, FILTER_VALIDATE_IP) ) {
$ip = $client;
} elseif ( filter_var($forward, FILTER_VALIDATE_IP) ) {
$ip = $forward;
} else {
$ip = $remote;
}
return $ip;
}
UPDATE WITH SOLUTION
Thanks to #mplungjan's suggestion I updated my code to the following, working code. Please note some differences with #mplungjan's code, because I had to make some adjustments to make it work in WordPress.
contents of bottom part of show-advert.php
<script>
jQuery(function() {
jQuery(".advertLink").on("click",function(e) {
e.preventDefault(); // stop the link unless it has a target _blank or similar
var href = this.href;
var id= <?php echo $advert_id; ?>;
jQuery.post("<?php echo get_home_url(); ?>/wp-content/plugins/facilitaire-advert-widget/save-advert-click.php",
{ "action":"register_click", "advert_id":id },
function() {
location=href;
}
);
});
});
</script>
Link of Advert<br />
<?php
Then in the top part of save-advert-click.php I have
<?php
// check for action signal
if($_POST['action'] == 'register_click') {
f1_add_advert_click( $_POST["advert_id"] );
}
/**
* Records a click event in the database
*/
function f1_add_advert_click ( $advert_id )
{
$user_ip = get_user_ip();
// need to load WordPress to be able to access the database
define( 'SHORTINIT', true );
require_once( '../../../wp-load.php' ); // localhost needs this, production can have require_once( $_SERVER['DOCUMENT_ROOT'] . '/wp-load.php' );
global $wpdb;
$table_name = $wpdb->prefix . 'f1_advert_clicks';
$wpdb->insert( $table_name, array(
'advert_id'=> $advert_id,
'user_agent'=> $_SERVER['HTTP_USER_AGENT'],
'ip_address'=> $user_ip
),
array(
'%d',
'%s',
'%s'
)
);
}
You will want to do something like
$(function() {
$(".advertLink").on("click",function(e) {
e.preventDefault(); // stop the link unless it has a target _blank or similar
var href = this.href;
var id=this.id; // or $(this).data("advertid") if you have data-advertid="advert1" on the link
$.post("./wp-content/plugins/facilitaire-advert-widget/save-advert-click.php",
{ "action":"call_this", "advert_ID":id },
function() {
location=href; // or window.open
}
);
});
});
using
Link of Advert
I'm trying to create a nice and easy iterator and it worked at first, then I realized I'd need more information for the function so I tried to extend it and well it did not work.
Example Usage
$easyCMS->iterate($post,
echo $content[0];
echo $content[1];
);
Class Function
public function iterate($d,$fn){
$this->item = $d;
foreach($this->item as $post){
echo $fn;
}
}
Current Index.php Usage
$post = $easyCMS->my_query('SELECT * FROM `newsPost`');
//returns array
$easyCMS->iterate($post,
$content[0]."<br>",
$content[1]."<br>",
$content[2]."<br>",
$content[3]."<br>",
$content[4]."<br>",
);
//$post would be the first argument and after that would be what we want our function to do.
I get the error =>
Parse error: syntax error, unexpected ';' in .../index.php on line 23
Which I know that it's the constant $content[num] but I'd like to know how I'd do this for I know I could with JavaScript using the call method.
My database table looks something like
id: 1 == content: "Whats up" == ...etc
I want my code to iterate over these so then I can write like so
$easyCMS->iterate($post,
'<div class="hello">'.$content[0].'</div><div id="post_'.$content[1].'"><div class="content">'.$content[2].'</div>'
);
the error is caused by:
$easyCMS->iterate($post,
$content[0]."<br>";
$content[1]."<br>";
$content[2]."<br>";
$content[3]."<br>";
$content[4]."<br>";
);
which should be
$easyCMS->iterate($post,
$content[0]."<br>",
$content[1]."<br>",
$content[2]."<br>",
$content[3]."<br>",
$content[4]."<br>"
);
i don't think that this code solves your needs
Here is the best way for an easy iterator, took me some time but I finally solved it.
Class Function
public function iterate($d,$fn){
foreach($d as $item){
$txt = str_replace('{author}',$item["author"],$fn);
$txt = str_replace('{id}',$item["id"],$txt );
$txt = str_replace('{content}',$item["content"],$txt);
$txt = str_replace('{date}',$item["date"],$txt);
echo $txt;
}
}
PHP page IE index.php
$post = $easyCMS->my_query('SELECT * FROM `newsPost`');
$easyCMS->iterate($post,'<div class="hello">{author}</div><div id="post_{id}"><div class="content">{content}</div></div>');
$easyCMS->my_query is just a regular query which returns specific information
my_query
public function my_query($sql)
{
$array=array();//add an array
$query = mysqli_query($this->connect,$sql);
if($query > 0){
$c = mysqli_num_rows($query);//get how many rows there are
if($c > 1){//if greater than one push into the array
while($fetch = mysqli_fetch_array($query)){//while loop to push
array_push($array, $fetch);
}
return $array;
}else{
return mysqli_fetch_row($query);//rows is only one
}
}else{
return "No such query";//if the query does not exist!
}
}
Can't help but think you're over-complicating things here.
If you're using an array without an index key then it would be as simple as:
public function iterate($d,$fn){
foreach($d as $content){
echo $content;
}
}
Only if an index is key=>pair do you need to it like:
foreach ($d as $key=>$value) {
stuff//
}
$easyCMS->iterate($post,
'<div class="hello">'.$content[0].'</div>
<div id="post_'.$content[1].'"><div class="content">'.$content[2].'</div>'
);
Is wrong. When using " and ', you want to wrap ' inside of the ".
If, what you want is to irerate through a loop inside a loop, you'd want something like:
Foreach($post as $pos) {
$class->some_func($pos);
}
public function some_func ($post) {
/formatting.
echo $post;
/formatting.
}
The simplest I can come up with, based on your code currently is:
foreach($stuff_from_database_call as $content)
echo "formatting stuff". $content . "/close formatting";
Technically you could 1 line it, so long as dont mind using . to join strings :)
Note the lack of [0] [1] etc, which is un-needed, since you are iterating through the array. However, if it was a key=>pair you'd do it like this:
foreach($stuff_from_database_call as $key=>$content)
echo "formatting stuff". $key[$content] . "/close formatting";
Updated this after you wrote out and accepted your own answer. Instead of:
public function iterate($d,$fn){
foreach($d as $item){
$txt = str_replace('{author}',$item["author"],$fn);
$txt = str_replace('{id}',$item["id"],$txt );
$txt = str_replace('{content}',$item["content"],$txt);
$txt = str_replace('{date}',$item["date"],$txt);
echo $txt;
}
}
I'd suggest something more like:
public function iterate($d,$fn){
foreach($d as $item=>$value){
$txt = str_replace('{$value}',$item[$value],$fn);
echo $txt;
}
}
This will make it a LOT more flexible, as you can easily add fields, without having to touch the function itself. When coding, ALWAYS try and do so with as much forethought as you can, so you save yourself headaches down the road.
Either way, glad you got it sorted, and glad you came back to post your sollution.
1 last afterthought. Try naming your variables a little more reader friendly :) $d is nowhere near descriptive enough. Just another avoidable headache, for yourself and for anyone else having to look at your code :)
I am having a problem with the responsive menu toggle not expanding on a site I am working on. Essentially when the site is resized below 768px the menu is replaced with a menu toggle that when clicked/tapped it should show the two options About & Shop. However when clicked nothing happens, it simply adds #navigation to the end of the URL.
I have managed to narrow down to one line of code that is for this plugin in my index.php file.
<?php if(sb_slides_display()){sb_slides_display();} ?>
It is a simple WordPress site with WooCommerce using the theme mystile. Link: http://bit.ly/1dvdeb0
If I take out the above code the problem is solved but then of course the slider is no longer activated. Any ideas why or how it can be fixed?
Also, here is the code in context:
<?php
// File Security Check
if ( ! function_exists( 'wp' ) && ! empty( $_SERVER['SCRIPT_FILENAME'] ) && basename( __FILE__ ) == basename( $_SERVER['SCRIPT_FILENAME'] ) ) {
die ( 'You do not have sufficient permissions to access this page!' );
}
?><?php
/**
* Index Template
*
* Here we setup all logic and XHTML that is required for the index template, used as both the homepage
* and as a fallback template, if a more appropriate template file doesn't exist for a specific context.
*
* #package WooFramework
* #subpackage Template
*/
get_header();
global $woo_options;
?>
<?php if(sb_slides_display()){sb_slides_display();} ?>
<?php if ( $woo_options[ 'woo_homepage_banner' ] == "true" ) { ?>
<div class="homepage-banner">
<?php
if ( $woo_options[ 'woo_homepage_banner' ] == "true" ) { $banner = $woo_options['woo_homepage_banner_path']; }
if ( $woo_options[ 'woo_homepage_banner' ] == "true" && is_ssl() ) { $banner = preg_replace("/^http:/", "https:", $woo_options['woo_homepage_banner_path']); }
?>
<img src="<?php echo $banner; ?>" alt="" />
<h1><span><?php echo $woo_options['woo_homepage_banner_headline']; ?></span></h1>
<div class="description"><?php echo wpautop($woo_options['woo_homepage_banner_standfirst']); ?></div>
</div>
<?php } ?>
<div id="content" class="col-full <?php if ( $woo_options[ 'woo_homepage_banner' ] == "true" ) echo 'with-banner'; ?> <?php if ( $woo_options[ 'woo_homepage_sidebar' ] == "false" ) echo 'no-sidebar'; ?>">
Thanks in advance for any help it's greatly appreciated! :)
EDIT: JavaScript page from console error Uncaught TypeError: Object [object Object] has no method 'fitVids' :
/*-----------------------------------------------------------------------------------*/
/* GENERAL SCRIPTS */
/*-----------------------------------------------------------------------------------*/
jQuery(document).ready(function($){
// Fix dropdowns in Android
if ( /Android/i.test( navigator.userAgent ) && jQuery( window ).width() > 769 ) {
$( '.nav li:has(ul)' ).doubleTapToGo();
}
// Table alt row styling
jQuery( '.entry table tr:odd' ).addClass( 'alt-table-row' );
// FitVids - Responsive Videos
jQuery( ".post, .widget, .panel" ).fitVids();
// Add class to parent menu items with JS until WP does this natively
jQuery("ul.sub-menu").parents('li').addClass('parent');
// Responsive Navigation (switch top drop down for select)
jQuery('ul#top-nav').mobileMenu({
switchWidth: 767, //width (in px to switch at)
topOptionText: 'Select a page', //first option text
indentString: ' ' //string for indenting nested items
});
// Show/hide the main navigation
jQuery('.nav-toggle').click(function() {
jQuery('#navigation').slideToggle('fast', function() {
return false;
// Animation complete.
});
});
// Stop the navigation link moving to the anchor (Still need the anchor for semantic markup)
jQuery('.nav-toggle a').click(function(e) {
e.preventDefault();
});
// Add parent class to nav parents
jQuery("ul.sub-menu, ul.children").parents().addClass('parent');
});
From Hobo in the comments above:
fitvids and mobileMenu are both declared in third-party.js. To my eye they look like they don't need noConflict - I think that's for when you want to use $ instead of jQuery, but your code uses jQuery, so should be OK. I now think the problem is that jQuery is being included twice - try removing the second one (v1.8.2, from the Google CDN). It's probably (judging by proximity) where your slicebox.js is included.