0

I have problem passing my instance variable of shortcode [answers] down to it's childrens [ans]. Couldn't use global since that loses it's value.

Here is the code:

function my_answers_shortcode($params, $content = null)
{
    static $instance = 0;
    $instance++;

    $output = "<div class='answers-wrapper'>
                    <div id='answers-{$instance}' class='answers'>";

    add_shortcode('ans', 'my_ans_shortcode');
    $output .= do_shortcode($content);

    $output .= "    </div>
                </div>";

    return $output;
}
add_shortcode('answers', 'my_answers_shortcode');

function my_ans_shortcode($atts, $content = null)
{
    global $post;
    static $ans = 0;
    $ans++;

    $output = " 
                <dl class='answer-item'>";

    $output .= "    <dd class='wp-caption-text answer-caption'>
                        <a href='?ins=".$instance."&ans=".$ans."'>".$content."</a> ".($_SESSION['page_'.($post->ID).'_ins_'.$instance.'_ans_'.$ans] == 'correct' ? "Correct!" : "")."
                    </dd>";

    $output .= "
                </dl>
                ";

    return $output;
}

1 Answer 1

1

You can wrap it in a class.

Here's an example:

class WPSE_Answers_Counting 
{
    private $instance_answers      = 0;
    private $instance_prev_answers = 0;
    private $instance_answer       = 0;

    public function init()
    {
        add_shortcode( 'answers', [ $this, 'answers_shortcode' ] );
        add_shortcode( 'ans',     [ $this, 'answer_shortcode'  ] );         
    }

    public function answers_shortcode( $atts = [], $content = null )
    {
        // Output with [answers] counting   
        return sprintf(
            "<div class='answers-wrapper'>
                <div id='answers-%d' class='answers'>
                    %s
                </div>
            </div>",
            $this->instance_answers++,
            do_shortcode( $content )
        );
    }

    public function answer_shortcode( $atts = [], $content = null )
    {   
        // Reset single [ans] counting after each  [answers]
        if( $this->instance_prev_answers != $this->instance_answers )
            $this->instance_answer = 1;

        // Output with [ans] counting   
        $out = sprintf(  
            "<dl class='answer-item'>
                <dd class='wp-caption-text answer-caption'>
                    <a href='?ins=%d&ans=%d'>%s</a> 
                </dd>
             </dl>",
            $this->instance_answers,
            $this->instance_answer++,
            esc_html( $content )
        );

        // Update the previous [answers] instance count
        $this->instance_prev_answers = $this->instance_answers;

        return $out;
    }

} // end class

Create an object instance, then this shortcode mayhem:

[answers][ans]a1[/ans][ans]b1[/ans][ans]c1[/ans][/answers]
[answers][ans]a2[/ans][ans]b2[/ans][ans]c2[/ans][/answers]
[answers][ans]a3[/ans][ans]b3[/ans][ans]c3[/ans][/answers]

will output as:

<div class='answers-wrapper'>
    <div id='answers-0' class='answers'>
        <dl class='answer-item'>
            <dd class='wp-caption-text answer-caption'>
                <a href='?ins=1&ans=1'>a1</a> 
            </dd>
         </dl>
         <dl class='answer-item'>
            <dd class='wp-caption-text answer-caption'>
                <a href='?ins=1&ans=2'>b1</a> 
            </dd>
         </dl>
         <dl class='answer-item'>
            <dd class='wp-caption-text answer-caption'>
                <a href='?ins=1&ans=3'>c1</a> 
            </dd>
         </dl>
    </div>
</div><br />
<div class='answers-wrapper'>
    <div id='answers-1' class='answers'>
        <dl class='answer-item'>
            <dd class='wp-caption-text answer-caption'>
                <a href='?ins=2&ans=1'>a2</a> 
            </dd>
        </dl>
        <dl class='answer-item'>
            <dd class='wp-caption-text answer-caption'>
                <a href='?ins=2&ans=2'>b2</a> 
            </dd>
        </dl>
        <dl class='answer-item'>
            <dd class='wp-caption-text answer-caption'>
                <a href='?ins=2&ans=3'>c2</a> 
            </dd>
         </dl>
    </div>
</div><br />
<div class='answers-wrapper'>
    <div id='answers-2' class='answers'>
        <dl class='answer-item'>
            <dd class='wp-caption-text answer-caption'>
                <a href='?ins=3&ans=1'>a3</a> 
            </dd>
        </dl>
        <dl class='answer-item'>
            <dd class='wp-caption-text answer-caption'>
                <a href='?ins=3&ans=2'>b3</a> 
            </dd>
         </dl>
         <dl class='answer-item'>
            <dd class='wp-caption-text answer-caption'>
                <a href='?ins=3&ans=3'>c3</a> 
            </dd>
         </dl>
    </div>
</div>

with the (hopfully) correct instance number counting you're after.

Update:

You'll probably want to reset the single [ans] counting after each [answers], so I adjusted the class to support that.

Here's the static version:

add_shortcode( 'answers', 'WPSE_Answers_Counting::answers_shortcode' );
add_shortcode( 'ans',     'WPSE_Answers_Counting::answer_shortcode'  );         

class WPSE_Answers_Counting 
{
    private static $instance_answers      = 0;
    private static $instance_prev_answers = 0;
    private static $instance_answer       = 0;

    public static function answers_shortcode( $atts = [], $content = null )
    {
        return sprintf(
            "<div class='answers-wrapper'>
                <div id='answers-%d' class='answers'>
                    %s
                </div>
            </div>",
            self::$instance_answers++,
            do_shortcode( $content )
        );
    }

    public static function answer_shortcode( $atts = [], $content = null )
    {   
        // Reset single [ans] coutning
        if( self::$instance_prev_answers != self::$instance_answers )
            self::$instance_answer = 1;

        $out = sprintf(  
            "<dl class='answer-item'>
                <dd class='wp-caption-text answer-caption'>
                    <a href='?ins=%d&ans=%d'>%s</a> 
                </dd>
             </dl>",
            self::$instance_answers,
            self::$instance_answer++,
            esc_html( $content )
        );

        // Update the previous instance 
        self::$instance_prev_answers = self::$instance_answers;

        return $out;
    }

} // end class
2
  • Waaow... What a awesome answer! Very neat. And it works. I will now study it several times, to learn how it works. Fascinating... Thank you very much! Commented Dec 9, 2015 at 15:22
  • Great, you're welcome @PeterWesterlund
    – birgire
    Commented Dec 9, 2015 at 15:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.