Is there a find and replace functions for SQL - sql

I have some values in my SQL i want to trim and replace.
I want to look in a key field _booking_persons and only store all between "" and remove the rest.
So at the moment i got this in all fields
s:14:"a:1:{i:0;i:4;}“
and i want to keep a:1:{i:0;i:4;} so everything between " ".
I tried to fix it with wordpress post_meta_update. So i tought maybe its easy to do that with SQL.
$args = array('post_type' => 'wc_booking', 'posts_per_page' => '-1' );
$the_query = new WP_Query( $args );
// The Loop
if ( $the_query->have_posts() ) {
while ( $the_query->have_posts() ) {
$the_query->the_post();
$post_id = get_the_ID();
$array = get_post_meta( $post_id, '_booking_persons', true );
$between = preg_replace('/(.*)"(.*)"(.*)/sm', '\2', $array);
update_post_meta( $post_id, '_booking_persons', $between );
}
/* Restore original Post Data */
wp_reset_postdata();
} else {
// no posts found
}
I expect a:1:{i:0;i:4;} but stay as it is s:14:"a:1:{i:0;i:4;}“

You can do this easily with substring_index function:
SELECT substring_index(substring_index('s:14:\"a:1:{i:0;i:4;}\"', '\"', 2), '\"', -1);
This will return:
a:1:{i:0;i:4;}
Note that you need to escape " character with \
You can see this in action here

Related

Automatically update ACF field upon date

Here is what I am trying to accomplish: turn off a True/False Advanced Custom Fields(ACF) option on a post if the current date is on or past a selected date on the same post. Also after that code, turn off a Sample Lesson True/False option inside of the lessons attached to the current post.
At first, all I had was the update_sample_child_lessons function with an 'init' action (i.e.add_action( 'init', 'update_sample_child_lessons' );), but that seemed to only run when I clicked update on the post. It did work and everything switched over, but it only ran when I manually clicked Update on the post. So then I did a little research and found that a Cron job should do the trick if I want the code to run automatically without me having to click update, but for some reason I can't seem to get it to work.
So if you know of a way to accomplish what I am trying to do with the code below, or with other code that is completely different, any suggestions or help would be much appreciated.
//CRON JOB TO RUN EVERYDAY
function myprefix_custom_cron_schedule( $schedules ) {
$schedules['every_day'] = array(
'interval' => 86400, //24 HOURS IN SECONDS
'display' => __( 'Every 24 hours' ),
);
return $schedules;
}
add_filter( 'cron_schedules', 'myprefix_custom_cron_schedule' );
if ( ! wp_next_scheduled( 'myprefix_cron_hook' ) ) {
wp_schedule_event( time(), 'every_day', 'myprefix_cron_hook' );
}
//AUTOMATICALLY ADJUSTS SAMPLE LESSON FREE OPTIONS AND FREE BANNER IF DATE IS PASSED
add_action( 'myprefix_cron_hook', 'update_sample_child_lessons' );
function update_sample_child_lessons() {
$allcourses = array(
'post_type' => 'sfwd-courses', //CUSTOM POST TYPE: COURSES
'posts_per_page' => -1 //QUERY ALL OF THEM
);
$query = new WP_Query($allcourses);
if ($query->have_posts()) {
global $post;
if ( ( in_array( $post->post_type, array( 'sfwd-courses' ), true ) )) { //ONLY DO ACTION IF ON CPT OF COURSES
while ($query->have_posts()) {
$query->the_post();
$course_id = learndash_get_course_id( $post->ID ); //GET THE COURSE ID
$free = get_field('display_free_lessons', $course_id); //GET THE FREE COURSE OPTION (TRUE/FALSE TICKER)
if (!empty($free)) { //ONLY DO REST OF CODE IF FREE OPTION IS TURNED ON
$freeDate = get_field('free_until', $course_id); //GET THE DATE FIELD THAT THE COURSE IS FREE UNTIL
$currentDate = date('Ymd'); //GET CURRENT DATE
$diff = strtotime($freeDate) - strtotime($currentDate); //GET THE DIFFERENCE BETWEEN THE TWO DATES
if ($diff <= 0) { //ONLY DO REST OF CODE IF DATE DIFFERENCE IS LESS THAN OR EQUAL TO ZERO
$value = '';
update_field('display_free_lessons', $value, $course_id); //UPDATES THE FREE OPTION FIELD TO FALSE(OR NOTHING)
//LESSON CODE
$lessons = array_slice(learndash_course_get_lessons($course_id), 1); //GET ALL THE LESSONS FROM THE COURSE EXCEPT FOR THE FIRST ONE
foreach ($lessons as $lesson) {
$lessonID = $lesson->ID; //GET THE LESSON ID
$lesson_meta = get_post_meta($lessonID); //GET THE METADATA FOR THE LESSON
if ( is_array( $lesson_meta ) ) {
foreach ( $lesson_meta as $meta_key => $meta_value ) {
if ( '_sfwd-lessons' === $meta_key ) {
$lesson_settings = maybe_unserialize( $meta_value[0] ); //SOME OF THE ARRAYS ARE SERIALIZED, SO UNSERIALIZE IF NEEDED
if ( isset( $lesson_settings['sfwd-lessons_sample_lesson'] ) ) {
$lesson_settings['sfwd-lessons_sample_lesson'] = ''; //TURN OFF THE SAMPLE LESSON OPTION ON THE LESSONS
}
update_post_meta( $lessonID, $meta_key, $lesson_settings );
}
}
}
} //END FOREACH
} //END IF DIFF IS 0
wp_reset_postdata();
}
}
}
}
}
Thanks for the comment #Luke Chaffey, I was actually able to figure it out after finding I had my cron actions reversed. Below is the final code that I got working so that it runs every day at 12am:
//CRON JOB TO RUN EVERYDAY
function custom_cron_schedule( $schedules ) {
$schedules['every_day'] = array(
'interval' => 86400,
'display' => __( 'Every 24 hours' ),
);
return $schedules;
}
add_filter( 'cron_schedules', 'custom_cron_schedule' );
$ve = get_option('gmt_offset') > 0 ? '-' : '+';
if ( ! wp_next_scheduled('cron_sample_lesson' ) ) {
wp_schedule_event(strtotime('00:00 tomorrow ' . $ve .
absint(get_option('gmt_offset')) . ' HOURS'), 'daily','cron_sample_lesson' );
}
add_action('cron_sample_lesson', 'update_sample_child_lessons' );
function update_sample_child_lessons() {...

posts_orderby not displaying the posts

I would like to customize my wordpress search page
First, i used the "posts_where" to modify the clause
function search_posts_where ($where) {
global $wp_query, $wpdb;
// Searching and not in admin
if (!is_admin() && $wp_query->is_search && isset($wp_query->query_vars['s'])) {
// Tables names
$post_title = "{$wpdb->prefix}posts.post_title";
$post_excerpt = "{$wpdb->prefix}posts.post_excerpt";
$post_content = "{$wpdb->prefix}posts.post_content";
$post_type = "{$wpdb->prefix}posts.post_type";
$post_status = "{$wpdb->prefix}posts.post_status";
$post_author = "{$wpdb->prefix}posts.post_author";
$post_ID = "{$wpdb->prefix}posts.ID";
$post_date = "{$wpdb->prefix}posts.post_date";
// Get the 's' parameters
$wp_query->query_vars['s'] ? $search_text = $wp_query->query_vars['s'] : $search_text = 'IS NULL';
// Write the where clause
$where = " AND ((($post_title LIKE '%$search_text%')";
$where .= " OR ($post_excerpt LIKE '%$search_text%')";
$where .= " OR ($post_content LIKE '%$search_text%')))";
$where .= " AND $post_type IN ('parcours')";
$where .= " AND $post_status = 'publish'";
$where .= " GROUP BY $post_ID";
}
return $where;
}
add_filter('posts_where', 'search_posts_where', 10, 2);
It works fine. All posts belonging to my custom post type 'parcours' are shown, depending on what I entered for the 's' query.
Second, i used the "posts_join" to add the meta table (not used yet !)
function search_posts_join ($join) {
global $wp_query, $wpdb;
// Searching and not in admin
if (!is_admin() && $wp_query->is_search && isset($wp_query->query_vars['s'])) {
// Tables names
$post_meta = "{$wpdb->prefix}postmeta";
$post_ID = "{$wpdb->prefix}posts.ID";
$post_meta_ID = "{$wpdb->prefix}postmeta.post_id";
// Join clause
$join .= "LEFT JOIN $post_meta ON ($post_ID = $post_meta_ID)";
}
return $join;
}
add_filter('posts_join', 'search_posts_join', 10, 2);
Still works perfectly !
Now the problem, i would like to order my posts in ascending direction (default is descending). So, i added the "posts_orderby" hook.
function search_posts_orderby ($orderby) {
global $wp_query, $wpdb;
// Searching and not in admin
if (!is_admin() && $wp_query->is_search) {
// Tables names
$post_title = "{$wpdb->prefix}posts.post_title";
$post_date = "{$wpdb->prefix}posts.post_date";
$post_ID = "{$wpdb->prefix}posts.ID";
// Order by clause
$orderby .= " ORDER BY $post_title ASC,";
$orderby .= " $post_date DESC";
}
return $orderby;
}
add_filter('posts_orderby', 'search_posts_orderby', 10, 2);
And here is the problem. All posts disapeared. Removing the "orderby" and they come back.
Looking at the SQL query, i have
"SELECT SQL_CALC_FOUND_ROWS wp_128444_posts.* FROM wp_128444_posts LEFT JOIN wp_128444_postmeta ON (wp_128444_posts.ID = wp_128444_postmeta.post_id) WHERE 1=1 AND (((wp_128444_posts.post_title LIKE '%tour%') OR (wp_128444_posts.post_excerpt LIKE '%tour%') OR (wp_128444_posts.post_content LIKE '%tour%'))) AND wp_128444_posts.post_type IN ('parcours') AND wp_128444_posts.post_status = 'publish' GROUP BY wp_128444_posts.ID ORDER BY wp_128444_posts.post_title LIKE '{5a35f6e9144541f93e08829126b2cb633436cebf95d774062fff749a12e6a465}tour{5a35f6e9144541f93e08829126b2cb633436cebf95d774062fff749a12e6a465}' DESC, wp_128444_posts.post_date DESC ORDER BY wp_128444_posts.post_title ASC, wp_128444_posts.post_date DESC LIMIT 0, 6"
I don't know why WP is adding the default ORDER BY, that i don't want.
Is is possible to remove it ?
I tried to replace my hook with "pre_get_posts" hook
function order_posts_by_title( $query ) {
if ( $query->is_search() && $query->is_main_query() ) {
$query->set( 'orderby', 'title' );
$query->set( 'order', 'ASC' );
}
}
add_action( 'pre_get_posts', 'order_posts_by_title' );
With this hook, it works !! Sounds very strange to me
Any explanation ?
Thanks

Wordpress Custom Post Type Sort by Title Last Word ASC

I am taking a custom post type and trying to display it by the last word of the post title. From there, I want to pass in a variable of what letter I would like to see (eg "starts_with" = "A") in the WP_Query. Lastly, I want to display this in ASC order. From this code, how do I display in ASC order?
function dp_posts_where( $where, $query ) {
global $wpdb;
$starts_with = $query->get( 'starts_with' );
if ( $starts_with ) {
$last_name = "RIGHT($wpdb->posts.post_title, LOCATE(' ', REVERSE($wpdb->posts.post_title)) - 1)";
$where .= " AND $last_name LIKE '$starts_with%'";
}
return $where;
}
add_filter( 'posts_where', 'dp_posts_where', 10, 2 );
Please advise! Thank you!

Stumped on this little SQL query

This SQL query is currently returning all values with the word anywhere in it. For instance, typing Mon will return Armoring, Behemoth, Emotion, etc etc. I'd like it to return words that start with the value, like, Monkey, Moment, Monday, etc.
Hope my explanation makes sense, code is below.
function action_ajax_drug_suggest() {
global $wpdb;
if ( empty( $_GET['term'] ) ) {
die();
}
$drug_name = $wpdb->esc_like( $_GET['term'] );
$table = $wpdb->prefix . self::TABLE_DRUG;
$posts = $wpdb->get_results( $wpdb->prepare( "
SELECT name
FROM {$table}
WHERE name LIKE '%%%s%%'
AND details <> ''
LIMIT 5",
$drug_name ) );
foreach( $posts as $post ) {
$names[] = array(
'label' => $post->name,
);
}
wp_send_json( $names );
}
try leaving out the first two %% signs
LIKE '%%%s%%' becomes LIKE '%s%%'

Datatables server side processing and column alias

In Datatables using server side processing, is it possible to use column alias when specifying the columns?
At the moment this works fine with:
$aColumns = array( 'datetime','username', 'user_ip', 'company', 'action' );
but I would like to change the format of the date using date format in MySQL so, in effect, I want to use:
$aColumns = array( 'DATE_FORMAT(datetime, "%d/%m/%Y - %H:%i:%s") as newdate';'username'; 'user_ip';'company'; 'action' );
The problem is that the alias has a comma and the aColumns array is comma seperated so it breaks when later, for example, it comes to:
$sQuery = "
SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ", implode(", ", $aColumns))."
FROM $sTable
$sWhere
$sOrder
$sLimit
";
Is there a way I can use the alias rather than the original value? Even simply changing the select statement does not work as aColumns is used throughout the script hence it needs that value to be set correctly
Thanks
Yes. I actually just struggled with this issue myself. Because the JSON output is determined through counting the amount of columns in the array, and because of the imploding array, you have to add your column alias to $sQuery instead of the $aColumns array. So you'll actually have one less column in your $aColumns array than you'll need. For example, in mine, I needed an alias called total created from multiplying price and qty. So I put all my unaliased columns in the $aColumns array, like this:
$aColumns = array( 'purchaseID', 'dateOfOrder', 'productID', 'price', 'QTY');
But then, in the $sQuery string that concatenates all the things necessary to create the proper query string, I added my column alias between the implode and FROM. Don't forget to put a comma after the implode though, because it doesn't add it for you. The original $sQuery string looks like this:
$sQuery = "
SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ", implode(", ", $aColumns))."
FROM `$sTable`
$sWhere
$dateSql
$sOrder
$sLimit
";
But mine, with the column alias added, looks like this:
$sQuery = "
SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ", implode(", ", $aColumns))."
, `price` * `QTY` AS `total` FROM `$sTable`
$sWhere
$dateSql
$sOrder
$sLimit
";
Finally, the last thing you have to do is alter the actual JSON output to make sure your extra column is accounted for in the FOR loop at the end right before the json_encode, because it inserts items into the $row array, which is what becomes 'aaData' (the returned row data), based on how many columns you've specified in the $aColumns array, and because you left out any you've aliased, the count will be wrong, and you will get an error that looks something like 'requested unknown parameter from data source row'. The original FOR loop looks like this:
while ( $aRow = mysql_fetch_array( $rResult ) )
{
$row = array();
for ( $i=0 ; $i<count($aColumns) ; $i++ )
{
if ( $aColumns[$i] == "version" )
{
/* Special output formatting for 'version' column */
$row[] = ($aRow[ $aColumns[$i] ]=="0") ? '-' : $aRow[ $aColumns[$i] ];
}
else if ( $aColumns[$i] != ' ' )
{
/* General output */
$row[] = $aRow[ $aColumns[$i] ];
}
}
$output['aaData'][] = $row;
}
Like I said, this FOR loop works based off the COUNT of the $aColumns array, and since I've added an alias, it's going to cut my results short. It's not going to return the last element in the array containing the returned columns, so I'm going to alter the code to look like this:
for ( $i=0 ; $i<count($aColumns) + 1; $i++ )
{
if ($i < count($aColumns)){
if ( $aColumns[$i] == "version" )
{
/* Special output formatting for 'version' column */
$row[] = ($aRow[ $aColumns[$i] ]=="0") ? '-' : $aRow[ $aColumns[$i] ];
}
else if ( $aColumns[$i] != ' ' )
{
/* General output */
$row[] = $aRow[ $aColumns[$i] ];
}
}
else {
$row[] = $aRow['total'];
}
}
$output['aaData'][] = $row;
}
All I changed was the counter condition from $i<count($aColumns) to $i<count($aColumns) + 1, because my alias makes the column count one higher than what's in the array. And I've added a wrapping if-else that just says that if the counter, $i, is higher than the number of columns I've specified in the $aColumns array, then we've added all the columns in the array to the output data, so because I only added one extra alias column, then that means I can go ahead and just add that to the $row array, which contains all the output data from the returned rows.
You can actually add in as many aliased columns as you need, you just need to scale the code accordingly. Hope this helps!