Showing posts with label wordpress. Show all posts
Showing posts with label wordpress. Show all posts

Monday, October 15, 2018

How to ignore the specific CSS codes coming from the WordPress plugin stylesheet?

Leave a Comment

I am working on a WordPress website built on custom theme in which I want to ignore some specific CSS codes coming from wordpress plugin style sheet.

Here is the link for that wordpress plugin style sheet.

The CSS codes from the above Wordpress plugin style sheet which I want to ignore is:

@media screen and (max-width: 575.98px) .gv-table-view tr:first-of-type {     border-top: 1px solid #ccc; }  @media screen and (max-width: 575.98px) .gv-table-view tr {     display: block;     position: relative;     padding: 1.2em 0;     overflow-x: auto; }   .gv-table-view th, .gv-table-view td {         padding: .3em;     }   @media screen and (max-width: 575.98px) .gv-table-view tr td {     display: table-row; }  @media screen and (max-width: 575.98px) .gv-table-view tr td:before {     content: attr(data-label);     font-weight: bold;     display: table-cell;     padding: 0.2em 0.6em 0.2em 0;     text-align: right;     width: 40%; } 


Problem Statement:

I want to ignore the above CSS codes in the mobile version of the following website url which is coming from wordpress plugin style-sheet. I am wondering where I need to go in my wordpress website in order to achieve that ?

If I take the above url in the mobile view, we can see the CSS codes mentioned above the problem statement.

8 Answers

Answers 1

You can't exactly ignore a stylesheet that comes with a plugin that you wish to use. You could try overwriting the plugins stylesheet with your own styles, but if you plan to update that plugin it could cause trouble.

A lot of people have been stating to use important and I wouldn't do that. You should leverage CSS cascading ability and write your own css reset for those classes:

A CSS Reset is a short, often compressed (minified) set of CSS rules that resets the styling of all HTML elements to a consistent baseline.

What you would need to do is change the style you want to change and reset the styles you don't, but you must implement these changes after the original style occurs to leverage CSS cascading ability. For example:

Reset Method

//Original @media screen and (max-width: 575.98px) .gv-table-view tr:first-of-type {     border-top: 1px solid #ccc; } //Reset must come after the plugins original style @media screen and (max-width: 575.98px) .gv-table-view tr:first-of-type {     border-top: none; } 

Make sure the stylesheet you're using to reset the plugins styles comes/loads after the plugins stylesheet.

It is only when you can't reset, or override a style through CSS cascading nature you should use important. More on that here.

In your <head> make sure your style.css folder is coming after the gravity views plugin stylesheet

Your Current Head

<head>     <link rel="stylesheet" id="twentysixteen-style-css" href="http://test.caubo.ca/wp-content/themes/caubo/style.css?ver=4.9.8" type="text/css" media="all">      <link rel="stylesheet" id="gravityview_font-css" href="http://test.caubo.ca/wp-content/plugins/gravityview/assets/css/font.css?ver=2.1.0.3" type="text/css" media="all"> </head> 

What it needs to look like

<head>     <link rel="stylesheet" id="gravityview_font-css" href="http://test.caubo.ca/wp-content/plugins/gravityview/assets/css/font.css?ver=2.1.0.3" type="text/css" media="all">      <link rel="stylesheet" id="twentysixteen-style-css" href="http://test.caubo.ca/wp-content/themes/caubo/style.css?ver=4.9.8" type="text/css" media="all"> </head> 

You can give your stylesheets priority in your functions.php file. For more information please check here.

Answers 2

I'd say you should check the handle of the plugin's stylesheet. Look into the wp_enqueue_style part and find out that handle, and then add your own styleshet AFTER that handle by using that handle as a dependency. For example, put this in your theme's function.php:

wp_enqueue_style( 'your_own_handle', 'path/to/your/overwrite_stylesheet.css', array('handle_of_plugin1','handle_of_plugin2')) 

With that done, you could overwrite all the plugin css either in whole or in parts.

Answers 3

To overwriting the plugin CSS you can use !important; for particular class

@media screen and (max-width: 575.98px) .gv-table-view tr:first-of-type { border-top: 10px solid #000000!important; } 

If their available id it that div you can use id rather than !important; and it will work if The developer of the plugin was not using !important throughout the plugin CSS

Answers 4

Override the rule in your Custom stylesheet and set properties to !important tag. Or override the rule on bottom of stylesheet file. Because is a cascading style and last properties executed that stay

.example{    Width:300px !important! } 

Answers 5

This could be done with the help of javascript also, but you could override the WP theme also using the appropriate media queries for the mobile version that adds those classes.

function isMobile() {    if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(navigator.userAgent) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(navigator.userAgent.substr(0,4))) {          return true;      } else {          return false;      }   }      if(isMobile()) {   let matches = document.querySelectorAll(".mobile");   matches.forEach(function(item) {   if(item.classList.contains('mobile')) {   item.classList.remove('mobile')   }   });   }   
.mobile {  font-style:italic;  text-transform: uppercase;  color: red;  }  p {  font-style:normal;  text-transform: capitalize;  color: blue;  }
<p class="mobile">Lorem ipsum dolor sit amet...</p>

You may check this in jsFiddle

Answers 6

Your additional CSS has still got priority but the plugin stylesheet (/plugins/gravityview/templates/css/table-view.css I guess) classes are more specific and therefore win, for example:

.gv-table-view tr td from the plugin wins over your .gv-container-2777 td you could just copy their css or change yours to be more specific e.g .gv-container-2777 tr td

Answers 7

Have you checked where is the wp_enqueue_style() in the plugin for the table-view.css style sheet is?

I would first locate the wp_enqueue_style() in the plugin itself to locate the handle script. Let's say the enqueue in the plugin is as follows:

wp_enqueue_style('gravityview_style_default_table', 'path-to-file.css', [], '2.1.0.3'); 

In your theme than you would need to wp_deregister_style() refering to the same handle, and create a new stylesheet 'gavityview-style.css' in your theme with the css you want from that plugin stylesheet as follows:

function manage_theme_styles() {   wp_deregister_style( 'gravityview_style_default_table',);    wp_enqueue_script( 'my-gravityview-style', get_template_directory_uri() . '/gavityview-style.css', array(), '1.0.0', true ); } add_action( 'wp_enqueue_scripts', 'wpdocs_theme_name_scripts', 99 ); 

Having said that every time you update the plugin you have to check the plugin's css and update your stylesheet with any changes made to the plugin. But since you are dealing with a plugin you have to check your css even if you choose to tackle your problem with other solutions.

Answers 8

You can achieve this in 2 ways.

Solution 1: All good plugins will define CSS handle for each of their CSS and its gravityview_style_default_table in your case. Just add the function given below in your theme's 'functions.php' to remove the particular CSS. Please note that this will remove the entire CSS and not the 'media queries' alone. You can then add the required CSS classes to your theme's stylesheet.

function remove_gravityview_table_style() {     //check if mobile device     $useragent=$_SERVER['HTTP_USER_AGENT'];     if(preg_match('/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i',$useragent)||preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i',substr($useragent,0,4))) {         //remove css         wp_dequeue_style('gravityview_style_default_table');         wp_deregister_style('gravityview_style_default_table');     } } add_action('wp_print_styles', 'remove_gravityview_table_style'); 

Solution 2: You can override the particular CSS file in your theme by copying it to [theme]/gravityview/css/table-view.css and make necessary changes (i.e. remove 'media queries').

Read More

Tuesday, October 9, 2018

wordpress sticky post on archive page with pagination

Leave a Comment

I have category page which is redirecing to archieve.php.

you can see here : https://www.dealfinder.lk/category/dining/

There are two sticky posts at the top.

1) Up to 25% OFF at &Co Pub and Kitchen with COMBANK Cards

2) 20% OFF at Robata – Movenpick Hotel Colombo for all HSBC Credit Cards

My pagination is 10 items per post

Right now, it shows me 12 items per post.

Here is my code :

function yell_category_sticky_posts( $posts, $wp_query ) {      global $wp_the_query;      // Don't continue if this isn't a category query, we're not in the main query or we're in the admin     if ( ! $wp_query->is_category || $wp_query !== $wp_the_query || is_admin() )         return $posts;      global $wpdb;      $q = $wp_query->query_vars;      $page = absint( $q['paged'] );      if ( empty( $page ) )         $page = 1;      $post_type = $q['post_type'];      $sticky_posts = get_option( 'sticky_posts' );      if ( $wp_query->is_category && $page <= 1 && is_array( $sticky_posts ) && !empty( $sticky_posts ) && ! $q['ignore_sticky_posts'] ) {          $num_posts = count( $posts );          $sticky_offset = 0;          // Loop over posts and relocate stickies to the front.         for ( $i = 0; $i < $num_posts; $i++ ) {              if ( in_array( $posts[$i]->ID, $sticky_posts ) ) {                  $sticky_post = $posts[$i];                  // Remove sticky from current position                 array_splice( $posts, $i, 1 );                  // Move to front, after other stickies                 array_splice( $posts, $sticky_offset, 0, array( $sticky_post ) );                  // Increment the sticky offset.  The next sticky will be placed at this offset.                 $sticky_offset++;                  // Remove post from sticky posts array                 $offset = array_search( $sticky_post->ID, $sticky_posts );                 unset( $sticky_posts[$offset] );              }          }          // If any posts have been excluded specifically, Ignore those that are sticky.         if ( !empty( $sticky_posts ) && !empty( $q['post__not_in'] ) )             $sticky_posts = array_diff( $sticky_posts, $q['post__not_in'] );          // Fetch sticky posts that weren't in the query results         if ( !empty( $sticky_posts ) ) {              $stickies__in = implode( ',', array_map( 'absint', $sticky_posts ));              // honor post type(s) if not set to any             $stickies_where = '';              if ( 'any' != $post_type && '' != $post_type ) {                  if ( is_array( $post_type ) )                     $post_types = join( "', '", $post_type );                  else                     $post_types = $post_type;                  $stickies_where = "AND $wpdb->posts.post_type IN ('" . $post_types . "')";             }              $stickies = $wpdb->get_results( "SELECT wp_posts.* FROM $wpdb->posts INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) WHERE 1=1  AND ( wp_term_relationships.term_taxonomy_id IN (" . get_term( $wp_query->query_vars['cat'], 'category' )->term_taxonomy_id . ") ) AND $wpdb->posts.ID IN ($stickies__in) $stickies_where" );              foreach ( $stickies as $sticky_post ) {                  // Ignore sticky posts are not published.                 if ( 'publish' != $sticky_post->post_status )                     continue;                  array_splice( $posts, $sticky_offset, 0, array( $sticky_post ) );                  $sticky_offset++;              }         }     }      return $posts;  } add_filter( 'the_posts', 'yell_category_sticky_posts', 10, 2 ); 

My Issue:

I want to show 10 posts per page, currently it shows 12 posts per page with sticky post.

This question is for master not for new learner.

Anybody master here? Thanks in advance

2 Answers

Answers 1

As I suggested in the comment, save the 'sticky posts' in meta (assuming is_featured_post as the 'meta key').

Run these only once to set the meta value for existing posts. You can skip this since you are already saving in the meta.

// set meta value of all posts to 0 $all_posts = get_posts(array('post_type'=>'post','posts_per_page'=>-1)); if( is_array( $all_posts ) ) {     foreach( $all_posts as $post ) {         update_post_meta( $post->ID, 'is_featured_post', '0'  );     } }  // set meta value of all sticky posts alone to 1 $sticky_posts = get_option( 'sticky_posts' ); if( is_array( $sticky_posts ) ) {     foreach ( $sticky_posts as $sticky_post ) {          update_post_meta( $sticky_post, 'is_featured_post', '1'  );     } } 

The below function will update the new sticky meta is_featured_post each time a post updated (or new post saved).

function save_sticky_meta( $post_id ) {     if ( isset( $_REQUEST['sticky'] ) ) {         update_post_meta( $post_id, 'is_featured_post', '1'  );     }     else {         update_post_meta( $post_id, 'is_featured_post', '0'  );     } } add_action( 'save_post', 'save_sticky_meta' ); add_action( 'edit_post', 'save_sticky_meta' ); 

Then use pre_get_posts action to set the category query. We are ordering by both 'meta' and 'date' descending to show the latest at top.

function include_sticky_posts( $query ) {     if ( ! is_admin() && $query->is_main_query() && $query->is_category() ) {         $query->set( 'meta_key', 'is_featured_post' );         $query->set( 'sticky_sort', true ); //custom sticky order query         $query->set( 'orderby', 'meta_value_num date' );         $query->set( 'order', 'DESC' );     } } add_action( 'pre_get_posts', 'include_sticky_posts' ); 

If you want to randomize non-sticky posts, change the order using the_posts filter as below.

add_filter( 'the_posts', 'sticky_posts_sort', 10, 2 ); function sticky_posts_sort( $posts, $query ) {     // if custom sort set from category query     if ( true !== $query->get( 'sticky_sort' ) )         return $posts;       // loop through posts & save sticky & other posts in seperate arrays     $sticky_posts = get_option( 'sticky_posts' );     $sticky_array = array();     $posts_array = array();     foreach ( $posts as $p ) {         if( in_array( $p->ID, $sticky_posts ) )             $sticky_array[] = $p;         else             $posts_array[] = $p;     }      // merge both arrays and randomize non-sticky posts alone     if( is_array( $posts_array ) )         shuffle( $posts_array );     if( is_array( $sticky_array ) && is_array( $posts_array ) )         $posts = array_merge( $sticky_array, $posts_array );     elseif( is_array( $sticky_array ) )         $posts = $sticky_array;     else         $posts = $posts_array;      return $posts; } 

Answers 2

The below function pushes stickies to the top, you should be able to use this to help in your case.

add_filter('the_posts', 'bump_sticky_posts_to_top'); function bump_sticky_posts_to_top($posts) {     $stickies = array();     foreach($posts as $i => $post) {         if(is_sticky($post->ID)) {             $stickies[] = $post;             unset($posts[$i]);         }     }     return array_merge($stickies, $posts); } 
Read More

Monday, October 8, 2018

WordPress CSRF Exploit Draft Status

Leave a Comment

How can I best secure WP against a CSRF exploit when creating a new post draft?

If I add a new post and save as draft, I can intercept the request using Burp Suite.

Using the engagement tool in Burp Suite, I can change the value of the post title and paste the URL back in to the browser which creates a new draft with the changed post title.

How can I secure against this?

Cheers

2 Answers

Answers 1

WordPress already provides a CSRF protection mechanism by using a nonce. When creating a new post, a new unique nonce is created. This nonce is required and must be submitted with the rest of the POST data in order for the post to be saved as a draft or be published. If the nonce is not present or invalid, the request is rejected. (Tested with Wordpress v4.9.8)

In your tests you were able to modify the draft because you submitted the correct nonce using Burp, but in a CSRF attack this value would be unknown. Burp is an intercepting proxy, so you practically performed a MITM attack on your own HTTP traffic. If you're concerned about MITM attacks you should use HTTPS. Of course an attacker could still intercept your network traffic, but all the data would be encrypted.

So, I wouldn't say that this is a CSRF exploit, but a MITM exploit. You can protect your WordPress installation from most public exploits by keeping your WordPress version, plugins and thems updated, and also you can find many security related plugins in https://wordpress.org/plugins/tags/security/.

I think the best tool for security tests on WordPress is WPScan. It has a huge database of vulnerabilities and it can detect possible exploits and enumerate users, version and plugins. WPScan is mostly a recon tool, but we can test if the reported vulnerabilities are exploitable with Metasploit or Wpxf, a less known but powerful tool that is specialized on WordPress exploitation. Note that those tools can only detect and exploit public exploits. If you want to discover new vulnerabilities then you could use Burp or similar scanners and study the WordPress source code.

If I have misunderstood the question, and you have a form that doesn't have a nonce (let's say you're writting a plugin), you can add a nonce with wp_nonce_field and then verify it in the script that receives the form with wp_verify_nonce. However, if you have a WordPress installation that doesn't use a nonce with its forms, you shouldn't try to add a nonce manually, but update to a newer version.

Answers 2

Wordpress does not use traditional nonces, instead binding them to a specific form action and user session combination, and persisting them for multiple usage over two ticks (default 12 hours each), which means they are by default valid for up to a full day, and may be repeatedly used over that time period, as well as being "refreshed" after a use to reset their time period entirely. This has been consistently criticized for a number of years by security professionals as misleading and insecure, and the WordPress core team has defended their stance by claiming that the requirement that someone has both the user session as well as the actual nonce makes this a negligible threat, although both a compromised host as well as a site that does not have valid ssl protection can make this pretty easy to accomplish.

The underlying issue you are encountering is symptomatic of the fact that a WordPress nonce is not a nonce at all. It is essentially an access control hash used repeatedly for a short duration for a single form action, and has no mechanism in place to insure its single use. This is why you were able to successfully intercept and re-use the nonce. FYI, this behavior can also be recreated pretty easily in Zed Attack Proxy, Wireshark, Charles Proxy, and numerous other similar utilities. Burp is not the only tool that is capable of uncovering this weakness.

You do however have some recourse to correct this if you want, but it is rather involved and not particularly simple to accomplish.

The following functions are pluggable, which means you can override them with your own, and also control the system interpretation of what a nonce is. You will need to provide your own nonce system using these specific methods, and return identical values to the original expected ones so you don't break plugins/core code functionality:

You could, for example, provide your own nonce implementation using a support from a package such as elhardoum/nonce-php or wbswjc/nonce, and then implement it through a custom plugin that overrides the above pluggable functions and uses them as wrappers for your own nonce implementation, although this is not incredibly straightforward and will require a great deal of custom logic to implement.

You will need to not only override the above pluggable functions, but will also need to call apply_filters similarly to their own source, properly nullify whatever changes plugins attempt to make that are bound to those filters, and also return an expected value in the exact same format as the original so you do not disrupt how other plugins/themes you may be using have implemented them.

If you believe that there is sufficient risk, or that the data your site is safeguarding is of sufficient importance, it is likely worth the effort. If you are not handling financial transactions or sensitive data, are properly secured behind ssl, or have no particular interest in writing a custom implementation of nonces and subsequently maintaining it to work around the ways it inevitably breaks numerous plugins who expect the default lax implementation to be present, then you are probably best off taking the core devs at their word and using the defaults, provided you update frequently, have a strong security plugin like wordfence or sucuri, and routinely run updates on all of your plugins/themes.

As an absolute minimum, you pretty much must have SSL in place to mitigate MITM attacks, and should use proper access control headers to mitigate CSRF.

Read More

Thursday, September 27, 2018

How to show uploaded php file as plain text instead of executing it in wordpress?

Leave a Comment

Edit a testme.php file in /tmp.

<?php echo  "test"; ?> 

Edit a new post titled test and upload file /tmp/testme.php ,pubish it with url http://home.local/wp/?p=4785.
enter image description here

I want to see the content in testme,click it,pop up new window in wordpress. enter image description here

Go on to click it.test shown in webpage.

My expect :
1.just click testme in test post for one time.
2.show the testme.php as plain text ,

<?php echo  "test"; ?> 

instead of the result of executing testme.php.

test 

I make a configuration according some material show php file as plain text in apache.

sudo vim /etc/apache2/sites-available/000-default.conf

<VirtualHost *:80>     ServerName www.home.local     ServerAdmin webmaster@localhost     DocumentRoot /var/www/html     ErrorLog ${APACHE_LOG_DIR}/error.log     CustomLog ${APACHE_LOG_DIR}/access.log combined         <Directory /var/www/html>             Options Indexes FollowSymLinks MultiViews             AllowOverride All             allow from all             php_flag engine off             AddType text/plain php         </Directory> </VirtualHost> 

Reboot apache2(build in debian).

sudo systemctl restart apache2 

To open the post http://home.local/wp/?p=4785,i got the following output in webpage:

<?php /**  * Front to the WordPress application. This file doesn't do anything, but loads  * wp-blog-header.php which does and tells WordPress to load the theme.  *  * @package WordPress  */  /**  * Tells WordPress to load the WordPress theme and output it.  *  * @var bool  */ define('WP_USE_THEMES', true);  /** Loads the WordPress Environment and Template */ require( dirname( __FILE__ ) . '/wp-blog-header.php' ); 

2 Answers

Answers 1

You already have the right code — AddType text/plain php, which will make Apache treats PHP files (or files where the name ends with .php) as plain-text files.

But assuming the following:

  • You have WordPress installed in the /var/www/html directory.

  • The PHP files are uploaded to the default uploads folder in WordPress (wp-content/uploads).

If you set the directory to /var/www/html/wp-content/uploads as in:

<Directory /var/www/html/wp-content/uploads>   AddType text/plain php </Directory> 

You'd get the results you wanted — only PHP files in the uploads folder will be treated as plain-text files, and not all PHP files in the /var/www/html directory. This explains the issue with "To open the post http://home.local/wp/?p=4785, I got the following output", where that output is the code in the file /var/www/html/index.php. I mean, you used <Directory /var/www/html>, which makes Apache treats the index.php file as a plain-text file, instead of executing the PHP code in the file.

ALTERNATE METHOD: Use the .htaccess file.

Particularly if you can't edit or have no access to the Apache's configuration (.conf) file.

  1. Create .htaccess in the uploads folder, if it's not already there.

  2. Then add AddType text/plain php in that file.

Additional Notes

I want to see the content in testme.php, click it, pop up new window

I'm sure you can do that or already have the code/solution, but an easy way, is just add target="_blank" to the attachment/file link.. or with JavaScript, you can use window.open().

And you must take full security measures since allowing people to upload PHP files could harm your site and/or your site users.

Answers 2

What are you trying to accomplish? It seems you're trying to get a hyperlink that displays the contents of a PHP file. WordPress posts are stored in the database. So when you say "publish it", what are you talking about? The database entry that refers to a WordPress post, or the PHP file? If all you want on the screen is the unexecuted contents of the PHP file, you shouldn't be publishing a WordPress "post". What is contained in the post? If you're talking about putting a PHP file as the CONTENT of a post, that would be a different thing too. Probably the easiest way to display the content of a PHP file is to just rename it to a text file.

myFile.php => myFile.php.txt

Read More

Tuesday, September 18, 2018

WordPress Newsletter plugin redirect to previous page after subscription confirmation

Leave a Comment

I am stuck with a problem I WordPress. I have integrated Newsletter plugin in the footer of my site. After subscription the page redirects to another page which does not exist. What I need is it should redirect to same page from where the user has subscribed. I tried many options but i didn't find any solution.

This is the plugin that I have integrated in my application. https://wordpress.org/plugins/newsletter/

Waiting for a response....

2 Answers

Answers 1

Go to Newsletter - Setting and more Select Dedicated Page, by default it must be "Newsletter" Page. If there is something else then select Newsletter Page and you're done.

Answers 2

Try this PHP shortcode of the plugin in which you can pass the current URL to the confirmation_url shortcode attribute.

<?php global $wp; echo do_shortcode('[newsletter_form confirmation_url="'.home_url( $wp->request ).'"]'); ?> 
Read More

Thursday, September 13, 2018

How to set permalink to fetch all children custom posts with parent post in wordpress?

Leave a Comment

I create parent-child relationship for custom posts types.

Generic : www.example.com/parent/parent_post

Sample : www.example.com/projects/project-one

In above URL parent is a custom post type and parent post is its single post. I can show parents all posts and single post respectively as archive-parent.php and single-parent.php .

As I mentioned earlier, I create parent-child relationship and with child post that stores 'post_parent' as parent id.

Generic : www.example.com/child/parent_post/child_post

Sample : www.example.com/project_article/project-one/first-article

And for specific child post, URL will be as above.

Below code is for to get specific child post.And it's working fine.

function my_add_rewrite_rules() {     add_rewrite_tag('%child%', '([^/]+)', 'child=');     add_permastruct('child', 'child/%parent%/%child%', false);     add_rewrite_rule('^child/([^/]+)/([^/]+)/?','index.php?child=$matches[2]','top'); } add_action( 'init', 'my_add_rewrite_rules' );  function my_permalinks($permalink, $post, $leavename) {     $post_id = $post->ID;     if($post->post_type != 'child' || empty($permalink) || in_array($post->post_status, array('draft', 'pending', 'auto-draft')))         return $permalink;     $parent = $post->post_parent;     $parent_post = get_post( $parent );     $permalink = str_replace('%parent%', $parent_post->post_name, $permalink);     return $permalink; } add_filter('post_type_link', 'my_permalinks', 10, 3); 

Generic : www.example.com/child/parent_post

Sample : www.example.com/project_article/project-one

Now I want all child posts with parent post, as in above URL.

I am new to word-press Please guide.

1 Answers

Answers 1

Assuming parent as parent custom post type, child as child custom post type and hope you need child posts URL like http://www.example.com/parent/parent-post/child/child-post instead of http://www.example.com/child/parent-post/child-post.

Change your my_add_rewrite_rules() function to the following.

function my_add_rewrite_rules() {     add_rewrite_tag('%child%', '([^/]+)', 'child=');     add_permastruct('child', '/parent/%parent%/child/%child%', false);     add_rewrite_rule('^parent/([^/]+)/child/([^/]+)/?','index.php?child=$matches[2]','top'); } add_action( 'init', 'my_add_rewrite_rules' ); 

After updating don't forgot to flush permalinks via 'Settings > Permalinks'.

Read More

Saturday, August 11, 2018

Woocommerce rating not showing in new custom theme

Leave a Comment

I am working on to new custom theme. I have installed woocommerce plugin. I have import product from xml files. I had tried to test rating functionality. Its working on wordpress default theme twentytwelve, twentysixteen. etc. But when I switched to my custom theme. comment section not showing rating.

Take a look on screenshot. Comment section has only textarea.

Here is my code of comments.php

<div class="comments">     <?php if (post_password_required()) : ?>     <p><?php _e( 'Post is password protected. Enter the password to view any comments.', 'html5blank' ); ?></p> </div>      <?php return; endif; ?>  <?php if (have_comments()) : ?>      <h2><?php comments_number(); ?></h2>      <ul>         <?php wp_list_comments('type=comment&callback=html5blankcomments'); // Custom callback in functions.php ?>     </ul>  <?php elseif ( ! comments_open() && ! is_page() && post_type_supports( get_post_type(), 'comments' ) ) : ?>      <p><?php _e( 'Comments are closed here.', 'html5blank' ); ?></p>  <?php endif; ?>  <?php comment_form(); ?>  </div> 

my screenshot

4 Answers

Answers 1

You might need to declare WooCommerce support if you are using custom theme in order to make it compatible with WooCommerce. Default WordPress themes would be normally compatible with WooCommerce and they will work without adding anything. You can read more here - https://docs.woocommerce.com/document/third-party-custom-theme-compatibility/.

Step 1: Add this to your theme's 'functions.php'.

function custom_theme_setup() {     add_theme_support( 'woocommerce' ); } add_action( 'after_setup_theme', 'custom_theme_setup' ); 

Step 2: If still reviews not showing, copy your theme's 'page.php' as 'woocommerce.php'. Remove the loop - <?php if(have_posts()): while(have_posts()): the_post(); ?> and <?php endwhile; endif; ?>. Replace the_content() with woocommerce_content().

Let me know whether these fixes the issue, else paste new 'woocommerce.php' contents in your question.

Answers 2

If you are creating custom theme then you have to copy templates from woocommerce to your custom theme then add folder name woocommerce to your custom theme.

Then copy single-product-reviews.php from plugins -> woocommerce -> templates and paste it to your custom theme newly created folder name woocommerce

Now you can customize your review template as per your need.

Answers 3

If you want to add ratings to comment section.

  1. You can follow this link to add through code
  2. You can use this plugin (Comment Rating Field Plugin) to add this

Answers 4

It might be a Setting issue in WooCommerce. Go to WooCommerce Menu, then to Settings -> Products Tab. You can find the options to Enable Rating and Review. Please check the screenshot.

enter image description here

Hope this will help you.

Read More

Sunday, July 22, 2018

Set page title in WordPress with PHP

Leave a Comment

I know this question has been asked thousands of times before, but I have attempted a lots of these solutions without any success.

Attempted solutions, among others (added to the template page)

add_filter('the_title','callback_to_set_the_title');  add_filter('wp_title', 'callback_to_set_the_title');  global $title; $title = 'My Custom Title';  add_filter( 'pre_get_document_title', 'callback_to_set_the_title' );  add_filter( 'document_title_parts', 'callback_to_set_the_title' ); 

The scenario is that I have a custom template for a job listing page. This page has url rewriting in place that rewrites domain.com/about/careers/search/job?slug=whatever to domain.com/about/careers/search/job/whatever - the slug is used to retrieve an entry from Redis that contains all the info for the job listing including the title I'd like to use.

Here's how I am rewriting the URL (from functions.php):

function job_listing_url_rewrite() {     global $wp_rewrite;     add_rewrite_tag('%slug%', '([^&]+)');     add_rewrite_rule('^about/careers/search/job/([a-zA-Z0-9-_]+)/?', 'index.php?page_id=6633&slug=$matches[1]', 'top');     $wp_rewrite->flush_rules(true); } add_action('init', 'job_listing_url_rewrite', 10, 0); 

4 Answers

Answers 1

I did some research with my template. My template calls get_header to print the html tags with head and so on, I guess yours does the same.

To replace the title, I start a output buffering right before calling that function and get it afterwards. after that i can replace the title easily with preg_replace

ob_start(); get_header(); $header = ob_get_clean(); $header = preg_replace('#<title>(.*?)<\/title>#', '<title>TEST</title>', $header); echo $header; 

Answers 2

I suspect that the logic for altering wp_title in the template is firing too late.

In most cases, wp_title is invoked in the header file, which will have been processed before getting to the template with your logic.

If you're able to add something like the following to your functions.php, I bet WP will set the title the way you intend.

<?php  // functions.php  function change_title_if_job_posting($query) {     $slug = $query->query->get('slug');      // The URL is a match, and your function above set the value of $slug on the query     if ('' !== $slug) {         /**          * Use the value of $slug here and reimplement whatever logic is          * currently in your template to get the data from redis.          *           * For this example, we'll pretend it is set to var $data. :)          */         $data = 'whatever-the-result-of-the-redis-req-and-subsequent-processing-is';          /**           * Changes the contents of the <title></title> tag.          *          * Break this out from a closure to it's own function          * if you want to also alter the get_the_title() function          * without duplicating logic!          */         add_filter('wp_title', function($title) use ($data) {             return $data;         });     } }  // This is the crux of it – we want to try hooking our function to the wp_title // filter as soon as your `slug` variable is set to the WP_Query; not all the way down in the template. add_action('parse_query', 'change_title_if_job_posting'); 

This will only add the function to the filter when the main WP_Query has a variable set on it called "slug", which should coincide with the logic you laid out above.

Answers 3

I understand that you have already tried using wp_title filter but please try it the following way

function job_listing_title_override ($title, $sep){     if (is_page_template('templates/job-listing.php')) {         $title = 'Job Listing Page '.$sep.' '. get_bloginfo( 'name', 'display' );     }     return $title; } add_filter( 'wp_title', 'job_listing_title_override', 10, 2 ); 

Answers 4

From qn and comments I assume you are using a custom page template (probably in a child theme & based on page.php) and not a custom post type?

I similarly use a custom page with non-WP database to display requested content (generating Title, plus unique meta tags for Google on the fly) e.g. http://travelchimps.com/country/france (?cc=france Title "France: travel advice") and travelchimps.com/country/cuba/health ( ?cc=cuba&spg=health "Cuba travel info: Health".)

I may be missing something in your qn, but with a custom page template you do not need filters/WP functionality for page title, you can use your own variable direct. If you need a meaningful index page of joblist titles you can also generate this direct from Redis.

functions.php:

//  allow WP to store querystring attribs for use in our pages function my_query_vars_filter($vars) {   # jobs   $vars[] .= 'slug';   # more vars } add_filter( 'query_vars', 'my_query_vars_filter' ); 

Custom page template:

<?php /* Template Name: JobQryPage*/  // *** get data (i don't know redis)  *** $redisKey = get_query_var('slug');  // validate as reqd // use $redisKey to select $jobInfo from Redis $PAGE_TITLE = $jobInfo['title']; // or whatever // maybe some meta tag stuff  // code copied from page.php ....     // maybe replace "get_header();" with modified header.php code     ...    // ** IN THE HTML FOR THE TITLE: CHANGE say "the_title();" to  "echo $PAGE_TITLE;" **    // e.g. ?>     <h2 class="post-title"><?php echo $PAGE_TITLE; ?></h2>    ...     <div class="post-content">     <?php // ** delete "< ?php the_content(); ? > or other code used to display page editor content           // and replace with your code to render your Redis $jobInfo ** ?>   </div>   <!-- remainder of page.php code --> 

The disadvantage of custom page template is it is "theme specific" - however it is a simple matter to create a new (same name template) using new theme's page.php as a base and copy in code from your old template.

I also prefer to use names to id's. So I used page editor to save an empty page (title and slug of country) with "CountryQryPage" selected as template; and in my site-functions plugin:

function tc_rewrite_rules($rules) {   global $wp_rewrite;   $tc_rule = array(     'country/(.+)/?' => 'index.php?pagename=' . 'country' . '&cc=$matches[1]'   );   return array_merge($tc_rule, $rules); } add_filter('page_rewrite_rules', 'tc_rewrite_rules'); 
Read More

Thursday, July 19, 2018

Apply woocommerce coupon only to the cart total, not to the tax line

Leave a Comment

I am working on a WooCommerce site. When I apply a coupon on the checkout page, it automatically applies to the tax as well.

I only want the coupon code to apply to the cart total. I have searched through google for a related hook or plugin, but can not find a working solution.

This is my current code hook in my functions.php, but it doesn't work as expected.

add_action('woocommerce_product_tax_class', 'set_tax_class'); function set_tax_class () {      if (!empty($woocommerce->cart->applied_coupons)){         $tax_class = 'gratuty';     }     return $tax_class; } 

I have also tried the woocommerce_cart_calculate_fees hook too, but it did not work.

Which hook should I use to update cart, when coupon is applied, without changing the tax?

0 Answers

Read More

Saturday, July 7, 2018

Apache two apps one domain share language /en - Magento & Wordpress

Leave a Comment

We have Wordpress in the root / in a physical subfolder /wp and Magento in /products.

We are wanting to make the sites multi-language using sub folders e.g domain.com/en

The problem arises as magento appends the store code (language) after the url so we have

domain.com/en (wordpress) domain.com/products/en (magento) 

Naturally we would like

domain.com/en domain.com/en/products 

Now it's very easy to make it work with some rewrite rule

RewriteRule ^(.*)/products/?(.*)$ /products/$1 [L] 

But still we have an issue as Magento generates the links as /products/en it's possible to start modifying where these links are generated like in

\Magento\Store\Model\Store  

In the _updatePathUseStoreView function, this doesn't seem to handle all links though

In general seems like a bad solution, another idea is to use Apache mod_substitute also seems bad practice, and overhead.

Another option is to have both apps in the root and have some lookup logic to see which url belongs to which app.

Any ideas for a setup that can purely use just Nginx/Apache. That does not compromise on having unique url's or regex'ing content.

This is my .htaccess in the root

<IfModule mod_rewrite.c> RewriteEngine on  RewriteCond %{HTTP_HOST} ^(www.)?domain.com$ RewriteCond %{REQUEST_URI} !^/wp/ RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d #RewriteCond %{REQUEST_URI} !^/(.*)/products RewriteRule ^(.*)$ /wp/$1 RewriteCond %{HTTP_HOST} ^(www.)?domain.com$ RewriteRule ^(/)?$ wp/index.php [L]  RewriteCond %{REQUEST_URI} ^/(.*)/products RewriteRule ^(.*)$ /products/index.php [L]  </IfModule> 

The exact spec I'm trying to achieve is this.

  • Wordpress is installed in /wp , Magento in /products
  • Language codes via subfolders used on both sites to appear as /en/wordpress-page /en/products/magento-page

Attempt 1 Use base link URL entering /en/products there and keeping the base URL as /products

as the first request is forwarded I had to work the setEnv like so in the root .htaccess

RewriteCond %{REQUEST_URI} ^/(.*)/products RewriteRule ^(.*)$ /products/index.php [E=MAGE_RUN_CODE:%1] [L] 

then in /products/.htaccess

RewriteCond "%{ENV:REDIRECT_MAGE_RUN_CODE}" RewriteRule .* - [E=MAGE_RUN_CODE:%{ENV:REDIRECT_MAGE_RUN_CODE}] [L] 

I checked the code was coming through on index.php by doing

 echo getenv('MAGE_RUN_CODE'); 

In my case the store code is "en" etc.. but the language switcher does not work it hits Magento but gets 404 even thought the store code is definitely coming through.

2 Answers

Answers 1

You only need some configuration from backoffice.

System => Configuration => General => Web => Url options

Add Store Code to Urls No

System => Configuration => General => Web => Unsecure

Base Link URL http://example.com/en/products/

System => Configuration => General => Web => Secure

Base Link URL https://example.com/en/products/

Then, add a rule in htaccess to set the correct store code:

SetEnvIf Host .*example.com/en* MAGE_RUN_CODE=en_store SetEnvIf Host .*example.com/fr* MAGE_RUN_CODE=fr_store

Answers 2

What is the exact spec you're trying to achieve?

Do you have multiple pages like /products, and multiple languages like /en?

I did something similar at BXR.SU — I didn't like the way OpenGrok, my backend, was handling the URLs, so, I would automatically make my nginx fix the URLs on top of OpenGrok, seamlessly fixing the URLs presented to the user, whereas the backend would continue to use the old URLs (e.g., with the /xref/ for most pages, which I don't like, and was set to remove with nginx); this approach appears to be similar to your spec, where you want to do this on the front-end web-server without doing any modifications to the backend.

The approach is briefly described at nginx redirect loop, remove index.php from url, with the idea being that nginx has two types of redirects — internal, where the contents of the $uri variable gets changed (without any visibility to the user), and external, where a 301 Moved (or some such) response is provided to the client (and the user would then see the browser making a request with the new URL).

E.g., you may want to have something like the following:

location /en/ {     # issue an external redirect, unless we're here from an internal one     if ($request_uri ~ "^(/en)(/product)(.*)") {         return 301 $2$1$3; # external redirect     }     proxy_pass …; } location /products/ {     rewrite ^(/products/)(en/)(.*) $2$1$3 last; # internal redirect     … } 
Read More

Error displaying oEmbed Wordpress

Leave a Comment

I've a problem with my wordpress website. When I insert some url for being embedded, it's not working fine.

Here is the issue URL : https://www.duosia.id/windows/cara-mengekstrak-files-menggunakan-winrar-dengan-mudah

And here is the Screenshot :

enter image description here

When I try to visit the embedded url. It's return 404 not found. You can check the embedded url here, https://www.duosia.id/windows/cara-mengekstrak-files-menggunakan-winrar-dengan-mudah/embed/

I've try these common solutions.

  1. Update everything including WordPress, the theme and plugins. Available updates appear in Dashboard > Updates.
  2. Deactivate all plugins in case there is a conflict. If the problem goes away while all plugins are inactive, then reactivate them one by one to determine which is causing the problem.
  3. Switch to the default theme (such as Twenty Thirteen) then try to do what was not working. If the problem remains, it is a general WordPress or hosting issue. If it happens only while using our theme, please let us know.
  4. Clear cache in both your browser and in any caching plugins that you are using (also disable services like CloudFlare, if used with your website).
  5. Revert code changes if you have modified the theme’s code. If using a child theme, reactivate the parent theme.

But, seems no one work.

2 Answers

Answers 1

The WordPress post embeds don't seem to be working on your site. This URL shows a live example of the problem:

https://www.duosia.id/windows/whatsapp-for-pc/

The two embeds present in that URL are returning a 404, therefore, oEmbeds are not loading properly and showing the 404 page:

https://www.duosia.id/windows/facebook-messenger-for-pc/embed/#?secret=kMPv636bx1 https://www.duosia.id/windows/line-for-pc/embed/#?secret=65m4VpxiYi

Have you tried testing those URLs in the plugin "Rewrite Rules Inspector"? You should see something like this for any of the "embed" URLs:

index.php?name=$matches[1]&embed=true 

Also, have you tried flushing the rewrite rules in WordPress or maybe setting the permalink structure to a different/default one (right now you seem to be using a structure of "category/post-name") to see if it changes anything?

Answers 2

For the file that you are embedding, are you uploading it to the Media Library or some other plugin?

First I would check on the server to verify that the file you are looking to access does exist.

Once you know that the file does exist, then repeat the steps you have listed again.

Read More

Friday, June 1, 2018

wordpress err_connection_reset in Chrome from specific country

Leave a Comment

I volunteer supporting a news website in Russia, which was hand-crafted in PHP back in 2002-2004. Needless to say, I was super excited when editors hired some folks to build a new version, based on WordPress. The old site is running on mydomain.press. I put the new WordPress version, which is meant to replace the old one, on subdomain.mydomain.press.

And there's a mysterious problem with it.

When an editor is trying to access the site at subdomain.mydomain.press, her browser (Chrome in Russia) instantly reports err_connection_reset, in 9 cases out of 10. Not spinning trying to load the site - an instant error is reported. On my machine (Canada) the same website opens no problem. Well, a little slow (hence I mentioned she's not even seeing the delay - the error is instant), but it opens in 10 out of 10 trials. When her Chrome gets the content (in that 1/10 case), it also shows a slight delay. Only the error case is instantaneous. The old site at mydomain.press is opening 100% of the time.

Connecting remotely to her Windows machine (I'm using Mac OS X) via TeamViewer, I did observe the behaviour described when using Chrome. Interestingly enough, IE didn't show this problem - it loads consistently, except that once in ~10 reloads the page loads with a garbled styling. As if some css isn't loaded properly (but not in a way that would make it an invalid document, obviously).

I'm completely out of my depth. I tried disabling her Windows Defender to see if it's the culprit - nope. I've tried to reset her IP address (as suggested by the same page which offered the earlier way to try and fix the err_connection_reset) - no dice.

I'm not seeing either error from my own Chrome, nor the garbled css (though I didn't try with IExplorer from Canada).

I know they had some ISPs in Russia block them (silly political reason, AFAIK) in the past - but this doesn't look like blocking; she'd be 100% unable to view it otherwise. She's not under any firewall (nor is the website).

what else... nginx is the server used, the setup is "basic", I suppose (I'm not that proficient in configuring it to try anything fancy).

And to make things even more mysterious - the website at mydomain.press (the old version, php-hand-crafted) is opening just fine, 100% of trials.

Opening using the IP-address doesn't change the picture, so doesn't look like a DNS issue.

Any ideas?

1 Answers

Answers 1

There is an ongoing battle of Roskomnadzor against Telegram messenger in Russia, which affects subnets, DNS and DPI hardware around the country. Try to connect via proxy or VPN server outside Russia and see if the problem goes away.

Read More

Sunday, May 27, 2018

Google Map on Listing Section Wordpress

Leave a Comment

I used business directory plugin which add listing section. Add the listing page, I try to add the map inside the listing page. The map seems to appear inside wordpress directory dashboard but it does not appear in the website. I know that this plugin got google map module, but is there any way to put google map without using the google map addon?Here is my code

<p style="text-align: center;"><img class="alignnone size-medium wp-image-291" src="https://harta-net.s3.amazonaws.com/uploads/2018/05/f84590ac-b53e-432d-9137-2241c7075f2d_tb-300x147.jpeg" alt="" width="300" height="147" /></p> <iframe style="border: 0;" src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3984.3164489624587!2d101.61260631430928!3d3.0093049978084196!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x31cdb36044fe6151%3A0x9c6f6535d01735ff!2sMasteron+Grand+Pavilion!5e0!3m2!1sen!2sin!4v1526629036980" width="600" height="450" frameborder="0" allowfullscreen="allowfullscreen"></iframe> 

directory dashboard image. Here is the link of my website

edit: Add the code and the website link

edit 2: try to use other google map plugin to add but still fail

3 Answers

Answers 1

you can try to add this on any page,post or sections of content/text box

   <iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3984.3164489624587!2d101.61260631430928!3d3.0093049978084196!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x31cdb36044fe6151%3A0x9c6f6535d01735ff!2sMasteron+Grand+Pavilion!5e0!3m2!1sen!2sin!4v1526629036980" width="600" height="450" frameborder="0" style="border:0" allowfullscreen></iframe> 

Answers 2

Try using Shortcode.

Here's a working code you can add to the theme's functions.php file:

add_shortcode( 'gmaps_iframe', 'gmaps_iframe_shortcode' ); function gmaps_iframe_shortcode( $atts ) {     $atts = shortcode_atts( [         'src'    => '',         'width'  => '600',         'height' => '450',     ], $atts );      return $atts['src'] ? sprintf( '<iframe style="border: 0;" src="%s" width="%s" ' .         'height="%s" frameborder="0" allowfullscreen="allowfullscreen"></iframe>',         esc_url( $atts['src'] ), esc_attr( $atts['width'] ), esc_attr( $atts['height'] )     ) : ''; } 

And you'd use it like this:

<p style="text-align: center;"><img class="alignnone size-medium wp-image-291" src="https://harta-net.s3.amazonaws.com/uploads/2018/05/f84590ac-b53e-432d-9137-2241c7075f2d_tb-300x147.jpeg" alt="" width="300" height="147" /></p> [gmaps_iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3984.3164489624587!2d101.61260631430928!3d3.0093049978084196!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x31cdb36044fe6151%3A0x9c6f6535d01735ff!2sMasteron+Grand+Pavilion!5e0!3m2!1sen!2sin!4v1526629036980"] Other content here, if any. 

You can also use https://wordpress.org/plugins/iframe/ if you don't want to or not familiar of editing the functions.php file. With that plugin, you'd have full control over the iframe attributes; and here's how you'd add the Google Maps iframe to the post/page content:

<p style="text-align: center;"><img class="alignnone size-medium wp-image-291" src="https://harta-net.s3.amazonaws.com/uploads/2018/05/f84590ac-b53e-432d-9137-2241c7075f2d_tb-300x147.jpeg" alt="" width="300" height="147" /></p> [iframe style="border: 0;" src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3984.3164489624587!2d101.61260631430928!3d3.0093049978084196!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x31cdb36044fe6151%3A0x9c6f6535d01735ff!2sMasteron+Grand+Pavilion!5e0!3m2!1sen!2sin!4v1526629036980" width="600" height="450" frameborder="0" allowfullscreen="allowfullscreen"] Other content here, if any. 

You can also try https://wordpress.org/plugins/shortcoder/, which allows you to create content-specific Shortcodes.

Answers 3

Hi Did you added the api key for google maps for specific live url? if not then you have to create and after that you have to mention in your iframe

Read More

Monday, May 21, 2018

WooCommerce product image filename in product title

Leave a Comment

I recently started a WooCommerce project for a photographer client. I installed the commercial WooCommerce Photography extension and the Product Add-Ons extension. The client wants to add the product image title (filename) to the name of the product. Is there a way to do it somehow?

The WooCommerce Photography extension creates individual products from the photos you upload. Every product has one photo as a product image.

Basically, what I want to achieve is to show the filename of the main product image inside the name of the generated product. As long as I have it in the order details page, I am good. Anyone with a similar experience?

1 Answers

Answers 1

Ok. Based on what I have understood from your question, following might be the solution for your problem.

First get featured image url. Ref: How to get featured image of a product in woocommerce

Now use this URL to get filename. Ref: https://gist.github.com/wooki/2709106

Once you get filename, you can echo it wherever needed or you can use this all in single-product template or order-details template.

Hope this helps.

Read More

Sunday, May 6, 2018

How to change wp-admin/edit.php categories filter to a multiselect?

Leave a Comment

I'm using GoDaddy hosting, with WordPress Managed plan, so I can't edit anything in wp-admin/ or wp-includes/ folder, the only folder I've permission is wp-content/.

I tried to look it on google, and tried to find the plugins, I found this plugin Post Filter Multiselect but it doesn't working anymore, my WordPress version is 4.9.5 and the plugin were not updated since 9 month ago. So I tried another plugins but neither of them are working.

If I want to add this with themes or plugins how to do it? because I can't found the answer, thank you.

What I want is to make the wp-admin/edit.php categories filter be a multiselect, because in 1 post, there are so many categories, so to narrow it down, it need multiple categories. and there are a lot of categories, around 50 categories.

2 Answers

Answers 1

Have you tried other plugins like search & filter ? I haven't used it myself but it seems to be what you are looking for. Also, have you tried contacting the support to see if they could grant you access to the folder?

Answers 2

OK, so this is slightly a sledgehammer-to-crack-nut approach, but you could install the Advanced Custom Fields plugin and create a Taxonomy field. You can select an Appearance of Multiple Values > Multi Select and make sure that Create Terms, Save Terms and Load Terms are all true so that your categories are synced properly with the post. Finally, in the field group settings you can select the checkbox to hide the normal categories meta box.

It's one that's worked for me in the past without requiring extra plugins (since I already use ACF).

Read More

Thursday, April 12, 2018

add custom wordpress attribute for generate thumbnail in xml feed

Leave a Comment

i want to create xml product feed for some external services so i using wordpress plugin to generate that feed.

the problem is that the plugin using main image for the feed. so i want to add custom attribute to change that main product image to thumbnail product image

the plugin and woocommerce doesn't have thumbnail attribute by default

i'm using WooCommerce Product Feed Plugin PRO wordpress plugin

enter image description here

0 Answers

Read More

Friday, March 9, 2018

Woocommerce require fields

Leave a Comment

Below is the code I am using to make states field mandatory for all places but for specific countries like Germany its still not mandatory. I want to make it mandatory for all.

add_filter( 'woocommerce_checkout_fields', 'custom_override_default_address_fields' ); function custom_override_default_address_fields($fields){         $fields['billing']['state']['required'] = true;         $fields['shipping']['state']['required'] = true;     }     return $fields; } 

2 Answers

Answers 1

I figured out WordPress itself removes the required state field in many countries (like Kuwait) and it can not be made required using,

   $fields['billing']['state']['required'] = true;    $fields['shipping']['state']['required'] = true; 

What I did is, I checked the size of of the input value in the state drop-down (when user presses order button) and if the value was empty, I showed an error.

function stateMandatory ($billingstate) {   if ($billingstate== "") {     wc_add_notice("State field is mandatory", "error");   }   return $order; } add_filter( 'woocommerce_create_order', 'stateMandatory', 10, 1 ); 

Answers 2

Note that your code is incorrect, remove the extra '}'.

Use woocommerce_default_address_fields instead of woocommerce_checkout_fields:

add_filter('woocommerce_default_address_fields', 'custom_override_default_address_fields');  function custom_override_default_address_fields( $fields ) {      $fields['state']['required'] = false;       return $fields; } 

If you have other filters, try to add a priority (a priority of 20 will run after code with 10 priority):

add_filter('woocommerce_default_address_fields', 'custom_override_default_address_fields', 100); 

And if you really need to use woocommerce_checkout_fields then use billing_stateand shipping_state instead of state:

add_filter('woocommerce_checkout_fields', 'custom_override_checkout_fields');  function custom_override_checkout_fields( $fields ) {   $fields['billing']['billing_state']['required'] = true;   $fields['shipping']['shipping_state']['required'] = true;    return $fields; } 
Read More

Monday, February 26, 2018

WordPress - Add gallery overlay to a metabox using wp.media

Leave a Comment

I'm trying to use a metabox to store a comma separated string of attachment IDs in WordPress.

I have the metabox working fine, but I'm trying to get the wp.media overlay to open in a way that allows the user to select multiple images, and drag and drop order them, then when clicking "select" button, that it puts the string of IDs into the metabox.

Please don't suggest a plugin. I know there are lots of them out there, but I'm building this into a theme and want the bare minimum code.

The JS & PHP I have is this:

jQuery('.custom-post-gallery').on( 'click', function(e){      e.preventDefault();        var image_frame;      if(image_frame){         image_frame.open();      }        // Define image_frame as wp.media object      image_frame = wp.media({          title: 'Select Gallery Images',          library : {              type : 'image'          },          multiple: true      });        image_frame.states.add([          new wp.media.controller.Library({              id:         'post-gallery',              title:      'Select Images for the Post Gallery',              priority:   20,              toolbar:    'main-gallery',              filterable: 'uploaded',              library:    wp.media.query( image_frame.options.library ),              multiple:   image_frame.options.multiple ? 'reset' : false,              editable:   true,              allowLocalEdits: true,              displaySettings: true,              displayUserSettings: true          });      ]);        image_frame.open();  });
<?php      $meta_key = 'custom_post_gallery';      $image_ids = get_post_meta( $post->ID, $meta_key, true );  ?>      <input class="custom-post-gallery" name="<?php echo $meta_key; ?>" type="text" value="<?php echo $image_ids; ?>"/>

This overlay just shows the UI to pick one image, or multiple, if holding control key, but no drag and drop ordering etc. Can I open it in the "gallery" mode somehow? And give it the IDs to use for currently selected images?

Thanks!

1 Answers

Answers 1

If i got you right, you've got text field which open media window on click and you want to insert the id's of the selected images into the field value (id's separated by comma) when clicking on select button. if that so, so this is what i modified:

Fix:

Error because of the semicolon (it is inside an array which can not have semicolon)

    displayUserSettings: true }); // --> here 

Modified:

image_frame variable needs to be set outside this scope and return after reopen action

var image_frame; // --> outside the scope if(image_frame){    image_frame.open();    // --> add return } 

Additions:

Wrap the JS and inject the jQuery as $ sign into the scope, now we can use $ sign instead of jQuery and prevent conflicts with other JS scripts:

(function($){ ... })(jQuery); 

Set the text field object as $that variable so we will be use it inside deeper scopes

var $that = $(this); 

Add the select action and insert the selected images id's separated by comma into the field value:

       image_frame.on( 'select', function() {              var ids = '', attachments_arr = [];              // Get media attachment details from the frame state             attachments_arr = image_frame.state().get('selection').toJSON();             $(attachments_arr).each(function(e){                 sep = ( e != ( attachments_arr.length - 1 ) ) ? ',' : '';                 ids += $(this)[0].id + sep;             });             $that.val(ids);          }); 

All together:

Just the JS part, which was modified:

(function($){      var image_frame;      $('.custom-post-gallery').on( 'click', function(e){          e.preventDefault();          // If the media frame already exists, reopen it.         if (image_frame){            image_frame.open();            return;         }          var $that = $(this);          // Define image_frame as wp.media object         image_frame = wp.media({             title: 'Select Gallery Images',             library : {                 type : 'image'             },             multiple: true         });          image_frame.states.add([             new wp.media.controller.Library({                 id:         'post-gallery',                 title:      'Select Images for the Post Gallery',                 priority:   20,                 toolbar:    'main-gallery',                 filterable: 'uploaded',                 library:    wp.media.query( image_frame.options.library ),                 multiple:   image_frame.options.multiple ? 'reset' : false,                 editable:   true,                 allowLocalEdits: true,                 displaySettings: true,                 displayUserSettings: true             })         ]);          image_frame.open();          image_frame.on( 'select', function() {              var ids = '', attachments_arr = [];              // Get media attachment details from the frame state             attachments_arr = image_frame.state().get('selection').toJSON();             $(attachments_arr).each(function(e){                 sep = ( e != ( attachments_arr.length - 1 ) ) ? ',' : '';                 ids += $(this)[0].id + sep;             });             $that.val(ids);          });      });     })(jQuery); 

This is working for me, tell me if you have any issue.

Read More

Monday, February 19, 2018

WordPress wp_title bloginfo on one webserver missing

Leave a Comment

Today I created for our website a staging environment to test new functionality.

Therefore I backed up the current homepage with UpdraftPlus and migrated this to the staging web server.

Everything is fine and the websites are almost identical.The only thing that is not equal, is the title.

I use this title statement <title><?php wp_title('-', true, 'right'); ?></title>.

On the origin website I get (how it should be):
On a sub page: Sitename - Blogname
On the home page: Blogname

The migrated:
On a subpage: Sitename -
On the home page: blank

Both systems are running on the same WordPress version 4.9.4 (latest) and PHP 7.0

Current research:
When I use <?php wp_title('-'); ?> I get - Sitename

I do know this question, but this is only a workaround.

0 Answers

Read More

Thursday, February 8, 2018

How to stream creation of a JSON File?

Leave a Comment

Am trying to create a JSON file from a large dump of a database query, and works when I set a LIMIT to 100000 rows being returned, but when I want all rows to be returned, it just goes to a 502 Error (The page request was canceled because it took too long to complete). Wondering if there is a way that I can streamline the creation of a JSON File in bits using php, or if there is a Library out there that will allow me to build the json file in parts?

Basically am running a .php file here to attempt to get all orders in json format from woocommerce, since the plugin I purchased "CSV Import Suite" does not work when importing orders, it just stays in the queue.

So, I decided to try and export all orders myself, but keep hitting a 502 Error Page and it never creates the .json file either, so am thinking I need a way to stream this somehow. Any help on this would be appreciated...

ini_set('memory_limit', '-1'); ini_set('max_execution_time', '-1'); set_time_limit(0); error_reporting(E_ALL); ob_implicit_flush(TRUE); ob_end_flush();  global $wpdb, $root_dir;  if (!defined('ABSPATH'))     $root_dir = dirname(__FILE__) . '/'; else     $root_dir = ABSPATH;   $download = isset($_GET['download']);  // Allows us to use WP functions in a .php file without 404 headers! require_once($root_dir . 'wp-config.php'); $wp->init(); $wp->parse_request(); $wp->query_posts(); $wp->register_globals();  if (empty($download))     $wp->send_headers();  // exclude $exclude_post_statuses = array('trash', 'wc-refunded', 'wc_cancelled');   $start_date = !empty($_GET['start_date']) ? DateTime::createFromFormat('Y-m-d', $_GET['start_date']) : ''; $end_date = !empty($_GET['end_date']) ? DateTime::createFromFormat('Y-m-d', $_GET['end_date']) : '';   $order_db = array(     'columns' => array(         'p' => array('ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_excerpt', 'post_status', 'comment_status', 'ping_status', 'post_password', 'post_name', 'to_ping', 'pinged', 'post_modified', 'post_modified_gmt', 'post_content_filtered', 'post_parent', 'guid', 'menu_order', 'post_type', 'post_mime_type', 'comment_count'),         'pm' => array('meta_id', 'post_id', 'meta_key', 'meta_value'),         'oi' => array('order_item_id', 'order_item_name', 'order_item_type', 'order_id'),         'oim' => array('meta_id', 'order_item_id', 'meta_key', 'meta_value')     ) );  $select_data = ''; $total_columns = count($order_db['columns']); $i = 1;  foreach($order_db['columns'] as $column_key => $columns) {     $select_data .= implode(', ', array_map(         function ($v, $k) { return $k . '.' . $v . ' AS ' . $k . '_' . $v; },         $columns,         array_fill(0, count($columns), $column_key)     ));      if ($i < $total_columns)         $select_data .= ', ';      $i++; }  // HUGE DATABASE DUMP HERE, needs to be converted to JSON, after getting all columns of all tables... $orders_query = $wpdb->get_results('     SELECT ' . $select_data . '     FROM ' . $wpdb->posts . ' AS p     INNER JOIN ' . $wpdb->postmeta . ' AS pm ON (pm.post_id = p.ID)     LEFT JOIN ' . $wpdb->prefix . 'woocommerce_order_items AS oi ON (oi.order_id = p.ID)     LEFT JOIN ' . $wpdb->prefix . 'woocommerce_order_itemmeta AS oim ON (oim.order_item_id = oi.order_item_id)     WHERE p.post_type = "shop_order"' . (!empty($exclude_post_statuses) ? ' AND p.post_status NOT IN ("' . implode('","', $exclude_post_statuses) . '")' : '') . (!empty($start_date) ? ' AND post_date >= "' . $start_date->format('Y-m-d H:i:s') . '"' : '') . (!empty($end_date) ? ' AND post_date <= "' . $end_date->format('Y-m-d H:i:s') . '"' : '') . '     ORDER BY p.ID ASC', ARRAY_A);  $json = array();  if (!empty($orders_query)) {     foreach($orders_query as $order_query)     {         if (!isset($json[$order_query['p_post_type']], $json[$order_query['p_post_type']][$order_query['p_post_name']]))             $json[$order_query['p_post_type']][$order_query['p_post_name']] = array(                 'posts' => array(),                 'postmeta' => array(),                 'woocommerce_order_items' => array(),                 'woocommerce_order_itemmeta' => array()             );          if (!empty($order_query['p_ID']))             $json[$order_query['p_post_type']][$order_query['p_post_name']]['posts'][$order_query['p_ID']] = array_filter($order_query, function($k) {                 $is_p = strpos($k, 'p_');                 return $is_p !== FALSE && empty($is_p);             }, ARRAY_FILTER_USE_KEY);          if (!empty($order_query['pm_meta_id']))             $json[$order_query['p_post_type']][$order_query['p_post_name']]['postmeta'][$order_query['pm_meta_id']] = array_filter($order_query, function($k) {                 $is_pm = strpos($k, 'pm_');                 return $is_pm !== FALSE && empty($is_pm);             }, ARRAY_FILTER_USE_KEY);          if (!empty($order_query['oi_order_item_id']))             $json[$order_query['p_post_type']][$order_query['p_post_name']]['woocommerce_order_items'][$order_query['oi_order_item_id']] = array_filter($order_query, function($k) {                 $is_io = strpos($k, 'oi_');                 return $is_io !== FALSE && empty($is_io);             }, ARRAY_FILTER_USE_KEY);           if (!empty($order_query['oim_meta_id']))             $json[$order_query['p_post_type']][$order_query['p_post_name']]['woocommerce_order_itemmeta'][$order_query['oim_meta_id']] = array_filter($order_query, function($k) {                 $is_oim = strpos($k, 'oim_');                 return $is_oim !== FALSE && empty($is_oim);             }, ARRAY_FILTER_USE_KEY);     } }  // Downloading or viewing? if (!empty($download)) {     // Outputs json in a textarea for you to copy and paste into a .json file for import...      if (!empty($json))     {         $filename = uniqid('orders_') . '.json';          $fp = fopen($filename, 'w');         fwrite($fp, json_encode($json));         fclose($fp);           $size   = filesize($root_dir . '/' . $filename);         header('Content-Description: File Transfer');         header('Content-Type: application/octet-stream');         header("Content-Disposition: attachment; filename=\"" . $filename . "\"");          header('Content-Transfer-Encoding: binary');         header('Connection: Keep-Alive');         header('Expires: 0');         header('Cache-Control: must-revalidate, post-check=0, pre-check=0');         header('Pragma: public');         header('Content-Length: ' . $size);          readfile($root_dir . '/' . $filename);     }  } else {     // Outputs json in a textarea for you to copy and paste into a .json file for import...     if (!empty($json))         echo '<textarea cols="200" rows="50">', json_encode($json), '</textarea>'; } 

The JSON File created could be a well over 500 MB, and possibly even up to 1 Gig of data. So, I believe PHP is running out of memory here, and needs to be processed bit by bit somehow, either in the background, or completely, without hitting the php memory limit. I believe the memory limit is set to 1024 MB, which is pretty high, but not high enough and tbh, for what I'm doing, I don't think we can ever have enough memory to perform the operation as is. Something needs to change in how I process the json and/or download it. And I do not want to create multiple json files, please only 1 JSON file.

5 Answers

Answers 1

I think there might be couple of issues. Firstly I would suggest you do some profiling.

    // HUGE DATABASE DUMP HERE, needs to be converted to JSON, after getting all columns of all tables...     echo 'Start Time: '. date("Y-m-d H:i:s");     echo ' Memory Usage: ' . (memory_get_usage()/1048576) . ' MB \n';      $orders_query = $wpdb->get_results('         SELECT ' . $select_data . '         FROM ' . $wpdb->posts . ' AS p         INNER JOIN ' . $wpdb->postmeta . ' AS pm ON (pm.post_id = p.ID)         LEFT JOIN ' . $wpdb->prefix . 'woocommerce_order_items AS oi ON (oi.order_id = p.ID)         LEFT JOIN ' . $wpdb->prefix . 'woocommerce_order_itemmeta AS oim ON (oim.order_item_id = oi.order_item_id)         WHERE p.post_type = "shop_order"' . (!empty($exclude_post_statuses) ? ' AND p.post_status NOT IN ("' . implode('","', $exclude_post_statuses) . '")' : '') . (!empty($start_date) ? ' AND post_date >= "' . $start_date->format('Y-m-d H:i:s') . '"' : '') . (!empty($end_date) ? ' AND post_date <= "' . $end_date->format('Y-m-d H:i:s') . '"' : '') . '         ORDER BY p.ID ASC', ARRAY_A);      echo 'End Time: '. date("Y-m-d H:i:s");     echo ' Memory Usage: ' . (memory_get_usage()/1048576) . ' MB \n';     die('Finished');      $json = array(); 

The above will help you to know how much memory is in use, upto this point. If it fails before it prints 'Finished', we know it is not a json issue. If the script works fine then we can first create a csv file rather json. Since you are running a select query, (at this point) it does not have to be nested json file which you require. A flat structure can be achieved by just creating a CSV file.

$csvFile = uniqid('orders') . '.csv'; $fp = fopen($csvFile, 'w'); if (!empty($orders_query)) {     $firstRow = true;     foreach($orders_query as $order_query)     {         if(true === $firstRow) {             $keys = array_keys($order_query);             fputcsv($fp, $order_query);             $firstRow = false;         }          fputcsv($fp, $order_query);     } } fclose($fp); 

If the above works fine you at-least have a csv file to work with.

At this point I am not sure how complex is your data structure nested. For e.g how many distinct values exist for 'p_post_type' and 'p_post_name' you are having. You might require to parse the csv file and create multiple json file for each ['p_post_type']['p_post_name']['posts'], ['p_post_type']['p_post_name']['posts'], ['p_post_type']['p_post_name']['woocommerce_order_items'] and ['p_post_type']['p_post_name']['woocommerce_order_itemmeta'].

If the number of files are few you can write a script to merge them automatically or do them manually. If you have too many nested items, the number of json files that might be created might be a lot and might be hard to merge them and might not be a feasible option.

If the number of json files are lot, I would like to know what is the purpose of having such a huge single json file. If export is an issue import might be an issue too, especially ingesting such a huge json file in memory. I believe if the purpose of creating the json file is to import it in some form, at some stage in future, I think you might have to look at the option of just having a csv file instead, which you use to filter out whatever is required at that point of time.

I hope this helps.

FURTHER UPDATE

It looks to me that $wpdb->get_results is using mysqli_query/mysql_query (depending on your configuration) to fetch the results. See wordpress query docs. It is not memory efficient way to fetch the data this way. I believe you might be failing at this point ($wpdb->get_results) itself. I would suggest you to run the query without using $wpdb. There is a concept of unbuffered query whenever large data retrieval is required, which has very low impact on the memory. Further information can be found here mysql unbuffering.

Even if you get past this point, you will still run into memory issues, due to the way how you are storing everything in $json variable which is eating up lot of your memory. $json is an array and it would interesting to know how PHP array works. PHP arrays are dynamic and they do not allocate extra memory every time a new element is added, since that would be extremely slow. It instead, increases the array size to the power of two, which means whenever the limit is exhausted it increases the array limit to twice its current limit and in the process tries to increase the memory to twice the limit. This has been less of an issue with PHP 7, since they have made some major changes to the php core. So if you have 2GB data that might be required to be stored in $json, the script might easily allocate anywhere between 3-4 GB memory, depending upon when it hits the limit. Further details can be found here php array and How does PHP memory actually work

If you consider the overhead of the $orders_query which is an array combined with overhead of $json it is quite substantial due to the way PHP array works.

You can also try to create another database B. So while you are reading from database A, you simultaneously start writing data to database B. In the end you have database B with all the data in it with the power of MySQL. You could also push the same data into a MongoDB which would be lightning fast and might help you with the json nesting you are after. MongoDB is meant to work really efficiently with large datasets.

JSON STREAMING SOLUTION

Firstly, I would like to say that streaming is sequential/linear process. As such, it is does not have memory of what was added before this point of time or what will added after this point of time. It works in small chunks and that is the reason it is so memory efficient. So when you actually write or read, the responsibility lies with the script, that it maintains a specific order, which is kind of saying you are writing/reading your own json, as streaming only understands text and has no clue about what json is and won't bother itself in writing/reading a correct one.

I have found a library on github https://github.com/skolodyazhnyy/json-stream which would help in you achieving what you want. I have experimented with the code and I can see it will work for you with some tweaks in your code.

I am going to write some pseudo-code for you.

//order is important in this query as streaming would require to maintain a proper order. $query1 = select distinct p_post_type from ...YOUR QUERY... order by p_post_type; $result1 = based on $query1;   $filename = 'data.json'; $fh = fopen($filename, "w"); $writer = new Writer($fh); $writer->enter(Writer::TYPE_OBJECT);    foreach($result1 as $fields1) {     $posttype = $fields1['p_post_type'];     $writer->enter($posttype, Writer::TYPE_ARRAY);       $query2 = select distinct p_post_name from ...YOUR QUERY... YOUR WHERE ... and p_post_type= $posttype order by p_post_type,p_post_name;     $result2 = based on $query2;      foreach($result2 as $fields2) {         $postname = $fields1['p_post_name'];         $writer->enter($postname, Writer::TYPE_ARRAY);           $query3 = select ..YOUR COLUMNS.. from ...YOUR QUERY... YOUR WHERE ... and p_post_type= $posttype and p_post_name=$postname where p_ID is not null order by p_ID;         $result3 = based on $query3;         foreach($result2 as $field3) {             $writer->enter('posts', Writer::TYPE_ARRAY);              // write an array item             $writer->write(null, $field3);         }         $writer->leave();           $query4 = select ..YOUR COLUMNS.. from ...YOUR QUERY... YOUR WHERE ... and p_post_type= $posttype and p_post_name=$postname where pm_meta_id is not null order by pm_meta_id;         $result4 = based on $query4;         foreach($result4 as $field4) {             $writer->enter('postmeta', Writer::TYPE_ARRAY);              // write an array item             $writer->write(null, $field4);         }        $writer->leave();           $query5 = select ..YOUR COLUMNS.. from ...YOUR QUERY... YOUR WHERE ... and p_post_type= $posttype and p_post_name=$postname where oi_order_item_id is not null order by oi_order_item_id;         $result5 = based on $query5;         foreach($result5 as $field5) {             $writer->enter('woocommerce_order_items', Writer::TYPE_ARRAY);              // write an array item             $writer->write(null, $field5);         }         $writer->leave();           $query6 = select ..YOUR COLUMNS.. from ...YOUR QUERY... YOUR WHERE ... and p_post_type= $posttype and p_post_name=$postname where oim_meta_id is not null order by oim_meta_id;         $result6 = based on $query6;         foreach($result6 as $field6) {             $writer->enter('woocommerce_order_itemmeta', Writer::TYPE_ARRAY);              // write an array item             $writer->write(null, $field5);         }         $writer->leave();       } $writer->leave();  fclose($fh); 

You might have to start limiting your queries to 10 something until you get it right. Since the code above might not just work as it is. You should be able to read the code in similar fashion as the same library has got a Reader class to help. I have tested both reader and writer and they seem to work fine.

Answers 2

Streaming is easy and has already been answered on SO many times. However I personally don't recommend you doing anything time consuming in PHP, because it sucks as a long running process, either in the command line or as a file server.

I assume you are using Apache. You should consider using SendFile and let Apache do the hard work for you. This method is far more efficient when dealing with huge files. This method is very easy, all you need to do is pass the path to the file in the header:

header('X-Sendfile: ' . $path_to_the_file); 

Should you use Nginx there's XSendFile support as well.

This method does not use a lot of memory, does not block the PHP process. The file does not need to be accessible in the webroot too. I use XSendFile all the time to serve 4K videos to authenticated users.

Answers 3

First, you should ask yourself a question: Do I need to write database dump myself?

If not then you can simply use some service that will do the work for you. Mysqldump-php should be able to do the job.

Then you can simply:

include_once(dirname(__FILE__) . '/mysqldump-php-2.0.0/src/Ifsnop/Mysqldump/Mysqldump.php'); $dump = new Ifsnop\Mysqldump\Mysqldump('mysql:host=localhost;dbname=testdb', 'username', 'password'); $dump->start('storage/work/dump.sql'); 

This should create .sql file. However, you wanted json file. That shouldn't be a problem though. This tool will do the rest of the job: http://www.csvjson.com/sql2json

You can also find the source code of sql2json on github: https://github.com/martindrapeau/csvjson-app

Answers 4

I believe you may be looking for Generators http://php.net/manual/en/language.generators.overview.php https://scotch.io/tutorials/understanding-php-generators

Instead of creating that huge $json array, you iterate over each $order_query and perform operations on each iteration, negating the need to store it in memory.

Answers 5

Your problem is that you get a large result set from your query, which is heavy since you have 3 joins.

You could define a limit and use offset to get the data in chunks and then output your json in parts. The main problem is to somehow get the json data in memory and then access it to output in parts.

For the latter cache or a nosql database could be used. My solution will use cache and in particular memcache:

class Cache {      private $cache;      public function __construct($cache)     {         $this->cache = $cache;     }      public function addPostName($postName)     {         $this->addKeyToJsonObject('postNames', $postName);     }      public function addKeyToJsonObject($rootName, $key)     {         $childNames = $this->cache->get($rootName);         if($childNames === false) {             $this->cache->set($rootName, [$key]);         }         else {             $childNamesList = $childNames;             // not found             if(array_search($key, $childNamesList) === false) {                 $childNamesList[] = $key;                 $this->cache->set($rootName, $childNamesList);             }         }     }      public function getPostNames()     {         return $this->cache->get('postNames');     }     public function set($key, $value) {         $this->cache->add($key, $value);     }      public function addPostIdsByNameAndType($postName, $type, $pid)     {         $this->addKeyToJsonObject($postName . '-' . $type, $pid);     }      public function getPostIdsByNameAndType($postName, $type)     {         return $this->cache->get($postName . '-' . $type);     }      public function addPostValueByNameTypeAndId($postName, $type, $pid, $value)     {         $this->cache->set($postName . '-' . $type . '-' . $pid, $value);     }      public function getPostValueByNameTypeAndId($postName, $type, $pid)     {         return $this->cache->get($postName . '-' . $type . '-' . $pid);     } } 

and then:

$memcache = new Memcache(); $memcache->connect('127.0.0.1', 11211) or die ("Could not connect");  $memcache->flush();  $cache = new Cache($memcache);  header('Content-disposition: attachment; filename=file.json'); header('Content-type: application/json'); echo '{"shop_order":{';  function getResultSet($wpdb, $offset = 1) {     return $wpdb->get_results('     SELECT ' . $select_data . ' FROM ' . $wpdb->posts . ' AS p INNER JOIN ' . $wpdb->postmeta . ' AS pm ON (pm.post_id = p.ID) LEFT JOIN ' . $wpdb->prefix . 'woocommerce_order_items AS oi ON (oi.order_id = p.ID) LEFT JOIN ' . $wpdb->prefix . 'woocommerce_order_itemmeta AS oim ON (oim.order_item_id = oi.order_item_id) WHERE p.post_type = "shop_order"' . (!empty($exclude_post_statuses) ? ' AND p.post_status NOT IN ("' . implode('","', $exclude_post_statuses) . '")' : '') . (!empty($start_date) ? ' AND post_date >= "' . $start_date->format('Y-m-d H:i:s') . '"' : '') . (!empty($end_date) ? ' AND post_date <= "' . $end_date->format('Y-m-d H:i:s') . '"' : '') . ' ORDER BY p.ID ASC LIMIT 1000 OFFSET ' . $offset, ARRAY_A);  } $offset = 1;  $orders_query = getResultSet($wpdb, 1); while(!empty($orders_query)) {     outputRowData($cache, $orders_query);     $memcache->flush();     ob_flush();     flush();   // flush the output to start the download     $offset = $offset + 1000;     $orders_query = getResultSet($wpdb, $offset); }  function outputRowData($cache, $orders_query) {     foreach($orders_query as $order_query) {          if(empty($order_query)) { continue; }         $cache->addPostName($order_query['p_post_name']);          // posts         if (!empty($order_query['p_ID'])) {             $cache->addPostIdsByNameAndType($order_query['p_post_name'],'posts', $order_query['p_ID']);              $value = array_filter($order_query, function($k) {                 $is_p = strpos($k, 'p_');                 return $is_p !== FALSE && empty($is_p);             }, ARRAY_FILTER_USE_KEY);             $cache->addPostValueByNameTypeAndId($order_query['p_post_name'],'posts', $order_query['p_ID'], $value);         }         if (!empty($order_query['pm_meta_id'])) {         $cache->addPostIdsByNameAndType($order_query['p_post_name'],'postmeta', $order_query['pm_meta_id']);          $value = array_filter($order_query, function($k) {             $is_pm = strpos($k, 'pm_');             return $is_pm !== FALSE && empty($is_pm);         }, ARRAY_FILTER_USE_KEY);         $cache->addPostValueByNameTypeAndId($order_query['p_post_name'],'postmeta', $order_query['pm_meta_id'], $value);     }         // here do the same for "woocommerce_order_items" and "woocommerce_order_itemmeta"     }      $cachedPostNames = $cache->getPostNames();     $firstRow = true;      foreach($cachedPostNames as $postName) {          if(empty($postName)) { continue; }          if($firstRow === false) {             echo ',';         }         $firstRow = false;          echo '"' . $postName . '":{';         $postIds = $cache->getPostIdsByNameAndType($postName, 'posts');         if(!$postIds) {             $postIds = [];         }          // generate posts         $postValues = [];         foreach ($postIds as $postId) {             $postValues[$postId] = $cache->getPostValueByNameTypeAndId($postName, 'posts', $postId);         }          $postMetaIds = $cache->getPostIdsByNameAndType($postName, 'postmeta');         if(!$postMetaIds) {             $postMetaIds = [];         }         $postMetaValues = [];         foreach ($postMetaIds as $postMetaId) {             $postMetaValues[$postMetaId] = $cache->getPostValueByNameTypeAndId($postName, 'postmeta', $postMetaId);         }         // here do the same for "woocommerce_order_items" and "woocommerce_order_itemmeta"          echo '"posts":' . json_encode($postValues) . ',';         echo '"postmeta":' . json_encode($postMetaValues);         echo '}';      } }   echo '}}'; 
Read More