When I insert new images from Unsplash.com the image size "full" returns a scaled image with "-scaled.jpg" at the end of the name file and is always limited to 2560 pixels. So how can I retrieve the real "full" size of the image?
You have first to disable this "feature" introduced in WordPress 5.3 by adding this line of code in your functions.php:
add_filter( 'big_image_size_threshold', '__return_false' );
This will disable the scaling down for any FUTURE uploads. But for existing images you have to update the image sizes.
Unfortunately the WordPress team proves once more its incompetence - they dind't provide any functions to update the postmeta for existing attachments and obviously they don't give a single f... about this issue as you can see here, where dozens of people expressed there anger about this so called feature.
I have created today a site with several thousands of dummy posts with featured images from Unsplash.com and where I needed the full size of the images. It took a couple of hours to run the script which downloaded and created the blog posts and the attachments posts. So it wasn't an option to me to delete all the posts and run the dummy script again once I've found out about the new "feature" and how to disable it.
So I wrote another script which took me still a bunch of time...
You need to put the following code in a php file and run/call it from either the browser or terminal. Don't forget to replace the path to the wp-load.php file. On my local machine it took just a couple of seconds for several thousand attachment posts.
<?php
require_once( "/absolute/or/relative/path/to/wordpress/wp-load.php" );
ini_set( 'max_execution_time', 3600 );
set_time_limit( 3600 );
$pdo = new PDO( "mysql:dbname=" . DB_NAME . ";host=" . DB_HOST, DB_USER, DB_PASSWORD );
/**
* replace _wp_attached_file meta_key
**/
global $wpdb;
$wp_postmeta = $wpdb->prefix . "postmeta";
try {
$pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );//Error Handling
$sql = "UPDATE $wp_postmeta SET meta_value = REPLACE(meta_value,'-scaled.jpg','.jpg') WHERE meta_key='_wp_attached_file' AND meta_value LIKE '%-scaled.jpg%'";
$result = $pdo->exec( $sql );
print_r( $result );
} catch ( PDOException $e ) {
print_r( $e->getMessage() );
}
/**
* replace _wp_attachment_metadata meta_key
**/
$image_metas = [];
try {
$pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );//Error Handling
$sql = "SELECT * FROM $wp_postmeta WHERE meta_value LIKE '%-scaled.jpg%' AND meta_key='_wp_attachment_metadata'";
$statement = $pdo->query( $sql );
$image_metas = $statement->fetchAll();
foreach ( $image_metas as $meta ) {
$meta_value = unserialize( $meta["meta_value"] );
$file = $meta_value["file"];
$meta_value["file"] = str_replace( "-scaled.jpg", ".jpg", $file );
update_post_meta( $meta["post_id"], $meta["meta_key"], $meta_value );
$result = get_post_meta( $meta["post_id"], $meta["meta_key"] );
print_r( $result );
}
} catch ( PDOException $e ) {
print_r( $e->getMessage() );
}
Related
I have a situation where i want to create a cron job after every WordPress blog post publish. Cron job will run after 7 days of publishing post and check if all the users have viewed the posts and email the list of not viewed post by users list. How can i achieve this. Its a WordPress website and there are around 300+ users, after each blog post publish user gets notification. So want to check who has viewed and who has not viewed the post.
If you want to start the cron job only the first time a post is published, you'll want to use the draft_to_publish hook.
draft_to_publish
Well there are Plugins capable of managing Stats and tracking users activities. I'm not sure which one fit to your needs but I'll try to give a simple approach to do it by yourself.
Tracking
We can set a custom field for those (posts/post-types) where we will store a list of users who read that post. Let's call it readerslist
On the single.php file we will add these lines to Update this field.
$list = explode(',',get_post_meta($post->ID, 'readerslist', true));
$user = get_current_user_id();
if (!in_array($user,$list)){
array_push($list, $user);
update_post_meta( $post->ID, 'readerslist', implode(",", $list) );
}
Now that we can retrieve who viewed the article? We could later find those who didn't read it yet.
Then in functions.php we could set up a hook that will execute when a post get published, to set a single scheduled cron job to send the absent readers.
<?php
function wpdocs_run_on_publish_only( $new_status, $old_status, $post ) {
{
if ($new_status != 'publish') {
return;
}
//You better add limitations to choose specific post_types you are targeting
$postid=$post->ID;
add_cron($postid);
}
add_action( 'transition_post_status', 'wpdocs_run_on_publish_only', 10, 3 );
function add_cron($postid){
$nxtweek = strtotime("+1 week");
add_action('sendemail', 'stats_mail', 10, 1);
wp_schedule_single_event(time() + $nxtweek, 'sendemail',array( $postid);
}
function stats_mail($postid)
{
$readerslist = get_post_meta( $postid, 'readerslist', true );
$users = get_users( array( 'fields' => array( 'ID' ) ) );
$absents = array_diff($users, explode(",",$readerslist));
//Now that you got the list of absent users
$names='';
foreach ($absents as $x){
$names.=$x.' : '.get_user_meta( $x,'first_name' , true ).' '.get_user_meta( $x,'last_name' , true ).'<br>';
}
$title=get_the_title($postid);
$to = 'you#example.com';
$subject = 'Users who didn\'t read '.$title;
$headers = array('Content-Type: text/html; charset=UTF-8');
wp_mail( $to, $subject, $names, $headers );
}
?>
Notice : I didn't tested the above code ! I made you this in order to show you how to do it. But there isn't much work to do here. Good luck
I tried your code, it works fine, but i am not able to make it working as i wanted, can you look into it. I don't know what i am doing wrong.
function wpdocs_run_on_publish_only( $new_status, $old_status, $post ) {
if ($new_status != 'publish') {
return;
}
$postid=$post->ID;
add_cron($postid);
}
add_action( 'transition_post_status', 'wpdocs_run_on_publish_only', 10, 3 );
function add_cron($postid){
$nxtweek = strtotime("+1 week");
add_action('sendemail', 'stats_mail', 10, 1);
if ( ! wp_next_scheduled( 'sendemail') ) {
wp_schedule_event(time() + $nxtweek, $nxtweek, 'sendemail', array($postid));
// i want to run cron every 7 days from the date of publishing post, until all user reads it, i tried this code but not working.
// wp_mail( 'email#company.com', $postid, 'test', null );
// For testing purpose if i send mail from here, it goes.
}
}
function stats_mail($postid) {
wp_mail( 'email#company.com', $postid, 'test', null );
// this doesnt work.
$readerslist = get_post_meta( $postid, 'readerslist', true );
$users = get_users( array( 'fields' => array( 'ID' ) ) );
$absents = array_diff($users, explode(",",$readerslist));
//Now that you got the list of absent users
$names='';
foreach ($absents as $x){
$names.=$x.' : '.get_user_meta( $x,'first_name' , true ).' '.get_user_meta( $x,'last_name' , true ).'<br>';
}
$title=get_the_title($postid);
$to = 'email#company.com';
$subject = 'Users who didn\'t read '.$title;
$headers = array('Content-Type: text/html; charset=UTF-8');
//wp_mail( $to, $subject, $names, $headers );
}
I need some php request for get list of all sites in wp-network. Is it possible?
As of WP 4.6 there is a new function to query sites, get_sites($query_arg) which is a parallel to the familiar get_posts($query_args) used for retrieving posts,
$blogs = get_sites();
foreach( $blogs as $b ){
$b->blog_id
//Do stuff
}
NOTE: As pointed out by #guido-walter-pettinari in the comment below, get_sites() is a front for instantiating a new WP_Sites_query object which sets some default query parameters, including the 'number' of sites to return to 100!
You can use
<?php wp_get_sites( $args ); ?>
Examples ,for bellow v 3.0
<?php
$blog_list = get_blog_list( 0, 'all' );
foreach ($blog_list AS $blog) {
echo 'Blog '.$blog['blog_id'].': '.$blog['domain'].$blog['path'].'<br />';
}
?>
Using WordPress functions is a bit problematic, when you aim compatibility with all multisite versions:
get_blog_list is not only deprecated, but it does not return sites not flagged as public either. Strangely, the oficial documentation hasn't warned us about that (you discover only when your code fails).
get_sites, in contrast, works only in WP 4.6.0 or higher
I prefer using the following code, which is compatible with all WordPress versions (as of 3.0.0, of course), and returns all sites of the installation (even the archived ones, deactivated ones, etc.):
global $wpdb;
$blogs = $wpdb->get_results( "SELECT blog_id, domain, path FROM $wpdb->blogs ORDER BY blog_id" );
If you want to filter your results, not showing the archived ones, deactivated ones and spam sites, you have to indicate that in the query as follows:
global $wpdb;
$blogs = $wpdb->get_results( "SELECT blog_id, domain, path FROM $wpdb->blogs WHERE archived = '0' AND deleted = '0' AND spam = '0' ORDER BY blog_id" );
Note: $blogs array is an object collection; you will have to build your own site list with the informations that comes inside every object (id, path, domain) that is more appropriate for you, as exemplified in Firefog and Aurovrata answers.
In the usual way, you will be unable to get the blog name. To fetch blog names, you can use this little hack as follows.
$blog_list = get_blog_list(0, 'all');
foreach ($blog_list as $blog) {
switch_to_blog( $blog['blog_id'] );
$option = 'blogname';
$value = get_option( $option );
echo $value . '<br />';
restore_current_blog();
}
Also, you can use the following alternative method to get the same result by calling the database directly.
global $wpdb;
foreach ($wpdb->get_results("SELECT blog_id, domain, path FROM $wpdb->blogs WHERE archived = '0' AND deleted = '0' AND spam = '0' ORDER BY blog_id") as $key => $blog) {
switch_to_blog( $blog->blog_id );
$option = 'blogname';
$value = get_option( $option );
echo $value . '<br />';
restore_current_blog();
}
Thanks for support!
I need to custom user url in my page using WordPress and BuddyPress.
This is example:
From: (current)
http://example.com/user/pum_su411
To
http://example.com/user/548234
With 548234 is ID of the user.
I want after completed the custom, all users will have url like above automatically.
Thanks for all solutions!
add this code to your theme functions.php file.
function _bp_core_get_user_domain($domain, $user_id, $user_nicename = false, $user_login = false) {
if ( empty( $user_id ) ){
return;
}
if( isset($user_nicename) ){
$user_nicename = bp_core_get_username($user_id);
}
$after_domain = bp_get_members_root_slug() . '/' . $user_id;
$domain = trailingslashit( bp_get_root_domain() . '/' . $after_domain );
$domain = apply_filters( 'bp_core_get_user_domain_pre_cache', $domain, $user_id, $user_nicename, $user_login );
if ( !empty( $domain ) ) {
wp_cache_set( 'bp_user_domain_' . $user_id, $domain, 'bp' );
}
return $domain;
}
add_filter('bp_core_get_user_domain', '_bp_core_get_user_domain', 10, 4);
function _bp_core_get_userid($userid, $username){
if(is_numeric($username)){
$aux = get_userdata( $username );
if( get_userdata( $username ) )
$userid = $username;
}
return $userid;
}
add_filter('bp_core_get_userid', '_bp_core_get_userid', 10, 2);
function _bp_get_activity_parent_content($content){
global $bp;
$user = get_user_by('slug', $bp->displayed_user->fullname); // 'slug' - user_nicename
return preg_replace('/href=\"(.*?)\"/is', 'href="'.bp_core_get_user_domain($user->ID, $bp->displayed_user->fullname).'"', $content);
}
add_filter( 'bp_get_activity_parent_content','_bp_get_activity_parent_content', 10, 1 );
function _bp_get_activity_action_pre_meta($content){
global $bp;
$fullname = $bp->displayed_user->fullname; // 'slug' - user_nicename
$user = get_user_by('slug', $fullname);
if(!is_numeric($user->ID) || empty($fullname)){
$args = explode(' ', trim(strip_tags($content)));
$fullname = trim($args[0]);
$user = get_user_by('slug', $fullname);
}
return preg_replace('/href=\"(.*?)\"/is', 'href="'.bp_core_get_user_domain($user->ID, $fullname).'"', $content);
}
add_action('bp_get_activity_action_pre_meta', '_bp_get_activity_action_pre_meta');
add_filter('bp_core_get_userid_from_nicename', '_bp_core_get_userid', 10, 2);
Just spent a bit of time going over the documentation, codex and files of BuddyPress and i can find ways of changing the /user/ part of the url but sadly not the /username side of it.
Reading through, it is controlled within the core of BuddyPress and any changes to the core can cause crashes and more than likely to cause problems or overwrites further down the line.
This isn't to say it's not possible though, it is most certainly possible, but it will require a great deal of editing to many many different files, an edit to a number of BuddyPress functions and there are no guarantee's on it working straight out or even working further down the line when files get update.
I would recommend going onto the BuddyPress Trac and putting in a ticket to have the feature added to change user url structure. It would be a cool feature to be able to swap between a username, full name, ID or any other unique identifiable string.
You can access it here: https://buddypress.trac.wordpress.org/
Alternatively, you can try what aSeptik has done above, but make sure to update that file with any changes when BuddyPress updates as well.
When i create a page, add a gallery, and browse this gallery on the front-end it will browse all the attachments that are associated with that page, instead of just the images within that gallery. Is there a way to filter all the other attachments and only show the images within a certain gallery? So that, for instance, when I delete the gallery and add a new gallery on the same page > only the new gallery is shown?
Any ideas?
This might not be the most elegant way, but i've found it very usefull.
Passing a post ID to the function below will load a gallery from the post_content of that post. So you would create a gallery and insert it into your post content, then in the template you run this function and will be returned with an array of attachments in that gallery which you are free to to whatever with, i.e slideshows and the likes.
function wp_load_gallery($post_id) {
$post = get_post( $post_id );
$regx = '/' . get_shortcode_regex() . '/';
preg_match( $regx, $post->post_content, $matches );
$ids = shortcode_parse_atts( $matches[3] );
$gallery = array( );
foreach( explode( ',', $ids['ids'] ) as $id ) {
if($id) {
$gallery[] = get_post( $id );
}
}
return $gallery;
}
Note that the shortcode is not cut from the content, so when you display the content you should run it through the strip_shortcodes function, i.e:
echo strip_shortcodes( get_the_content() );
This allows you to update the gallery whenever you want with whatever you want.
EDIT:
To simply display all images:
$gallery = wp_load_gallery($YOUR_POST_ID);
foreach($gallery as $image) {
echo wp_get_attachment_image($image->ID);
}
Firstly, sorry if this has been dealt with before, I've spent quite a while searching posts to no avail.
I have a Wordpress blog and a Concrete5 site. I am trying to write out the three most recent Wordpress blog posts on the Concrete5 site. I cannot use RSS as both sites are on the same server and internal RSS is disabled (is there a way to get around this?).
I have written a block for concrete and have put this code in view.php ...
<?php
define('WP_USE_THEMES', false);
require('path-to-wordpress/wp-blog-header.php');
?>
... This results in "Error establishing a database connection".
If I run this outside of Concrete it works fine (I'm currently using this code elsewhere on the server, no probe).
I've also tried with wp_load.php, same result.
Sorry if this is really obvious, I've been working on it for a while now :(
Thanks in advance.
Sadly this simple approach to loading Wordpress does not work in concrete for whatever reason, some kind of conflicting definition or something. If you are trying to load Wordpress posts on a Concrete5 site on the same server you might well find that using RSS will not work for you as sometimes servers block internal requests to prevent looping.
This is the position I found myself in so I decided to access the Wordpress table myself building on code posted by 'jcrens8392' on the Concrete5 forums , so here it is for anyone who finds them self in the same position.
// posts and stuff
$category = 3
$items = 4
// wordpress db stuff
$dbUser = 'user';
$dbPass = 'password';
$dbHost = 'localhost';
$dbName = 'name';
// connect to wordpress database
$conn = mysql_connect($dbHost, $dbUser, $dbPass);
// handle connection errors
if(!$conn) {
$aDebug['Unable to connect to DB'] = mysql_error();
} elseif(!mysql_select_db($dbName, $conn)) {
$aDebug['Unable to select database'] = mysql_error();
}
// make SQL query
else {
$sQuery = "SELECT wp_posts.post_date, wp_posts.post_content , wp_posts.guid , wp_posts.post_title, wp_posts.post_excerpt, wp_posts.post_name FROM wp_posts , wp_term_relationships WHERE post_type = 'post' AND post_status = 'publish' AND wp_posts.ID = wp_term_relationships.object_id AND wp_term_relationships.term_taxonomy_id = ".$category." ORDER BY post_date DESC LIMIT ".$items;
$rPosts = mysql_query($sQuery, $conn);
}
// plonk posts into a convinient array
$posts = array();
while($row = mysql_fetch_array($rPosts)){
$excerpt = $controller->getExcerpt( utf8_encode( strip_tags( $row['post_content'] ) ) , 0 , 200 ) .' Read More →';
$date = $controller->simplifyDate( $row['post_date'] );
$temp = array ( 'post_title' => $row['post_title'] , 'post_excerpt' => $excerpt , 'post_date' => $date , 'post_link' => $row['guid'] );
array_push( $posts , $temp );
}
I put these functions in controller.php (excerpt function from phpsnaps)...
function getExcerpt($str, $startPos=0, $maxLength=100) {
if(strlen($str) > $maxLength) {
$excerpt = substr($str, $startPos, $maxLength-3);
$lastSpace = strrpos($excerpt, ' ');
$excerpt = substr($excerpt, 0, $lastSpace);
$excerpt .= '...';
} else {
$excerpt = $str;
}
return $excerpt;
}
function simplifyDate($str) {
$months = array("January","February","March","April","May","June","July","August","September","October","November","December");
$strs = split ( ' ' , $str );
$date = split ( '-' , $strs[0] );
$month = $months[ $date[1] - 1 ];
$day = $date[2];
$year = $date[0];
return $day . ' ' . $month . ' ' . $year;
}
This really isn't the ideal solution, it does, however, have the distinct advantage of working. Hope this helps someone.