Pull out random number of questions like 04 out of 10 - php

I have function previously made which get me a set of questions array each time shuffled in a new set of order each time when i take a quiz with shuffle() function
Original array (Q1,Q2,Q3,Q4,Q5,Q6)
1st time it gives me (Q2,Q4,Q1,Q3,Q6,Q5)
2nd time it gives me (Q3,Q4,Q2,Q6,Q1,Q5) and so on.
everytime a new set of questions.
This is the function code working for only for shuffle
/**
* Update user questions.
*
* #param $quiz_id
* #param $course_id
* #param $user_id
*/
public function update_user_questions( $quiz_id, $course_id, $user_id ) {
global $wpdb;
$item = null;
switch ( current_action() ) {
case 'pmi-course/user/quiz-redone':
$item = $wpdb->get_row(
$wpdb->prepare( "
SELECT * FROM {$wpdb->prefix}pmicourse_user_items
WHERE item_id = %d
AND user_id = %d
AND ref_id = %d
ORDER BY user_item_id DESC
", $quiz_id, $user_id, $course_id )
);
break;
case 'pmi-course/user/quiz-started':
break;
}
if ( ! $item ) {
return;
}
if ( ! $item->status == 'started' ) {
return;
}
$random_quiz = get_user_meta( $user_id, 'random_quiz', true );
$quiz = LP_Quiz::get_quiz( $quiz_id );
if ( $quiz && $questions = $quiz->get_questions() ) {
$questions = array_keys( $questions );
shuffle( $questions );
$question_id = reset( $questions );
// set user current question
$user = pmi_course_get_current_user();
$user_course = $user->get_course_data( $course_id );
$item_quiz = $user_course->get_item($quiz_id);
$item_quiz->set_meta( '_current_question', $question_id );
$item_quiz->update_meta();
pmi_course_update_user_item_meta( $item->user_item_id, 'current_question', $question_id );
if ( empty( $random_quiz ) ) {
$random_quiz = array( $quiz_id => $questions );
} else {
$random_quiz[ $quiz_id ] = $questions;
}
update_user_meta( $user_id, 'random_quiz', $random_quiz );
}
}
/**
* Random quiz questions.
*
* #param $quiz_questions
* #param $quiz_id
*
* #return array
*/
public function random_questions( $quiz_questions, $quiz_id ) {
if ( get_post_meta( $quiz_id, '_lp_random_mode', true ) == 'yes' ) {
// get user meta random quiz
$random_quiz = get_user_meta( get_current_user_id(), 'random_quiz', true );
if ( is_admin() || empty( $random_quiz ) || empty( $random_quiz[ $quiz_id ] ) ) {
return $quiz_questions;
}
$questions = array();
if ( array_key_exists( $quiz_id, $random_quiz ) && sizeof( $random_quiz[ $quiz_id ] ) == sizeof( $quiz_questions ) ) {
foreach ( $random_quiz[ $quiz_id ] as $question_id ) {
if ( $question_id ) {
$questions[ $question_id ] = $question_id;
}
}
} else {
$question_ids = array_keys( $quiz_questions );
shuffle( $question_ids );
$random_quiz[ $quiz_id ] = $question_ids;
$questions = array();
foreach ( $question_ids as $id ) {
$questions[ $id ] = $quiz_questions[ $id ];
}
}
return $questions;
}
return $quiz_questions;
}
This is what i tried to pull out specific number of questions randomly like "4" questions out of "6" questions from a set but it gives the random result one time and not again like shuffle() i know array_rand() gives different value each time but why not in my case. may be i am doing something wrong . I have put down both the case either can anyone identify me what i am doing wrong or the solution could be extended to more better. Any help would be appreciated.
Original array (Q1,Q2,Q3,Q4,Q5,Q6)
First time (Q1,Q4,Q5,Q6)
Second time (Q1,Q4,Q5,Q6)
Third time (Q1,Q4,Q5,Q6) ---i want different sets for each time
What i tried to achieve this
///for first function
if ( $quiz && $questions = $quiz->get_questions() ) {
$questions = array_rand( $questions , 4);
$question_id = reset( $questions );
///for second function
if ( array_key_exists( $quiz_id, $random_quiz ) && sizeof( $random_quiz[ $quiz_id ] ) < sizeof( $quiz_questions ) ) {
foreach ( $random_quiz[ $quiz_id ] as $question_id ) {
if ( $question_id ) {
$questions[ $question_id ] = $question_id;
}
}
} else {
question_ids = array_rand( $quiz_questions , 4);
$random_quiz[ $quiz_id ] = $question_ids;
questions = array();
foreach ( $question_ids as $id ) {
$questions[ $id ] = $quiz_questions[ $id ];
}
}

Simple function to grab a set of random elements from an array:
$questions = array("Question 1","Question 2","Question 3","Question 4","Question 5","Question 6","Question 7","Question 8","Question 9","Question 10");
function shuffle_questions($questions, $num_questions){
$random_questions = [];
for($i = 0; $i < $num_questions){
$random_num = rand(0, 9);
$random_questions[] = $questions[$random_num];
}
return $random_questions;
}
If you only want it to return unique questions (Probably what you're looking for)
function shuffle_questions($questions, $num_questions){
$questions_temp = $questions;
$random_questions = [];
for ($i = 0; $i++; $i < $num_questions){
$key = array_rand($questions_temp, 1);
$random_questions[] = $questions_temp[$key];
$unset($questions_temp[$key]);
}
return $random_questions;
}

Related

Use PHP shortcode value as CSS value

I am facing the following problem. On my website I am trying to use a WordPress shortcode as input for a background color gradient.
The PHP is as follows:
function vip_relative_time() {
$post_date = get_the_time('U');
$delta = time() - $post_date;
$delta2 = intval(($delta/86400));
return $delta2;
}
add_shortcode('relativetime', 'vip_relative_time');
This code returns the amount of days that is between today and the post date. The goal is that the section on my website has a color gradient based on the above calculated days.
So when the calculating returns 50, 50% of the section will be filled with the selected color. This seems to work when I am editing the page:
But when I publish the page the the gradient is gone an I get the following error:
Warning
: Illegal string offset 'size' in
/home/customer/www/nicow23.sg-host.com/public_html/wp-content/plugins/elementor/includes/base/controls-stack.php
on line
1251
Anyone who can help me out to fix this problem? Do I maybe need to change the datatype of my shortcode?
Thanks in advance!
The code in controls-stack.php
/**
* Parse dynamic settings.
*
* Retrieve the settings with rendered dynamic tags.
*
* #since 2.0.0
* #access public
*
* #param array $settings Optional. The requested setting. Default is null.
* #param array $controls Optional. The controls array. Default is null.
* #param array $all_settings Optional. All the settings. Default is null.
*
* #return array The settings with rendered dynamic tags.
*/
public function parse_dynamic_settings( $settings, $controls = null, $all_settings = null ) {
if ( null === $all_settings ) {
$all_settings = $this->get_settings();
}
if ( null === $controls ) {
$controls = $this->get_controls();
}
foreach ( $controls as $control ) {
$control_name = $control['name'];
$control_obj = Plugin::$instance->controls_manager->get_control( $control['type'] );
if ( ! $control_obj instanceof Base_Data_Control ) {
continue;
}
if ( $control_obj instanceof Control_Repeater ) {
if ( ! isset( $settings[ $control_name ] ) ) {
continue;
}
foreach ( $settings[ $control_name ] as & $field ) {
$field = $this->parse_dynamic_settings( $field, $control['fields'], $field );
}
continue;
}
$dynamic_settings = $control_obj->get_settings( 'dynamic' );
if ( ! $dynamic_settings ) {
$dynamic_settings = [];
}
if ( ! empty( $control['dynamic'] ) ) {
$dynamic_settings = array_merge( $dynamic_settings, $control['dynamic'] );
}
if ( empty( $dynamic_settings ) || ! isset( $all_settings[ Manager::DYNAMIC_SETTING_KEY ][ $control_name ] ) ) {
continue;
}
if ( ! empty( $dynamic_settings['active'] ) && ! empty( $all_settings[ Manager::DYNAMIC_SETTING_KEY ][ $control_name ] ) ) {
$parsed_value = $control_obj->parse_tags( $all_settings[ Manager::DYNAMIC_SETTING_KEY ][ $control_name ], $dynamic_settings );
$dynamic_property = ! empty( $dynamic_settings['property'] ) ? $dynamic_settings['property'] : null;
if( is_array( $settings ) )
{
if ( $dynamic_property ) {
$settings[ $control_name ][ $dynamic_property ] = $parsed_value;
} else {
$settings[ $control_name ] = $parsed_value;
}
} else {
$settings[ $control_name ] = $parsed_value;
}
}
}
return $settings;
}
On or before line 1251, you should be checking if $settings is an array before trying to set its keys. If you do a var_dump($settings) prior to line 1251. It will probably tell you that it is not an array, and instead a string.
should be like this:
if( is_array( $settings ) )
{
//make sure we have an array first
if ( $dynamic_property ) {
$settings[ $control_name ][ $dynamic_property ] = $parsed_value;
} else {
$settings[ $control_name ] = $parsed_value;
}
} else {
//do something else
}

Insert Ads after X paragraph php

Hi im try to use a class to insert adsense blocks after x numbers of paragraph etc.
its works with regular text, but dont works with adsense codes.
the full code is HERE
<?php
namespace keesiemeijer\Insert_Content;
function insert_content( $content, $insert_content = '', $args = array() ) {
$args = array_merge( get_defaults(), (array) $args );
if ( empty( $insert_content ) ) {
return $content;
}
// Validate arguments
$args['parent_element_id'] = trim( (string) $args['parent_element_id'] );
$args['insert_element'] = trim( (string) $args['insert_element'] );
$args['insert_element'] = $args['insert_element'] ? $args['insert_element'] : 'p';
$args['insert_after_p'] = abs( intval( $args['insert_after_p'] ) );
$parent_element = false;
// Content wrapped in the parent HTML element (to be inserted).
$insert_content = "<{$args['insert_element']}>{$insert_content}</{$args['insert_element']}>";
$nodes = new \DOMDocument();
// Load the HTML nodes from the content.
#$nodes->loadHTML( $content );
if ( $args['parent_element_id'] ) {
$parent_element = $nodes->getElementById( $args['parent_element_id'] );
if ( !$parent_element ) {
// Parent element not found.
return $content;
}
// Get all paragraphs from the parent element.
$p = $parent_element->getElementsByTagName( 'p' );
} else {
// Get all paragraphs from the content.
$p = $nodes->getElementsByTagName( 'p' );
}
$insert_nodes = new \DOMDocument();
#$insert_nodes->loadHTML( $insert_content );
$insert_element = $insert_nodes->getElementsByTagName( $args['insert_element'] )->item( 0 );
if ( !$insert_element ) {
return $content;
}
// Get paragraph indexes
$nodelist = get_node_indexes( $p, $args );
// Check if paragraphs are found.
if ( !empty( $nodelist ) ) {
$insert_index = get_item_index( $nodelist, $args );
if ( false === $insert_index ) {
return $content;
}
// Insert content after this (paragraph) node.
$insert_node = $p->item( $insert_index );
// Insert the nodes
insert_content_element( $nodes, $insert_node, $insert_element );
$html = get_HTML( $nodes );
if ( $html ) {
$content = $html;
}
} else {
// No paragraphs found.
if ( (bool) $args['insert_if_no_p'] ) {
if ( $parent_element ) {
// Insert content after parent element.
insert_content_element( $nodes, $parent_element, $insert_element );
$html = get_HTML( $nodes );
if ( $html ) {
$content = $html;
}
} else {
// Add insert content after the content/
$content .= $insert_content;
}
}
}
return $content;
}
/**
* Get default arguments.
*
* #return array Array with default arguments.
*/
function get_defaults() {
return array(
'parent_element_id' => '',
'insert_element' => 'p',
'insert_after_p' => '',
'insert_if_no_p' => true,
'top_level_p_only' => true,
);
}
function get_node_indexes( $nodes, $args ) {
$args = array_merge( get_defaults(), (array) $args );
$nodelist = array();
$length = isset( $nodes->length ) ? $nodes->length : 0;
$parent_id = trim( $args['parent_element_id'] );
for ( $i = 0; $i < $length; ++$i ) {
$nodelist[ $i ] = $i;
$parent = false;
$node = $nodes->item( $i );
if ( $parent_id ) {
if ( $node->parentNode->hasAttribute( 'id' ) ) {
$parent_id_attr = $node->parentNode->getAttribute( 'id' );
$parent = ( $parent_id === $parent_id_attr );
}
} else {
$parent = ( 'body' === $node->parentNode->nodeName );
}
if ( (bool) $args['top_level_p_only'] && !$parent ) {
// Remove nested paragraphs from the list.
unset( $nodelist[ $i ] );
}
}
return array_values( $nodelist );
}
function get_item_index( $nodelist, $args ) {
if ( empty( $nodelist ) ) {
return false;
}
$args = array_merge( get_defaults(), (array) $args );
$count = count( $nodelist );
$insert_index = abs( intval( $args['insert_after_p'] ) );
end( $nodelist );
$last = key( $nodelist );
reset( $nodelist );
if ( !$insert_index ) {
if ( 1 < $count ) {
// More than one paragraph found.
// Get middle position to insert the HTML.
$insert_index = $nodelist[ floor( $count / 2 ) -1 ];
} else {
// One paragraph
$insert_index = $last;
}
} else {
// start counting at 0.
--$insert_index;
--$count;
if ( $insert_index > $count ) {
if ( (bool) $args['insert_if_no_p'] ) {
// insert after last paragraph.
$insert_index = $last;
} else {
return false;
}
}
}
return $nodelist[ $insert_index ];
}
/**
* Insert an element (and it's child elements) in the content.
*
* #param object $nodes DOMNodeList instance containing all nodes.
* #param object $insert_node DOMElement object to insert nodes after
* #param object $insert DOMElement object to insert
* #return void
*/
function insert_content_element( $nodes, $insert_node, $insert_element ) {
$next_sibling = isset( $insert_node->nextSibling ) ? $insert_node->nextSibling : false;
if ( $next_sibling ) {
// get sibling element (exluding text nodes and whitespace).
$next_sibling = nextElementSibling( $insert_node );
}
if ( $next_sibling ) {
// Insert before next sibling.
$next_sibling->parentNode->insertBefore( $nodes->importNode( $insert_element, true ), $next_sibling );
} else {
// Insert as child of parent element.
$insert_node->parentNode->appendChild( $nodes->importNode( $insert_element, true ) );
}
}
function nextElementSibling( $node ) {
while ( $node && ( $node = $node->nextSibling ) ) {
if ( $node instanceof \DOMElement ) {
break;
}
}
return $node;
}
function get_HTML( $nodes ) {
$body_node = $nodes->getElementsByTagName( 'body' )->item( 0 );
if ( $body_node ) {
// Convert nodes from the body element to a string containing HTML.
$content = $nodes->saveHTML( $body_node );
// Remove first body element only.
$replace_count = 1;
return str_replace( array( '<body>', '</body>' ) , array( '', '' ), $content, $replace_count );
}
return '';
}
to call the function
$args = array(
'insert_after_p' => 3, // Insert after the second paragraph
);
echo keesiemeijer\Insert_Content\insert_content($content, $insert_content, $args );

Can I modify this wordpress plugin function with a action/filter hook?

I need to modify 3 lines in a function created by a plugin.
Here is the original function (look for my commented section in the middle, highlighted by the asterisks):
/**
* function to modify order_items of renewal order
*
* #param array $order_items
* #param int $original_order_id
* #param int $renewal_order_id
* #param int $product_id
* #param string $new_order_role
* #return array $order_items
*/
public function sc_subscriptions_renewal_order_items( $order_items = null, $original_order_id = 0, $renewal_order_id = 0, $product_id = 0, $new_order_role = null ) {
$is_subscription_order = wcs_order_contains_subscription( $original_order_id );
if ( $is_subscription_order ) {
$return = false;
} else {
$return = true;
}
if ( $return ) {
return $order_items;
}
$pay_from_credit_of_original_order = get_option( 'pay_from_smart_coupon_of_original_order', 'yes' );
if ( $pay_from_credit_of_original_order != 'yes' ) return $order_items;
if ( $new_order_role != 'child' ) return $order_items;
if ( empty( $renewal_order_id ) || empty( $original_order_id ) ) return $order_items;
$original_order = $this->get_order( $original_order_id );
$renewal_order = $this->get_order( $renewal_order_id );
$coupon_used_in_original_order = $original_order->get_used_coupons();
$coupon_used_in_renewal_order = $renewal_order->get_used_coupons();
if ( sizeof( $coupon_used_in_original_order ) > 0 ) {
$smart_coupons_contribution = array();
foreach ( $coupon_used_in_original_order as $coupon_code ) {
$coupon = new WC_Coupon( $coupon_code );
if ( ! empty( $coupon->discount_type ) && $coupon->discount_type == 'smart_coupon' && ! empty( $coupon->amount ) && ! in_array( $coupon_code, $coupon_used_in_renewal_order, true ) ) {
$renewal_order_total = $renewal_order->get_total();
/* ************
THE BELOW 3 LINES ARE WHAT I NEED TO REMOVE
**************** */
if ( $coupon->amount < $renewal_order_total ) {
continue;
}
/* ************
THE ABOVE 3 LINES ARE WHAT I NEED TO REMOVE
**************** */
$discount = min( $renewal_order_total, $coupon->amount );
if ( $discount > 0 ) {
$new_order_total = $renewal_order_total - $discount;
update_post_meta( $renewal_order_id, '_order_total', $new_order_total );
update_post_meta( $renewal_order_id, '_order_discount', $discount );
if ( $new_order_total <= floatval(0) ) {
update_post_meta( $renewal_order_id, '_renewal_paid_by_smart_coupon', 'yes' );
}
$renewal_order->add_coupon( $coupon_code, $discount );
$smart_coupons_contribution[ $coupon_code ] = $discount;
$used_by = $renewal_order->get_user_id();
if ( ! $used_by ) {
$used_by = $renewal_order->billing_email;
}
$coupon->inc_usage_count( $used_by );
}
}
}
if ( ! empty( $smart_coupons_contribution ) ) {
update_post_meta( $renewal_order_id, 'smart_coupons_contribution', $smart_coupons_contribution );
}
}
return $order_items;
}
I want to remove the lines that I commented out in the middle of the above code:
if ( $coupon->amount < $renewal_order_total ) {
continue;
}
Is there any way to do this without editing the core plugin code? Could I write my own function to change those lines?
Thank you for any help you can provide!
If this function is hooked in with an action/filter hook then you can remove it by remove_action or remove_filter and hook in your function there.
https://codex.wordpress.org/Function_Reference/remove_action
https://codex.wordpress.org/Function_Reference/remove_filter
So check where this function gets called.

Get Inner HTML - PHP

I have the following code:
$data = file_get_contents('http://www.robotevents.com/robot-competitions/vex-robotics-competition?limit=all');
echo "Downloaded";
$dom = new domDocument;
#$dom->loadHTML($data);
$dom->preserveWhiteSpace = false;
$tables = $dom->getElementsByTagName('table');
$rows = $tables->item(2)->getElementsByTagName('tr');
foreach ($rows as $row) {
$cols = $row->getElementsByTagName('td');
for ($i = 0; $i < $cols->length; $i++) {
echo $cols->item($i)->nodeValue . "\n";
}
}
The final field has an Link which I need to store the URL of. Also, The script outputs characters such as "Â". Does anyone know how to do/fix these things?
I would recommend not using DOM to parse HTML, as it has problems with invalid HTML. INstead use regular expression
I use this class:
<?php
/**
* Class to return HTML elements from a HTML document
* #version 0.3.1
*/
class HTMLQuery
{
protected $selfClosingTags = array( 'area', 'base', 'br', 'hr', 'img', 'input', 'link', 'meta', 'param' );
private $html;
function __construct( $html = false )
{
if( $html !== false )
$this->load( $html );
}
/**
* Load a HTML string
*/
public function load( $html )
{
$this->html = $html;
}
/**
* Returns elements from the HTML
*/
public function getElements( $element, $attribute_match = false, $value_match = false )
{
if( in_array( $element, $this->selfClosingTags ) )
preg_match_all( "/<$element *(.*)*\/>/isU", $this->html, $matches );
else
preg_match_all( "/<$element(.*)>(.*)<\/$element>/isU", $this->html, $matches );
if( $matches )
{
#Create an array of matched elements with attributes and content
foreach( $matches[0] as $key => $el )
{
$current_el = array( 'name' => $element );
$attributes = $this->parseAttributes( $matches[1][$key] );
if( $attributes )
$current_el['attributes'] = $attributes;
if( $matches[2][$key] )
$current_el['content'] = $matches[2][$key];
$elements[] = $current_el;
}
#Return only elements with a specific attribute and or value if specified
if( $attribute_match != false && $elements )
{
foreach( $elements as $el_key => $current_el )
{
if( $current_el['attributes'] )
{
foreach( $current_el['attributes'] as $att_name => $att_value )
{
$keep = false;
if( $att_name == $attribute_match )
{
$keep = true;
if( $value_match == false )
break;
}
if( $value_match && ( $att_value == $value_match ) )
{
$keep = true;
break;
}
elseif( $value_match && ( $att_value != $value_match ) )
$keep = false;
}
if( $keep == false )
unset( $elements[$el_key] );
}
else
unset( $elements[$el_key] );
}
}
}
if( $elements )
return array_values( $elements );
else
return array();
}
/**
* Return an associateive array of all the form inputs
*/
public function getFormValues()
{
$inputs = $this->getElements( 'input' );
$textareas = $this->getElements( 'textarea' );
$buttons = $this->getElements( 'button' );
$elements = array_merge( $inputs, $textareas, $buttons );
if( $elements )
{
foreach( $elements as $current_el )
{
$attribute_name = mb_strtolower( $current_el['attributes']['name'] );
if( in_array( $current_el['name'], array( 'input', 'button' ) ) )
{
if( isset( $current_el['attributes']['name'] ) && isset( $current_el['attributes']['value'] ) )
$form_values[$attribute_name] = $current_el['attributes']['value'];
}
else
{
if( isset( $current_el['attributes']['name'] ) && isset( $current_el['content'] ) )
$form_values[$attribute_name] = $current_el['content'];
}
}
}
return $form_values;
}
/**
* Parses attributes into an array
*/
private function parseAttributes( $str )
{
$str = trim( rtrim( trim( $str ), '/' ) );
if( $str )
{
preg_match_all( "/([^ =]+)\s*=\s*[\"'“”]{0,1}([^\"'“”]*)[\"'“”]{0,1}/i", $str, $matches );
if( $matches[1] )
{
foreach( $matches[1] as $key => $att )
{
$attribute_name = mb_strtolower( $att );
$attributes[$attribute_name] = $matches[2][$key];
}
}
}
return $attributes;
}
}
?>
Usage is:
$c = new HTMLQuery();
$x = $c->getElements( 'tr' );
print_r( $x );

URL dissector that splits up a query string

Ok so basically I am reading through this piece of source code and do not understand the purpose of a specific area.
class URL_Processor
{
private static $urlPath;
private static $urlBits = array();
/*
Gets data from the current URL
#return Void
*/
public function getURLData()
{
$urldata = (isset($_GET['page'])) ? $_GET['page'] : '' ;
self::$urlPath = $urldata;
if( $urldata == '' )
{
self::$urlBits[] = 'home';
self::$urlPath = 'home';
}
else
{
$data = explode( '/', $urldata );
while ( !empty( $data ) && strlen( reset( $data ) ) === 0 )
{
array_shift( $data );
}
while ( !empty( $data ) && strlen( end( $data ) ) === 0)
{
array_pop($data);
}
self::$urlBits = $this->array_trim( $data );
}
}
private function array_trim( $array )
{
while ( ! empty( $array ) && strlen( reset( $array ) ) === 0)
{
array_shift( $array );
}
while ( !empty( $array ) && strlen( end( $array ) ) === 0)
{
array_pop( $array );
}
return $array;
}
}
So basically from my understanding the two while loops with 'array_shift' in the getURLData method empty out the array but according to my logic the second while loop wont even be able to empty anything out because the first while loop already did.
Then the last line of the method getURLData
self::$urlBits = $this->array_trim( $data );
does the same thing but how if the passed in argument is empty already?
Very confused!!!
The first while loop removes all leading elements in the array where their string length is zero, the second one does the same with trailing elements. reset($array) will point to the first, end($array) to the last element.
Why he mushes it through a second time? I don't know.

Categories