Exemplo n.º 1
0
    /**
     * Function ConstructGoogleForm loads HTML from a Google Form URL,
     * processes it, and inserts it into a WordPress filter to output
     * as part of a post, page, or widget.
     *
     * @return An HTML string if successful, false otherwise.
     * @see RenderGoogleForm
     */
    static function ConstructGoogleForm()
    {
        //wpgform_load_js_css() ;
        //  Any preset params?
        $presets = $_GET;
        //  Eliminate the Google Form's query variable if it is set
        if (!empty($presets) && array_key_exists(WPGFORM_CPT_QV_FORM, $presets)) {
            unset($presets[WPGFORM_CPT_QV_FORM]);
        }
        $locale_cookie = new WP_HTTP_Cookie(array('name' => 'locale', 'value' => get_locale()));
        //  Property short cut
        $o =& self::$options;
        //  Account for existing forms not having the override option
        if (!array_key_exists('override_google_default_text', $o)) {
            $o['override_google_default_text'] = 'off';
        }
        $wpgform_options = wpgform_get_plugin_options();
        if (WPGFORM_DEBUG && $wpgform_options['http_request_timeout']) {
            $timeout = $wpgform_options['http_request_timeout_value'];
        } else {
            $timeout = $wpgform_options['http_api_timeout'];
        }
        if (WPGFORM_DEBUG) {
            wpgform_whereami(__FILE__, __LINE__, 'ConstructGoogleForm');
        }
        if (WPGFORM_DEBUG) {
            wpgform_preprint_r($_POST);
        }
        $global_override_google_default_text = (int) $wpgform_options['override_google_default_text'] === 1;
        //  Some servers running ModSecurity issue 403 errors because something
        //  in the form's POST parameters has triggered a positive match on a rule.
        if (!empty($_SERVER) && array_key_exists('REDIRECT_STATUS', $_SERVER) && $_SERVER['REDIRECT_STATUS'] == '403') {
            return sprintf('<div class="wpgform-google-error gform-google-error">%s %s<span class="wpgform-google-error gform-google-error">%s</span> %s.</div>', __('Unable to process Google Form.', WPGFORM_I18N_DOMAIN), __('Server is responding with', WPGFORM_I18N_DOMAIN), __('403 Permission Denied', WPGFORM_I18N_DOMAIN), __('error', WPGFORM_I18N_DOMAIN));
        }
        //  If no URL then return as nothing useful can be done.
        if (!$o['form']) {
            return false;
        } else {
            $form = $o['form'];
            $uid = $o['uid'];
            $prefix = $o['css_prefix'];
            $suffix = $o['css_suffix'];
            $confirm = $o['confirm'];
            $alert = $o['alert'];
            $sendto = $o['sendto'];
            //  The old short code supports the 'spreadsheet' attribute which
            //  takes precedence over the new attribute 'results' for backward
            //  compatibility.
            $results = $o['spreadsheet'] === false ? $o['results'] : $o['spreadsheet'];
            //  Check to see if form has a Google Form default text overrides - older forms won't
            $local_override_google_default_text = (int) array_key_exists('override_google_default_text', $o) ? $o['override_google_default_text'] === 'on' : 0;
        }
        if (WPGFORM_DEBUG) {
            wpgform_whereami(__FILE__, __LINE__, 'ConstructGoogleForm');
        }
        //  Should email confirmation be sent to user?
        $user_email = $o['user_email'] === 'on';
        $user_email_html = '';
        $user_email_sendto = "";
        //  Generate the User Email HTML if requested
        //printf('<h1>%s::%s -> %s</h1>', basename(__FILE__), __LINE__, $uid) ;
        if ($user_email) {
            $current_user = wp_get_current_user();
            if (0 != $current_user->ID) {
                $user_email_sendto = $current_user->user_email;
            }
            $user_email_html .= '<div class="wpgform-user-email">';
            $user_email_html .= sprintf('<div class="%sss-item %sss-item-required %sss-text">', $prefix, $prefix, $prefix);
            $user_email_html .= sprintf('<div class="%sss-form-entry">', $prefix);
            $user_email_html .= sprintf('<label for="wpgform-user-email" class="%sss-q-title">%s', $prefix, __('Email Address'));
            $user_email_html .= sprintf('<span class="%sss-required-asterisk">*</span></label>', $prefix);
            $user_email_html .= sprintf('<label for="wpgform-user-email" class="%sss-q-help"></label>', $prefix);
            $user_email_html .= sprintf('<input style="width: 250px;" type="text" id="%swpgform-user-email" class="%sss-q-short" value="%s" name="%swpgform-user-email">', $uid, $prefix, $user_email_sendto, $uid);
            $user_email_html .= '</div></div></div>';
        }
        //  Display CAPTCHA?
        $captcha_html = '';
        $captcha = $o['captcha'] === 'on';
        //  Generate the CAPTCHA HTML if requested
        if ($captcha) {
            $captcha_operators = array();
            if ((int) $wpgform_options['captcha_operator_plus'] === 1) {
                $captcha_operators[] = '+';
            }
            if ((int) $wpgform_options['captcha_operator_minus'] === 1) {
                $captcha_operators[] = '-';
            }
            if ((int) $wpgform_options['captcha_operator_mult'] === 1) {
                $captcha_operators[] = '*';
            }
            //  Default to addition if for some reason no operators are enabled
            if (empty($captcha_operators)) {
                $captcha_operators[] = '+';
            }
            //  Get random operator for A and B terms
            $op1 = $captcha_operators[rand(0, count($captcha_operators) - 1)];
            //  Get random operator for including C term when using 3 terms, use '+' otherwise
            $op2 = (int) $wpgform_options['captcha_terms'] === 3 ? $captcha_operators[rand(0, count($captcha_operators) - 1)] : '+';
            //  Generate a random value for A
            $a = rand(0, 19);
            //  Generate a random value for B
            $b = rand(0, 19);
            //  Generate a random value for C only when using 3 terms, use 0 otherwise
            $c = (int) $wpgform_options['captcha_terms'] === 3 ? rand(0, 19) : 0;
            if ((int) $wpgform_options['captcha_terms'] === 2) {
                $x = eval('return sprintf("%s%s%s", $a, $op1, $b);');
            } else {
                $x = eval('return sprintf("%s%s%s%s%s", $a, $op1, $b, $op2, $c);');
            }
            self::$wpgform_captcha = array('a' => $a, 'b' => $b, 'c' => $c, 'x' => $x);
            //  Build the CAPTCHA HTML
            $captcha_html .= '<div class="wpgform-captcha">';
            $captcha_html .= sprintf('<div class="%sss-item %sss-item-required %sss-text">', $prefix, $prefix, $prefix);
            $captcha_html .= sprintf('<div class="%sss-form-entry">', $prefix);
            if ((int) $wpgform_options['captcha_terms'] === 2) {
                $captcha_html .= sprintf('<label for="%swpgform-captcha" class="%sss-q-title">%s %s %s %s ?', $uid, $prefix, __('What is', WPGFORM_I18N_DOMAIN), $a, $op1, $b);
            } else {
                $captcha_html .= sprintf('<label for="%swpgform-captcha" class="%sss-q-title">%s %s %s %s %s %s?', $uid, $prefix, __('What is', WPGFORM_I18N_DOMAIN), $a, $op1, $b, $op2, $c);
            }
            $captcha_html .= sprintf('<span class="%sss-required-asterisk">*</span></label>', $prefix);
            $captcha_html .= sprintf('<label for="%swpgform-captcha" class="%sss-q-help"></label>', $uid, $prefix);
            $captcha_html .= sprintf('<input style="width: 100px;" type="text" id="%swpgform-captcha" class="%sss-q-short" value="" name="%swpgform-captcha">', $uid, $prefix, $uid);
            $captcha_html .= '</div></div>';
            //  Add in the optional CAPTCHA description if one has been set
            if (!empty($wpgform_options['captcha_description'])) {
                $captcha_html .= sprintf('<div class="wpgform-captcha-description">%s</div>', $wpgform_options['captcha_description']);
            }
            $captcha_html .= '</div>';
        }
        //  Use jQuery validation?  Force it on when CAPTCHA is on
        $validation = $o['validation'] === 'on' | $captcha;
        //  Output the H1 title included in the Google Form?
        $title = $o['title'] === 'on';
        //  Map H1 tags to H2 tags?  Apparently helps SEO ...
        $maph1h2 = $o['maph1h2'] === 'on';
        //  Insert <br> elements between labels and input boxes?
        $br = $o['br'] === 'on';
        //  Google Legal Stuff?
        $legal = $o['legal'] !== 'off';
        //  Should form be set to readonly?
        $readonly = $o['readonly'] === 'on';
        //  Should email confirmation be sent to admin?
        $email = $o['email'] === 'on';
        //  Who should email confirmation be sent to?
        if (is_email($o['sendto'])) {
            $sendto = $o['sendto'];
        }
        //  How many columns?
        $columns = $o['columns'];
        //  Minimum columnize width
        $minvptwidth = $o['minvptwidth'];
        //  Column order?
        $columnorder = $o['columnorder'] == 'right-to-left' ? 'right' : 'left';
        //  The Unite theme from Paralleus mucks with the submit buttons
        //  which breaks the ability to submit the form to Google correctly.
        //  This hack will "unbreak" the submit buttons.
        $unitethemehack = $o['unitethemehack'] === 'on';
        if (WPGFORM_DEBUG) {
            wpgform_whereami(__FILE__, __LINE__, 'ConstructGoogleForm');
        }
        //  Show the custom confirmation via AJAX instead of redirect?
        $style = $o['style'] === 'none' ? null : $o['style'];
        // Use WP Transient API Cache?
        $use_transient = $o['use_transient'] === 'on';
        $transient_time = $o['transient_time'];
        //  WordPress converts all of the ampersand characters to their
        //  appropriate HTML entity or some variety of it.  Need to undo
        //  that so the URL can be actually be used.
        $form = str_replace(array('&#038;', '&#38;', '&amp;'), '&', $form);
        if (!is_null($confirm)) {
            $confirm = str_replace(array('&#038;', '&#38;', '&amp;'), '&', $confirm);
        }
        //  If there were any preset values to pass into the form, add them to the URL
        if (!empty($presets)) {
            //  The name of the form fields are munged, they need
            //  to be restored before the parameters can be posted
            //  so they match what Google expects.
            $patterns = array('/entry_([0-9]+)_(single|group)_/', '/entry_([0-9]+)_/', '/entry_([0-9]+)/');
            $replacements = array('entry.\\1.\\2.', 'entry.\\1.', 'entry.\\1');
            foreach ($replacements as $key => $value) {
                $replacements[$key] = sprintf('%s%s', $uid, $value);
            }
            foreach ($presets as $key => $value) {
                $presets[preg_replace($patterns, $replacements, $key)] = urlencode($value);
                //  Really shouldn't need both forms of the field but to
                //  handle old and new Google Forms we keep both.  This may
                //  go away once Google completely converts to the new version
                //  of Google Forms.
                $presets[$key] = urlencode($value);
                //unset($presets[$key]) ;
            }
            $form = add_query_arg($presets, $form);
        }
        //  The initial rendering of the form content is done using this
        //  "remote get", all subsequent renderings will be the result of
        //  "post processing".
        if (!self::$posted) {
            if ($use_transient && is_multisite()) {
                if (false === (self::$response = get_site_transient(WPGFORM_FORM_TRANSIENT . $o['id']))) {
                    // There was no transient, so let's regenerate the data and save it
                    self::$response = wp_remote_get($form, array('sslverify' => false, 'timeout' => $timeout, 'redirection' => 12, 'user-agent' => $_SERVER['HTTP_USER_AGENT']));
                    set_site_transient(WPGFORM_FORM_TRANSIENT . $o['id'], self::$response, $transient_time * MINUTE_IN_SECONDS);
                }
            } elseif ($use_transient && !is_multisite()) {
                if (false === (self::$response = get_transient(WPGFORM_FORM_TRANSIENT . $o['id']))) {
                    // There was no transient, so let's regenerate the data and save it
                    self::$response = wp_remote_get($form, array('sslverify' => false, 'timeout' => $timeout, 'redirection' => 12, 'user-agent' => $_SERVER['HTTP_USER_AGENT']));
                    set_transient(WPGFORM_FORM_TRANSIENT . $o['id'], self::$response, $transient_time * MINUTE_IN_SECONDS);
                }
            } else {
                self::$response = wp_remote_get($form, array('sslverify' => false, 'timeout' => $timeout, 'redirection' => 12, 'user-agent' => $_SERVER['HTTP_USER_AGENT']));
            }
        }
        //  Retrieve the HTML from the URL
        if (is_wp_error(self::$response)) {
            $error_string = self::$response->get_error_message();
            echo '<div id="message" class="wpgform-google-error"><p>' . $error_string . '</p></div>';
            if (WPGFORM_DEBUG) {
                wpgform_whereami(__FILE__, __LINE__, 'ConstructGoogleForm');
                wpgform_preprint_r(self::$response);
            }
            //  Clean up the transient if an error is encountered
            if ($use_transient && is_multisite()) {
                delete_site_transient(WPGFORM_FORM_TRANSIENT . $o['id']);
            } elseif ($use_transient) {
                delete_transient(WPGFORM_FORM_TRANSIENT . $o['id']);
            }
            return sprintf('<div class="wpgform-google-error gform-google-error">%s</div>', __('Unable to retrieve Google Form.  Please try reloading this page.', WPGFORM_I18N_DOMAIN));
        } else {
            $html = self::$response['body'];
        }
        if (WPGFORM_DEBUG) {
            wpgform_whereami(__FILE__, __LINE__, 'ConstructGoogleForm');
            wpgform_htmlspecialchars_preprint_r(self::$response);
            //wpgform_htmlspecialchars_preprint_r($html) ;
        }
        //  Filter the HTML unlesss explicitly told not to
        if ((int) $wpgform_options['disable_html_filtering'] !== 1) {
            //  Need to filter the HTML retrieved from the form and strip off the stuff
            //  we don't want.  This gets rid of the HTML wrapper from the Google page.
            $allowed_tags = array('a' => array('href' => array(), 'title' => array(), 'target' => array(), 'class' => array()), 'b' => array(), 'abbr' => array('title' => array()), 'acronym' => array('title' => array()), 'code' => array(), 'pre' => array(), 'em' => array(), 'strong' => array(), 'ul' => array(), 'ol' => array(), 'li' => array(), 'p' => array(), 'br' => array(), 'div' => array('class' => array()), 'h1' => array('class' => array()), 'h2' => array('class' => array()), 'h3' => array('class' => array()), 'h4' => array('class' => array()), 'h5' => array('class' => array()), 'h6' => array('class' => array()), 'i' => array(), 'img' => array('class' => array(), 'alt' => array(), 'title' => array(), 'src' => array()), 'label' => array('class' => array(), 'for' => array()), 'input' => array('id' => array(), 'name' => array(), 'class' => array(), 'type' => array(), 'value' => array(), 'checked' => array()), 'select' => array('name' => array(), 'for' => array(), 'checked' => array()), 'option' => array('value' => array(), 'selected' => array()), 'form' => array('id' => array(), 'class' => array(), 'action' => array(), 'method' => array(), 'target' => array(), 'onsubmit' => array()), 'script' => array('type' => array()), 'span' => array('class' => array(), 'style' => array()), 'style' => array(), 'table' => array('class' => array(), 'style' => array()), 'tbody' => array('class' => array(), 'style' => array()), 'textarea' => array('id' => array(), 'name' => array(), 'class' => array(), 'type' => array(), 'value' => array(), 'rows' => array(), 'cols' => array()), 'thead' => array('class' => array(), 'style' => array()), 'tr' => array('class' => array()), 'td' => array('class' => array(), 'style' => array()));
            //  Process the HTML
            $html = wp_kses($html, $allowed_tags);
        }
        $patterns = array('/entry\\.([0-9]+)\\.(single|group)\\./', '/entry\\.([0-9]+)_/', '/entry\\.([0-9]+)/', '/entry_([0-9]+)\\.(single|group)\\./', '/entry_([0-9]+)_/', '/entry_([0-9]+)/');
        $replacements = array('entry.\\1_\\2_', 'entry.\\1_', 'entry.\\1', 'entry_\\1_\\2_', 'entry_\\1_', 'entry_\\1');
        foreach ($replacements as $key => $value) {
            $replacements[$key] = sprintf('%s%s', $uid, $value);
        }
        //  Handle form id attribute
        $patterns[] = '/id="ss-form"/';
        $replacements[] = sprintf('id="%sss-form"', $uid);
        //  Handle submit button id attribute
        $patterns[] = '/id="ss-submit"/';
        $replacements[] = sprintf('id="%sss-submit"', $uid);
        //  Handle "submit another response" link
        //$patterns[] = '/' . $form . '/' ;
        //$replacements[] = "ZZZ" ;
        //  Process HTML replacements
        $html = preg_replace($patterns, $replacements, $html);
        if (WPGFORM_DEBUG) {
            wpgform_whereami(__FILE__, __LINE__, 'ConstructGoogleForm');
            wpgform_htmlspecialchars_preprint_r($html);
        }
        //  Did we end up with anything prior to the first DIV?  If so, remove it as
        //  it should have been removed by wp_kses() but sometimes stuff slips through!
        $first_div = strpos($html, '<div');
        if (WPGFORM_DEBUG) {
            wpgform_whereami(__FILE__, __LINE__, 'ConstructGoogleForm');
            wpgform_htmlspecialchars_preprint_r($html);
            wpgform_preprint_r($first_div);
        }
        //  If there are no DIVs, then we have garbage and should stop now!
        if ($first_div === false) {
            return sprintf('<div class="wpgform-google-error gform-google-error">%s</div>', __('Unexpected content encountered, unable to retrieve Google Form.', WPGFORM_I18N_DOMAIN));
        }
        if (WPGFORM_DEBUG) {
            wpgform_whereami(__FILE__, __LINE__, 'ConstructGoogleForm');
        }
        //  Strip off anything prior to the first  DIV, we don't want it.
        if ($first_div !== 0) {
            $html = substr($html, $first_div);
        }
        //  The Google Forms have some Javascript embedded in them which needs to be
        //  stripped out.  I am not sure why it is in there, it doesn't appear to do
        //  much of anything useful.
        $html = preg_replace('#<script[^>]*>.*?</script>#is', '<!-- Google Forms unnessary Javascript removed -->' . PHP_EOL, $html);
        //  Allow H1 tags through if user wants them (which is the default)
        if (!$title) {
            $html = preg_replace('#<h1[^>]*>.*?</h1>#is', '', $html);
        }
        //  Map H1 tags to H2 tags?
        if ($maph1h2) {
            $html = preg_replace('/<h1/i', '<h2', $html);
            $html = preg_replace('/h1>/i', 'h2>', $html);
        }
        //  Augment labels with some sort of a suffix?
        if (!is_null($suffix)) {
            $html = preg_replace('/<\\/label>/i', "{$suffix}</label>", $html);
        }
        //  Need to extract form action and rebuild form tag, and add hidden field
        //  which contains the original action.  This action is used to submit the
        //  form via wp_remote_post().
        if (preg_match_all('/(action(\\s*)=(\\s*)([\\"\'])?(?(1)(.*?)\\2|([^\\s\\>]+)))/', $html, $matches)) {
            for ($i = 0; $i < count($matches[0]); $i++) {
                $action = $matches[0][$i];
            }
            //$html = str_replace($action, 'action="' . get_permalink(get_the_ID()) . '"', $html) ;
            $html = str_replace($action, 'action=""', $html);
            $action = preg_replace(array('/^action=/i', '/"/'), array('', ''), $action);
            $action = base64_encode(serialize($action));
            $wgformid = self::$wpgform_form_id++;
            //  Add some hidden input fields to faciliate control of subsquent actions
            $html = preg_replace('/<\\/form>/i', "<input type=\"hidden\" value=\"{$action}\" name=\"wpgform-action\"><input type=\"hidden\" value=\"{$wgformid}\" name=\"wpgform-form-id\"></form>", $html);
        } else {
            $action = null;
            $wgformid = self::$wpgform_form_id++;
        }
        //  Handle "placeholders"
        $fields = wpgform_placeholder_meta_box_content(true);
        foreach ($fields as $field) {
            if ('placeholder' == $field['type']) {
                //  When using deprecated gform shortcode there is no meta data
                if (!array_key_exists('id', $o)) {
                    continue;
                }
                $meta_field = get_post_meta($o['id'], $field['id'], true);
                $meta_type = get_post_meta($o['id'], $field['type_id'], true);
                $meta_value = get_post_meta($o['id'], $field['value_id'], true);
                if (!empty($meta_field)) {
                    foreach ($meta_field as $key => $value) {
                        $pattern = sprintf('/name="%s"/', $meta_field[$key]);
                        $replacement = sprintf('name="%s" placeholder="%s"', $meta_field[$key], $meta_value[$key]);
                        $html = preg_replace($pattern, $replacement, $html);
                    }
                }
            }
        }
        //  The Unite theme from Paralleus mucks with the submit buttons
        //  which breaks the ability to submit the form to Google correctly.
        //  This hack will "unbreak" the submit buttons.
        if ($unitethemehack) {
            $html = preg_replace('/<input type="submit"/i', '<input class="noStyle" type="submit"', $html);
        }
        if (WPGFORM_DEBUG) {
            wpgform_whereami(__FILE__, __LINE__, 'ConstructGoogleForm');
        }
        //  Encode all of the short code options so they can
        //  be referenced if/when needed during form processing.
        $html = preg_replace('/<\\/form>/i', "<input type=\"hidden\" value=\"" . base64_encode(serialize($o)) . "\" name=\"wpgform-options\"></form>", $html);
        //  Output custom CSS?
        $css = '';
        if ($wpgform_options['custom_css'] == 1 && !empty($wpgform_options['custom_css_styles'])) {
            $css .= '<style>' . $wpgform_options['custom_css_styles'] . '</style>';
        }
        //  Output form specific custom CSS?
        if ($wpgform_options['custom_css'] == 1 && !empty($o['form_css'])) {
            $css .= '<style>' . $o['form_css'] . '</style>';
        }
        //  Tidy up CSS to ensure it isn't affected by 'the_content' filters
        $patterns = array('/[\\r\\n]+/', '/ +/');
        $replacements = array('', ' ');
        $css = preg_replace($patterns, $replacements, $css) . PHP_EOL;
        //  Output Javscript for form validation, make sure any class prefix is included
        //  Need to fix the name arguments for checkboxes so PHP will pass them as an array correctly.
        //  This jQuery script reformats the checkboxes so that Googles Python script will read them.
        //$vMsgs_js = &self::$vMsgs_js ;
        //$vRules_js = &self::$vRules_js ;
        $vMsgs_js = array();
        $vRules_js = array();
        $js = sprintf('
<script type="text/javascript">
//  Google Forms v%s jQuery script
jQuery(document).ready(function($) {
', WPGFORM_VERSION);
        //  Insert breaks between labels and input fields?
        if ($br) {
            $js .= sprintf('
    //  Insert br elements before input and textarea boxes
    $("#%sss-form textarea").before("<br/>");
    $("#%sss-form input[type=text]").before("<br/>");
', $uid, $uid);
        }
        //  Did short code specify a CSS prefix?
        if (!is_null($prefix)) {
            $js .= sprintf('
    //  Manipulate CSS classes to account for CSS prefix
    $("div.ss-form-container [class]").each(function(i, el) {
        var c = $(this).attr("class").split(" ");
        for (var i = 0; i < c.length; ++i) {
            $(this).removeClass(c[i]).addClass("%s" + c[i]);
        }
    });
    $("div.ss-form-container").removeClass("ss-form-container").addClass("%s" + "ss-form-container");
', $prefix, $prefix);
        }
        //  Hide Google Legal Stuff?
        if (!(bool) $legal) {
            $js .= sprintf('
    //  Hide Google Legal content
    $("div.%sss-legal").hide();
', $prefix);
            //  Somewhat unsupported but it works, a Google Spreadsheet can
            //  be rendered by Google Forms.  If the Legal is disabled,
            //  the block of code that Google adds to the form is removed.
            $js .= sprintf('
    //  Remove Powered by Google content
    $("div div span.powered").parent().empty();
');
        }
        //  Is Email User enabled?
        if ($user_email) {
            $js .= sprintf('
    //  Construct Email User Validation
    if ($("#%sss-form input[type=submit][name=submit]").length) {
        $("#%sss-form input[type=submit][name=submit]").before(\'%s\');
        $("div.wpgform-user-email").show();
        $.validator.addClassRules("wpgform-user-email", {
            required: true
        });
    }
', $uid, $uid, $user_email_html);
            $vRules_js[] = '    "wpgform-user-email": { email: true }';
            $vMsgs_js[] = sprintf('    "wpgform-user-email": "%s"', __('A valid email address is required.', WPGFORM_I18N_DOMAIN));
        }
        //  Is CAPTCHA enabled?
        if ($captcha) {
            $js .= sprintf('
    //  Construct CAPTCHA
    $.validator.methods.equal = function(value, element, param) { return value == param; };
    if ($("#%sss-form input[type=submit][name=submit]").length) {
        $("#%sss-form input[type=submit][name=submit]").before(\'%s\');
        $("div.wpgform-captcha").show();
        $.validator.addClassRules("wpgform-captcha", {
            required: true,
        });
    }
', $uid, $uid, $captcha_html, self::$wpgform_captcha['c']);
            $vRules_js[] = sprintf('    "%swpgform-captcha": { equal: %s }', $uid, self::$wpgform_captcha['x']);
            $vMsgs_js[] = sprintf('    "%swpgform-captcha": "%s" ', $uid, __('Incorrect answer.', WPGFORM_I18N_DOMAIN));
        }
        //  Build extra jQuery Validation rules
        $fields = wpgform_validation_meta_box_content(true);
        $patterns = array('/^entry.([0-9]+).(single|group)./', '/^entry.([0-9]+)_/', '/^entry.([0-9]+)/');
        $replacements = array('entry_\\1_\\2_', 'entry_\\1_', 'entry_\\1');
        foreach ($fields as $field) {
            if ('validation' == $field['type']) {
                //  When using deprecated gform shortcode there is no meta data
                if (!array_key_exists('id', $o)) {
                    continue;
                }
                $meta_field = get_post_meta($o['id'], $field['id'], true);
                $meta_type = get_post_meta($o['id'], $field['type_id'], true);
                $meta_value = get_post_meta($o['id'], $field['value_id'], true);
                if (!empty($meta_field)) {
                    foreach ($meta_field as $key => $value) {
                        $mf = preg_replace($patterns, $replacements, $meta_field[$key]);
                        if (!empty($value)) {
                            if ($meta_type[$key] == 'regex') {
                                $extras[$value][] = sprintf('%s: "%s"', $meta_type[$key], empty($meta_value[$key]) ? 'true' : $meta_value[$key]);
                            } elseif ($meta_type[$key] == 'required' || $meta_type[$key] == 'email') {
                                $vRules_js[] = sprintf('    "%s": { %s: true }', $value, $meta_type[$key]);
                                if (!empty($meta_value[$key])) {
                                    $vMsgs_js[] = sprintf('    "%s": "%s"', $value, $meta_value[$key]);
                                }
                            } else {
                                $extras[$value][] = sprintf('%s: %s', $meta_type[$key], empty($meta_value[$key]) ? 'true' : $meta_value[$key]);
                            }
                        }
                    }
                }
            }
        }
        //  Include jQuery validation?
        if ($validation) {
            $js .= sprintf('
    //  jQuery inline validation
    $("div > .ss-item-required textarea").addClass("wpgform-required");
    $("div > .ss-item-required input:not(.ss-q-other)").addClass("wpgform-required");
    $("div > .%sss-item-required textarea").addClass("wpgform-required");
    $("div > .%sss-item-required input:not(.%sss-q-other)").addClass("wpgform-required");
    $.validator.addClassRules("wpgform-required", { required: true });
    $.validator.addMethod("regex", function(value, element, regexp) { var re = new RegExp(regexp); return this.optional(element) || re.test(value); }, "Please check your input.");
', $prefix, $prefix, $prefix, '', '', __('Please check your input.', WPGFORM_I18N_DOMAIN));
        }
        //  Now the tricky part - need to output rules and messages
        if ($validation) {
            $js .= sprintf('
    $("#%sss-form").validate({
        invalidHandler: function(event, validator) {
            // \'this\' refers to the form
            var errors = validator.numberOfInvalids();
            if (errors) {
              var message = errors == 1
                ? \'You missed 1 field. It has been highlighted\'
                : \'You missed \' + errors + \' fields. They have been highlighted\';
              $("div.error span").html(message);
              $("div.error").show();
              //$("div.error-message").show();
            } else {
              $("div.error").hide();
              //$("div.error-message").hide();
            }
          },
        //errorClass: "wpgform-error",
        errorClass: "error-message",
        rules: {%s', $uid, PHP_EOL);
            if (!empty($extras)) {
                foreach ($extras as $key => $value) {
                    $js .= sprintf('           "%s%s": {', $uid, $key);
                    foreach ($value as $vk => $extra) {
                        $k = array_keys($value);
                        $js .= sprintf('%s%s', $extra, end($k) === $vk ? '}' : ', ');
                    }
                    $k = array_keys($extras);
                    $js .= sprintf('%s%s%s', end($k) === $key ? '' : ',', PHP_EOL, end($k) === $key ? '        ' : '');
                }
            }
            if (!empty($vRules_js)) {
                //  Clean up JS if extras were already output
                if (!empty($extras)) {
                    $js = sprintf('%s,%s', substr($js, 0, strrpos($js, '}') + 1), PHP_EOL);
                }
                foreach ($vRules_js as $rk => $r) {
                    $k = array_keys($vRules_js);
                    $js .= sprintf('       %s%s', $r, end($k) === $rk ? sprintf('%s        },', PHP_EOL) : sprintf(',%s', PHP_EOL));
                }
            } else {
                $js .= '},';
            }
            $js .= sprintf('%s        messages: {%s', PHP_EOL, PHP_EOL);
            if (!empty($vMsgs_js)) {
                foreach ($vMsgs_js as $mk => $m) {
                    $k = array_keys($vMsgs_js);
                    $js .= sprintf('       %s%s', $m, end($k) === $mk ? sprintf('%s        },', PHP_EOL) : sprintf(',%s', PHP_EOL));
                }
            } else {
                $js .= '        }';
            }
            $js .= '
    }) ;' . PHP_EOL;
        }
        //  Handle hidden fields
        $u = wp_get_current_user();
        $unknown = __('Unknown', WPGFORM_I18N_DOMAIN);
        $values = array('value' => $unknown, 'url' => array_key_exists('URL', $_SERVER) ? $_SERVER['URL'] : $unknown, 'timestamp' => current_time('Y-m-d H:i:s'), 'remote_addr' => array_key_exists('REMOTE_ADDR', $_SERVER) ? $_SERVER['REMOTE_ADDR'] : $unknown, 'remote_host' => array_key_exists('REMOTE_HOST', $_SERVER) ? $_SERVER['REMOTE_HOST'] : $unknown, 'http_referer' => array_key_exists('HTTP_REFERER', $_SERVER) ? $_SERVER['HTTP_REFERER'] : $unknown, 'http_user_agent' => array_key_exists('HTTP_USER_AGENT', $_SERVER) ? $_SERVER['HTTP_USER_AGENT'] : $unknown, 'user_email' => $u instanceof WP_User ? $u->user_email : $unknown, 'user_login' => $u instanceof WP_User ? $u->user_login : $unknown);
        //  We'll ignore the optional value for any field type except value, url, or timestamp
        $ignore = array_slice(array_keys($values), 3);
        //  Handle and "hiddenfields"
        $fields = wpgform_hiddenfields_meta_box_content(true);
        $patterns = array('/^entry.([0-9]+).(single|group)./', '/^entry.([0-9]+)_/', '/^entry.([0-9]+)/');
        $replacements = array('entry_\\1_\\2_', 'entry_\\1_', 'entry_\\1');
        foreach ($fields as $field) {
            if ('hiddenfield' == $field['type']) {
                //  When using deprecated gform shortcode there is no meta data
                if (!array_key_exists('id', $o)) {
                    continue;
                }
                $meta_field = get_post_meta($o['id'], $field['id'], true);
                $meta_type = get_post_meta($o['id'], $field['type_id'], true);
                $meta_value = get_post_meta($o['id'], $field['value_id'], true);
                foreach ($replacements as $key => $value) {
                    $replacements[$key] = sprintf('%s%s', $uid, $value);
                }
                if (!empty($meta_field)) {
                    foreach ($meta_field as $key => $value) {
                        $mf = preg_replace($patterns, $replacements, $meta_field[$key]);
                        if (empty($meta_value[$key]) || in_array($meta_type[$key], $ignore)) {
                            $meta_value[$key] = $values[$meta_type[$key]];
                        }
                        if (!empty($mf)) {
                            $js .= sprintf('    $("#%s").val("%s");%s', $mf, $meta_value[$key], PHP_EOL);
                            $js .= sprintf('    $("#%s").parent().css("display", "none");%s', $mf, PHP_EOL);
                        }
                    }
                }
            }
        }
        //  Always include the jQuery to clean up the checkboxes
        $js .= sprintf('
    //  Fix checkboxes to work with Google Python
    $("div.%sss-form-container input:checkbox").each(function(index) {
        this.name = this.name + \'[]\';
    });
', $prefix);
        //    if ($("div.%sss-radio label:last+span.%sss-q-other-container").length) {
        //        $("div.%sss-radio label:last+span.%sss-q-other-container").prev().contents().filter(function() {
        //            return this.nodeType == 3;
        //        })[0].nodeValue = "%s";
        //    }
        //  Replace Google supplied text?  Form specific or global?
        if ($local_override_google_default_text) {
            $js .= sprintf('
    //  Replace Google supplied text with "form specific override" values
    $("div.%sss-required-asterisk").text("* %s");
    $("div.%sss-radio div.%sss-printable-hint").text("%s");
    if ($("div.%sss-radio label:last+span.%sss-q-other-container").length) {
        $("div.%sss-radio label:last+span.%sss-q-other-container").prev().find("span.%sss-choice-label").text("%s");
    }
    $("div.%sss-checkbox div.%sss-printable-hint").text("%s");
    $("div.%sss-form-container :input[name=\\"back\\"]").attr("value", "\\u00ab %s");
    $("div.%sss-form-container :input[name=\\"continue\\"]").attr("value", "%s \\u00bb");
    $("div.%sss-form-container :input[name=\\"submit\\"]").attr("value", "%s");', $prefix, $o['required_text_override'], $prefix, $prefix, $o['radio_buttons_text_override'], $prefix, $prefix, $prefix, $prefix, $prefix, $o['radio_buttons_other_text_override'], $prefix, $prefix, $o['check_boxes_text_override'], $prefix, $o['back_button_text_override'], $prefix, $o['continue_button_text_override'], $prefix, $o['submit_button_text_override']);
        } elseif ($global_override_google_default_text) {
            $js .= sprintf('
    //  Replace Google supplied text with "global override" values
    $("div.%sss-required-asterisk").text("* %s");
    $("div.%sss-radio div.%sss-printable-hint").text("%s");
    if ($("div.%sss-radio label:last+span.%sss-q-other-container").length) {
        $("div.%sss-radio label:last+span.%sss-q-other-container").prev().contents().filter(function() {
            return this.nodeType == 3;
        })[0].nodeValue = "%s";
    }
    $("div.%sss-checkbox div.%sss-printable-hint").text("%s");
    $("div.%sss-form-container :input[name=\\"back\\"]").attr("value", "\\u00ab %s");
    $("div.%sss-form-container :input[name=\\"continue\\"]").attr("value", "%s \\u00bb");
    $("div.%sss-form-container :input[name=\\"submit\\"]").attr("value", "%s");', $prefix, $wpgform_options['required_text_override'], $prefix, $prefix, $wpgform_options['radio_buttons_text_override'], $prefix, $prefix, $prefix, $prefix, $wpgform_options['radio_buttons_other_text_override'], $prefix, $prefix, $wpgform_options['check_boxes_text_override'], $prefix, $wpgform_options['back_button_text_override'], $prefix, $wpgform_options['continue_button_text_override'], $prefix, $wpgform_options['submit_button_text_override']);
        }
        //  Before closing the <script> tag, is the form read only?
        if ($readonly) {
            $js .= sprintf('
    //  Put form in read-only mode
    $("div.%sss-form-container :input").attr("disabled", true);
        ', $prefix);
        }
        //  Before closing the <script> tag, is this the confirmation
        //  AND do we have a custom confirmation page or alert message?
        if (self::$posted && is_null($action) && !is_null($alert) && self::$wpgform_submitted_form_id == self::$wpgform_form_id - 1) {
            $js .= PHP_EOL . '    alert("' . $alert . '") ;';
        }
        //  Add jQuery to support multiple columns
        $js .= sprintf('
    //  Columnize the form
    //  Make sure we don\'t split labels and input fields
    $("div.%sss-item").addClass("wpgform-dontsplit");
    //  Wrap all of the form content in a DIV so it can be split
    $("#%sss-form").wrapInner("<div style=\\"border: 0px dashed blue;\\" class=\\"wpgform-wrapper\\"></div>");
    //  Columnize the form content taking into account the new minwidth setting.
    $(function(){
        var width = $(window).width();
        var minwidth = %s;
        if (minwidth == 0 || width > minwidth) {
        $(".wpgform-wrapper").columnize({
            columns : %s,
            columnFloat : "%s",
            cssClassPrefix : "wpgform"
        });
        //  Wrap each column so it can styled easier
        $(".wpgform-column").wrapInner("<div style=\\"border: 0px dashed green;\\" class=\\"wpgform-column-wrapper\\"></div>");
        }
    });
    $("#%sss-form").append("<div style=\\"border: 0px dashed black; clear: both;\\"></div>");
    $("div.%sss-form-container").after("<div style=\\"border: 0px dashed black; clear: both;\\"></div>");
        ', $prefix, $uid, $minvptwidth, $columns, $columnorder, $uid, $prefix);
        //  Remap the re-submit form URL
        $js .= sprintf('
    //  Change "Submit another response" URL to point to WordPress URL
    //  Changing the HREF attribute to an empty string results in the URL
    //  being the page the form is on.
    $("a.ss-bottom-link").attr("href", "");
');
        //  Load the confirmation URL via AJAX?
        if (self::$posted && is_null($action) && !is_null($confirm) && self::$wpgform_submitted_form_id == self::$wpgform_form_id - 1 && $style === WPGFORM_CONFIRM_AJAX && !self::$post_error) {
            $js .= PHP_EOL . '    //  Confirmation page by AJAX page load';
            //$js .= PHP_EOL . '    $("body").load("' . $confirm . ' body") ;' ;
            $js .= PHP_EOL . '    $.get( "' . $confirm . '", function( data ) {
        $( ".result" ).html( data );
    });';
        }
        //  Load the confirmation URL via Redirect?
        if (self::$posted && is_null($action) && !is_null($confirm) && self::$wpgform_submitted_form_id == self::$wpgform_form_id - 1 && $style === WPGFORM_CONFIRM_REDIRECT && !self::$post_error) {
            $js .= PHP_EOL . '    //  Confirmation page by redirect';
            $js .= PHP_EOL . '    window.location.replace("' . $confirm . '") ;';
        }
        $js .= PHP_EOL . '});' . PHP_EOL . '</script>';
        //  Tidy up Javascript to ensure it isn't affected by 'the_content' filters
        //$js = preg_replace($patterns, $replacements, $js) . PHP_EOL ;
        //  Send email?
        if (self::$posted && is_null($action) && ($email || $user_email)) {
            if (is_null($sendto) || empty($sendto)) {
                $sendto = get_bloginfo('admin_email');
            }
            //  If sending notification email, need to account for more than one address
            if ($email) {
                foreach (explode(';', $sendto) as $s) {
                    if (is_email(trim($s))) {
                        wpGForm::SendConfirmationEmail($wpgform_options['email_format'], trim($s), $results);
                    }
                }
            }
            //  Send confirmation email?
            if ($user_email && is_email(self::$wpgform_user_sendto)) {
                wpGForm::SendConfirmationEmail($wpgform_options['email_format'], self::$wpgform_user_sendto);
            }
        }
        //  Check browser compatibility?  The jQuery used by this plugin may
        //  not work correctly on old browsers or IE running in compatibility mode.
        if ($wpgform_options['browser_check'] == 1) {
            require_once ABSPATH . '/wp-admin/includes/dashboard.php';
            //  Let's check the browser version just in case ...
            self::$browser_check = wp_check_browser_version();
            if (self::$browser_check && self::$browser_check['upgrade']) {
                if (self::$browser_check['insecure']) {
                    $css .= '<div class="wpgform-browser-warning gform-browser-warning"><h4>' . __('Warning:  You are using an insecure browser!') . '</h4></div>';
                } else {
                    $css .= '<div class="wpgform-browser-warning gform-browser-warning"><h4>' . __('Warning:  Your browser is out of date!  Please update now.') . '</h4></div>';
                }
            }
        }
        if (WPGFORM_DEBUG) {
            $debug = '<h2 class="wpgform-debug gform-debug"><a href="#" class="wpgform-debug-wrapper gform-debug-wrapper">Show wpGForm Debug Content</a></h2>';
        } else {
            $debug = '';
        }
        //  Assemble final HTML to return.  To handle pages with more than one
        //  form, Javascript, CSS, and debug control should only be rendered once!
        $onetime_html = '';
        if (WPGFORM_DEBUG) {
            printf('<h2>%s:  %s</h2>', __('Form Id:', WPGFORM_I18N_DOMAIN), self::$wpgform_form_id - 1);
            if (!is_null(self::$wpgform_submitted_form_id)) {
                printf('<h2>%s:  %s</h2>', __('Submitted Form Id', WPGFORM_I18N_DOMAIN), self::$wpgform_submitted_form_id);
            } else {
                printf('<h2>%s:</h2>', __('No Submitted Form Id', WPGFORM_I18N_DOMAIN));
            }
        }
        if (!self::$wpgform_js) {
            if (is_null(self::$wpgform_submitted_form_id) || self::$wpgform_submitted_form_id == self::$wpgform_form_id - 1) {
                //self::$wpgform_js = true ;
                self::$wpgform_footer_js .= $js;
            }
        }
        if (!self::$wpgform_css) {
            $onetime_html .= PHP_EOL . $css;
            self::$wpgform_css = true;
        }
        if (!self::$wpgform_debug) {
            $onetime_html .= $debug;
            self::$wpgform_debug = true;
        }
        $html = $onetime_html . $html;
        //  Log form submission?
        if (self::$posted && is_null($action) && $wpgform_options['form_submission_log'] == 1) {
            $unknown = __('Unknown', WPGFORM_I18N_DOMAIN);
            $log = array('url' => array_key_exists('URL', $_SERVER) ? $_SERVER['URL'] : $unknown, 'timestamp' => current_time('Y-m-d H:i:s'), 'remote_addr' => array_key_exists('REMOTE_ADDR', $_SERVER) ? $_SERVER['REMOTE_ADDR'] : $unknown, 'remote_host' => array_key_exists('REMOTE_HOST', $_SERVER) ? $_SERVER['REMOTE_HOST'] : $unknown, 'http_referer' => array_key_exists('HTTP_REFERER', $_SERVER) ? $_SERVER['HTTP_REFERER'] : $unknown, 'http_user_agent' => array_key_exists('HTTP_USER_AGENT', $_SERVER) ? $_SERVER['HTTP_USER_AGENT'] : $unknown, 'form' => array_key_exists('id', $o) ? $o['id'] : null, 'post_id' => get_the_ID());
            //  Try and log against the Google Form post ID but
            //  fall back to Post or Page ID if the old short code
            //  is being used.
            if (!is_null($log['form'])) {
                add_post_meta($log['form'], WPGFORM_LOG_ENTRY_META_KEY, $log, false);
            }
        }
        return $html;
    }
/**
 * Action to save WordPress Google Form meta box data for CPT.
 *
 */
function wpgform_save_meta_box_data($post_id)
{
    global $post;
    // verify nonce - needs to come from either a CPT Edit screen or CPT Quick Edit
    if (isset($_POST[WPGFORM_PREFIX . 'meta_box_nonce']) && wp_verify_nonce($_POST[WPGFORM_PREFIX . 'meta_box_nonce'], plugin_basename(__FILE__)) || isset($_POST[WPGFORM_PREFIX . 'meta_box_qe_nonce']) && wp_verify_nonce($_POST[WPGFORM_PREFIX . 'meta_box_qe_nonce'], plugin_basename(__FILE__))) {
        //wpgform_whereami(__FILE__, __LINE__) ;
        // check for autosave - if autosave, simply return
        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
            return $post_id;
        }
        // check permissions - make sure action is allowed to be performed
        if ('page' == $_POST['post_type']) {
            if (!current_user_can('edit_page', $post_id)) {
                return $post_id;
            }
        } elseif (!current_user_can('edit_post', $post_id)) {
            return $post_id;
        }
        //  Get the meta box fields for the appropriate CPT and
        //  return if the post isn't a CPT which shouldn't happen
        if (get_post_type($post_id) == WPGFORM_CPT_FORM) {
            $fields = array_merge(wpgform_primary_meta_box_content(true), wpgform_secondary_meta_box_content(true), wpgform_validation_meta_box_content(true), wpgform_hiddenfields_meta_box_content(true), wpgform_placeholder_meta_box_content(true), wpgform_text_overrides_meta_box_content(true));
        } else {
            return $post_id;
        }
        //  Loop through all of the fields and update what has changed
        //  accounting for the fact that Short URL fields are always
        //  updated and CPT fields are ignored in Quick Edit except for
        //  the Short URL field.
        foreach ($fields as $field) {
            //  Only update other Post Meta fields when on the edit screen - ignore in quick edit mode
            if (isset($_POST[WPGFORM_PREFIX . 'meta_box_nonce'])) {
                if (array_key_exists($field['id'], $_POST)) {
                    $new = $_POST[$field['id']];
                    $old = get_post_meta($post_id, $field['id'], true);
                    if ($new && $new != $old) {
                        update_post_meta($post_id, $field['id'], $new);
                    } elseif ('' == $new && $old) {
                        delete_post_meta($post_id, $field['id'], $old);
                    } else {
                        if ($field['id'] == WPGFORM_PREFIX . 'form' || $field['id'] == WPGFORM_PREFIX . 'transient_reset') {
                            // If form cache reset was selected, or the URL was updated
                            // let's delete the transient and uncheck the "reset" option
                            delete_transient(WPGFORM_FORM_TRANSIENT . $post_id);
                            if ($field['id'] == WPGFORM_PREFIX . 'transient_reset' && $new == 'on') {
                                $new = '';
                            }
                        }
                        //wpgform_whereami(__FILE__, __LINE__);
                    }
                } else {
                    delete_post_meta($post_id, $field['id']);
                }
            }
        }
        //  Set the post content to the shortcode for the form for rendering the CPT URL slug
        if (!wp_is_post_revision($post_id)) {
            // unhook this function so it doesn't loop infinitely
            remove_action('save_post_' . WPGFORM_CPT_FORM, 'wpgform_save_meta_box_data');
            // update the post, which calls save_post again
            wp_update_post(array('ID' => $post_id, 'post_content' => sprintf('[wpgform id=\'%d\']', $post_id)));
            // re-hook this function
            add_action('save_post_' . WPGFORM_CPT_FORM, 'wpgform_save_meta_box_data');
        }
    } else {
        return $post_id;
    }
}